Added text box to the 'net_menu'.
[krufty_fps.git] / server_twisted.py
blobd350c526bd09b6c67d45d4168480eab325e89e24
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 = 5
26 running = 1
28 # defining protocol stuff
30 SERVERREQUEST = "i_want_server"
31 SERVEROFFER = "Want_server?"
32 SERVERKILL = "DIE_server!!"
33 YOUTHERE = "you_there?"
34 IMHERE = "yeah,i'm_here"
35 WANTIN = "i_want_in"
36 YOUREIN = "urine"
37 IMOUT = "i_leave"
38 GETLIST = "get_list"
39 LIST = "peoples_on_server"
40 SOMEONEJOINED = "dude,someone_joined"
41 SOMEONELEFT = "someone_left"
42 YOUROUT = "get_lost_punk"
43 LETTER = "listen_to_me"
45 # end protocol stuff
47 MULTICAST = '234.0.0.1'
49 def main():
51 # parsing command line options
53 if (len(sys.argv) > 1):
54 config_file = sys.argv[1]
55 else:
56 print "main(): No config file specified, using", CONFIG
57 config_file = CONFIG
59 global parsed_config
60 parsed_config = parse_config(config_file)
62 if (parsed_config['error']):
63 print "main(): Error parsing config, ending"
64 return
66 signal(SIGINT, handler)
68 run(parsed_config)
70 def run(configuration):
72 global running
74 if running:
75 print "run(): Beginning..."
77 global the_messenger
78 global the_broadcast
80 global members
81 members = {}
83 the_broadcast = Broadcast()
84 the_messenger = Messenger()
86 the_messenger.echo_members = []
88 if configuration.has_key('broadcast'):
89 reactor.listenMulticast(configuration['broadcast'], the_broadcast)
90 else:
91 print "Server.__init__(): No broadcast socket number chosen, using", BROADCAST
92 reactor.listenMulticast(BROADCAST, the_broadcast)
94 if configuration.has_key('message'):
95 reactor.listenUDP(configuration['message'], the_messenger)
96 else:
97 print "Server.__init__(): No message socket number chosen, using", MESSAGE
98 reactor.listenUDP(MESSAGE, the_messenger)
100 echo_request = task.LoopingCall(the_messenger.echo_request)
102 if configuration.has_key('echo_time'):
103 echo_request.start(configuration['echo_time'])
104 else:
105 print "run(): No echo_time specified in config, using default of", ECHO_TIME
106 echo_request.start(ECHO_TIME)
108 reactor.run()
110 print "run(): Ending..."
112 return
114 def handler(signal, frame):
116 global running
117 running = 0
119 reactor.stop()
121 return
123 def is_end():
125 if not running:
126 reactor.stop()
128 return
130 def parse_config(filename):
132 parsed = {'error': 1}
134 if (exists(filename)):
135 dom = parse(filename)
136 else:
137 print "parse_config():", filename, "doesn't exist"
138 return parsed
140 if (dom.childNodes[0].nodeName == 'server_config'):
141 for node in dom.childNodes[0].childNodes:
143 if (node.nodeName == 'name' and len(node.childNodes)):
144 parsed['name'] = node.childNodes[0].nodeValue
146 if (node.nodeName == 'password' and len(node.childNodes)):
147 parsed['password'] = node.childNodes[0].nodeValue
149 if (node.nodeName == 'broadcast' and len(node.childNodes)):
150 parsed['broadcast'] = int(node.childNodes[0].nodeValue)
152 if (node.nodeName == 'message' and len(node.childNodes)):
153 parsed['message'] = int(node.childNodes[0].nodeValue)
155 if (node.nodeName == 'echo_time' and len(node.childNodes)):
156 parsed['echo_time'] = int(node.childNodes[0].nodeValue)
158 parsed['error'] = 0
160 return parsed
162 class Broadcast(DatagramProtocol):
164 def startProtocol(self):
166 self.transport.joinGroup(MULTICAST)
168 def datagramReceived(self, data, address):
170 global parsed_config
172 if data[0:len(SERVERREQUEST)] == SERVERREQUEST:
174 new_message = ''.join([SERVEROFFER, " ",
175 str(parsed_config['message']),
176 " ", parsed_config['name']])
178 destination = (address[0], int(data[len(SERVERREQUEST) + 1:]))
180 the_messenger.transport.write(new_message, destination)
182 print "Broadcast.datagramReceived(): Received SERVERREQUEST, responded with SERVEROFFER"
184 return
186 class Messenger(DatagramProtocol):
188 def datagramReceived(self, data, (host, port)):
190 global members
191 global parsed_config
193 if data[:len(WANTIN)] == WANTIN:
195 if not members.has_key(data[len(WANTIN) + 1:]):
196 print "Messenger.datagramReceived(): WANTIN received, responding with YOUREIN"
198 response = ''.join([SOMEONEJOINED, " ", data[len(WANTIN) + 1:]])
200 for member in members:
201 self.transport.write(response, members[member])
203 members[data[len(WANTIN) + 1:]] = (host, port)
204 response = YOUREIN
205 self.transport.write(response, (host, port))
207 if data[:len(IMHERE)] == IMHERE:
209 if (host, port) in members.values():
211 # print "Messenger.datagramReceived(): IMHERE received"
213 for name in members:
214 if members[name] == (host, port):
215 if name in self.echo_members:
216 self.echo_members.remove(name)
218 if data[:len(YOUTHERE)] == YOUTHERE:
220 #print "Messenger.datagramReceived(): YOUTHERE received, responding with IMHERE"
222 self.transport.write(IMHERE, (host, port))
224 if data[:len(IMOUT)] == IMOUT:
226 if (host, port) in members.values():
227 print "Messenger.datagramReceived(): IMOUT received, notifying others"
229 response = ''.join([SOMEONELEFT, " "])
231 the_name = ''
232 for name in members.keys():
233 if members[name] == (host, port):
234 the_name = name
236 self.ejectMember(the_name)
238 else:
239 print "Messenger.datagramReceived(): IMOUT received, but sender not present in listing"
241 if data[:len(GETLIST)] == GETLIST:
242 print "Messenger.datagramReceived(): GETLIST received, responding with LIST"
244 response = ''.join([LIST, ' '])
246 for iname in members:
247 response = ''.join([response, iname, ' '])
249 self.transport.write(response, (host, port))
251 if data[:len(SERVERKILL)] == SERVERKILL:
253 if data[len(SERVERKILL) + 1:] == parsed_config['password']:
254 print "Messenger.datagramReceived(): SERVERKILL received, dying now."
255 reactor.stop()
257 if data[:len(LETTER)] == LETTER:
259 responses = []
261 origin = ''
263 for name in members:
264 if members[name] == (host, port):
265 origin = name
267 if origin == '':
268 print "Messenger.datagramReceived(): LETTER received, but originator not in listing"
269 else:
270 print "Messenger.datagramReceived(): LETTER received, forwarding it on..."
272 response = [''.join([LETTER, ':', origin, ':']), []]
273 message = ''
275 if data[len(LETTER):len(LETTER) + 2] == '::':
277 message = data[data.find("::") + 2:]
278 response[0] = ''.join([response[0], message])
280 for name in members:
281 if origin != name:
283 responses.append(response)
284 response[-1][1] = members[name]
285 else:
287 message = data[the_data.find(':', data.find(':') + 1) + 1:]
288 response[0] = ''.join([response[0], messsage])
290 string_parts = data[data.find(':') + 1:
291 data.find(':', data.find(':') + 1)].split()
293 for dest in string_parts:
295 if members.has_key(dest):
297 responses.append(response)
298 responses[-1][1] = members[dest]
300 for response_i in responses:
302 self.transport.write(response_i[0], response_i[1])
304 return
306 def ejectMember(self, name):
308 reactor.callFromThread(self.ejectThreadMember, name)
310 return
312 def ejectThreadMember(self, name):
313 if name in members.keys():
314 response = YOUROUT
315 self.transport.write(response, members[name])
317 del members[name]
319 response = ''.join([SOMEONELEFT, " ", name])
321 for member in members:
323 self.transport.write(response, members[member])
324 print "notify debug", members[member], response
326 return
328 def echo_request(self):
330 global members
331 global parsed_config
333 ejecters = []
335 if len(members):
336 #print "Messenger.echo_request(): Sending YOUTHERE messages..."
337 pass
339 for member in members:
340 if member in self.echo_members:
342 ejecters.append(member)
344 else:
345 self.transport.write(YOUTHERE, members[member])
346 self.echo_members.append(member)
348 for person in ejecters:
350 self.ejectMember(person)
351 print "Messenger.echo_request(): Member ejected for lack of communication, name:", person
353 return
355 if __name__ == '__main__':
356 main()