def unpickleMethod(im_name, im_self, im_class): 'support function for copy_reg to unpickle method refs' try: unbound = getattr(im_class,im_name) if im_self is None: return unbound bound=instancemethod(unbound.im_func, im_self, im_class) return bound except AttributeError: log.msg("Method",im_name,"not on class",im_class) assert im_self is not None,"No recourse: no instance to guess from." # Attempt a common fix before bailing -- if classes have # changed around since we pickled this method, we may still be # able to get it by looking on the instance's current class. unbound = getattr(im_self.__class__,im_name) log.msg("Attempting fixup with",unbound) if im_self is None: return unbound bound=instancemethod(unbound.im_func, im_self, im_self.__class__) return bound
def doRead(self): """Called when my socket is ready for reading. This accepts a connection and calls self.protocol() to handle the wire-level protocol. """ try: if platformType == "posix": numAccepts = self.numberAccepts else: # win32 event loop breaks if we do more than one accept() # in an iteration of the event loop. numAccepts = 1 for i in range(numAccepts): # we need this so we can deal with a factory's buildProtocol # calling our loseConnection if self.disconnecting: return try: skt, addr = self.socket.accept() except socket.error, e: if e.args[0] in (EWOULDBLOCK, EAGAIN): self.numberAccepts = i break elif e.args[0] == EPERM: # Netfilter on Linux may have rejected the # connection, but we get told to try to accept() # anyway. continue elif e.args[0] in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED): # Linux gives EMFILE when a process is not allowed # to allocate any more file descriptors. *BSD and # Win32 give (WSA)ENOBUFS. Linux can also give # ENFILE if the system is out of inodes, or ENOMEM # if there is insufficient memory to allocate a new # dentry. ECONNABORTED is documented as possible on # both Linux and Windows, but it is not clear # whether there are actually any circumstances under # which it can happen (one might expect it to be # possible if a client sends a FIN or RST after the # server sends a SYN|ACK but before application code # calls accept(2), however at least on Linux this # _seems_ to be short-circuited by syncookies. log.msg("Could not accept new connection (%s)" % ( errorcode[e.args[0]],)) break raise protocol = self.factory.buildProtocol(self._buildAddr(addr)) if protocol is None: skt.close() continue s = self.sessionno self.sessionno = s+1 transport = self.transport(skt, protocol, addr, self, s, self.reactor) transport = self._preMakeConnection(transport) protocol.makeConnection(transport) else:
def reapProcess(self): """ Try to reap a process (without blocking) via waitpid. This is called when sigchild is caught or a Process object loses its "connection" (stdout is closed) This ought to result in reaping all zombie processes, since it will be called twice as often as it needs to be. (Unfortunately, this is a slightly experimental approach, since UNIX has no way to be really sure that your process is going to go away w/o blocking. I don't want to block.) """ try: try: pid, status = os.waitpid(self.pid, os.WNOHANG) except OSError, e: if e.errno == errno.ECHILD: # no child process pid = None else: raise except: log.msg('Failed to reap %d:' % self.pid) log.err() pid = None if pid: self.processEnded(status) unregisterReapProcessHandler(pid, self)
def unpickleModule(name): 'support function for copy_reg to unpickle module refs' if oldModules.has_key(name): log.msg("Module has moved: %s" % name) name = oldModules[name] log.msg(name) return __import__(name,{},{},'x')
def connectionLost(self, reason): """ Cleans up the socket. """ log.msg('(Port %s Closed)' % self._realPortNumber) self._realPortNumber = None d = None if hasattr(self, "deferred"): d = self.deferred del self.deferred base.BasePort.connectionLost(self, reason) self.connected = False self._closeSocket() del self.socket del self.fileno try: self.factory.doStop() except: self.disconnecting = False if d is not None: d.errback(failure.Failure()) else: raise else: self.disconnecting = False if d is not None: d.callback(None)
def __getstate__(self): log.msg( "WARNING: serializing ephemeral %s" % self ) import gc if getattr(gc, 'get_referrers', None): for r in gc.get_referrers(self): log.msg( " referred to by %s" % (r,)) return None
def startListening(self): """Create and bind my socket, and begin listening on it. This is called on unserialization, and must be called after creating a server to begin listening on the specified port. """ log.msg("%s starting on %r" % (self.factory.__class__, repr(self.port))) if self.wantPID: self.lockFile = lockfile.FilesystemLock(self.port + ".lock") if not self.lockFile.lock(): raise CannotListenError, (None, self.port, "Cannot acquire lock") else: if not self.lockFile.clean: try: # This is a best-attempt at cleaning up # left-over unix sockets on the filesystem. # If it fails, there's not much else we can # do. The bind() below will fail with an # exception that actually propegates. if stat.S_ISSOCK(os.stat(self.port).st_mode): os.remove(self.port) except: pass self.factory.doStart() try: skt = self.createInternetSocket() skt.bind(self.port) except socket.error, le: raise CannotListenError, (None, self.port, le)
def _bindSocket(self): log.msg("%s starting on %s"%(self.protocol.__class__, repr(self.port))) try: skt = self.createInternetSocket() # XXX: haha misnamed method if self.port: skt.bind(self.port) except socket.error, le: raise error.CannotListenError, (None, self.port, le)
def logPacketData(data): lines = len(data)/16 if lines*16 != len(data): lines=lines+1 for i in range(lines): d = tuple(data[16*i:16*i+16]) hex = map(lambda x: "%02X"%ord(x),d) text = map(lambda x: (len(repr(x))>3 and '.') or x, d) log.msg(' '.join(hex)+ ' '*3*(16-len(d)) +''.join(text)) log.msg('')
def doStart(self): """Make sure startFactory is called. Users should not call this function themselves! """ if not self.numPorts: if self.noisy: log.msg("Starting factory %r" % self) self.startFactory() self.numPorts = self.numPorts + 1
def doStart(self): """Make sure startProtocol is called. This will be called by makeConnection(), users should not call it. """ if not self.numPorts: if self.noisy: log.msg("Starting protocol %s" % self) self.startProtocol() self.numPorts = self.numPorts + 1
def oscar_Cookie(self,data): snac=readSNAC(data[1]) if self.icq: i=snac[5].find("\000") snac[5]=snac[5][i:] tlvs=readTLVs(snac[5]) if tlvs.has_key(6): self.cookie=tlvs[6] server,port=string.split(tlvs[5],":") d = self.connectToBOS(server, int(port)) d.addErrback(lambda x: log.msg("Connection Failed! Reason: %s" % x)) if self.deferred: d.chainDeferred(self.deferred) self.disconnect() elif tlvs.has_key(8): errorcode=tlvs[8] try: errorurl=tlvs[4] except KeyError: raise Exception('You are throttled for repeated logins') if errorcode=='\000\030': error="You are attempting to sign on again too soon. Please try again later." elif errorcode=='\000\005': error="Invalid Username or Password." else: error=repr(errorcode) self.error(error,errorurl) else: log.msg('hmm, weird tlvs for %s cookie packet' % str(self)) log.msg(tlvs) log.msg('snac') log.msg(str(snac)) return "None"
def __del__(self): """Print tracebacks and die. If the *last* (and I do mean *last*) callback leaves me in an error state, print a traceback (if said errback is a Failure). """ if self.failResult is not None: log.msg("Unhandled error in Deferred:", isError=True) debugInfo = self._getDebugTracebacks() if debugInfo != '': log.msg("(debug: " + debugInfo + ")", isError=True) log.err(self.failResult)
def doStop(self): """Make sure stopProtocol is called. This will be called by the port, users should not call it. """ assert self.numPorts > 0 self.numPorts = self.numPorts - 1 self.transport = None if not self.numPorts: if self.noisy: log.msg("Stopping protocol %s" % self) self.stopProtocol()
def dataReceived(self,data): # if isinstance(self, ChatService): # logPacketData(data) self.buf=self.buf+data flap=self.readFlap() while flap: func=getattr(self,"oscar_%s"%self.state,None) if not func: log.msg("no func for state: %s" % self.state) state=func(flap) if state: self.state=state flap=self.readFlap()
def doStop(self): """Make sure stopFactory is called. Users should not call this function themselves! """ if self.numPorts == 0: # this shouldn't happen, but does sometimes and this is better # than blowing up in assert as we did previously. return self.numPorts = self.numPorts - 1 if not self.numPorts: if self.noisy: log.msg("Stopping factory %r" % self) self.stopFactory()
def versionUpgrade(self): """(internal) Do a version upgrade. """ bases = _aybabtu(self.__class__) # put the bases in order so superclasses' persistenceVersion methods # will be called first. bases.reverse() bases.append(self.__class__) # don't forget me!! # first let's look for old-skool versioned's if self.__dict__.has_key("persistenceVersion"): # Hacky heuristic: if more than one class subclasses Versioned, # we'll assume that the higher version number wins for the older # class, so we'll consider the attribute the version of the older # class. There are obviously possibly times when this will # eventually be an incorrect assumption, but hopefully old-school # persistenceVersion stuff won't make it that far into multiple # classes inheriting from Versioned. pver = self.__dict__['persistenceVersion'] del self.__dict__['persistenceVersion'] highestVersion = 0 highestBase = None for base in bases: if not base.__dict__.has_key('persistenceVersion'): continue if base.persistenceVersion > highestVersion: highestBase = base highestVersion = base.persistenceVersion if highestBase: self.__dict__['%s.persistenceVersion' % reflect.qual(highestBase)] = pver for base in bases: # ugly hack, but it's what the user expects, really if (Versioned not in base.__bases__ and not base.__dict__.has_key('persistenceVersion')): continue currentVers = base.persistenceVersion pverName = '%s.persistenceVersion' % reflect.qual(base) persistVers = (self.__dict__.get(pverName) or 0) if persistVers: del self.__dict__[pverName] assert persistVers <= currentVers, "Sorry, can't go backwards in time." while persistVers < currentVers: persistVers = persistVers + 1 method = base.__dict__.get('upgradeToVersion%s' % persistVers, None) if method: log.msg( "Upgrading %s (of %s @ %s) to version %s" % (reflect.qual(base), reflect.qual(self.__class__), id(self), persistVers) ) method(self) else: log.msg( 'Warning: cannot upgrade %s to version %s' % (base, persistVers) )
def connectionLost(self, reason=None): """Cleans up my socket. """ log.msg('(Port %s Closed)' % repr(self.port)) base.BasePort.connectionLost(self, reason) if hasattr(self, "protocol"): # we won't have attribute in ConnectedPort, in cases # where there was an error in connection process self.protocol.doStop() self.connected = 0 self.socket.close() del self.socket del self.fileno if hasattr(self, "d"): self.d.callback(None) del self.d
def _preenDescriptors(self): log.msg("Malformed file descriptor found. Preening lists.") readers = self._reads.keys() writers = self._writes.keys() self._reads.clear() self._writes.clear() for selDict, selList in ((self._reads, readers), (self._writes, writers)): for selectable in selList: try: select.select([selectable], [selectable], [selectable], 0) except Exception, e: log.msg("bad descriptor %s" % selectable) self._disconnectSelectable(selectable, e, False) else: selDict[selectable] = 1
def _cbRequestSSI(self, snac, args = ()): if snac[1] == 0x0f: # same SSI as we have return itemdata = snac[5][3:] if args: revision, groups, permit, deny, permitMode, visibility = args else: version, revision = struct.unpack('!BH', snac[5][:3]) groups = {} permit = [] deny = [] permitMode = None visibility = None while len(itemdata)>4: nameLength = struct.unpack('!H', itemdata[:2])[0] name = itemdata[2:2+nameLength] groupID, buddyID, itemType, restLength = \ struct.unpack('!4H', itemdata[2+nameLength:10+nameLength]) tlvs = readTLVs(itemdata[10+nameLength:10+nameLength+restLength]) itemdata = itemdata[10+nameLength+restLength:] if itemType == 0: # buddies groups[groupID].addUser(buddyID, SSIBuddy(name, tlvs)) elif itemType == 1: # group g = SSIGroup(name, tlvs) if groups.has_key(0): groups[0].addUser(groupID, g) groups[groupID] = g elif itemType == 2: # permit permit.append(name) elif itemType == 3: # deny deny.append(name) elif itemType == 4: # permit deny info if not tlvs.has_key(0xcb): continue # this happens with ICQ permitMode = {1:'permitall',2:'denyall',3:'permitsome',4:'denysome',5:'permitbuddies'}[ord(tlvs[0xca])] visibility = {'\xff\xff\xff\xff':'all','\x00\x00\x00\x04':'notaim'}[tlvs[0xcb]] elif itemType == 5: # unknown (perhaps idle data)? pass else: log.msg('%s %s %s %s %s' % (name, groupID, buddyID, itemType, tlvs)) timestamp = struct.unpack('!L',itemdata)[0] if not timestamp: # we've got more packets coming # which means add some deferred stuff d = defer.Deferred() self.requestCallbacks[snac[4]] = d d.addCallback(self._cbRequestSSI, (revision, groups, permit, deny, permitMode, visibility)) return d return (groups[0].users,permit,deny,permitMode,visibility,timestamp,revision)
def mainLoop(self): while self._started: try: while self._started: # Advance simulation time in delayed event # processors. self.runUntilCurrent() # XXX f**k this shit.. WHY does twisted's select() # block signals? this is NOT NORMAL self.doIteration(1) #t2 = self.timeout() #t = self.running and t2 #self.doIteration(t) except: log.msg("Unexpected error in main loop.") log.err() else: log.msg('Main loop terminated.')
def registerReapProcessHandler(pid, process): """ Register a process handler for the given pid, in case L{reapAllProcesses} is called. @param pid: the pid of the process. @param process: a process handler. """ if pid in reapProcessHandlers: raise RuntimeError("Try to register an already registered process.") try: auxPID, status = os.waitpid(pid, os.WNOHANG) except: log.msg('Failed to reap %d:' % pid) log.err() auxPID = None if auxPID: process.processEnded(status) else: # if auxPID is 0, there are children but none have exited reapProcessHandlers[pid] = process
def retry(self, connector=None): """Have this connector connect again, after a suitable delay. """ if not self.continueTrying: if self.noisy: log.msg("Abandoning %s on explicit request" % (connector,)) return if connector is None: if self.connector is None: raise ValueError("no connector to retry") else: connector = self.connector self.retries += 1 if self.maxRetries is not None and (self.retries > self.maxRetries): if self.noisy: log.msg("Abandoning %s after %d retries." % (connector, self.retries)) return self.delay = min(self.delay * self.factor, self.maxDelay) if self.jitter: self.delay = random.normalvariate(self.delay, self.delay * self.jitter) if self.noisy: log.msg("%s will retry in %d seconds" % (connector, self.delay,)) from include.twisted.internet import reactor def reconnector(): self._callID = None connector.connect() self._callID = reactor.callLater(self.delay, reconnector)
def _handleSignals(self): """ Install the signal handlers for the Twisted event loop. """ try: import signal except ImportError: log.msg("Warning: signal module unavailable -- " "not installing signal handlers.") return if signal.getsignal(signal.SIGINT) == signal.default_int_handler: # only handle if there isn't already a handler, e.g. for Pdb. signal.signal(signal.SIGINT, self.sigInt) signal.signal(signal.SIGTERM, self.sigTerm) # Catch Ctrl-Break in windows if hasattr(signal, "SIGBREAK"): signal.signal(signal.SIGBREAK, self.sigBreak) if platformType == 'posix': signal.signal(signal.SIGCHLD, self._handleSigchld)
def oscar_unknown(self,snac): log.msg("unknown for %s" % self) log.msg(snac)
def oscar_04_07(self, snac): """ ICBM message (instant message) """ data = snac[3] cookie, data = data[:8], data[8:] channel = struct.unpack('!H',data[:2])[0] data = data[2:] user, data = self.parseUser(data, 1) tlvs = readTLVs(data) if channel == 1: # message flags = [] multiparts = [] for k, v in tlvs.items(): if k == 2: while v: v = v[2:] # skip bad data messageLength, charSet, charSubSet = struct.unpack('!3H', v[:6]) messageLength -= 4 message = [v[6:6+messageLength]] if charSet == 0: pass # don't add anything special elif charSet == 2: message.append('unicode') elif charSet == 3: message.append('iso-8859-1') elif charSet == 0xffff: message.append('none') if charSubSet == 0xb: message.append('macintosh') if messageLength > 0: multiparts.append(tuple(message)) v = v[6+messageLength:] elif k == 3: flags.append('acknowledge') elif k == 4: flags.append('auto') elif k == 6: flags.append('offline') elif k == 8: iconLength, foo, iconSum, iconStamp = struct.unpack('!LHHL',v) if iconLength: flags.append('icon') flags.append((iconLength, iconSum, iconStamp)) elif k == 9: flags.append('buddyrequest') elif k == 0xb: # unknown pass elif k == 0x17: flags.append('extradata') flags.append(v) else: log.msg('unknown TLV for incoming IM, %04x, %s' % (k,repr(v))) # unknown tlv for user SNewdorf # t: 29 # v: '\x00\x00\x00\x05\x02\x01\xd2\x04r\x00\x01\x01\x10/\x8c\x8b\x8a\x1e\x94*\xbc\x80}\x8d\xc4;\x1dEM' # XXX what is this? self.receiveMessage(user, multiparts, flags) elif channel == 2: # rondevouz status = struct.unpack('!H',tlvs[5][:2])[0] requestClass = tlvs[5][10:26] moreTLVs = readTLVs(tlvs[5][26:]) if requestClass == CAP_CHAT: # a chat request exchange = struct.unpack('!H',moreTLVs[10001][:2])[0] name = moreTLVs[10001][3:-2] instance = struct.unpack('!H',moreTLVs[10001][-2:])[0] if not self.services.has_key(SERVICE_CHATNAV): self.connectService(SERVICE_CHATNAV,1).addCallback(lambda x: self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\ addCallback(self._cbGetChatInfoForInvite, user, moreTLVs[12])) else: self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\ addCallback(self._cbGetChatInfoForInvite, user, moreTLVs[12]) elif requestClass == CAP_SEND_FILE: if moreTLVs.has_key(11): # cancel log.msg('cancelled file request') log.msg(status) return # handle this later name = moreTLVs[10001][9:-7] desc = moreTLVs[12] log.msg('file request from %s, %s, %s' % (user, name, desc)) self.receiveSendFileRequest(user, name, desc, cookie) else: log.msg('unsupported rondevouz: %s' % requestClass) log.msg(repr(moreTLVs)) else: log.msg('unknown channel %02x' % channel) log.msg(tlvs)
def initDone(self): """ called when we get the rate information, which means we should do other init. stuff. """ log.msg('%s initDone' % self) pass
def updateBuddy(self, user): """ called when a buddy changes status, with the OSCARUser for that buddy. """ log.msg('%s updateBuddy %s' % (self, user)) pass
def offlineBuddy(self, user): """ called when a buddy goes offline """ log.msg('%s offlineBuddy %s' % (self, user)) pass
def __init__(self, name, warn, tlvs): self.name = name self.warning = warn self.flags = [] self.caps = [] for k,v in tlvs.items(): if k == 1: # user flags v=struct.unpack('!H',v)[0] for o, f in [(1,'trial'), (2,'unknown bit 2'), (4,'aol'), (8,'unknown bit 4'), (16,'aim'), (32,'away'), (1024,'activebuddy')]: if v&o: self.flags.append(f) elif k == 2: # member since date self.memberSince = struct.unpack('!L',v)[0] elif k == 3: # on-since self.onSince = struct.unpack('!L',v)[0] elif k == 4: # idle time self.idleTime = struct.unpack('!H',v)[0] elif k == 5: # unknown pass elif k == 6: # icq online status if v[2] == '\x00': self.icqStatus = 'online' elif v[2] == '\x01': self.icqStatus = 'away' elif v[2] == '\x02': self.icqStatus = 'dnd' elif v[2] == '\x04': self.icqStatus = 'out' elif v[2] == '\x10': self.icqStatus = 'busy' else: self.icqStatus = 'unknown' elif k == 10: # icq ip address self.icqIPaddy = socket.inet_ntoa(v) elif k == 12: # icq random stuff self.icqRandom = v elif k == 13: # capabilities caps=[] while v: c=v[:16] if c==CAP_ICON: caps.append("icon") elif c==CAP_IMAGE: caps.append("image") elif c==CAP_VOICE: caps.append("voice") elif c==CAP_CHAT: caps.append("chat") elif c==CAP_GET_FILE: caps.append("getfile") elif c==CAP_SEND_FILE: caps.append("sendfile") elif c==CAP_SEND_LIST: caps.append("sendlist") elif c==CAP_GAMES: caps.append("games") else: caps.append(("unknown",c)) v=v[16:] caps.sort() self.caps=caps elif k == 14: pass elif k == 15: # session length (aim) self.sessionLength = struct.unpack('!L',v)[0] elif k == 16: # session length (aol) self.sessionLength = struct.unpack('!L',v)[0] elif k == 30: # no idea pass else: log.msg("unknown tlv for user %s\nt: %s\nv: %s"%(self.name,k,repr(v)))