def close(self): if getattr(self, 'socket', None) is not None: asocket.close(self) if self.callback is not None: self.callback, cb = None, self.callback cb.error()
def __init__(self, proxy, conn, post): asocket.__init__(self, conn) self.callback = None self.post_negotiate = post self._negotiating = False if proxy is None: proxy = {} self._proxyinfo = proxy.copy() self.mid = (self._proxyinfo.get('addr', ''), self._proxyinfo.get('port',0)) self.end = ('',0)
def __init__(self, *a, **k): asocket.__init__(self, *a, **k) self.set_terminator('\r\n\r\n') self.push('HEAD / HTTP/1.0\r\n\r\n') self.push_handler(lambda d: log.info(repr(d)))
def __repr__(self): parentrepr = asocket.__repr__(self).strip('<>') return '<%s, fileno=%r>' % (parentrepr, self._fileno)
def handle_close(self): log.info('ProxySocket.handle_close - calling callback.error') self.close() asocket.handle_close(self)
def _pconnect(self): asocket.connect(self, self.mid)
def _connectRealSocket(self): self.sock = AsyncSocket(self.asyncSocketManager) self.sock.connect((self.ip, self.port)) self.sockNum = self.sock.fileno() self.realSockStatus.addConn(self.sockNum, self.destId) self.realSockStatus.setWantsToSend(True, self.sockNum)
class SamBaseDestination: def __init__(self, destId, asyncSocketManager, realSockStatus, log, ip, port, sessionName, sessionType, sessionDirection, sessionOptions): self.destId = destId self.asyncSocketManager = asyncSocketManager self.realSockStatus = realSockStatus self.log = log #session - stats self.sessionName = sessionName self.sessionType = sessionType self.sessionDirection = sessionDirection self.sessionOptions = sessionOptions #session - state self.sessionEstablished = False self.sessionKey = None #socket self.sock = None self.sockNum = None self.ip = ip self.port = port self.connected = False self.inMessage = None self.inQueue = deque() self.outQueue = deque() self._connectRealSocket() ##internal functions - socket def _connectRealSocket(self): self.sock = AsyncSocket(self.asyncSocketManager) self.sock.connect((self.ip, self.port)) self.sockNum = self.sock.fileno() self.realSockStatus.addConn(self.sockNum, self.destId) self.realSockStatus.setWantsToSend(True, self.sockNum) def _closeRealSocket(self): self.inMessage = None self.outQueue.clear() self.realSockStatus.removeConn(self.sockNum) self.connected = False self.sock.close() self.sock = None def _reconnectRealSocket(self): self._closeRealSocket() self._connectRealSocket() def _sendOverRealSocket(self, data): self.outQueue.append(data) if len(self.outQueue) == 1: #first message in buffer, add to sockets with send interest self.realSockStatus.setWantsToSend(True, self.sockNum) if self.log is not None: self.log.debug("Send Message: \"%s\"", data.split('\n')[0]) ##internal functions - destinations def _establishedDestination(self): pass def _failDestination(self, reason): self.sessionKey = None self.sessionEstablished = False self._reconnectRealSocket() def _removeDestination(self): self._closeRealSocket() ##internal functions - messages def _handleCustomMessage(self, message): if self.log is not None: self.log.warn("Received unknown message from Sam bridge: \"%s\"", str(message)) def _handleNameLookup(self, message): pass def _handleMessages(self, messages): for message in messages: messageType = message['msgType'] messageParas = message['msgParas'] if messageType=='HELLO REPLY': #handshake reply if messageParas['RESULT'].upper()=='OK' and messageParas['VERSION']=='2.0': #send session create message assert len(self.outQueue)==0, "just handshaked and stuff to send?!" self._sendOverRealSocket(SamMessages.sessionCreateMessage(self.sessionType, self.sessionName, self.sessionDirection, self.sessionOptions)) else: #something borked self._failDestination('Invalid HELLO REPLY: Result<%s> Version<%s>' % (messageParas['RESULT'], messageParas['VERSION'])) elif messageType=='SESSION STATUS': #session established if not messageParas['RESULT'].upper()=='OK': #urgh self._failDestination('Failed to setup session: "%s"' % (messageParas['RESULT'],)) else: #ok, session is established self.sessionEstablished = True self._sendOverRealSocket('NAMING LOOKUP NAME=ME\n') self._establishedDestination() elif messageType=='NAMING REPLY': #reply to destination request if not messageParas['NAME'].upper() == 'ME': self._handleNameLookup(message) elif messageParas['RESULT'].upper() == 'OK': self.sessionKey = messageParas['VALUE'] else: self._handleCustomMessage(message) ##external functions - socket events def errorEvent(self): self._failDestination('Connection to SAM failed') def sendEvent(self): if not self.connected: #connected, send handshake as soon as possible self.connected = True self.realSockStatus.setWantsToRecv(True, self.sockNum) self.realSockStatus.setWantsToSend(False, self.sockNum) self._sendOverRealSocket("HELLO VERSION MIN=2.0 MAX=2.0\n") else: #already connected, send data assert len(self.outQueue) > 0, 'Empty outbuffer, but trying to send?!' while len(self.outQueue) > 0: #still something in the queue, try to send the next message data = self.outQueue.popleft() bytesSend = self.sock.send(data) if bytesSend < len(data): #not all data send, push remaining data back into queue and abort loop self.outQueue.appendleft(data[bytesSend:]) break if len(self.outQueue) == 0: #managed to empty the queue, nothing to send anymore self.realSockStatus.setWantsToSend(False, self.sockNum) def recvEvent(self): data = self.sock.recv() dataLen = len(data) messages = [] offset = 0 #process data while not offset >= dataLen: #loop until all received data was processed if self.inMessage is None: ##there is no finished message that needs bulk data endOfMessage = data.find('\n', offset) if endOfMessage == -1: #only the beginning of a message, store it in the inbound queue self.inQueue.append(data[offset:]) offset = dataLen else: #the whole message or the ending message = data[offset:endOfMessage] offset = endOfMessage + 1 if len(self.inQueue) > 0: #get the beginning of the message out of the queue self.inQueue.append(message) message = ''.join(self.inQueue) self.inQueue.clear() #parse message if self.log is not None: self.log.debug("Got Message: \"%s\"", message) message = SamMessages.parseMessage(message) #check if we need to wait for more data if 'SIZE' in message['msgParas']: message['Data'] = [] message['DataCurrentLen'] = 0 message['DataTargetLen'] = int(message['msgParas']['SIZE']) self.inMessage = message else: messages.append(message) else: ##only missing a few bytes here ... assert len(self.inQueue) == 0, 'receiving data but stuff in the inqueue?!' missingBytes = self.inMessage['DataTargetLen'] - self.inMessage['DataCurrentLen'] remainingBytes = dataLen - offset if remainingBytes >= missingBytes: #got all if self.log is not None: self.log.debug("Got missing %i bytes for message", missingBytes) self.inMessage['Data'].append(data[offset:offset+missingBytes]) self.inMessage['DataCurrentLen'] += missingBytes assert self.inMessage['DataCurrentLen'] == self.inMessage['DataTargetLen'], 'message finished but too short?!' offset += missingBytes messages.append(self.inMessage) self.inMessage = None else: #still missing a bit if self.log is not None: self.log.debug("Got %i bytes for message but still missing %i bytes", remainingBytes, (missingBytes - remainingBytes)) self.inMessage['Data'].append(data[offset:]) self.inMessage['DataCurrentLen'] += remainingBytes offset += remainingBytes #handle messages self._handleMessages(messages) ##external functions - destination def getOwnDestination(self): return self.sessionKey def shutdown(self): self._removeDestination() ##external functions - changing settings def changeSessionAddress(self, ip=None, port=None, reconnect=False): if ip is not None: self.ip = ip if port is not None: self.port = port if reconnect: self._failDestination('SESSION_ADDR_CHANGE') def changeSessionName(self, sessionName, reconnect=False): self.sessionName = sessionName if reconnect: self._failDestination('SESSION_NAME_CHANGE') def changeSessionOption(self, option, value, reconnect=False): self.sessionOptions[option] = value if reconnect: self._failDestination('SESSION_OPTION_CHANGE') def removeSessionOption(self, option, reconnect=False): del self.sessionOptions[option] if reconnect: self._failDestination('SESSION_OPTION_CHANGE') def replaceSessionOptions(self, sessionOptions, reconnect=False): self.sessionOptions = sessionOptions if reconnect: self._failDestination('SESSION_OPTION_CHANGE')