~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/chat.py

  • Committer: David Coles
  • Date: 2010-02-24 08:19:50 UTC
  • Revision ID: coles.david@gmail.com-20100224081950-5g3w565es0dyv8aj
docs: Worksheets and Exercise developer documentation

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import socket
28
28
import traceback
29
29
 
 
30
SOCKETTIMEOUT = 60
 
31
BLOCKSIZE = 1024
 
32
 
30
33
class Terminate(Exception):
31
 
    """Exception thrown when server is to be shut down. It will attempt to sned 
32
 
    the final_response to the client and then exits"""
 
34
    """Exception thrown when server is to be shut down. It will attempt to
 
35
    send the final_response to the client and then exits"""
33
36
    def __init__(self, final_response=None):
34
37
        self.final_response = final_response
35
38
 
36
39
    def __str__(self):
37
40
        return repr(self.final_response)
38
41
 
 
42
class ProtocolError(Exception):
 
43
    """Exception thrown when client violates the the chat protocol"""
 
44
    pass
39
45
 
40
46
def start_server(port, magic, daemon_mode, handler, initializer = None):
41
47
    # Attempt to open the socket.
81
87
 
82
88
    while True:
83
89
        (conn, addr) = s.accept()
 
90
        conn.settimeout(SOCKETTIMEOUT)
84
91
        try:
85
92
            # Grab the input
86
 
            buf = cStringIO.StringIO()
87
 
            blk = conn.recv(1024)
88
 
            while blk:
89
 
                buf.write(blk)
90
 
                try:
91
 
                    blk = conn.recv(1024, socket.MSG_DONTWAIT)
92
 
                except:
93
 
                    # Exception thrown if it WOULD block (but we
94
 
                    # told it not to wait) - ie. we are done
95
 
                    blk = None
96
 
            inp = buf.getvalue()
 
93
            inp = recv_netstring(conn)
97
94
            env = cjson.decode(inp)
98
 
            
 
95
 
99
96
            # Check that the message is 
100
97
            digest = hashlib.md5(env['content'] + magic).hexdigest()
101
98
            if env['digest'] != digest:
106
103
 
107
104
            response = handler(content)
108
105
 
109
 
            conn.sendall(cjson.encode(response))
 
106
            send_netstring(conn, cjson.encode(response))
110
107
 
111
108
            conn.close()
112
109
 
113
110
        except Terminate, t:
114
111
            # Try and send final response and then terminate
115
112
            if t.final_response:
116
 
                conn.sendall(cjson.encode(t.final_response))
 
113
                send_netstring(conn, cjson.encode(t.final_response))
117
114
            conn.close()
118
115
            sys.exit(0)
119
116
        except Exception:
126
123
                "value": str(e_val),
127
124
                "traceback": tb_dump.getvalue()
128
125
            }
129
 
            conn.sendall(cjson.encode(json_exc))
 
126
            send_netstring(conn, cjson.encode(json_exc))
130
127
            conn.close()
131
128
 
132
129
 
133
130
def chat(host, port, msg, magic, decode = True):
134
131
    sok = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
135
132
    sok.connect((host, port))
 
133
    sok.settimeout(SOCKETTIMEOUT)
136
134
    content = cjson.encode(msg)
137
135
    digest = hashlib.md5(content + magic).hexdigest()
138
136
    env = {'digest':digest,'content':content}
139
 
    sok.send(cjson.encode(env))
140
 
 
141
 
    buf = cStringIO.StringIO()
142
 
    blk = sok.recv(1024)
143
 
    while blk:
144
 
        buf.write(blk)
145
 
        try:
146
 
            blk = sok.recv(1024, socket.MSG_DONTWAIT)
147
 
        except socket.error, e:
148
 
            if e[0] != 11:
149
 
                raise
150
 
            # Exception thrown if it WOULD block (but we
151
 
            # told it not to wait) - ie. we are done
152
 
            blk = None
153
 
    inp = buf.getvalue()
 
137
    json = cjson.encode(env)
 
138
 
 
139
    send_netstring(sok, json)
 
140
    inp = recv_netstring(sok)
 
141
 
154
142
    sok.close()
155
143
 
156
144
    if decode:
158
146
    else:
159
147
        return inp
160
148
 
 
149
 
 
150
def send_netstring(sok, data):
 
151
    netstring = "%d:%s,"%(len(data),data)
 
152
    sok.sendall(netstring)
 
153
 
 
154
 
 
155
def recv_netstring(sok):
 
156
    # Decode netstring
 
157
    size_buffer = []
 
158
    c = sok.recv(1)
 
159
    while c != ':':
 
160
        # Limit the Netstring to less than 10^10 bytes (~1GB).
 
161
        if len(size_buffer) >= 10:
 
162
            raise ProtocolError(
 
163
                    "Could not read Netstring size in first 9 bytes: '%s'"%(
 
164
                    ''.join(size_buffer)))
 
165
        size_buffer.append(c)
 
166
        c = sok.recv(1)
 
167
    try:
 
168
        # Message should be length plus ',' terminator
 
169
        recv_expected = int(''.join(size_buffer)) + 1
 
170
    except ValueError, e:
 
171
        raise ProtocolError("Could not decode Netstring size as int: '%s'"%(
 
172
                ''.join(size_buffer)))
 
173
 
 
174
    # Read data
 
175
    buf = []
 
176
    recv_data = sok.recv(min(recv_expected, BLOCKSIZE))
 
177
    recv_size = len(recv_data)
 
178
    while recv_size < recv_expected:
 
179
        buf.append(recv_data)
 
180
        recv_data = sok.recv(min(recv_expected-recv_size, 1024))
 
181
        recv_size = recv_size + len(recv_data)
 
182
    assert(recv_size == recv_expected)
 
183
 
 
184
    # Did we receive the correct amount?
 
185
    if recv_data[-1] != ',':
 
186
        raise ProtocolError("Netstring did not end with ','")
 
187
    buf.append(recv_data[:-1])
 
188
 
 
189
    return ''.join(buf)