Added the textbox images.
[krufty_fps.git] / server_twisted.py
blob99929087db0672e3a2afc77517b2e571cf679ccd
1 #!/usr/bin/python
3 # This is a twisted version of the server
5 import os, sys
6 from os.path import exists
8 import signal
9 from signal import *
11 from xml.dom.minidom import parse, parseString
13 from twisted.internet.protocol import DatagramProtocol
14 from twisted.internet import reactor
15 from twisted.internet import task
17 CONFIG = 'config.xml'
19 BROADCAST = 50030
20 MESSAGE = 40031
21 PASSWORD = "changethis"
22 NAME = "default"
24 ECHO_TIME = 1
26 ECHO_COUNT = 5 # this is the number of times one can ignore an echo until the server drops you
28 running = 1
30 # defining protocol stuff
32 SERVERREQUEST = "i_want_server"
33 SERVEROFFER = "Want_server?"
34 SERVERKILL = "DIE_server!!"
35 YOUTHERE = "you_there?"
36 IMHERE = "yeah,i'm_here"
37 WANTIN = "i_want_in"
38 YOUREIN = "urine"
39 IMOUT = "i_leave"
40 GETLIST = "get_list"
41 LIST = "peoples_on_server"
42 SOMEONEJOINED = "dude,someone_joined"
43 SOMEONELEFT = "someone_left"
44 YOUROUT = "get_lost_punk"
45 LETTER = "listen_to_me"
46 NAMEDENIED = "name_in_use"
48 # end protocol stuff
50 MULTICAST = '234.0.0.1'
52 def main():
54 # parsing command line options
56 if (len(sys.argv) > 1):
57 config_file = sys.argv[1]
58 else:
59 print "main(): No config file specified, using", CONFIG
60 config_file = CONFIG
62 global parsed_config
63 parsed_config = parse_config(config_file)
65 if (parsed_config['error']):
66 print "main(): Error parsing config, ending"
67 return
69 signal(SIGINT, handler)
71 run(parsed_config)
73 def run(configuration):
75 global running
77 if running:
78 print "run(): Beginning..."
80 global the_messenger
81 global the_broadcast
83 global members
84 members = {}
86 global ECHO_COUNT
88 if configuration.has_key('echo_number'):
89 ECHO_COUNT = configuration['echo_number']
90 else:
91 print "No echo_number specified in config file, using default of", ECHO_COUNT
93 the_broadcast = Broadcast()
94 the_messenger = Messenger()
96 the_messenger.echo_members = []
98 if configuration.has_key('broadcast'):
99 reactor.listenMulticast(configuration['broadcast'], the_broadcast)
100 else:
101 print "Server.__init__(): No broadcast socket number chosen, using", BROADCAST
102 reactor.listenMulticast(BROADCAST, the_broadcast)
104 if configuration.has_key('message'):
105 reactor.listenUDP(configuration['message'], the_messenger)
106 else:
107 print "Server.__init__(): No message socket number chosen, using", MESSAGE
108 reactor.listenUDP(MESSAGE, the_messenger)
110 echo_request = task.LoopingCall(the_messenger.echo_request)
112 if configuration.has_key('echo_time'):
113 echo_request.start(configuration['echo_time'])
114 else:
115 print "run(): No echo_time specified in config, using default of", ECHO_TIME
116 echo_request.start(ECHO_TIME)
118 reactor.run()
120 print "run(): Ending..."
122 return
124 def handler(signal, frame):
126 global running
127 running = 0
129 reactor.stop()
131 return
133 def is_end():
135 if not running:
136 reactor.stop()
138 return
140 def parse_config(filename):
142 parsed = {'error': 1}
144 if (exists(filename)):
145 dom = parse(filename)
146 else:
147 print "parse_config():", filename, "doesn't exist"
148 return parsed
150 if (dom.childNodes[0].nodeName == 'server_config'):
151 for node in dom.childNodes[0].childNodes:
153 if (node.nodeName == 'name' and len(node.childNodes)):
154 parsed['name'] = node.childNodes[0].nodeValue
156 if (node.nodeName == 'password' and len(node.childNodes)):
157 parsed['password'] = node.childNodes[0].nodeValue
159 if (node.nodeName == 'broadcast' and len(node.childNodes)):
160 parsed['broadcast'] = int(node.childNodes[0].nodeValue)
162 if (node.nodeName == 'message' and len(node.childNodes)):
163 parsed['message'] = int(node.childNodes[0].nodeValue)
165 if (node.nodeName == 'echo_time' and len(node.childNodes)):
166 parsed['echo_time'] = int(node.childNodes[0].nodeValue)
168 if (node.nodeName == 'echo_number' and len(node.childNodes)):
169 parsed['echo_number'] = int(node.childNodes[0].nodeValue)
171 parsed['error'] = 0
173 return parsed
175 class Broadcast(DatagramProtocol):
177 def startProtocol(self):
179 self.transport.joinGroup(MULTICAST)
181 def datagramReceived(self, data, address):
183 global parsed_config
185 if data[0:len(SERVERREQUEST)] == SERVERREQUEST:
187 new_message = ''.join([SERVEROFFER, " ",
188 str(parsed_config['message']),
189 " ", parsed_config['name']])
191 destination = (address[0], int(data[len(SERVERREQUEST) + 1:]))
193 the_messenger.transport.write(new_message, destination)
195 print "Broadcast.datagramReceived(): Received SERVERREQUEST, responded with SERVEROFFER"
197 return
199 class Messenger(DatagramProtocol):
201 def datagramReceived(self, data, (host, port)):
203 global members
204 global parsed_config
206 if data[:len(WANTIN)] == WANTIN:
208 if not members.has_key(data[len(WANTIN) + 1:]):
209 print "Messenger.datagramReceived(): WANTIN received, responding with YOUREIN"
211 response = ''.join([SOMEONEJOINED, " ", data[len(WANTIN) + 1:]])
213 for member in members:
214 self.transport.write(response, members[member])
216 members[data[len(WANTIN) + 1:]] = (host, port)
217 response = YOUREIN
218 self.transport.write(response, (host, port))
220 else:
221 if (host, port) in members.values():
222 print "Messenger.datagramReceived(): WANTIN received from a current member, responding with YOUREIN"
223 response = YOUREIN
224 self.transport.write(response, (host, port))
226 else:
227 response = NAMEDENIED
228 self.transport.write(response, (host, port))
230 if data[:len(IMHERE)] == IMHERE:
232 if (host, port) in members.values():
234 # print "Messenger.datagramReceived(): IMHERE received"
236 for name in members:
237 if members[name] == (host, port):
238 if name in self.echo_members:
239 while self.echo_members.count(name):
240 self.echo_members.remove(name)
242 if data[:len(YOUTHERE)] == YOUTHERE:
244 #print "Messenger.datagramReceived(): YOUTHERE received, responding with IMHERE"
246 self.transport.write(IMHERE, (host, port))
248 if data[:len(IMOUT)] == IMOUT:
250 if (host, port) in members.values():
251 print "Messenger.datagramReceived(): IMOUT received, notifying others"
253 response = ''.join([SOMEONELEFT, " "])
255 the_name = ''
256 for name in members.keys():
257 if members[name] == (host, port):
258 the_name = name
260 self.ejectMember(the_name)
262 else:
263 print "Messenger.datagramReceived(): IMOUT received, but sender not present in listing"
265 if data[:len(GETLIST)] == GETLIST:
266 print "Messenger.datagramReceived(): GETLIST received, responding with LIST"
268 response = ''.join([LIST, ' '])
270 for iname in members:
271 response = ''.join([response, iname, ' '])
273 self.transport.write(response, (host, port))
275 if data[:len(SERVERKILL)] == SERVERKILL:
277 if data[len(SERVERKILL) + 1:] == parsed_config['password']:
278 print "Messenger.datagramReceived(): SERVERKILL received, dying now."
279 reactor.stop()
281 if data[:len(LETTER)] == LETTER:
283 responses = []
285 origin = ''
287 for name in members:
288 if members[name] == (host, port):
289 origin = name
291 if origin == '':
292 print "Messenger.datagramReceived(): LETTER received, but originator not in listing"
293 else:
294 print "Messenger.datagramReceived(): LETTER received, forwarding it on..."
296 response = [''.join([LETTER, ':', origin, ':']), []]
297 message = ''
299 if data[len(LETTER):len(LETTER) + 2] == '::':
301 message = data[data.find("::") + 2:]
302 response[0] = ''.join([response[0], message])
304 for name in members:
305 if origin != name:
307 responses.append(response)
308 responses[-1][1] = members[name]
309 else:
311 message = data[the_data.find(':', data.find(':') + 1) + 1:]
312 response[0] = ''.join([response[0], messsage])
314 string_parts = data[data.find(':') + 1:
315 data.find(':', data.find(':') + 1)].split()
317 for dest in string_parts:
319 if members.has_key(dest):
321 responses.append(response)
322 responses[-1][1] = members[dest]
324 for response_i in responses:
326 self.transport.write(response_i[0], response_i[1])
328 return
330 def ejectMember(self, name):
332 reactor.callFromThread(self.ejectThreadMember, name)
334 return
336 def ejectThreadMember(self, name):
337 if name in members.keys():
338 response = YOUROUT
339 self.transport.write(response, members[name])
341 del members[name]
343 response = ''.join([SOMEONELEFT, " ", name])
345 for member in members:
347 self.transport.write(response, members[member])
348 print "notify debug", members[member], response
350 return
352 def echo_request(self):
354 global members
355 global parsed_config
356 global ECHO_COUNT
358 ejecters = []
360 if len(members):
361 #print "Messenger.echo_request(): Sending YOUTHERE messages..."
362 pass
364 for member in members:
366 if self.echo_members.count(member) > ECHO_COUNT:
367 ejecters.append(member)
369 else:
370 self.transport.write(YOUTHERE, members[member])
371 self.echo_members.append(member)
373 for person in ejecters:
375 self.ejectMember(person)
376 print "Messenger.echo_request(): Member ejected for suspicion of communism, name:", person
378 temp_members = []
380 for echo_request_item in self.echo_members:
381 if person != echo_request_item:
382 temp_members.append(echo_request_item)
384 self.echo_members = temp_members
386 return
388 if __name__ == '__main__':
389 main()