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 from protocol
import *
32 MULTICAST
= '234.0.0.1'
36 # parsing command line options
38 if (len(sys
.argv
) > 1):
39 config_file
= sys
.argv
[1]
41 print "main(): No config file specified, using", CONFIG
45 parsed_config
= parse_config(config_file
)
47 if (parsed_config
['error']):
48 print "main(): Error parsing config, ending"
51 signal(SIGINT
, handler
)
55 def run(configuration
):
60 print "run(): Beginning..."
70 if configuration
.has_key('echo_number'):
71 ECHO_COUNT
= configuration
['echo_number']
73 print "No echo_number specified in config file, using default of", ECHO_COUNT
75 the_broadcast
= Broadcast()
76 the_messenger
= Messenger()
78 the_messenger
.echo_members
= []
80 if configuration
.has_key('broadcast'):
81 reactor
.listenMulticast(configuration
['broadcast'], the_broadcast
)
83 print "Server.__init__(): No broadcast socket number chosen, using", BROADCAST
84 reactor
.listenMulticast(BROADCAST
, the_broadcast
)
86 if configuration
.has_key('message'):
87 reactor
.listenUDP(configuration
['message'], the_messenger
)
89 print "Server.__init__(): No message socket number chosen, using", MESSAGE
90 reactor
.listenUDP(MESSAGE
, the_messenger
)
92 echo_request
= task
.LoopingCall(the_messenger
.echo_request
)
94 if configuration
.has_key('echo_time'):
95 echo_request
.start(configuration
['echo_time'])
97 print "run(): No echo_time specified in config, using default of", ECHO_TIME
98 echo_request
.start(ECHO_TIME
)
102 print "run(): Ending..."
106 def handler(signal
, frame
):
122 def parse_config(filename
):
124 parsed
= {'error': 1}
126 if (exists(filename
)):
127 dom
= parse(filename
)
129 print "parse_config():", filename
, "doesn't exist"
132 if (dom
.childNodes
[0].nodeName
== 'server_config'):
133 for node
in dom
.childNodes
[0].childNodes
:
135 if (node
.nodeName
== 'name' and len(node
.childNodes
)):
136 parsed
['name'] = node
.childNodes
[0].nodeValue
138 if (node
.nodeName
== 'password' and len(node
.childNodes
)):
139 parsed
['password'] = node
.childNodes
[0].nodeValue
141 if (node
.nodeName
== 'broadcast' and len(node
.childNodes
)):
142 parsed
['broadcast'] = int(node
.childNodes
[0].nodeValue
)
144 if (node
.nodeName
== 'message' and len(node
.childNodes
)):
145 parsed
['message'] = int(node
.childNodes
[0].nodeValue
)
147 if (node
.nodeName
== 'echo_time' and len(node
.childNodes
)):
148 parsed
['echo_time'] = int(node
.childNodes
[0].nodeValue
)
150 if (node
.nodeName
== 'echo_number' and len(node
.childNodes
)):
151 parsed
['echo_number'] = int(node
.childNodes
[0].nodeValue
)
157 class Broadcast(DatagramProtocol
):
159 def startProtocol(self
):
161 self
.transport
.joinGroup(MULTICAST
)
163 def datagramReceived(self
, data
, address
):
167 if data
[0:len(SERVERREQUEST
)] == SERVERREQUEST
:
169 new_message
= ''.join([SERVEROFFER
, " ",
170 str(parsed_config
['message']),
171 " ", parsed_config
['name']])
173 destination
= (address
[0], int(data
[len(SERVERREQUEST
) + 1:]))
175 the_messenger
.transport
.write(new_message
, destination
)
177 print "Broadcast.datagramReceived(): Received SERVERREQUEST, responded with SERVEROFFER"
181 class Messenger(DatagramProtocol
):
183 def datagramReceived(self
, data
, (host
, port
)):
188 if data
[:len(WANTIN
)] == WANTIN
:
190 if not members
.has_key(data
[len(WANTIN
) + 1:]):
191 print "Messenger.datagramReceived(): WANTIN received, responding with YOUREIN"
193 response
= ''.join([SOMEONEJOINED
, " ", data
[len(WANTIN
) + 1:]])
195 for member
in members
:
196 self
.transport
.write(response
, members
[member
])
198 members
[data
[len(WANTIN
) + 1:]] = (host
, port
)
200 self
.transport
.write(response
, (host
, port
))
203 if (host
, port
) in members
.values():
204 print "Messenger.datagramReceived(): WANTIN received from a current member, responding with YOUREIN"
206 self
.transport
.write(response
, (host
, port
))
209 response
= NAMEDENIED
210 self
.transport
.write(response
, (host
, port
))
212 if data
[:len(IMHERE
)] == IMHERE
:
214 if (host
, port
) in members
.values():
216 # print "Messenger.datagramReceived(): IMHERE received"
219 if members
[name
] == (host
, port
):
220 if name
in self
.echo_members
:
221 while self
.echo_members
.count(name
):
222 self
.echo_members
.remove(name
)
224 if data
[:len(YOUTHERE
)] == YOUTHERE
:
226 #print "Messenger.datagramReceived(): YOUTHERE received, responding with IMHERE"
228 self
.transport
.write(IMHERE
, (host
, port
))
230 if data
[:len(IMOUT
)] == IMOUT
:
232 if (host
, port
) in members
.values():
233 print "Messenger.datagramReceived(): IMOUT received, notifying others"
235 response
= ''.join([SOMEONELEFT
, " "])
238 for name
in members
.keys():
239 if members
[name
] == (host
, port
):
242 self
.ejectMember(the_name
)
245 print "Messenger.datagramReceived(): IMOUT received, but sender not present in listing"
247 if data
[:len(GETLIST
)] == GETLIST
:
248 print "Messenger.datagramReceived(): GETLIST received, responding with LIST"
250 response
= ''.join([LIST
, ' '])
252 for iname
in members
:
253 response
= ''.join([response
, iname
, ' '])
255 self
.transport
.write(response
, (host
, port
))
257 if data
[:len(SERVERKILL
)] == SERVERKILL
:
259 if data
[len(SERVERKILL
) + 1:] == parsed_config
['password']:
260 print "Messenger.datagramReceived(): SERVERKILL received, dying now."
263 if data
[:len(LETTER
)] == LETTER
:
270 if members
[name
] == (host
, port
):
274 print "Messenger.datagramReceived(): LETTER received, but originator not in listing"
276 print "Messenger.datagramReceived(): LETTER received, forwarding it on..."
278 response
= [''.join([LETTER
, ':', origin
, ':']), []]
281 if data
[len(LETTER
):len(LETTER
) + 2] == '::':
283 message
= data
[data
.find("::") + 2:]
284 response
[0] = ''.join([response
[0], message
])
289 responses
.append(response
)
290 responses
[-1][1] = members
[name
]
293 message
= data
[the_data
.find(':', data
.find(':') + 1) + 1:]
294 response
[0] = ''.join([response
[0], messsage
])
296 string_parts
= data
[data
.find(':') + 1:
297 data
.find(':', data
.find(':') + 1)].split()
299 for dest
in string_parts
:
301 if members
.has_key(dest
):
303 responses
.append(response
)
304 responses
[-1][1] = members
[dest
]
306 for response_i
in responses
:
308 self
.transport
.write(response_i
[0], response_i
[1])
312 def ejectMember(self
, name
):
314 reactor
.callFromThread(self
.ejectThreadMember
, name
)
318 def ejectThreadMember(self
, name
):
319 if name
in members
.keys():
321 self
.transport
.write(response
, members
[name
])
325 response
= ''.join([SOMEONELEFT
, " ", name
])
327 for member
in members
:
329 self
.transport
.write(response
, members
[member
])
330 print "notify debug", members
[member
], response
334 def echo_request(self
):
343 #print "Messenger.echo_request(): Sending YOUTHERE messages..."
346 for member
in members
:
348 if self
.echo_members
.count(member
) > ECHO_COUNT
:
349 ejecters
.append(member
)
352 self
.transport
.write(STILLIN
, members
[member
])
353 self
.echo_members
.append(member
)
355 for person
in ejecters
:
357 self
.ejectMember(person
)
358 print "Messenger.echo_request(): Member ejected for suspicion of communism, name:", person
362 for echo_request_item
in self
.echo_members
:
363 if person
!= echo_request_item
:
364 temp_members
.append(echo_request_item
)
366 self
.echo_members
= temp_members
370 if __name__
== '__main__':