def testParams(self): """Func should be callable with params""" def a(p1, p2, p3): return p1 + p2 + p3 fc = FunctionCall(a, {'p1' : 'a', 'p2' : 'b', 'p3' : 'c'}) self.assert_(fc.func(*fc.funcArgs))
def testNoParams(self): """Func should be callable without exceptions""" def a(): pass fc = FunctionCall(a) self.assert_(callable(fc.func)) fc.func()
def testSameHashParams(self): """If the args are substituted after creation, the hash shouldn't change""" def a(arg1, arg2): return arg1+arg2 fc = FunctionCall(a, {'arg1' : 1, 'arg2' : 2}) hash1 = fc.__hash__() fc.funcArgs = {'arg1' : 2, 'arg2' : 'something else'} hash2 = fc.__hash__() self.assert_(hash1 == hash2)
def testSameHashFunc(self): """If the function is substituted after creation, the hash shouldn't change""" def a(): pass def b(): return "asdf" fc = FunctionCall(a) hash1 = fc.__hash__() fc.func = b hash2 = fc.__hash__() self.assert_(hash1 == hash2)
def handle(self, tree, msg, lastRetVal=None): self.done = False tpool = msg.conn.server.threadpool msg.conn.data['user']['requestedRoster'] = True # the actual function executing in the thread def act(): # TODO: verify that it's coming from a known user jid = msg.conn.data['user']['jid'] resource = msg.conn.data['user']['resource'] id = tree.get('id') if id is None: logging.warning('[%s] No id in roster get query. Tree: %s', self.__class__, tree) # TODO: throw exception here return roster = Roster(jid) roster.loadRoster() res = Element('iq', { 'to': '/'.join([jid, resource]), 'type': 'result', 'id': id }) res.append(roster.getAsTree()) return chainOutput(lastRetVal, res) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle(self, tree, msg, lastRetVal=None): self.done = False tpool = msg.conn.server.threadpool # the actual function executing in the thread def act(): data = msg.conn.data data['sasl']['in-progress'] = True mech = tree.get('mechanism') if mech == 'PLAIN': data['sasl']['mech'] = 'PLAIN' authtext64 = tree.text plain = mechs.SASLPlain(msg) data['sasl']['mechObj'] = plain return chainOutput(lastRetVal, plain.handle(authtext64)) elif mech == 'DIGEST-MD5': data['sasl']['mech'] = 'DIGEST-MD5' digest = mechs.SASLDigestMD5(msg) data['sasl']['mechObj'] = digest return chainOutput(lastRetVal, digest.handle()) else: logging.warning("[%s] Mechanism %s not implemented", self.__class__, mech) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle_read(self): def cb(exception=None): print 'called back', exception def check(asdf): print asdf return True checkFunc = FunctionCall(check, {'asdf': 'test string'}) self.watch_function(checkFunc, cb) print self.recv(4096)
def handle(self, tree, msg, lastRetVal=None): self.done = False tpool = msg.conn.server.threadpool # the actual function executing in the thread def act(): mech = msg.conn.data['sasl']['mechObj'] if not mech: # TODO: close connection logging.warning( "[%s] Mech object doesn't exist in connection data for %s", self.__class__, msg.conn.addr) logging.debug("[%s] %s", self.__class__, msg.conn.data) return text = tree.text if text: return chainOutput(lastRetVal, mech.handle(text.strip())) else: return chainOutput(lastRetVal, mech.handle(tree)) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle(self, tree, msg, lastRetVal=None): def sleep(arg): """This is the actual function executing in the thread""" # time.sleep(10) # this also worked but slows down tests return 'success' def cb(workReq, retVal): """Asyncore calls this back when checkFunc returns true""" self.passed = retVal req = pjs.threadpool.makeRequests(sleep, [([0], None)], cb) def checkFunc(): """Asyncore will run this regularly and call cb when true""" return self.passed def initFunc(): """Asyncore will execute this function before checkFunc""" [self.threadpool.putRequest(r) for r in req] return FunctionCall(checkFunc), FunctionCall(initFunc)
def testInitFuncWithParams(self): """Init function with two parameters""" def cb(e=None): self.passed = self.passed and e is None def check(param1, param2): return True def init(a, b): self.passed = a and b checkFunc = FunctionCall(check, { 'param1': 'non-empty string', 'param2': 'asdfasdf' }) initFunc = FunctionCall(init, {'a': 'str', 'b': 'str'}) self.server.watch_function(checkFunc, cb, initFunc) asyncore.poll() self.assert_(self.passed)
def testInitFunc(self): """Simple init function""" def cb(e=None): self.passed = self.passed and e is None def check(param1, param2): return True def init(): self.passed = True checkFunc = FunctionCall(check, { 'param1': 'non-empty string', 'param2': 'asdfasdf' }) initFunc = FunctionCall(init) self.server.watch_function(checkFunc, cb, initFunc) asyncore.poll() self.assert_(self.passed)
def testSimple(self): """Simple callback and simple check function with no params""" def cb(e=None): self.passed = True and e is None def check(): return True checkFunc = FunctionCall(check) self.server.watch_function(checkFunc, cb) asyncore.poll() self.assert_(self.passed)
def testCheckParam(self): """Check function has one parameter""" def cb(e=None): self.passed = self.passed and e is None def check(param1): if param1: self.passed = True return True checkFunc = FunctionCall(check, {'param1': 'non-empty string'}) self.server.watch_function(checkFunc, cb) asyncore.poll() self.assert_(self.passed)
def testCheckParams(self): """Check function has more than one parameters""" def cb(e=None): self.passed = self.passed and e is None def check(param1, param2): if param1 and param2: self.passed = True return True checkFunc = FunctionCall(check, { 'param1': 'non-empty string', 'param2': 'asdfasdf' }) self.server.watch_function(checkFunc, cb) asyncore.poll() self.assert_(self.passed)
def handle(self, tree, msg, lastRetVal=None): self.done = False self.retVal = lastRetVal tpool = msg.conn.server.threadpool def act(): # TODO: verify that it's coming from a known user jid = msg.conn.data['user']['jid'] cjid = JID(tree.get('to')) type = tree.get('type') if not cjid: logging.warning('[%s] No contact jid specified in subscription ' +\ 'query. Tree: %s', self.__class__, tree) # TODO: throw exception here return roster = Roster(jid) # get the RosterItem cinfo = roster.getContactInfo(cjid.getBare()) retVal = lastRetVal # C2S SUBSCRIBE if type == 'subscribe': # we must always route the subscribe presence so as to allow # the other servers to resynchronize their sub lists. # RFC 3921 9.2 if not cinfo: # contact doesn't exist, but according to RFC 3921 # section 8.2 bullet 4 we MUST create a new roster entry # for it with empty name and groups. roster.updateContact(cjid.getBare()) # now refetch the contact info cinfo = roster.getContactInfo(cjid.getBare()) cid = cinfo.id name = cinfo.name subscription = cinfo.subscription groups = cinfo.groups # update the subscription state if subscription == Subscription.NONE: roster.setSubscription(cid, Subscription.NONE_PENDING_OUT) subscription = Subscription.NONE_PENDING_OUT elif subscription == Subscription.NONE_PENDING_IN: roster.setSubscription(cid, Subscription.NONE_PENDING_IN_OUT) subscription = Subscription.NONE_PENDING_IN_OUT elif subscription == Subscription.FROM: roster.setSubscription(cid, Subscription.FROM_PENDING_OUT) subscription = Subscription.FROM_PENDING_OUT # send a roster push with ask query = Roster.createRosterQuery( cjid.getBare(), Subscription.getPrimaryNameFromState(subscription), name, groups, {'ask': 'subscribe'}) # stamp presence with 'from' JID treeCopy = deepcopy(tree) treeCopy.set('from', jid) # prepare the presence data for routing d = { 'to': cjid, 'data': treeCopy, } retVal = chainOutput(retVal, d) # sequence of events in reverse order # push the roster first, in case we have to create a new # s2s connection msg.setNextHandler('route-server') msg.setNextHandler('roster-push') return chainOutput(retVal, query) # C2S SUBSCRIBED elif type == 'subscribed': if not cinfo: logging.warning("[%s] 'subscribed' presence received for " +\ "non-existent contact %s", self.__class__, cjid) else: subscription = cinfo.subscription if cinfo.subscription in (Subscription.NONE_PENDING_IN, Subscription.NONE_PENDING_IN_OUT, Subscription.TO_PENDING_IN): # update state and deliver if cinfo.subscription == Subscription.NONE_PENDING_IN: roster.setSubscription(cinfo.id, Subscription.FROM) subscription = Subscription.FROM elif cinfo.subscription == Subscription.NONE_PENDING_IN_OUT: roster.setSubscription( cinfo.id, Subscription.FROM_PENDING_OUT) subscription = Subscription.FROM_PENDING_OUT elif cinfo.subscription == Subscription.TO_PENDING_IN: roster.setSubscription(cinfo.id, Subscription.BOTH) subscription = Subscription.BOTH # roster stanza query = Roster.createRosterQuery( cjid.getBare(), Subscription.getPrimaryNameFromState(subscription), cinfo.name, cinfo.groups) # stamp presence with 'from' treeCopy = deepcopy(tree) treeCopy.set('from', jid) toRoute = tostring(treeCopy) # create available presence stanzas for all resources of the user resources = msg.conn.server.launcher.getC2SServer( ).data['resources'] jidForResources = resources.has_key( jid) and resources[jid] if jidForResources: out = u'' for i in jidForResources: out += "<presence from='%s/%s'" % (jid, i) out += " to='%s'/>" % cjid.getBare() # and queue for routing toRoute += out # prepare the presence data for routing d = { 'to': cjid, 'data': toRoute, } retVal = chainOutput(retVal, d) # next handlers in reverse order msg.setNextHandler('route-server') msg.setNextHandler('roster-push') return chainOutput(retVal, query) # C2S UNSUBSCRIBE elif type == 'unsubscribe': # we must always route the unsubscribe presence so as to allow # the other servers to resynchronize their sub lists. # RFC 3921 9.2 if not cinfo: # we don't have this contact in our roster, but route the # presence anyway # stamp presence with 'from' treeCopy = deepcopy(tree) treeCopy.set('from', jid) # prepare the presence data for routing d = { 'to': cjid, 'data': treeCopy, } msg.setNextHandler('route-server') return chainOutput(retVal, d) else: subscription = cinfo.subscription if subscription == Subscription.BOTH: # mutual roster.setSubscription(cinfo.id, Subscription.FROM) subscription = Subscription.FROM elif subscription in ( Subscription.NONE_PENDING_OUT, # one way Subscription.NONE_PENDING_IN_OUT, Subscription.TO, Subscription.TO_PENDING_IN): if subscription == Subscription.NONE_PENDING_OUT \ or subscription == Subscription.TO: roster.setSubscription(cinfo.id, Subscription.NONE) subscription = Subscription.NONE elif subscription == Subscription.NONE_PENDING_IN_OUT \ or subscription == Subscription.TO_PENDING_IN: roster.setSubscription( cinfo.id, Subscription.NONE_PENDING_IN) subscription = Subscription.NONE_PENDING_IN # roster stanza query = Roster.createRosterQuery( cjid.getBare(), Subscription.getPrimaryNameFromState(subscription), cinfo.name, cinfo.groups) # stamp presence with 'from' treeCopy = deepcopy(tree) treeCopy.set('from', jid) # prepare the presence data for routing d = { 'to': cjid, 'data': treeCopy, } retVal = chainOutput(retVal, d) # schedules handlers in reverse order msg.setNextHandler('route-server') msg.setNextHandler('roster-push') return chainOutput(retVal, query) # C2S UNSUBSCRIBED elif type == 'unsubscribed': if not cinfo: logging.warning("[%s] 'unsubscribed' presence received for " +\ "non-existent contact %s", self.__class__, cjid) else: subscription = cinfo.subscription if subscription not in (Subscription.NONE, Subscription.NONE_PENDING_OUT, Subscription.TO): if subscription == Subscription.NONE_PENDING_IN \ or subscription == Subscription.FROM: roster.setSubscription(cinfo.id, Subscription.NONE) subscription = Subscription.NONE elif subscription == Subscription.NONE_PENDING_IN_OUT \ or subscription == Subscription.FROM_PENDING_OUT: roster.setSubscription( cinfo.id, Subscription.NONE_PENDING_OUT) subscription = Subscription.NONE elif subscription == Subscription.TO_PENDING_IN \ or subscription == Subscription.BOTH: roster.setSubscription(cinfo.id, Subscription.TO) subscription = Subscription.TO # roster query if subscription == Subscription.NONE_PENDING_OUT: itemArgs = {'ask': 'subscribe'} else: itemArgs = {} query = roster.createRosterQuery( cjid.getBare(), Subscription.getPrimaryNameFromState(subscription), cinfo.name, cinfo.groups, itemArgs) # stamp presence with 'from' treeCopy = deepcopy(tree) treeCopy.set('from', jid) toRoute = tostring(treeCopy) # create unavailable presence stanzas for all resources of the user resources = msg.conn.server.launcher.getC2SServer( ).data['resources'] jidForResources = resources.has_key( jid) and resources[jid] if jidForResources: out = u'' for i in jidForResources: out += "<presence from='%s/%s'" % (jid, i) out += " to='%s' type='unavailable'/>" % cjid.getBare( ) # and add to output toRoute += out # prepare the presence data for routing d = { 'to': cjid, 'data': toRoute, } retVal = chainOutput(retVal, d) # handlers in reverse order msg.setNextHandler('route-server') msg.setNextHandler('roster-push') return chainOutput(retVal, query) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle(self, tree, msg, lastRetVal=None): self.done = False self.retVal = lastRetVal tpool = msg.conn.server.threadpool def act(): d = msg.conn.data retVal = lastRetVal jid = d['user']['jid'] resource = d['user']['resource'] roster = Roster(jid) presTree = deepcopy(tree) presTree.set('from', '%s/%s' % (jid, resource)) probes = [] if tree.get('to') is None and not d['user']['active']: # initial presence # TODO: we don't need to do it every time. we can cache the # data after the first resource is active and just resend # that to all new resources d['user']['active'] = True # get jids of the contacts whose status we're interested in cjids = roster.getPresenceSubscriptions() probeTree = Element('presence', { 'type': 'probe', 'from' : '%s/%s' \ % (jid, resource) }) # TODO: replace this with a more efficient router handler for cjid in cjids: probeTree.set('to', cjid) probeRouteData = {'to': cjid, 'data': deepcopy(probeTree)} probes.append(probeRouteData) # they're sent first. see below # broadcast to other resources of this user retVal = self.broadcastToOtherResources( presTree, msg, retVal, jid, resource) elif tree.get('to') is not None: # TODO: directed presence return elif tree.get('type') == 'unavailable': # broadcast to other resources of this user d['user']['active'] = False retVal = self.broadcastToOtherResources( presTree, msg, retVal, jid, resource) # record this stanza as the last presence sent from this client lastPresence = deepcopy(tree) lastPresence.set('from', '%s/%s' % (jid, resource)) d['user']['lastPresence'] = lastPresence # lookup contacts interested in presence cjids = roster.getPresenceSubscribers() # TODO: replace this with another router handler that would send # it out to all cjids in a batch instead of queuing a handler # for each for cjid in cjids: presTree.set('to', cjid) presRouteData = {'to': cjid, 'data': deepcopy(presTree)} retVal = chainOutput(retVal, presRouteData) msg.setNextHandler('route-server') # send the probes first for probe in probes: msg.setNextHandler('route-server') retVal = chainOutput(retVal, probe) return retVal def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc) def resume(self): return self.retVal class C2SSubscriptionHandler(ThreadedHandler): """Handles subscriptions sent from clients within <presence> stanzas. ie. <presence> elements with types. """ def __init__(self): # this is true when the threaded handler returns self.done = False # used to pass the output to the next handler self.retVal = None
def handle(self, tree, msg, lastRetVal=None): self.done = False tpool = msg.conn.server.threadpool # the actual function executing in the thread def act(): # TODO: verify that it's coming from a known user jid = msg.conn.data['user']['jid'] id = tree.get('id') if id is None: logging.warning('[%s] No id in roster get query. Tree: %s', self.__class__, tree) # TODO: throw exception here return # RFC 3921 says in section 7.4 "an item", so we only handle the # first <item> item = tree[0][0] # iq -> query -> item cjid = item.get('jid') name = item.get('name') if cjid is None: logging.warning("[%s] Client trying to add a roster item " + \ "without a jid. Tree: %s", self.__class__, tree) # TODO: throw exception here return roster = Roster(jid) xpath = './{jabber:iq:roster}query/{jabber:iq:roster}item[@subscription="remove"]' if tree.find(xpath) is not None: # we're removing the roster item. See 3921 8.6 out = "<presence from='%s' to='%s' type='unsubscribe'/>" \ % (jid, cjid) out += "<presence from='%s' to='%s' type='unsubscribed'/>" \ % (jid, cjid) # create unavailable presence stanzas for all resources of the user resources = msg.conn.server.launcher.getC2SServer( ).data['resources'] jidForResources = resources.has_key(jid) and resources[jid] if jidForResources: for i in jidForResources: out += "<presence from='%s/%s'" % (jid, i) out += " to='%s' type='unavailable'/>" % cjid # prepare routing data d = {'to': cjid, 'data': out} query = deepcopy(tree[0]) retVal = chainOutput(lastRetVal, query) if roster.removeContact(cjid) is False: # We don't even have this contact in the roster anymore. # The contact is probably local (like ourselves). # This happens with some clients (like pidgin/gaim) who # cache the roster and don't delete some items even when # they're not present in the roster the server sends out # anymore. If we send the presence here it # will probably arrive after roster-push (due to s2s) # and will confuse the clients into thinking they still # have that contact in their roster. This creates an # undeletable contact. We can't do much about this. # If/when the s2s component can do a shortcut delivery of # stanzas to local users, while in the same phase, this # problem should go away, as it will allow the roster-push # to arrive after presences every time. pass # route the presence first, then do a roster push msg.setNextHandler('roster-push') msg.setNextHandler('route-server') return chainOutput(retVal, d) # we're updating/adding the roster item groups = [ i.text for i in list(item.findall('{jabber:iq:roster}group')) ] cid = roster.updateContact(cjid, groups, name) # get the subscription status before roster push sub = roster.getSubPrimaryName(cid) # prepare the result for roster push query = Roster.createRosterQuery(cjid, sub, name, groups) msg.setNextHandler('roster-push') return chainOutput(lastRetVal, query) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle(self, tree, msg, lastRetVal=None): self.done = False tpool = msg.conn.server.threadpool def act(): # we have to be passed a tree to work # or a tuple with routingData and a tree if not isinstance(lastRetVal, list): logging.warning('[%s] lastRetVal is not a list', self.__class__) return if isinstance(lastRetVal[-1], Element): if lastRetVal[-1].tag.find('query') == -1: logging.warning('[%s] Got a non-query Element last return value' +\ '. Last return value: %s', self.__class__, lastRetVal) elif isinstance(lastRetVal[-1], tuple): if not isinstance(lastRetVal[-1][0], dict) \ or not isinstance(lastRetVal[-1][1], Element): logging.warning('[%s] Got a non-query Element last return value' +\ '. Last return value: %s', self.__class__, lastRetVal) return else: logging.warning('[%s] Roster push needs either a <query> Element ' +\ 'as the last item in lastRetVal or a tuple ' + \ 'with (routeData, query Element)', self.__class__) return # this is the roster <query> that we'll send # it could be a tuple if we got routing data as well query = lastRetVal.pop(-1) routeData = None # did we get routing data (from S2S) if isinstance(query, tuple): routeData = query[0] query = query[1] if routeData: jid = routeData['jid'] resources = routeData['resources'] else: jid = msg.conn.data['user']['jid'] resource = msg.conn.data['user']['resource'] resources = msg.conn.server.data['resources'][jid] for res, con in resources.items(): # don't send the roster to clients that didn't request it if con.data['user']['requestedRoster']: iq = Element( 'iq', { 'to': '%s/%s' % (jid, res), 'type': 'set', 'id': generateId()[:10] }) iq.append(query) # TODO: remove this. debug. logging.debug("Sending " + tostring(iq)) con.send(tostring(iq)) if tree.tag == '{jabber:client}iq' and tree.get('id'): # send an ack to client if this is in reply to a roster get/set id = tree.get('id') d = { 'to': '%s/%s' % (jid, resource), 'type': 'result', 'id': id } iq = Element('iq', d) return chainOutput(lastRetVal, iq) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle(self, tree, msg, lastRetVal=None): self.done = False tpool = msg.conn.server.threadpool # the actual function executing in the thread def act(): data = msg.conn.data # check for policy violation violation = checkPolicyViolation(msg) if violation is not None: msg.setLastHandler('close-stream') return chainOutput(lastRetVal, violation) id = tree.get('id') if not id: logging.debug("[%s] No id specified in iq-auth set request", self.__class__) data['iqauth']['in-progress'] = True username = tree[0].find('{jabber:iq:auth}username') if username is not None: username = username.text resource = tree[0].find('{jabber:iq:auth}resource') if resource is not None: resource = resource.text if username is None or resource is None: iq = makeNotAcceptable(id) return chainOutput(lastRetVal, iq) digest = tree[0].find('{jabber:iq:auth}digest') if digest is not None: digest = digest.text password = tree[0].find('{jabber:iq:auth}password') if password is not None: password = password.text if digest: data['iqauth']['mech'] = 'digest' auth = mechs.IQAuthDigest(msg) try: auth.handle(username, digest) except IQAuthError: return chainOutput(lastRetVal, makeNotAuthorized(id)) elif password: data['iqauth']['mech'] = 'plain' plain = mechs.IQAuthPlain(msg) try: plain.handle(username, password) except IQAuthError: return chainOutput(lastRetVal, makeNotAuthorized(id)) else: iq = makeNotAcceptable(id) return chainOutput(lastRetVal, iq) # do the resource binding # TODO: check that we don't already have such a resource bindResource(msg, resource) data['iqauth']['complete'] = True return chainOutput(lastRetVal, makeSuccess(id)) def cb(workReq, retVal): self.done = True # make sure we pass the lastRetVal along if retVal is None: self.retVal = lastRetVal else: self.retVal = retVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)
def handle(self, tree, msg, lastRetVal=None): self.done = False self.retVal = lastRetVal tpool = msg.conn.server.threadpool def act(): d = msg.conn.data if 'new-s2s-conn' not in d or \ 'hostname' not in d['new-s2s-conn'] or \ 'ip' not in d['new-s2s-conn']: logging.warning( "[%s] Invoked without necessary data in connection", self.__class__) return local = False if d['new-s2s-conn'].get('local'): local = True sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((d['new-s2s-conn']['ip'], d['new-s2s-conn'].setdefault('port', 5269))) serv = msg.conn.server.launcher.getS2SServer() if not serv: logging.warning("[%s] Can't find an S2SServer in launcher", self.__class__) return if local: conn = serv.createLocalOutConnection(sock) # if we're connecting to ourselves, we don't need the <stream>. # instead just send out the outQueue data = d['new-s2s-conn'].get('queue') if data is not None: conn.send(prepareDataForSending(data)) else: sOutConn = serv.createRemoteOutConnection(sock) # copy over any queued messages to send once fully connected sOutConn.outQueue.extend(d['new-s2s-conn'].setdefault( 'queue', [])) # register the connection with the S2S server serverConns = serv.s2sConns.setdefault( d['new-s2s-conn']['hostname'], [None, None]) serverConns[1] = sOutConn # send the initial stream # commenting this out for now as it causes expat problems sOutConn.send("<?xml version='1.0' ?>") sOutConn.send("<stream:stream xmlns='jabber:server' " +\ "xmlns:stream='http://etherx.jabber.org/streams' " +\ "to='%s' " % d['new-s2s-conn']['hostname'] + \ "version='1.0'>") def cb(workReq, retVal): self.done = True # we don't return anything, but make sure we pass the # lastRetVal along self.retVal = lastRetVal req = threadpool.makeRequests(act, None, cb) def checkFunc(): # need to poll manually or the callback's never called from the pool poll(tpool) return self.done def initFunc(): tpool.putRequest(req[0]) return FunctionCall(checkFunc), FunctionCall(initFunc)