-
Notifications
You must be signed in to change notification settings - Fork 0
/
app_server.py
186 lines (139 loc) · 5.11 KB
/
app_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/python
# This uses the above '#!' instead of '#!/usr/bin/env python' so that the
# busybox 'pidof' can find this process by name.
import ConfigParser
import logging
import logging.config
import optparse
import os
import socket
import struct
import sys
sys.path.append("/usr/bin")
import app_connected_msg
solo_conf = "/etc/sololink.conf"
# items read from solo_conf
app_server_port = 0
app_address_file = ""
def get_request(sock):
"""get one request from socket
A request is a 32-bit byte count followed by opaque data. The byte count
includes itself, i.e. the minimum byte count is four. The request is
returned as a string, with the initial byte count still included. The
purpose of "requests" at this level is really to just provide for reliable
datagrams over TCP.
"""
# Read byte count
# XXX This is inefficient but simple; we never want to read beyond the end
# of the request we are receiving, to avoid needing to save state between
# calls to get_request.
pkt = ""
while len(pkt) < 4:
try:
b = sock.recv(1)
except socket.error as se:
# Android app: disconnect wifi without closing app and you get:
# socket.error: [Errno 110] Connection timed out
logger.info("socket.error: %s", str(se))
return None
except socket.timeout as st:
# Has not been observed to happen.
logger.info("socket.timeout: %s", str(st))
return None
if not b:
return None
pkt += b
(pkt_len, ) = struct.unpack("!I", pkt)
logger.debug("packet length %d", pkt_len)
# Read the rest of the packet
# XXX Super-inefficient. Don't read beyond the end of the current packet.
while len(pkt) < pkt_len:
try:
b = sock.recv(1)
except socket.error as se:
logger.info("socket.error: %s", str(se))
return None
except socket.timeout as st:
logger.info("socket.timeout: %s", str(st))
return None
if not b:
return None
pkt += b
return pkt
def set_app_ip(app_ip):
f = open(app_address_file, "w")
f.write(app_ip + "\n")
f.close()
def unset_app_ip():
# allow it to not exist (unlink fails)
try:
os.unlink(app_address_file)
except:
pass
# app server connection loop
def app_server():
# socket we will use to listen for connections
listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
# After 1 second, start KEEPALIVE
listen_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
# 5 seconds in between keepalive pings
listen_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 5)
# 5 max fails
listen_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
listen_sock.bind(("", app_server_port))
# only allow one connection
listen_sock.listen(0)
while True:
logger.info("waiting for connection")
# wait for connection
(sock, address) = listen_sock.accept()
logger.info("connection from %s", str(address))
set_app_ip(address[0])
logger.info("app IP is %s", address[0])
app_connected_msg.send_connected()
# process requests from the client
while True:
# Get one request. We don't yet use these; it is the existence of
# the connection that is meaningful.
pkt = get_request(sock)
if not pkt:
# Remote end closed the connection
break
logger.info("received request: %s", str([hex(ord(x)) for x in pkt]))
### end while True
app_connected_msg.send_disconnected()
unset_app_ip()
logger.info("closing connection")
try:
sock.shutdown(socket.SHUT_RDWR)
except socket.error as se:
# Android app: disconnect wifi without closing app and you get:
# socket.error: [Errno 107] Transport endpoint is not connected
logger.info("socket.error: %s", str(se))
except socket.timeout as st:
# Has not been observed to happen.
logger.info("socket.timeout: %s", str(st))
sock.close()
### end while True
### end app_server()
if __name__ == "__main__":
logging.config.fileConfig(solo_conf)
logger = logging.getLogger("app")
logger.info("starting")
config = ConfigParser.SafeConfigParser()
# if the config file is not found, and empty list is returned and the
# "get" operations later fail
config.read(solo_conf)
# read configuration items
try:
app_server_port = config.getint("solo", "appServerPort")
app_address_file = config.get("solo", "appAddressFile")
except:
logger.error("error reading config from %s", solo_conf)
sys.exit(1)
parser = optparse.OptionParser("app_server [options]")
(opts, args) = parser.parse_args()
app_server()
# app_server never returns