Package spade :: Package xmppd :: Module xmppd
[hide private]
[frames] | no frames]

Source Code for Module spade.xmppd.xmppd

   1  #!/usr/bin/python 
   2  # -*- coding: UTF-8 -*- 
   3   
   4  # XMPPD :: eXtensible Messaging and Presence Protocol Daemon 
   5   
   6  # Copyright (C) 2005 Kristopher Tate / BlueBridge Technologies Group, Inc. 
   7  # Copyright (C) 2004 Alexey Nezhdanov 
   8  # 
   9  # This program is free software; you can redistribute it and/or modify 
  10  # it under the terms of the GNU General Public License as published by 
  11  # the Free Software Foundation; either version 2 of the License, or 
  12  # (at your option) any later version. 
  13  # 
  14  # This program is distributed in the hope that it will be useful, 
  15  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  16  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  17  # GNU General Public License for more details. 
  18  # 
  19  # You should have received a copy of the GNU General Public License 
  20  # along with this program; if not, write to the Free Software 
  21  # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
  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  #globals()['LANG_LIST'] = [] 
  38   
  39  globals()['SERVER_MOTD'] = "Hello, I'm Help Desk. Type 'menu' for help." 
  40   
  41  globals()['PORT_5222'] = 5222 # Default XMPP port for c2s 
  42  globals()['PORT_5223'] = 5223 # Default XMPP port for c2s (w/ TLS) 
  43  globals()['PORT_5269'] = 5269 # Default XMPP port for s2s 
  44  globals()['PORT_8000'] = 8001 # Port to open for all XMLRPC requests 
  45   
  46  globals()['MAXREQUESTLENGTH'] = 10000 # maximum allowed length of XML-RPC request (in bytes) 
  47  globals()['XMPPD_MAX_CONNECTIONS'] = 1 # [SOCKER] Set maximum number of connections for this node. 
  48   
  49  globals()['SOCKER_TGUID'] = 'BBTECH_XMPPD' # CHANGE THIS IF YOU ARE TO USE SOCKER! 
  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  # Transport-level flags 
  60  SOCKET_UNCONNECTED  = 0 
  61  SOCKET_ALIVE        = 1 
  62  SOCKET_DEAD         = 2 
  63  # XML-level flags 
  64  STREAM__NOT_OPENED  = 1 
  65  STREAM__OPENED      = 2 
  66  STREAM__CLOSING     = 3 
  67  STREAM__CLOSED      = 4 
  68  # XMPP-session flags 
  69  SESSION_NOT_AUTHED  = 1 
  70  SESSION_AUTHED      = 2 
  71  SESSION_BOUND       = 3 
  72  SESSION_OPENED      = 4 
  73  # XMLRPC-session flags 
  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   
