3 # This is a twisted version of the server
6 from os
.path
import exists
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
21 PASSWORD
= "changethis"
26 ECHO_COUNT
= 5 # this is the number of times one can ignore an echo until the server drops you
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"
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"
50 MULTICAST
= '234.0.0.1'
54 # parsing command line options
56 if (len(sys
.argv
) > 1):
57 config_file
= sys
.argv
[1]
59 print "main(): No config file specified, using", CONFIG
63 parsed_config
= parse_config(config_file
)
65 if (parsed_config
['error']):
66 print "main(): Error parsing config, ending"
69 signal(SIGINT
, handler
)
73 def run(configuration
):
78 print "run(): Beginning..."
88 if configuration
.has_key('echo_number'):
89 ECHO_COUNT
= configuration
['echo_number']
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
)
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
)
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'])
115 print "run(): No echo_time specified in config, using default of", ECHO_TIME
116 echo_request
.start(ECHO_TIME
)
120 print "run(): Ending..."
124 def handler(signal
, frame
):
140 def parse_config(filename
):
142 parsed
= {'error': 1}
144 if (exists(filename
)):
145 dom
= parse(filename
)
147 print "parse_config():", filename
, "doesn't exist"
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
)
175 class Broadcast(DatagramProtocol
):
177 def startProtocol(self
):
179 self
.transport
.joinGroup(MULTICAST
)
181 def datagramReceived(self
, data
, address
):
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"
199 class Messenger(DatagramProtocol
):
201 def datagramReceived(self
, data
, (host
, port
)):
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
)
218 self
.transport
.write(response
, (host
, port
))
221 if (host
, port
) in members
.values():
222 print "Messenger.datagramReceived(): WANTIN received from a current member, responding with YOUREIN"
224 self
.transport
.write(response
, (host
, port
))
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"
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
, " "])
256 for name
in members
.keys():
257 if members
[name
] == (host
, port
):
260 self
.ejectMember(the_name
)
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."
281 if data
[:len(LETTER
)] == LETTER
:
288 if members
[name
] == (host
, port
):
292 print "Messenger.datagramReceived(): LETTER received, but originator not in listing"
294 print "Messenger.datagramReceived(): LETTER received, forwarding it on..."
296 response
= [''.join([LETTER
, ':', origin
, ':']), []]
299 if data
[len(LETTER
):len(LETTER
) + 2] == '::':
301 message
= data
[data
.find("::") + 2:]
302 response
[0] = ''.join([response
[0], message
])
307 responses
.append(response
)
308 responses
[-1][1] = members
[name
]
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])
330 def ejectMember(self
, name
):
332 reactor
.callFromThread(self
.ejectThreadMember
, name
)
336 def ejectThreadMember(self
, name
):
337 if name
in members
.keys():
339 self
.transport
.write(response
, 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
352 def echo_request(self
):
361 #print "Messenger.echo_request(): Sending YOUTHERE messages..."
364 for member
in members
:
366 if self
.echo_members
.count(member
) > ECHO_COUNT
:
367 ejecters
.append(member
)
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
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
388 if __name__
== '__main__':