-
Notifications
You must be signed in to change notification settings - Fork 0
/
ggbg-server.py
163 lines (138 loc) · 4.7 KB
/
ggbg-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
#!/usr/bin/python
import os, sys, select, socket
from select import select as select_call
from greenlet import greenlet
HOST = ''
try:
COMMAND = sys.argv[0]
PORT = int(sys.argv[1])
except:
PORT = 13111
def select(r, w, e, t=None):
'''a select() wrapper that allows tuples to represent sockets'''
x = r or w or e
if not x: return [],[],[]
x = x[0]
for i in range(len(x)): # identify proper tuple index
#print 'type check', i, type(x[i])
if isinstance(x[i], socket.socket):
break
if r: ra = zip(*r)[i]
else: ra = ()
if w: wa = zip(*w)[i]
else: wa = ()
if e: ea = zip(*e)[i]
else: ea = ()
r2, w2, e2 = select_call (ra, wa, ea, t)
return (filter(lambda a:a[i] in r2, r),
filter(lambda a:a[i] in w2, w),
filter(lambda a:a[i] in e2, e))
def tell(sock, msg1, msg2=''):
msg = msg1 + msg2
print 'telling', sock, msg
if len(msg) > 260 or len(msg) <= 0:
raise IndexError("message length too long (0 < %d < 260)" % len(msg))
sock.send(chr(len(msg)-5) + msg)
def broadcast(msg1, msg2='', exclude=()):
global socks
if not isinstance(exclude, (tuple, list)):
exclude = (exclude,)
msg = msg1 + msg2
print 'broadcasting', msg
for sock, greenlet, hostname in socks[1:]:
if sock not in exclude:
tell(sock, msg)
# Greenlet responsible for client interaction
def client(sock):
tell(sock, 'CHAT', 'Welcome to the server!')
buf = '' # packet buffer
bytes_remaining = 0
greenlet.getcurrent().parent.switch(None)
while 1:
# Received a partial packet; return control to parent greenlet while we wait for the rest of it
if bytes_remaining:
print 'SWITCH: if bytes_remaining'
greenlet.getcurrent().parent.switch(None)
# In between incoming packets
else:
# A packet was completed?
if buf:
# Pass message packet up to parent greenlet
print 'SWITCH: if buf'
greenlet.getcurrent().parent.switch(buf[:4], buf[4:])
buf = ''
# A packet is beginning...
if (not bytes_remaining) and (not buf):
# When parent greenlet returns to us, we have a new data ready
buf = sock.recv(1)
# Check for disconnect
if len(buf) == 0:
raise socket.error(107, 'apparent disconnection')
bytes_remaining = ord(buf)+5
buf = ''
# Check that there is no more data available before returning control
print
print 'select_call()'
r, w, e = select_call([sock], [], [], 0)
print 'select_call() returned'
print
if not r:
print 'SWITCH: if not r'
greenlet.getcurrent().parent.switch(None)
# Receive more data
more = sock.recv(bytes_remaining)
# Check for disconnect
if not more:
raise socket.error(107, 'apparent disconnection (packet dropped)')
# Pump message packet buffering
buf += more
bytes_remaining -= len(more)
def main():
global socks
socks = [(server, greenlet.getcurrent(), HOST or '*')]
while 1:
r, w, e = select(socks, [], socks)
for sock in e:
print 'error on', sock
for sock, proc, addr in r:
try:
if sock is server:
print 'connection incoming'
sock, addr = server.accept()
proc = greenlet(client)
socks.append( (sock, proc, addr) )
proc.switch(sock)
else:
val = proc.switch()
if val:
code, msg = val
print addr, code, msg
if code == 'CHAT':
broadcast(code, msg, exclude=sock)
except socket.error, e:
code = e[0]
if code in [104, 107]:
print 'socket disconnect:', e
else:
print 'socket error:', e
sock.close()
# Remove
for i in range(len(socks)):
if socks[i][0] == sock:
socks.remove(socks[i])
break
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(5)
print 'Serving'
greenlets = []
try:
main()
except KeyboardInterrupt:
print 'Bye'
print 'Closing socket'
server.close()
#except Exception, e:
# print 'Closing socket'
# server.close()
# raise e