80 -class fake_select:
81 - def __init__(self):
82 ## poll flags 83 self.POLLIN = 0x0001 84 self.POLLOUT = 0x0004 85 self.POLLERR = 0x0008 86 87 ## synonyms 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 ## ignored 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
103 - class poll:
104 - def __init__(self):
105 ## poll flags 106 self.POLLIN = 0x0001 107 self.POLLOUT = 0x0004 108 self.POLLERR = 0x0008 109 110 ## synonyms 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 ## ignored 119 self.POLLHUP = 0x0010 120 self.POLLNVAL = 0x0020 121 self._registered = {}
122
123 - def register(self,fd,eventmask=None):
124 try: 125 self._registered[fd.fileno()] = {'fd':fd,'mask':eventmask} 126 return True 127 except: 128 return False
129 - def unregister(self,fd):
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 #Select does not work with every list empty. PATCH: 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 #Import all of the localization files 192 globals().update({'LANG_LIST':[]}) 193 #for m in os.listdir('locale'): 194 # if m[:2]=='__' or m[-3:]<>'.py': continue 195 # execfile(os.getcwd() + '/locale/' + m[:-3] + '.py') 196 from locales import * 197
198 -class localizer:
199 - def __init__(self,lang=None):
200 global DEFAULT_LANG 201 self._default = DEFAULT_LANG 202 if lang == None or type(lang) != type(''): 203 self._lang = DEFAULT_LANG 204 else: 205 self._lang = lang
206
207 - def set_lang(self,lang):
208 self._lang = lang 209 return True
210
211 - def localize(self,val,lang=None):
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
225 - def build_localeset(self,records):
226 for record in records.split('\n')[1:]: 227 var,code,text=record.split(' -- ') 228 name=var.upper().replace('-','_') 229 #if globals()['cmd_options'].enable_debug == True: print 'adding ' + name + '::' + code 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
236 -class Session_Dummy:
237 "Session_Dummy is used to trick dispatch into actually sending information!"
238 - def __init__(self,server):
239 self.Stream() 240 self.DEBUG = server.Dispatcher.DEBUG 241 self._expected={}
242
243 - class Stream:
244 - def __init__(self):
245 self._mini_dom = None
246 247
248 -class Session:
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
295 - def StartStream(self):
296 self._stream_state=STREAM__NOT_OPENED 297 self.Stream=simplexml.NodeBuilder() 298 self.Stream._dispatch_depth=2 299 self.Stream.dispatch=self.dispatch 300 self.Parse=self.Stream.Parse 301 self.Stream.stream_footer_received=self._stream_close 302 if self.TYP=='client': 303 self.Stream.stream_header_received=self._catch_stream_id 304 self._stream_open() 305 else: 306 self.Stream.stream_header_received=self._stream_open
307
308 - def receive(self):
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): # length of 0 means disconnect 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 #self.enqueue(chunk) 329 except: 330 pass 331 self.enqueue(chunk)
332
333 - def enqueue(self,stanza):
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
345 - def push_queue(self,failreason=ERR_RECIPIENT_UNAVAILABLE):
346 347 if self._stream_state>=STREAM__CLOSED or self._socket_state>=SOCKET_DEAD: # the stream failed. Return all stanzas that are still waiting for delivery. 348 self._owner.deactivatesession(self) 349 self.trusted=1 350 for key in self.deliver_key_queue: # Not sure. May be I 351 self.dispatch(Error(self.deliver_queue_map[key],failreason)) # should simply re-dispatch it? 352 for stanza in self.stanza_queue: # But such action can invoke 353 self.dispatch(Error(stanza,failreason)) # Infinite loops in case of S2S connection... 354 self.deliver_queue_map,self.deliver_key_queue,self.stanza_queue={},[],[] 355 return 356 elif self._session_state>=SESSION_AUTHED: # FIXME! 357 #### LOCK_QUEUE 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) # should be re-evaluated for SSL connection. 362 self.deliver_queue_map[self._stream_pos_queued]=stanza # position of the stream when stanza will be successfully and fully sent 363 self.deliver_key_queue.append(self._stream_pos_queued) 364 self.stanza_queue=[] 365 #### UNLOCK_QUEUE 366 367 if self.sendbuffer and select.select([],[self._sock],[])[1]: 368 try: 369 # LOCK_QUEUE 370 sent=self._send(str(self.sendbuffer)) 371 except Exception, err: 372 #self.DEBUG('server','Attempting to kill %i!!!\n%s'%(self._sock.fileno(),err),'warn') 373 self.DEBUG('Attempting to kill %i!!!\n%s'%(self._sock.fileno(),err),'warn') 374 # UNLOCK_QUEUE 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 # Should be acquired from socket somehow. Take SSL into account. 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 # UNLOCK_QUEUE 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
396 - def libevent_write(self):
397 if self.sendbuffer: 398 399 try: 400 # LOCK_QUEUE 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 # UNLOCK_QUEUE 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 # Should be acquired from socket somehow. Take SSL into account. 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 # UNLOCK_QUEUE 416
417 - def dispatch(self,stanza):
418 if self._stream_state==STREAM__OPENED: # if the server really should reject all stanzas after he is closed stream (himeself)? 419 self.DEBUG(stanza.__str__(),'dispatch') 420 return self.Dispatcher.dispatch(stanza,self)
421
422 - def fileno(self): return self._sock.fileno()
423
424 - def _catch_stream_id(self,ns=None,tag='stream',attrs={}):
425 if not attrs.has_key('id') or not attrs['id']: 426 return self.terminate_stream(STREAM_INVALID_XML) 427 self.ID=attrs['id'] 428 if not attrs.has_key('version'): self._owner.Dialback(self)
429
430 - def _stream_open(self,ns=None,tag='stream',attrs={}):
431 text='<?xml version="1.0" encoding="utf-8"?>\n<stream:stream' 432 if self.TYP=='client': 433 text+=' to="%s"'%self.peer 434 else: 435 text+=' id="%s"'%self.ID 436 if not attrs.has_key('to'): text+=' from="%s"'%self._owner.servernames[0] 437 else: text+=' from="%s"'%attrs['to'] 438 if attrs.has_key('xml:lang'): text+=' xml:lang="%s"'%attrs['xml:lang'] 439 #if self.xmlns: xmlns=self.xmlns 440 if self.Stream.xmlns in [NS_CLIENT, NS_COMPONENT_ACCEPT]: self.xmlns = xmlns = self.Stream.xmlns 441 else: xmlns=NS_SERVER 442 text+=' xmlns:db="%s" xmlns:stream="%s" xmlns="%s"'%(NS_DIALBACK,NS_STREAMS,xmlns) 443 if attrs.has_key('version') or self.TYP=='client': text+=' version="1.0"' 444 self.send(text+'>') 445 self.set_stream_state(STREAM__OPENED) 446 if self.TYP=='client': return 447 if tag<>'stream': return self.terminate_stream(STREAM_INVALID_XML) 448 if ns<>NS_STREAMS: return self.terminate_stream(STREAM_INVALID_NAMESPACE) 449 if self.Stream.xmlns<>self.xmlns: return self.terminate_stream(STREAM_BAD_NAMESPACE_PREFIX) 450 if not attrs.has_key('to'): return self.terminate_stream(STREAM_IMPROPER_ADDRESSING) 451 if attrs['to'] not in self._owner.servernames: return self.terminate_stream(STREAM_HOST_UNKNOWN) 452 self.ourname=attrs['to'].lower() 453 if self.TYP=='server' and attrs.has_key('version'): self.send_features()
454
455 - def send_features(self):
456 features=Node('stream:features') 457 if NS_TLS in self.waiting_features: 458 features.NT.starttls.setNamespace(NS_TLS) 459 features.T.starttls.NT.required 460 if NS_SASL in self.waiting_features: 461 features.NT.mechanisms.setNamespace(NS_SASL) 462 for mec in self._owner.SASL.mechanisms: 463 features.T.mechanisms.NT.mechanism=mec 464 else: 465 if NS_BIND in self.waiting_features: features.NT.bind.setNamespace(NS_BIND) 466 if NS_SESSION in self.waiting_features: features.NT.session.setNamespace(NS_SESSION) 467 self.send(features)
468
469 - def getResource(self):
470 jid=self.peer 471 try: barejid,resource=jid.split('/') 472 except: return None 473 return resource
474
475 - def getRoster(self):
476 split_jid = self.getSplitJID() 477 return self._owner.DB.get(split_jid[1],split_jid[0],'roster')
478
479 - def getGroups(self):
480 split_jid = self.getSplitJID() 481 return self._owner.DB.get(split_jid[1],split_jid[0],'groups')
482
483 - def getName(self):
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
489 - def getSplitJID(self):
490 return self._owner.tool_split_jid(self.peer)
491
492 - def getBareJID(self):
493 try: 494 return '%s@%s'%self.getSplitJID()[0:2] 495 except: 496 # Component JID 497 return self.peer.split("/")[0]
498
499 - def getKarma(self):
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
506 - def updateKarma(self,karma):
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
513 - def feature(self,feature):
514 if feature not in self.features: self.features.append(feature) 515 self.unfeature(feature)
516
517 - def unfeature(self,feature):
518 if feature in self.waiting_features: self.waiting_features.remove(feature)
519
520 - def _stream_close(self,unregister=1):
521 if self._stream_state>=STREAM__CLOSED: return 522 self.set_stream_state(STREAM__CLOSING) 523 self.send('</stream:stream>') 524 self.set_stream_state(STREAM__CLOSED) 525 self.push_queue() # decompose queue really since STREAM__CLOSED 526 if unregister: self._owner.unregistersession(self) 527 if self.lib_event != None: self.lib_event.delete() 528 self._destroy_socket()
529
530 - def terminate_stream(self,error=None,unregister=1):
531 if self._stream_state>=STREAM__CLOSING: return 532 if self._stream_state<STREAM__OPENED: 533 self.set_stream_state(STREAM__CLOSING) 534 self._stream_open() 535 else: 536 self.set_stream_state(STREAM__CLOSING) 537 p=Presence(typ='unavailable') 538 p.setNamespace(NS_CLIENT) 539 self.Dispatcher.dispatch(p,self) 540 if error: 541 if isinstance(error,Node): self.send(error) 542 else: self.send(ErrorNode(error)) 543 self._stream_close(unregister=unregister) 544 if self.slave_session: 545 self.slave_session.terminate_stream(STREAM_REMOTE_CONNECTION_FAILED)
546
547 - def _destroy_socket(self):
548 """ breaking cyclic dependancy to let python's GC free memory just now """ 549 self.Stream.dispatch=None 550 self.Stream.stream_footer_received=None 551 self.Stream.stream_header_received=None 552 self.Stream.destroy() 553 self._sock.close() 554 self.set_socket_state(SOCKET_DEAD)
555
556 - def start_feature(self,f):
557 if self.feature_in_process: raise "Starting feature %s over %s !"%(f,self.feature_in_process) 558 self.feature_in_process=f
559 - def stop_feature(self,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
562 - def set_socket_state(self,newstate):
563 if self._socket_state<newstate: self._socket_state=newstate
564 - def set_session_state(self,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 # if newstate==SESSION_OPENED: self.enqueue(Message(self.peer,SERVER_MOTD,frm=self.ourname)) # Remove in prod. quality server 574 if newstate==SESSION_OPENED: 575 # Enqueue previously stored messages 576 for msg in self._owner.DB.get_storage(self.peer, ""): 577 #print "### ENQ ", str(msg) 578 self.enqueue(msg)
579
580 - def set_stream_state(self,newstate):
581 if self._stream_state<newstate: self._stream_state=newstate
582
583 -class Socker_client:
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: #See if the Socker server will say hello... 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
610 - def get_uuid(self):
611 if self.conn_okay == True: 612 return self._proxy.uuidgen({}) 613 else: 614 return None
615
616 - def get_hostname(self):
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
627 - def get_sguid(self):
628 return self._sguid
629
630 - def get_tguid(self):
631 return self._tguid
632
633 - def send_broadcast(self,stanza):
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}) #Send broadcast to Socker 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) #Send request to Socker 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
666 - def add_data(self,data):
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
672 - def remove_data(self,data):
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
678 - def add_data_root(self,data):
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
684 - def remove_data_root(self,data):
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
690 - def destroy(self):
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}) #Send request to Socker 693 694 if res['code'] != 1: 695 return None 696 else: 697 self._registered = [] 698 return res
699
700 -class RPC_Client:
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
713 - def RPC_handler(self,data):
714 "Handler for incoming remote procedure calls" 715 try: 716 if self.stage == XMLRPC_STAGE_ZERO: 717 self.stage = XMLRPC_STAGE_ONE #Get client's headers out of the buffer 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
742 - def receive(self):
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: # length of 0 means disconnect 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 # print "sent",msg,sent 757 if sent == 0: 758 self.terminate() 759 totalsent = totalsent + sent 760 except: 761 pass
762
763 - def fileno(self): return self._sock.fileno()
764 - def getsockname(self): return self._sock.getsockname()
765
766 - def terminate(self):
767 # Handle our socket 768 self._owner.unregistersession(self) 769 self._sock.close()
770 771
772 - def rpc_dispatch(self, method, params):
773 try: 774 # We are forcing the 'export_' prefix on methods that are 775 # callable through XML-RPC to prevent potential security 776 # problems 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
786 - def rpcexport_socker(self,inpt):
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
808 - def rpcexport_hello(self,inpt):
809 return {'code':1,'msg':'Hello!'}
810
811 - def rpcexport_status(self,inpt):
812 "RPC endpoint to get status information" 813 return {'code':1,'msg':'RC-OK','data':self._owner.tool_get_status()}
814
815 -class multisession_manager:
816
817 - def __init__(self,owner,nthreads=128):
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
829 - def destroy(self):
830 for t in self.threads.values(): t.stop()
831
832 - def select_thread(self):
833 return random.choice(self.threads.values())
834
835 - def registersession(self,s):
837
838 - def unregistersession(self,s):
839 self.threads[s.thread_id].unregistersession(s)
840
841 - class multisession_thread(threading.Thread):
842
843 - def __init__(self,owner,index):
844 845 threading.Thread.__init__(self) 846 847 self.alive = True # Boolean attribute indicating wether the thread is alive 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
856 - def run(self):
857 while self.isAlive() and self.alive: 858 for fileno,ev in self.sockpoll.poll(1000): 859 try: sess=self.sockets[fileno] 860 except: sess = None 861 862 if isinstance(sess,Session): 863 try: 864 data=sess.receive() 865 except IOError: # client closed the connection 866 sess.terminate_stream() 867 self.unregistersession(sess) 868 data='' 869 if data: 870 try: 871 sess.Parse(data) 872 except simplexml.xml.parsers.expat.ExpatError: 873 sess.terminate_stream(STREAM_XML_NOT_WELL_FORMED) 874 self.unregistersession(sess) 875 if time.time() - sess.last_seen >= 60.0: 876 sess.terminate_stream() 877 self.unregistersession(sess)
878
879 - def stop(self):
880 self.alive = False
881
882 - def registersession(self,s):
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
894 - def unregistersession(self,s):
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()] # Destroy the record 907 self._owner.DEBUG('server',self._owner._l(SERVER_NODE_UNREGISTERED)%{'fileno':s.fileno(),'raw':s}) 908 self.SESS_LOCK.release()
909
910 -class Server:
911 - def __init__(self,cfgfile="./xmppd.xml",cmd_options={},under_restart=False):
912 # threading.Thread.__init__(self) 913 self.defaultNamespace = NS_CLIENT 914 #Load localizer as _l 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 # Do we have lib event??? 922 #print "LIBEVENT ENABLED" 923 except: 924 cmd_options['select_enabled'] = True # If not, we'll have to just use the old select :/ 925 #print "SELECT ENABLED" 926 if not cmd_options['select_enabled']: event.init() 927 928 # Components dict 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: # and getattr(select,'poll',None) == None: 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 #Config file 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 #psyco.log() 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 #Temp lang stuff 985 globals()['DEFAULT_LANG'] = cmd_options.setdefault('language','en') # Changed to the --lang flag 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 #stats 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 #if issubclass(addon,PlugIn): 1010 try: 1011 if self.__dict__.has_key(addon().__class__.__name__) and under_restart == True: 1012 # self.DEBUG('server','Plugging-out?','info') 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 #else: self.__dict__[addon().__class__.__name__]=addon() 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 #Generate port map 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'])) #add host_name specific later 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: #event 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
1085 - def tool_split_jid(self,jid):
1086 "Returns tuple of id,server,resource" 1087 if "@" in jid: 1088 try: id,extras=jid.split('@') 1089 except: return None 1090 try: server,resource=extras.split('/') 1091 except: return (id,extras) 1092 return (id,server,resource) 1093 else: # Component or Server 1094 if "/" in jid: # With resource 1095 server, extras = jid.split("/") 1096 return (server, extras) 1097 else: # No resource, only dots 1098 return (jid)
1099
1100 - def tool_timeDurration(self,the_time):
1101 days = floor(the_time/60/60/24) 1102 hours = floor((the_time - days*60*60*24)/60/60) 1103 minutes = floor((the_time - days*60*60*24 - hours*60*60)/60) 1104 seconds = floor((the_time - days*60*60*24 - hours*60*60 - minutes*60)) 1105 return (days,hours,minutes,seconds)
1106
1107 - def tool_readableTimeDurration(self,in_time):
1108 if type(in_time) != ((1,)): in_time = self.tool_timeDurration(in_time) 1109 out = '' 1110 if in_time[0]>=1: out += '%i%s '%(in_time[0],'d') 1111 if in_time[1]>=1: out += '%i%s '%(in_time[1],'h') 1112 if in_time[2]>=1: out += '%i%s '%(in_time[2],'m') 1113 if in_time[3]>=1: out += '%i%s '%(in_time[3],'s') 1114 return out
1115
1116 - def tool_get_status(self):
1117 "Get this node's status" 1118 data = {} 1119 data['soft'] = 'BlueBridge Jibber-Jabber 0.3' 1120 1121 data['no_registered'] = {} 1122 for x in self.servernames: 1123 data['no_registered'][x] = self.DB.getNumRegistered(x) 1124 1125 data['uptime'] = self.tool_readableTimeDurration(time.time() - self.up_since) 1126 data['raw_uptime'] = time.time() - self.up_since 1127 data['no_routes'] = len(self.routes.keys()) 1128 data['no_reg_users_conn'] = len(self.Router._data) 1129 data['no_conn_servers'] = self.num_servers 1130 data['no_msg_routed'] = self.num_messages 1131 return data
1132
1133 - def feature(self,feature):
1134 if feature and feature not in self.features: self.features.append(feature)
1135
1136 - def unfeature(self,feature):
1137 if feature and feature in self.features: self.features.remove(feature)
1138
1139 - def registersession(self,s):
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 #s._registered=1 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: #if 'event' in globals().keys(): 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
1167 - def unregistersession(self,s):
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 #s._registered=0 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() # Kill libevent event 1185 del self.leventobjs[s.fileno()] 1186 1187 del self.sockets[s.fileno()] # Destroy the record 1188 self.DEBUG('server',self._l(SERVER_NODE_UNREGISTERED)%{'fileno':s.fileno(),'raw':s}) 1189 self.SESS_LOCK.release()
1190
1191 - def activatesession(self,s,peer=None):
1192 #print "### TRYING TO ACTIVATE SESSION %s WITH PEER %s"%(str(s),str(peer)) 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 #print "### ACTIVATED SESSION %s WITH PEER %s"%(str(s),str(peer)) 1202
1203 - def getsession(self, jid):
1204 try: return self.routes[jid] 1205 except KeyError: pass
1206
1207 - def deactivatesession(self, peer):
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 #print "### TRYING TO DE-ACTIVATE SESSION OF PEER %s : %s"%(str(peer),str(s)) 1212 return s
1213
1214 - def run(self):
1215 global GLOBAL_TERMINATE 1216 if 'event' in globals().keys(): event.signal(2,self._lib_out).add() 1217 if self.cmd_options['select_enabled'] == True: 1218 while GLOBAL_TERMINATE == False: 1219 self.select_handle() 1220 1221 elif 'event' in globals().keys(): event.dispatch()
1222 1223
1224 - def libevent_read_callback(self, ev, fd, evtype, pipe):
1225 "Functions as a callback for libevent pased " 1226 self._socket_handler(self.sockets[fd.fileno()],'libevent')
1227 1228
1229 - def select_handle(self):
1230 "Handles select-based socket handling" 1231 for fileno,ev in self.sockpoll.poll(1000): 1232 self._socket_handler(self.sockets[fileno],'select')
1233
1234 - def _socket_handler(self,sock,mode):
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: # client closed the connection 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: # client closed the connection 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 # self.DEBUG('server','%s:%s is a client!'%(host,port),'info') 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: # client closed the connection 1274 sess.terminate() 1275 data='' 1276 if data: sess.send("") #let it know that we're ready to accept 1277 return True 1278 1279 else: 1280 # self.DEBUG('server','%s:%s is a server!'%(host,port),'info') 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
1288 - def _lib_out(self):
1289 if isinstance(self._socker,Socker_client): self._socker.destroy() 1290 event.abort() 1291 self.DEBUG('server',self._l(SERVER_SHUTDOWN_MSG),'info') 1292 self.shutdown(STREAM_SYSTEM_SHUTDOWN)
1293
1294 - def shutdown(self,reason):
1295 global GLOBAL_TERMINATE 1296 GLOBAL_TERMINATE = True 1297 socklist=self.sockets.keys() 1298 for fileno in socklist: 1299 s=self.sockets[fileno] 1300 if isinstance(s,socket.socket): 1301 try: 1302 self.unregistersession(s) 1303 s.shutdown(2) 1304 s.close() 1305 except: 1306 pass 1307 elif isinstance(s,Session): s.terminate_stream(reason) 1308 try: 1309 self.multisession_manager.destroy() 1310 except: 1311 self.DEBUG('server',"Could not destroy multisession manager","warn")
1312
1313 - def S2S(self,ourname,domain,slave_session=None,port=None,route_everything=False):
1314 ### THIS IS FUCKING DANGEROUS!!!!! 1315 #s = self.getsession(domain) 1316 #if s: return s 1317 ### THIS IS FUCKING DANGEROUS!!!!! 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
1326 - def _connect_session(self,session,domain,port):
1327 print session.DEBUG(self._l(SERVER_S2S_ATTEMPT_CONNECTION)%{'server':domain},'info') 1328 if port == None: 1329 port = 5269 1330 else: 1331 print "s2s port set", port 1332 try: session._sock.connect((domain,port)) 1333 except socket.error,err: 1334 print session.DEBUG(self._l(SERVER_S2S_THREAD_ERROR)%err,'error') 1335 self.num_servers -= 1 1336 session.set_session_state(SESSION_BOUND) 1337 session.set_socket_state(SOCKET_DEAD) 1338 if err[0]==errno.ETIMEDOUT: failreason=ERR_REMOTE_SERVER_TIMEOUT 1339 elif err[0]==socket.EAI_NONAME: failreason=ERR_REMOTE_SERVER_NOT_FOUND 1340 else: failreason=ERR_UNDEFINED_CONDITION 1341 session.push_queue(failreason) 1342 session.terminate_stream(STREAM_REMOTE_CONNECTION_FAILED,unregister=0) 1343 return 1344 session.set_socket_state(SOCKET_ALIVE) 1345 session.push_queue() 1346 self.registersession(session)
1347
1348 - def Privacy(self,peer,stanza):
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 #Stanza Stuff 1356 to=stanza['to'] 1357 if not to: return # Not for us. 1358 to_node=to.getNode() 1359 if not to_node: return # Yep, not for us. 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 #Session stuff 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 # Take the blue pill 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 # Take the blue pill 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 # Take the blue pill 1424 return
1425
1426 - def Dialback(self,session):
1428
1429 - def pick_rand(self):
1430 "return random int from 7000 to 8999 -- used for random port" 1431 import random 1432 return random.randrange(7000,8999)
1433
1434 -def start_new_thread_fake(func,args):
1435 func(*args)
1436
1437 -def testrun():
1438 thread.start_new_thread=start_new_thread_fake 1439 import modules 1440 modules.stream.thread.start_new_thread=start_new_thread_fake 1441 return Server()
1442
1443 -class get_input(threading.Thread):
1444 - def __init__(self,owner):
1445 self._owner = owner 1446 threading.Thread.__init__(self)
1447 - def run(self):
1448 global GLOBAL_TERMINATE 1449 while GLOBAL_TERMINATE == False: 1450 the_input = raw_input("") 1451 if the_input == 'restart': 1452 self._owner.DEBUG('server','Stand-by; Restarting entire server!','info') 1453 self._owner.shutdown(STREAM_SYSTEM_SHUTDOWN) 1454 self._owner.DEBUG('server','Server has been shutdown, restarting NOW!','info') 1455 GLOBAL_TERMINATE = False 1456 self._owner.__init__(['always'],True) 1457 1458 elif the_input == 'sys_debug': 1459 print sys.exc_info() 1460 print traceback.print_exc() 1461 elif the_input.split(' ')[0] == 'restart': 1462 1463 import modules 1464 reload(modules) 1465 for addon in modules.addons: 1466 if addon().__class__.__name__.lower() == the_input.split(' ')[1].lower(): 1467 if issubclass(addon,PlugIn): 1468 if self._owner.__dict__.has_key(addon().__class__.__name__): 1469 # self.DEBUG('server','Plugging-out?','info') 1470 1471 self._owner.DEBUG('server','Plugging %s out of %s.'%(addon(),s),'stop') 1472 if addon().DBG_LINE in self._owner.debug_flags: 1473 self._owner.debug_flags.remove(addon().DBG_LINE) 1474 if getattr(addon(),'_exported_methods',None) != None: 1475 for method in addon()._exported_methods: del self._owner.__dict__[method.__name__] 1476 if getattr(addon(),'_old_owners_methods',None) != None: 1477 for method in addon()._old_owners_methods: self._owner.__dict__[method.__name__]=method 1478 del self._owner.__dict__[addon().__class__.__name__] 1479 if addon().__class__.__dict__.has_key('plugout'): addon().plugout() 1480 self._owner.unfeature(addon.NS) 1481 1482 addon().PlugIn(s) 1483 else: 1484 addon().PlugIn(s) 1485 else: self._owner.__dict__[addon.__class__.__name__]=addon() 1486 self._owner.feature(addon.NS) 1487 1488 elif the_input.split(' ')[0] == 'start': 1489 1490 import modules 1491 reload(modules) 1492 for addon in modules.addons: 1493 if addon().__class__.__name__.lower() == the_input.split(' ')[1].lower(): 1494 if issubclass(addon,PlugIn): 1495 addon().PlugIn(s) 1496 else: self._owner.__dict__[addon.__class__.__name__]=addon() 1497 self._owner.feature(addon.NS) 1498 1499 elif the_input.split(' ')[0] == 'stop': 1500 1501 import modules 1502 reload(modules) 1503 for addon in modules.addons: 1504 if addon().__class__.__name__.lower() == the_input.split(' ')[1].lower(): 1505 if issubclass(addon,PlugIn): 1506 if self._owner.__dict__.has_key(addon().__class__.__name__): 1507 # self.DEBUG('server','Plugging-out?','info') 1508 1509 self._owner.DEBUG('server','Plugging %s out of %s.'%(addon(),s),'stop') 1510 if addon().DBG_LINE in self._owner.debug_flags: 1511 self._owner.debug_flags.remove(addon().DBG_LINE) 1512 if getattr(addon(),'_exported_methods',None) != None: 1513 for method in addon()._exported_methods: del self._owner.__dict__[method.__name__] 1514 if getattr(addon(),'_old_owners_methods',None) != None: 1515 for method in addon()._old_owners_methods: self._owner.__dict__[method.__name__]=method 1516 del self._owner.__dict__[addon().__class__.__name__] 1517 if addon().__class__.__dict__.has_key('plugout'): addon().plugout() 1518 else: 1519 self._owner.DEBUG('server','Error: Could not un-plug %s'%addon().__class__.__name__,'error') 1520 else: 1521 if getattr(addon(),'_exported_methods',None) != None: 1522 for method in addon()._exported_methods: del self._owner.__dict__[method.__name__] 1523 if getattr(addon(),'_old_owners_methods',None) != None: 1524 for method in addon()._old_owners_methods: self._owner.__dict__[method.__name__]=method 1525 del self._owner.__dict__[addon().__class__.__name__] 1526 if addon().__class__.__dict__.has_key('plugout'): addon().plugout() 1527 if self._owner.__dict__.has_key(addon().__class__.__name__) == True: 1528 self._owner.DEBUG('server','Error: Could not un-plug %s'%addon().__class__.__name__,'error') 1529 self._owner.unfeature(addon.NS) 1530 1531 elif the_input == 'quit': 1532 GLOBAL_TERMINATE = True 1533 event.abort() 1534 break 1535 time.sleep(.01)
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 #Create the xmppd server 1580 s=Server() 1581 # s=Server(cmd_options=eval(str(cmd_options))) 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 # s.DEBUG('server',s._l(SERVER_SHUTDOWN_MSG),'info') 1592 # s.shutdown(STREAM_SYSTEM_SHUTDOWN) 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 #write traceback 1602 traceback.print_exc(None,tbfd) 1603 tbfd.close() 1604 if cmd_options.disable_fallback == True: GLOBAL_TERMINATE = True 1605