1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 "XMPPD :: eXtensible Messaging and Presence Protocol Daemon"
24
25 __author__ = "Kristopher Tate <kris@bbridgetech.com>"
26 __version__ = "0.3-RC1"
27 __copyright__ = "Copyright (C) 2005 BlueBridge Technologies Group, Inc."
28 __license__ = "GPL"
29
30
31 from xmpp import *
32 from math import *
33 import traceback
34
35 import socket,select,random,os,sys,thread,errno,time,threading,hashlib
36 globals()['DEFAULT_LANG'] = 'en'
37
38
39 globals()['SERVER_MOTD'] = "Hello, I'm Help Desk. Type 'menu' for help."
40
41 globals()['PORT_5222'] = 5222
42 globals()['PORT_5223'] = 5223
43 globals()['PORT_5269'] = 5269
44 globals()['PORT_8000'] = 8001
45
46 globals()['MAXREQUESTLENGTH'] = 10000
47 globals()['XMPPD_MAX_CONNECTIONS'] = 1
48
49 globals()['SOCKER_TGUID'] = 'BBTECH_XMPPD'
50
51
52 GLOBAL_TERMINATE = False
53
54 """
55 _socket_state live/dead
56 _session_state no/in-process/yes
57 _stream_state not-opened/opened/closing/closed
58 """
59
60 SOCKET_UNCONNECTED = 0
61 SOCKET_ALIVE = 1
62 SOCKET_DEAD = 2
63
64 STREAM__NOT_OPENED = 1
65 STREAM__OPENED = 2
66 STREAM__CLOSING = 3
67 STREAM__CLOSED = 4
68
69 SESSION_NOT_AUTHED = 1
70 SESSION_AUTHED = 2
71 SESSION_BOUND = 3
72 SESSION_OPENED = 4
73
74 XMLRPC_STAGE_ZERO = 0
75 XMLRPC_STAGE_ONE = 1
76 XMLRPC_STAGE_TWO = 2
77 XMLRPC_STAGE_THREE = 4
78 XMLRPC_STAGE_FOUR = 8
79
82
83 self.POLLIN = 0x0001
84 self.POLLOUT = 0x0004
85 self.POLLERR = 0x0008
86
87
88 self.POLLNORM = self.POLLIN
89 self.POLLPRI = self.POLLIN
90 self.POLLRDNORM = self.POLLIN
91 self.POLLRDBAND = self.POLLIN
92 self.POLLWRNORM = self.POLLOUT
93 self.POLLWRBAND = self.POLLOUT
94
95
96 self.POLLHUP = 0x0010
97 self.POLLNVAL = 0x0020
98
99 """def select(self, rlist, wlist, xlist, timeout=1.0):
100 import select
101 return select.select(rlist, wlist, xlist, timeout)"""
102
105
106 self.POLLIN = 0x0001
107 self.POLLOUT = 0x0004
108 self.POLLERR = 0x0008
109
110
111 self.POLLNORM = self.POLLIN
112 self.POLLPRI = self.POLLIN
113 self.POLLRDNORM = self.POLLIN
114 self.POLLRDBAND = self.POLLIN
115 self.POLLWRNORM = self.POLLOUT
116 self.POLLWRBAND = self.POLLOUT
117
118
119 self.POLLHUP = 0x0010
120 self.POLLNVAL = 0x0020
121 self._registered = {}
122
124 try:
125 self._registered[fd.fileno()] = {'fd':fd,'mask':eventmask}
126 return True
127 except:
128 return False
130 try:
131 del self._registered[fd.fileno()]
132 return True
133 except:
134 return False
135 - def poll(self,timeout=None):
136
137 data = {}
138 poll = {'in':[],'out':[],'err':[]}
139 out = []
140 for x,y in self._registered.iteritems():
141 if y['mask']&self.POLLIN == self.POLLIN: poll['in'] += [y['fd']]
142 if y['mask']&self.POLLOUT == self.POLLOUT: poll['out'] += [y['fd']]
143 if y['mask']&self.POLLERR == self.POLLERR: poll['err'] += [y['fd']]
144
145
146 if len(poll['in'])==0 and len(poll['out'])==0 and len(poll['err'])==0:
147 if timeout: time.sleep(timeout/1000.0)
148 return out
149
150 if timeout < 1 or timeout == None:
151 pi,po,pe = select.select(poll['in'],poll['out'],poll['err'])
152 else:
153 pi,po,pe = select.select(poll['in'],poll['out'],poll['err'],timeout/1000.0)
154
155 for x in poll['in']:
156 if x in pi:
157 if data.has_key(x.fileno()) == True:
158 data[x.fileno()]['mask'] = data[x.fileno()]['mask'] | self.POLLIN
159 else:
160 data[x.fileno()] = {'fd':x,'mask':self.POLLIN}
161
162 for x in poll['out']:
163 if x in po:
164 if data.has_key(x.fileno()) == True:
165 data[x.fileno()]['mask'] = data[x.fileno()]['mask'] | self.POLLOUT
166 else:
167 data[x.fileno()] = {'fd':x,'mask':self.POLLOUT}
168
169 for x in poll['err']:
170 if x in pe:
171 if data.has_key(x.fileno()) == True:
172 data[x.fileno()]['mask'] = data[x.fileno()]['mask'] | self.POLLERR
173 else:
174 data[x.fileno()] = {'fd':x,'mask':self.POLLERR}
175
176
177 for k,d in data.iteritems():
178 out += [(k,d['mask'])]
179 return out
180
181
182 try:
183 select.poll()
184 except:
185 import select as original_select
186 select = fake_select()
187 select.select = original_select.select
188
189
190
191
192 globals().update({'LANG_LIST':[]})
193
194
195
196 from locales import *
197
206
208 self._lang = lang
209 return True
210
212 if lang == None or val.has_key(lang) == False:
213 lang = self._lang
214 if val.has_key(lang) == False and val.has_key(self._default) == True:
215 lang = self._default
216
217 try:
218 return val[lang]
219 except:
220 if len(val.keys()) > 0:
221 return val[val.keys()[0]]
222 else:
223 return ''
224
226 for record in records.split('\n')[1:]:
227 var,code,text=record.split(' -- ')
228 name=var.upper().replace('-','_')
229
230 if globals().has_key(name):
231 globals()[name].update({code:text})
232 else:
233 globals()[name] = {code:text}
234 del var,code,text
235
237 "Session_Dummy is used to trick dispatch into actually sending information!"
242
245 self._mini_dom = None
246
247
249 - def __init__(self,socket,server,xmlns,peer=None):
250 self._lock = thread.allocate_lock()
251 self.xmlns=xmlns
252 if peer:
253 self.TYP='client'
254 self.peer=peer
255 self._socket_state=SOCKET_UNCONNECTED
256 else:
257 self.TYP='server'
258 self.peer=None
259 self._socket_state=SOCKET_ALIVE
260 server.num_servers += 1
261 self._sock=socket
262 self._send=socket.send
263 self._recv=socket.recv
264 self._registered=0
265 self.trusted=0
266 self.conn_since = time.time()
267 self.last_seen = time.time()
268 self.isAdmin = False
269
270 self.Dispatcher=server.Dispatcher
271 self.DBG_LINE='session'
272 self.DEBUG=server.Dispatcher.DEBUG
273 self._expected={}
274 self._owner=server
275 if self.TYP=='server': self.ID=`random.random()`[2:]
276 else: self.ID=None
277
278 self.sendbuffer=''
279 self.lib_event = None
280 self._stream_pos_queued=None
281 self._stream_pos_sent=0
282 self.deliver_key_queue=[]
283 self.deliver_queue_map={}
284 self.stanza_queue=[]
285
286 self._session_state=SESSION_NOT_AUTHED
287 self.waiting_features=[]
288 for feature in [NS_TLS,NS_SASL,NS_BIND,NS_SESSION]:
289 if feature in server.features: self.waiting_features.append(feature)
290 self.features=[]
291 self.feature_in_process=None
292 self.slave_session=None
293 self.StartStream()
294
307
309 """Reads all pending incoming data. Raises IOError on disconnect."""
310 try:
311 received = self._recv(10240)
312 except:
313 received = ''
314
315 if len(received):
316 self.DEBUG(`self._sock.fileno()`+' '+received,'got')
317 self.last_seen = time.time()
318 else:
319 self.DEBUG(self._owner._l(SESSION_RECEIVE_ERROR),'error')
320 self.set_socket_state(SOCKET_DEAD)
321 raise IOError("Peer disconnected")
322 return received
323
324 - def send(self,chunk):
325 try:
326 if isinstance(chunk,Node): chunk = unicode(chunk).encode('utf-8')
327 elif type(chunk)==type(u''): chunk = chunk.encode('utf-8')
328
329 except:
330 pass
331 self.enqueue(chunk)
332
334 """ Takes Protocol instance as argument. """
335 self._lock.acquire()
336 try:
337 self._owner.num_messages += 1
338 if isinstance(stanza,Protocol):
339 self.stanza_queue.append(stanza)
340 else: self.sendbuffer+=str(stanza)
341 if self._socket_state>=SOCKET_ALIVE: self.push_queue()
342 finally:
343 self._lock.release()
344
346
347 if self._stream_state>=STREAM__CLOSED or self._socket_state>=SOCKET_DEAD:
348 self._owner.deactivatesession(self)
349 self.trusted=1
350 for key in self.deliver_key_queue:
351 self.dispatch(Error(self.deliver_queue_map[key],failreason))
352 for stanza in self.stanza_queue:
353 self.dispatch(Error(stanza,failreason))
354 self.deliver_queue_map,self.deliver_key_queue,self.stanza_queue={},[],[]
355 return
356 elif self._session_state>=SESSION_AUTHED:
357
358 for stanza in self.stanza_queue:
359 txt=stanza.__str__().encode('utf-8')
360 self.sendbuffer+=txt
361 self._stream_pos_queued+=len(txt)
362 self.deliver_queue_map[self._stream_pos_queued]=stanza
363 self.deliver_key_queue.append(self._stream_pos_queued)
364 self.stanza_queue=[]
365
366
367 if self.sendbuffer and select.select([],[self._sock],[])[1]:
368 try:
369
370 sent=self._send(str(self.sendbuffer))
371 except Exception, err:
372
373 self.DEBUG('Attempting to kill %i!!!\n%s'%(self._sock.fileno(),err),'warn')
374
375 self.set_socket_state(SOCKET_DEAD)
376 self.DEBUG(self._owner._l(SESSION_SEND_ERROR),'error')
377 return self.terminate_stream()
378 self.DEBUG(`self._sock.fileno()`+' '+self.sendbuffer[:sent],'sent')
379 self._stream_pos_sent+=sent
380 self.sendbuffer=self.sendbuffer[sent:]
381 self._stream_pos_delivered=self._stream_pos_sent
382 while self.deliver_key_queue and self._stream_pos_delivered>self.deliver_key_queue[0]:
383 del self.deliver_queue_map[self.deliver_key_queue[0]]
384 self.deliver_key_queue.remove(self.deliver_key_queue[0])
385
386 """
387 elif self.lib_event == None:
388 if globals()['cmd_options'].enable_debug == True: print 'starting-up libevent write-event for %i'%self._sock.fileno()
389 self.lib_event = event.write(self._sock,self.libevent_write)
390 self.lib_event.add()
391 else:
392 self.lib_event.add()"""
393
394
395
397 if self.sendbuffer:
398
399 try:
400
401 sent=self._send(str(self.sendbuffer))
402 except Exception,err:
403 self.DEBUG('server','Attempting to kill %i!!!\n%s'%(self._sock.fileno(),err),'warn')
404
405 self.set_socket_state(SOCKET_DEAD)
406 self.DEBUG(self._owner._l(SESSION_SEND_ERROR),'error')
407 return self.terminate_stream()
408 self.DEBUG(`self._sock.fileno()`+' '+self.sendbuffer[:sent],'sent')
409 self._stream_pos_sent+=sent
410 self.sendbuffer=self.sendbuffer[sent:]
411 self._stream_pos_delivered=self._stream_pos_sent
412 while self.deliver_key_queue and self._stream_pos_delivered>self.deliver_key_queue[0]:
413 del self.deliver_queue_map[self.deliver_key_queue[0]]
414 self.deliver_key_queue.remove(self.deliver_key_queue[0])
415
416
421
423
429
454
468
470 jid=self.peer
471 try: barejid,resource=jid.split('/')
472 except: return None
473 return resource
474
476 split_jid = self.getSplitJID()
477 return self._owner.DB.get(split_jid[1],split_jid[0],'roster')
478
480 split_jid = self.getSplitJID()
481 return self._owner.DB.get(split_jid[1],split_jid[0],'groups')
482
484 split_jid = self.getSplitJID()
485 name = self._owner.DB.get(split_jid[1],split_jid[0],'name')
486 if name == None: name = '%s@%s'%split_jid[0:2]
487 return name
488
491
493 try:
494 return '%s@%s'%self.getSplitJID()[0:2]
495 except:
496
497 return self.peer.split("/")[0]
498
500 split_jid = self.getSplitJID()
501 if split_jid != None:
502 return self._owner.DB.get_store(split_jid[1],split_jid[0],'karma')
503 else:
504 return None
505
507 split_jid = self.getSplitJID()
508 if split_jid != None:
509 return self._owner.DB.store(split_jid[1],split_jid[0],karma,'karma')
510 else:
511 return None
512
516
519
529
546
555
557 if self.feature_in_process: raise "Starting feature %s over %s !"%(f,self.feature_in_process)
558 self.feature_in_process=f
560 if self.feature_in_process<>f: self.DEBUG("Stopping feature %s instead of %s !"%(f,self.feature_in_process),'info')
561 self.feature_in_process=None
563 if self._socket_state<newstate: self._socket_state=newstate
565 if self._session_state<newstate:
566 if self._session_state<SESSION_AUTHED and \
567 newstate>=SESSION_AUTHED: self._stream_pos_queued=self._stream_pos_sent
568 self._session_state=newstate
569 split_jid = self.getSplitJID()
570 if split_jid != None and split_jid[0] in self._owner.administrators[self.ourname]:
571 self.isAdmin = True
572 self.DEBUG(self._owner._l(SESSION_ADMIN_SET)%str(split_jid[0]),'info')
573
574 if newstate==SESSION_OPENED:
575
576 for msg in self._owner.DB.get_storage(self.peer, ""):
577
578 self.enqueue(msg)
579
581 if self._stream_state<newstate: self._stream_state=newstate
582
584 - def __init__(self,owner,socker_host,tguid,sguid=None):
585 self._owner = owner
586 self._proxy = xmlrpclib.ServerProxy('http://%s'%socker_host)
587
588 try:
589 ok_res = self._proxy.hello({})
590 if ok_res['code'] == 1: self.conn_okay = True
591 except:
592 self.conn_okay = False
593
594 self._tguid = tguid
595 if self.owner.cmd_options.setdefault('hostname',False) != None:
596 self.owner.DEBUG('server', "[SOCKER] hostname set to <%s>" % self.owner.cmd_options['hostname'],'info')
597 self._hostname = str(self.owner.cmd_options['hostname'])
598 else:
599 self._hostname = None
600
601 if sguid == None:
602 self._sguid = self.get_uuid()
603 else:
604 self._sguid = sguid
605
606 self._chain = {}
607 self.fake_to_real_port = {}
608 self._registered = []
609
611 if self.conn_okay == True:
612 return self._proxy.uuidgen({})
613 else:
614 return None
615
617 if self.conn_okay == True:
618 res = self._proxy.hostname({})
619 if res.has_key('hostname'):
620 self._hostname = res['hostname']
621 return res['hostname']
622 else:
623 return None
624 else:
625 return None
626
629
632
634 if self.conn_okay == True:
635 res = self._proxy.broadcast({'type_guid':self._tguid+'_p%s'%str(self.fake_to_real_port[str(globals()['PORT_5222'])]),'server_guid':self._sguid,'stanza':stanza})
636 if res['code'] != 1:
637 return None
638 else:
639 return res
640
641 - def add_port(self,outside_port,host,port,options=None):
642 self.onwer.DEBUG('server' "[SOCKER] attempting to add route to Socker [%s]"%str((outside_port,host,port,options)),'info')
643 if host == None and self._hostname != None:
644 host = self._hostname
645 elif host == None and self._hostname == None:
646 host = self.get_hostname()
647
648 self._chain[self._tguid+'_p%s'%str(outside_port)] = self._proxy.getchain({'type_guid':self._tguid+'_p%s'%str(outside_port)})
649 if self._chain[self._tguid+'_p%s'%str(outside_port)]['code'] != 1:
650 del self._chain[self._tguid+'_p%s'%str(outside_port)]
651
652 inpt = {'outside_port':outside_port,'type_guid':self._tguid+'_p%s'%str(outside_port),'server_guid':self._sguid,'server_host':host,'server_port':port}
653 if options != None: inpt.update(options)
654
655 if self.conn_okay == True:
656 res = self._proxy.add(inpt)
657 if res['code'] != 1:
658 return None
659 else:
660 self._registered += [res]
661 self.fake_to_real_port[str(port)] = outside_port
662 return res
663 else:
664 return None
665
667 if self.conn_okay == True:
668 res = self._proxy.data({'act':'add','type_guid':self._tguid+'_p%s'%str(self.fake_to_real_port[str(globals()['PORT_5222'])]),'server_guid':self._sguid,'pass':globals()['RPC_PASSWORD'],'add':data})
669 if res['code'] == 1: return True
670 return False
671
673 if self.conn_okay == True:
674 res = self._proxy.data({'act':'remove','type_guid':self._tguid+'_p%s'%str(self.fake_to_real_port[str(globals()['PORT_5222'])]),'server_guid':self._sguid,'pass':globals()['RPC_PASSWORD'],'remove':data})
675 if res['code'] == 1: return True
676 return False
677
679 if self.conn_okay == True:
680 res = self._proxy.data({'act':'add','type_guid':self._tguid+'_p%s'%str(self.fake_to_real_port[str(globals()['PORT_5222'])]),'pass':globals()['RPC_PASSWORD'],'add':data})
681 if res['code'] == 1: return True
682 return False
683
685 if self.conn_okay == True:
686 res = self._proxy.data({'act':'remove','type_guid':self._tguid+'_p%s'%str(self.fake_to_real_port[str(globals()['PORT_5222'])]),'pass':globals()['RPC_PASSWORD'],'remove':data})
687 if res['code'] == 1: return True
688 return False
689
691 for registered in self._registered:
692 res = self._proxy.delete({'handle':registered['handle'],'type_guid':self._tguid+'_p%s'%str(registered['outside_port']),'server_guid':self._sguid})
693
694 if res['code'] != 1:
695 return None
696 else:
697 self._registered = []
698 return res
699
701 - def __init__(self,owner,socket,addr,host,port):
702 self._sock = socket
703 self._owner = owner
704
705 self.addr = addr
706 self.host = host
707 self.port = port
708
709
710 self.stage = XMLRPC_STAGE_ZERO
711 self.RPC_handler(None)
712
714 "Handler for incoming remote procedure calls"
715 try:
716 if self.stage == XMLRPC_STAGE_ZERO:
717 self.stage = XMLRPC_STAGE_ONE
718 elif self.stage == XMLRPC_STAGE_ONE:
719 self.stage = XMLRPC_STAGE_TWO
720
721 params, method = xmlrpclib.loads(data)
722 if type(params[0]) == type({}):
723 aside = params[0]
724 aside['_socket'] = self._sock
725 aside['_socket_info'] = (self.host,self.port)
726 params = (aside,)
727 result = self.rpc_dispatch(method, params)
728 if getattr(result,'faultCode',None) != None:
729 response = xmlrpclib.dumps(result)
730 else:
731 response = xmlrpclib.dumps(result, methodresponse=1)
732
733 except:
734 response = xmlrpclib.dumps(xmlrpclib.Fault(1, "Socker(tm): %s"%traceback.format_exc()))
735
736 if self.stage == XMLRPC_STAGE_TWO:
737 final_output = ["HTTP/1.1 200 OK","Server: BlueBridge Socker(tm)","Content-Length: %i"%len(response),"Connection: close","Content-Type: text/xml","",response]
738 self.send('\n'.join(final_output))
739 self.terminate()
740
741
743 """Reads all pending incoming data. Raises IOError on disconnect."""
744 try: received = self._sock.recv(globals()['MAXREQUESTLENGTH'])
745 except: received = ''
746
747 if len(received) == 0:
748 raise IOError("Peer disconnected")
749 return received
750
751 - def send(self,msg):
752 try:
753 totalsent = 0
754 while totalsent < len(msg):
755 sent = self._sock.send(msg[totalsent:])
756
757 if sent == 0:
758 self.terminate()
759 totalsent = totalsent + sent
760 except:
761 pass
762
765
770
771
773 try:
774
775
776
777 func = getattr(self, 'rpcexport_' + method)
778 except AttributeError:
779 raise Exception('method "%s" is not supported' % method)
780 else:
781 result = func(*params)
782 if getattr(result,'faultCode',None) == None:
783 result = (result,)
784 return result
785
787 "RPC endpoint for all Socker™ related inquiries."
788
789 if 'pass' not in inpt or inpt['pass'] != globals()['RPC_PASSWORD']: return {'code':0,'msg':'PASS-BAD'}
790
791 if inpt['act'] == 'bc':
792 try:
793 self._owner.Dispatcher.dispatch(Node(node=inpt['stanza']),Session_Dummy(self._owner))
794 except:
795 pass
796 return {'code':1,'msg':'BC-OK'}
797 elif inpt['act'] == 'sd':
798 try:
799 if inpt['time'] > time.time():
800 event.timeout(int(time.time()-inpt['time']), self._owner._lib_out)
801 else:
802 event.timeout(1, self._owner._lib_out)
803 except:
804 pass
805 return {'code':1,'msg':'SD-OK'}
806 return {'code':0,'msg':'RC-BAD'}
807
809 return {'code':1,'msg':'Hello!'}
810
812 "RPC endpoint to get status information"
813 return {'code':1,'msg':'RC-OK','data':self._owner.tool_get_status()}
814
816
818
819 self._owner = owner
820 self.nthreads = nthreads
821
822 self.threads = {}
823
824 for i in range(0,nthreads):
825 t = self.multisession_thread(self._owner,i)
826 t.start()
827 self.threads[i] = t
828
831
833 return random.choice(self.threads.values())
834
837
840
842
844
845 threading.Thread.__init__(self)
846
847 self.alive = True
848
849 self.sockpoll = select.poll()
850 self.sockets = {}
851 self.SESS_LOCK=thread.allocate_lock()
852
853 self._owner = owner
854 self.index = index
855
878
881
883 self.SESS_LOCK.acquire()
884 s.thread_id = self.index
885 if isinstance(s,Session):
886 if s._registered:
887 self.SESS_LOCK.release()
888 return
889 s._registered=1
890 self.sockets[s.fileno()]=s
891 self.sockpoll.register(s,1 | 2 | 8)
892 self.SESS_LOCK.release()
893
895 self.SESS_LOCK.acquire()
896 if isinstance(s,Session):
897 if not s._registered:
898 p=Presence(typ='unavailable')
899 p.setNamespace(NS_CLIENT)
900 self._owner.Dispatcher.dispatch(p,s)
901 self.SESS_LOCK.release()
902 return
903 s._registered=0
904 self.sockpoll.unregister(s)
905
906 del self.sockets[s.fileno()]
907 self._owner.DEBUG('server',self._owner._l(SERVER_NODE_UNREGISTERED)%{'fileno':s.fileno(),'raw':s})
908 self.SESS_LOCK.release()
909
911 - def __init__(self,cfgfile="./xmppd.xml",cmd_options={},under_restart=False):
912
913 self.defaultNamespace = NS_CLIENT
914
915 self.l = localizer()
916 self._l = self.l.localize
917 for x in globals()['LANG_LIST']: self.l.build_localeset(x)
918
919 cmd_options.setdefault('select_enabled',False)
920 try:
921 import event
922
923 except:
924 cmd_options['select_enabled'] = True
925
926 if not cmd_options['select_enabled']: event.init()
927
928
929 self.components = {}
930
931 self.sockets={}
932 self.leventobjs={}
933
934 debug_path = cmd_options.setdefault('debug_file',sys.stdout)
935 if debug_path != sys.stdout: debug_file = file(debug_path,'w+')
936 else: debug_file = debug_path
937 if cmd_options.setdefault('enable_debug',[])!=[]: debug = ['always']
938 else: debug = []
939 self._DEBUG=Debug.Debug(debug,debug_path)
940 self.DEBUG=self._DEBUG.Show
941 self.debug_flags=self._DEBUG.debug_flags
942 self.debug_flags.append('session')
943 self.debug_flags.append('dispatcher')
944 self.debug_flags.append('server')
945
946 if cmd_options['select_enabled'] != True:
947 self.sockpoll = fake_select.poll()
948 self.DEBUG('server', 'Using fake_select poll', 'info')
949 elif cmd_options['select_enabled'] == True:
950 self.sockpoll=select.poll()
951 self.DEBUG('server', 'Using select poll', 'info')
952
953 self.ID=`random.random()`[2:]
954
955
956
957 self.cfgfile = cfgfile
958 if not os.path.exists(self.cfgfile):
959 self.DEBUG('server','Could not load configuration file for xmppd. Bye', 'error')
960 self.shutdown(STREAM_SYSTEM_SHUTDOWN)
961 sys.exit(1)
962
963 if cmd_options.setdefault('enable_psyco',False):
964 self.DEBUG('server',"Starting PsyCo...",'info')
965 try:
966 import psyco
967
968 psyco.full()
969 self.DEBUG('server',"PsyCo is loaded.",'ok')
970 except:
971 self.DEBUG('server', "Could not Load PsyCo!",'error')
972
973
974 if cmd_options.setdefault('socker_info',False): import xmlrpclib
975
976 if not cmd_options.setdefault('password',None):
977 globals()['RPC_PASSWORD'] = hashlib.sha1(str(time.time())+globals()['SOCKER_TGUID']+hashlib.sha1(str(time.time())).hexdigest()).hexdigest()
978 else:
979 globals()['RPC_PASSWORD'] = cmd_options['password']
980
981 self.DEBUG('server',"[SECURITY] RPC_PASSWORD SET TO [%(pass)s]"%{'pass':globals()['RPC_PASSWORD']},'info')
982
983
984
985 globals()['DEFAULT_LANG'] = cmd_options.setdefault('language','en')
986
987 self.multisession_manager = multisession_manager(self)
988
989 self._component=0
990 self.SESS_LOCK=thread.allocate_lock()
991 self.Dispatcher=dispatcher.Dispatcher()
992 self.Dispatcher._owner=self
993 self.Dispatcher._init()
994
995
996 self.up_since = time.time()
997 self.num_messages = 0
998 self.num_servers = 0
999
1000 self.features=[]
1001
1002 self.routes={}
1003 self.sisters={}
1004
1005 import modules
1006 if under_restart == True:
1007 reload(modules)
1008 for addon in modules.addons:
1009
1010 try:
1011 if self.__dict__.has_key(addon().__class__.__name__) and under_restart == True:
1012
1013
1014 self.DEBUG('server','Plugging %s out of %s.'%(addon(),self),'stop')
1015 if addon().DBG_LINE in self.debug_flags:
1016 self.debug_flags.remove(addon().DBG_LINE)
1017 if getattr(addon(),'_exported_methods',None) != None:
1018 for method in addon()._exported_methods: del self.__dict__[method.__name__]
1019 if getattr(addon(),'_old_owners_methods',None) != None:
1020 for method in addon()._old_owners_methods: self.__dict__[method.__name__]=method
1021 del self.__dict__[addon().__class__.__name__]
1022 if addon().__class__.__dict__.has_key('plugout'): return addon().plugout()
1023
1024 addon().PlugIn(self)
1025 else:
1026 addon().PlugIn(self)
1027
1028 except: self.__dict__[addon().__class__.__name__]=addon()
1029 self.feature(addon.NS)
1030
1031 self.cmd_options = cmd_options
1032
1033 self._socker = None
1034 if cmd_options.setdefault('socker_info',None):
1035 self._socker = Socker_client(self,cmd_options['socker_info'],globals()['SOCKER_TGUID'])
1036 if self._socker != None and self._socker.conn_okay == True:
1037 self.DEBUG('server',"[SOCKER] Socker(tm) support is enabled.",'info')
1038 self.DEBUG('server' "[SOCKER] Randomizing incoming connection ports.",'info')
1039
1040
1041 guide = [[globals()['PORT_5222'],self.pick_rand(),'5222'],[globals()['PORT_5223'],self.pick_rand(),'5223'],[globals()['PORT_5269'],self.pick_rand(),'5269'],[globals()['PORT_8000'],self.pick_rand(),'8000']]
1042
1043 port_map = {}
1044 for x in guide:
1045 if x[2] != '8000': port_map[str(x[0])] = x[1]
1046 globals()['PORT_%s'%x[2]] = x[1]
1047
1048 for port, new_port in port_map.iteritems():
1049 sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1050 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1051 sock.bind(('', new_port))
1052 sock.listen(4)
1053 self.registersession(sock)
1054 info = self._socker.add_port(int(port),None,new_port,{'conn_max':globals()['XMPPD_MAX_CONNECTIONS'],'xmlrpc-callback':'http://%s:%i'%(self._socker._hostname,globals()['PORT_8000']),'pass':globals()['RPC_PASSWORD']})
1055 if info == None:
1056 self._socker.destroy()
1057 raise Exception
1058 else:
1059 if cmd_options.setdefault('socker_info',None):
1060 self.DEBUG('server',"[SOCKER] Socker(tm) support could not be enabled. Please make sure that the Socker server is active.",'error')
1061 self._socker = None
1062 for port in [globals()['PORT_5222'],globals()['PORT_5223'],globals()['PORT_5269']]:
1063 sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1064 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1065 sock.bind(('', port))
1066 sock.listen(4)
1067 self.registersession(sock)
1068
1069 s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1070 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1071 s.bind(('', globals()['PORT_8000']))
1072 s.listen(4)
1073
1074 if cmd_options['select_enabled'] == True:
1075 reg_method = 'select'
1076 self.sockpoll.register(s,1 | 2 | 8)
1077 else:
1078 reg_method = 'libevent'
1079 self.leventobjs[s.fileno()]= event.event(self.libevent_read_callback, handle = s, evtype = event.EV_TIMEOUT | event.EV_READ | event.EV_PERSIST)
1080 if self.leventobjs[s.fileno()] != None:
1081 self.leventobjs[s.fileno()].add()
1082 self.sockets[s.fileno()]=s
1083
1084
1099
1106
1115
1132
1135
1138
1140 self.SESS_LOCK.acquire()
1141 if isinstance(s,Session):
1142 if s._registered:
1143 self.SESS_LOCK.release()
1144 if self._DEBUG.active: raise "Twice session Registration!"
1145 else: return
1146
1147 self.multisession_manager.registersession(s)
1148 self.SESS_LOCK.release()
1149 return
1150 reg_method = ''
1151 self.sockets[s.fileno()]=s
1152 if self.cmd_options['select_enabled'] == True:
1153 reg_method = 'select'
1154 self.sockpoll.register(s,1 | 2 | 8)
1155 else:
1156 reg_method = 'libevent'
1157 self.leventobjs[s.fileno()]= event.event(self.libevent_read_callback, handle = s, evtype = event.EV_TIMEOUT | event.EV_READ | event.EV_PERSIST)
1158 if self.leventobjs[s.fileno()] != None:
1159 self.leventobjs[s.fileno()].add()
1160 if isinstance(self._socker,Socker_client):
1161 socker_notice = "->[SOCKER(TM)]"
1162 else:
1163 socker_notice = ''
1164 self.DEBUG('server',self._l(SERVER_NODE_REGISTERED)%{'fileno':s.fileno(),'raw':s,'method':reg_method,'socker_notice':socker_notice})
1165 self.SESS_LOCK.release()
1166
1168 self.SESS_LOCK.acquire()
1169 if isinstance(s,Session):
1170 if not s._registered:
1171 p=Presence(typ='unavailable')
1172 p.setNamespace(NS_CLIENT)
1173 self.Dispatcher.dispatch(p,s)
1174 self.SESS_LOCK.release()
1175 if self._DEBUG.active: raise "Twice session UNregistration!"
1176 else: return
1177
1178 self.multisession_manager.unregistersession(s)
1179 self.SESS_LOCK.release()
1180 return
1181 if getattr(self,'sockpoll',None) != None:
1182 self.sockpoll.unregister(s)
1183 elif self.leventobjs.has_key(s.fileno()) == True and self.leventobjs[s.fileno()] != None:
1184 self.leventobjs[s.fileno()].delete()
1185 del self.leventobjs[s.fileno()]
1186
1187 del self.sockets[s.fileno()]
1188 self.DEBUG('server',self._l(SERVER_NODE_UNREGISTERED)%{'fileno':s.fileno(),'raw':s})
1189 self.SESS_LOCK.release()
1190
1192
1193 try:
1194 if not peer: peer=s.peer
1195 alt_s=self.getsession(peer)
1196 if s==alt_s: return
1197 elif alt_s: self.deactivatesession(peer)
1198 self.routes[peer]=s
1199 except Exception,e:
1200 print "###########ERRORRRRRRRRR "+ str(e)
1201
1202
1204 try: return self.routes[jid]
1205 except KeyError: pass
1206
1208 s=self.getsession(peer)
1209 if self.routes.has_key(peer): del self.routes[peer]
1210 if self.sisters.has_key(peer): del self.sisters[peer]
1211
1212 return s
1213
1222
1223
1225 "Functions as a callback for libevent pased "
1226 self._socket_handler(self.sockets[fd.fileno()],'libevent')
1227
1228
1233
1235 "Accepts incoming sockets and ultimately handles the core-routing of packets"
1236 if isinstance(sock,Session):
1237 sess=sock
1238 try:
1239 data=sess.receive()
1240 except IOError:
1241 sess.terminate_stream()
1242 data=''
1243 if data:
1244 try:
1245 sess.Parse(data)
1246 except simplexml.xml.parsers.expat.ExpatError:
1247 sess.terminate_stream(STREAM_XML_NOT_WELL_FORMED)
1248 if time.time() - sess.last_seen >= 60.0:
1249 sess.terminate_stream()
1250
1251 elif isinstance(sock,RPC_Client):
1252 sess=sock
1253 try:
1254 data=sess.receive()
1255 except IOError:
1256 sess.terminate()
1257 data=''
1258 if data:
1259 sess.RPC_handler(data)
1260
1261 elif isinstance(sock,socket.socket):
1262 conn, addr = sock.accept()
1263 host,port=sock.getsockname()
1264 if port in [globals()['PORT_5222'],globals()['PORT_5223']]:
1265 sess=Session(conn,self,NS_CLIENT)
1266
1267
1268 elif port == globals()['PORT_8000']:
1269 sess = RPC_Client(self,conn,addr,host,port)
1270 self.registersession(sess)
1271 try:
1272 data=sess.receive()
1273 except IOError:
1274 sess.terminate()
1275 data=''
1276 if data: sess.send("")
1277 return True
1278
1279 else:
1280
1281 sess=Session(conn,self,NS_SERVER)
1282 self.registersession(sess)
1283 if port==globals()['PORT_5223']:
1284 self.TLS.startservertls(sess)
1285
1286 else: raise "Unknown instance type: %s"%sock
1287
1293
1312
1313 - def S2S(self,ourname,domain,slave_session=None,port=None,route_everything=False):
1314
1315
1316
1317
1318 s=Session(socket.socket(socket.AF_INET, socket.SOCK_STREAM),self,NS_SERVER,domain)
1319 s.slave_session=slave_session
1320 if route_everything == True: self.sisters[domain+'_'+str(port)]=s
1321 s.ourname=ourname
1322 self.activatesession(s)
1323 self._connect_session(s,domain,port)
1324 return s
1325
1347
1349 self.DEBUG('server',self._l(SERVER_PVCY_ACTIVATED),'warn')
1350 template_input = {'jid_from':unicode(peer.peer).encode('utf-8'),'jid_to':unicode(stanza['to']).encode('utf-8')}
1351 split_jid=self.tool_split_jid(peer.peer)
1352 if split_jid == None: return
1353 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_CHECK)%template_input,'info')
1354
1355
1356 to=stanza['to']
1357 if not to: return
1358 to_node=to.getNode()
1359 if not to_node: return
1360 to_domain=to.getDomain()
1361 if to_domain in self.components.keys(): component=True
1362 else:component = False
1363 if to_domain in self.servernames and to_domain != to:
1364 bareto=to_node+'@'+to_domain
1365 name=stanza.getName()
1366 typ=stanza.getType()
1367 to_roster=self.DB.get(to_domain,to_node,'roster')
1368
1369 if self.DB.get(to_domain,to_node,'anon_allow') == 'yes':
1370 anon_allow=True
1371 else:
1372 anon_allow=False
1373
1374 to_working_roster_item=None
1375
1376 roster=peer.getRoster()
1377 node = split_jid[0]
1378 domain = split_jid[1]
1379 resource = split_jid[2]
1380
1381 if name=='presence':
1382 if stanza.getType() in ["subscribe", "subscribed", "unsubscribe", "unsubscribed"]:
1383 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_CLEAR_ONEWAY_PRESENCE)%template_input,'info')
1384 return
1385
1386 if node+'@'+domain == bareto:
1387 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_CLEAR_UNLIMITED)%template_input,'info')
1388 return
1389
1390 if to_roster != None:
1391 for x,y in to_roster.iteritems():
1392 if x == node+'@'+domain:
1393 to_working_roster_item = y
1394 break;
1395
1396 if to_working_roster_item == None and anon_allow==False:
1397 peer.send(Error(stanza,ERR_NOT_AUTHORIZED))
1398 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_NOTCLEAR_DOUBLEFALSE)%template_input,'error')
1399 raise NodeProcessed
1400 elif to_working_roster_item == None and anon_allow==True:
1401 to_working_roster_item = {}
1402 to_working_roster_item['subscription'] = 'none'
1403
1404 for z,a in roster.iteritems():
1405 if z == bareto:
1406 if a['subscription']=='both' and to_working_roster_item.has_key('subscription') and to_working_roster_item['subscription']=='both':
1407 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_CLEAR_BIDIRECTIONAL)%template_input,'info')
1408 return
1409 elif to_working_roster_item['subscription']=='from':
1410 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_CLEAR_ONEWAY)%template_input,'info')
1411 return
1412 elif to_working_roster_item['subscription']=='to':
1413 peer.send(Error(stanza,ERR_NOT_AUTHORIZED))
1414 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_NOTCLEAR_MODETO)%template_input,'error')
1415 raise NodeProcessed
1416
1417
1418 if anon_allow == True or str(to) in self.servernames:
1419 return
1420 else:
1421 peer.send(Error(stanza,ERR_NOT_AUTHORIZED))
1422 self.DEBUG('server',self._l(SERVER_PVCY_ACCESS_NOTCLEAR_FALSEANON)%template_input,'error')
1423 raise NodeProcessed
1424 return
1425
1428
1430 "return random int from 7000 to 8999 -- used for random port"
1431 import random
1432 return random.randrange(7000,8999)
1433
1436
1442
1536
1537 if __name__=='__main__':
1538
1539 from optparse import OptionParser
1540
1541 parser = OptionParser(usage="%prog [options] [-l lang_code] [--hostname=HOST] [-s host[:ip]]",version="%%prog %s"%__version__)
1542 parser.add_option("-p", "--psyco",
1543 action="store_true", dest="enable_psyco",
1544 help="Enable PsyCo")
1545
1546 parser.add_option("--nofallback",
1547 action="store_true", dest="disable_fallback",
1548 help="Disables fallback support (Upon a major error, the server will not try to restart itself.)")
1549
1550 parser.add_option('-l',"--lang", metavar="lang_code", default='en',dest="language",
1551 help="Used to explicitly set the daemon's default language.")
1552
1553 parser.add_option("-d", "--debug",
1554 action="store_true", dest="enable_debug",
1555 help="Enables debug messaging to console")
1556
1557 parser.add_option("--hostname", metavar="HOST", dest="hostname",
1558 help="Used to explicitly set the hostname or IP of this daemon.")
1559
1560 parser.add_option("--password", metavar="PASSWD", dest="password",
1561 help="Sets the default password for this node/daemon."\
1562 "(The password is generated, otherwise.)")
1563
1564 parser.add_option('-s',"--socker", metavar="host[:ip]", dest="socker_info",
1565 help="Enables, and connects to the host:ip " \
1566 "of a socker(tm) socket multiplexor. [EXPERIMENTAL]")
1567
1568 parser.add_option('-r',"--router", metavar="host[:ip]", dest="router_info",
1569 help="Enables, and connects to an outside router @ host:ip [EXPERIMENTAL]")
1570
1571
1572 parser.add_option("-i",
1573 action="store_true", dest="enable_interactive",
1574 help="Enables Interactive mode, allowing a console user to interactively edit the server in realtime.")
1575
1576 (cmd_options, cmd_args) = parser.parse_args()
1577
1578
1579
1580 s=Server()
1581
1582
1583 inpt_service = get_input(s)
1584 inpt_service.setDaemon(True)
1585
1586 if cmd_options.enable_interactive == True: inpt_service.start()
1587 print "Starting server . . ."
1588 while GLOBAL_TERMINATE == False:
1589 try:
1590 s.run()
1591
1592
1593 except KeyboardInterrupt:
1594 s.DEBUG('server',s._l(SERVER_SHUTDOWN_MSG),'info')
1595 s.shutdown(STREAM_SYSTEM_SHUTDOWN)
1596 except:
1597 if 'event' in globals().keys(): event.abort()
1598 s.DEBUG("server", 'Check your traceback file, please!','warn')
1599 tbfd = file('xmppd.traceback','a')
1600 tbfd.write(str('\nTRACEBACK REPORT FOR XMPPD for %s\n' + '='*55 + '\n')%time.strftime('%c'))
1601
1602 traceback.print_exc(None,tbfd)
1603 tbfd.close()
1604 if cmd_options.disable_fallback == True: GLOBAL_TERMINATE = True
1605