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

« back to all changes in this revision

Viewing changes to ivle/chat.py

  • Committer: me at id
  • Date: 2009-01-15 05:53:45 UTC
  • mto: This revision was merged to the branch mainline in revision 1090.
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:branches%2Fstorm:1161
bin/ivle-showenrolment: Switch to ivle.database.User.enrolments from
    ivle.db.get_enrolment, removing the dependency on ivle.db.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
import cjson
23
23
import cStringIO
24
 
import hashlib
 
24
import md5
25
25
import sys
26
26
import os
27
27
import socket
28
28
import traceback
29
29
 
30
 
SOCKETTIMEOUT = 60
31
 
BLOCKSIZE = 1024
32
 
 
33
30
class Terminate(Exception):
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"""
 
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"""
36
33
    def __init__(self, final_response=None):
37
34
        self.final_response = final_response
38
35
 
39
36
    def __str__(self):
40
37
        return repr(self.final_response)
41
38
 
42
 
class ProtocolError(Exception):
43
 
    """Exception thrown when client violates the the chat protocol"""
44
 
    pass
45
39
 
46
40
def start_server(port, magic, daemon_mode, handler, initializer = None):
47
41
    # Attempt to open the socket.
59
53
            os._exit(0) # kill off parent again.
60
54
        os.umask(077)
61
55
 
62
 
        try:
63
 
            MAXFD = os.sysconf("SC_OPEN_MAX")
64
 
        except:
65
 
            MAXFD = 256
66
 
 
67
 
        # Close all file descriptors, except the socket.
68
 
        for i in xrange(MAXFD):
69
 
            if i == s.fileno():
70
 
                continue
71
 
            try:
72
 
                os.close(i)
73
 
            except OSError:
74
 
                pass
75
 
 
76
 
        si = os.open(os.devnull, os.O_RDONLY)
77
 
        os.dup2(si, sys.stdin.fileno())
78
 
 
79
 
        so = os.open(os.devnull, os.O_WRONLY)
80
 
        os.dup2(so, sys.stdout.fileno())
81
 
 
82
 
        se = os.open(os.devnull, os.O_WRONLY)
83
 
        os.dup2(se, sys.stderr.fileno())
84
 
 
85
56
    if initializer:
86
57
        initializer()
87
58
 
88
59
    while True:
89
60
        (conn, addr) = s.accept()
90
 
        conn.settimeout(SOCKETTIMEOUT)
91
61
        try:
92
62
            # Grab the input
93
 
            inp = recv_netstring(conn)
 
63
            buf = cStringIO.StringIO()
 
64
            blk = conn.recv(1024)
 
65
            while blk:
 
66
                buf.write(blk)
 
67
                try:
 
68
                    blk = conn.recv(1024, socket.MSG_DONTWAIT)
 
69
                except:
 
70
                    # Exception thrown if it WOULD block (but we
 
71
                    # told it not to wait) - ie. we are done
 
72
                    blk = None
 
73
            inp = buf.getvalue()
94
74
            env = cjson.decode(inp)
95
 
 
 
75
            
96
76
            # Check that the message is 
97
 
            digest = hashlib.md5(env['content'] + magic).hexdigest()
 
77
            digest = md5.new(env['content'] + magic).digest().encode('hex')
98
78
            if env['digest'] != digest:
99
79
                conn.close()
100
80
                continue
103
83
 
104
84
            response = handler(content)
105
85
 
106
 
            send_netstring(conn, cjson.encode(response))
 
86
            conn.sendall(cjson.encode(response))
107
87
 
108
88
            conn.close()
109
89
 
110
90
        except Terminate, t:
111
91
            # Try and send final response and then terminate
112
92
            if t.final_response:
113
 
                send_netstring(conn, cjson.encode(t.final_response))
 
93
                conn.sendall(cjson.encode(t.final_response))
114
94
            conn.close()
115
95
            sys.exit(0)
116
96
        except Exception:
123
103
                "value": str(e_val),
124
104
                "traceback": tb_dump.getvalue()
125
105
            }
126
 
            send_netstring(conn, cjson.encode(json_exc))
 
106
            conn.sendall(cjson.encode(json_exc))
127
107
            conn.close()
128
108
 
129
109
 
130
110
def chat(host, port, msg, magic, decode = True):
131
111
    sok = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
132
112
    sok.connect((host, port))
133
 
    sok.settimeout(SOCKETTIMEOUT)
134
113
    content = cjson.encode(msg)
135
 
    digest = hashlib.md5(content + magic).hexdigest()
 
114
    digest = md5.new(content + magic).digest().encode("hex")
136
115
    env = {'digest':digest,'content':content}
137
 
    json = cjson.encode(env)
138
 
 
139
 
    send_netstring(sok, json)
140
 
    inp = recv_netstring(sok)
141
 
 
 
116
    sok.send(cjson.encode(env))
 
117
 
 
118
    buf = cStringIO.StringIO()
 
119
    blk = sok.recv(1024)
 
120
    while blk:
 
121
        buf.write(blk)
 
122
        try:
 
123
            blk = sok.recv(1024, socket.MSG_DONTWAIT)
 
124
        except socket.error, e:
 
125
            if e[0] != 11:
 
126
                raise
 
127
            # Exception thrown if it WOULD block (but we
 
128
            # told it not to wait) - ie. we are done
 
129
            blk = None
 
130
    inp = buf.getvalue()
142
131
    sok.close()
143
132
 
144
133
    if decode:
146
135
    else:
147
136
        return inp
148
137
 
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)