Ejemplo n.º 1
0
 def _close(self):
     #called once the socket should be finally really closed
     if self.inQueueSize > 0:
         #not empty receive buffer
         self.i2pSockStatus.setRecvable(False, self.connId)
         
     if self.errorReason is None and self.connected and (not self.waitingForClose) and self.outQueueSize < self.outMaxQueueSize:
         #socket did not fail up to now, was not waiting for close and has free space in its send buffer => it was sendable
         self.i2pSockStatus.setSendable(False, self.connId)
         
     if self.errorReason is not None:
         #socket failed before
         self.i2pSockStatus.setErrored(False, self.connId)
         
     elif self.state == 'init':
         #socket was waiting for name query
         self.failFunc(self.connId)
     
     elif self.state == 'connected' or self.state == 'connecting':
         #socket was ok
         assert self.samId is not None, 'uhm, we need the id ...'
         self.failFunc(self.connId)
         self.sendFunc(SamMessages.streamCloseMessage(self.samId))
     
     self.state = 'closed'
     self.removeFunc(self.connId)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 def sendEvent(self):
     #called to send data out of the outbound queue - triggered when the sam bridge allows further sending
     assert self.state == 'connected', 'wrong state, expected "connected", got "%s"' % (self.state,)
     self.sendable = True
     
     if self.outQueueSize == 0:
         #nothing to send
         data = None
         if self.waitingForClose:
             #was waiting for close and done sending, so close it now
             self._close()
         
     elif self.outQueueSize <= 32768:
         #fits into a single message
         data = ''.join(self.outQueue)
         dataSize = len(data)
         self.outQueue.clear()
         self.outQueueSize = 0
         
     else:
         #too much data for a single message
         data = deque()
         dataSize = 0
         while dataSize < 32768:
             #add chunks until the limit is reached
             dataChunk = self.outQueue.popleft()
             dataChunkLen = len(dataChunk)
             if dataSize + dataChunkLen < 32768:
                 #take entire chunk
                 data.append(dataChunk)
                 dataSize += dataChunkLen
                 self.outQueueSize -= dataChunkLen
             else:
                 #only take a part of the chunk
                 useableDataChunkLen = 32768 - dataSize
                 data.append(dataChunk[:useableDataChunkLen])
                 self.outQueue.appendleft(dataChunk[useableDataChunkLen:])
                 self.outQueueSize -= useableDataChunkLen
                 dataSize += useableDataChunkLen
         data = ''.join(data)
         
     if data is not None:
         #something to send
         if (not self.waitingForClose) and \
            self.outQueueSize < self.outMaxQueueSize and \
            (self.outQueueSize + dataSize) >= self.outMaxQueueSize:
             #buffer was full and is not full anymore
             self.i2pSockStatus.setSendable(True, self.connId)
             
         #send data to the sam bridge
         self.sendFunc(SamMessages.streamSendMessage(self.samId, data))   
         
         #remember data, in case sam rejects it
         self.outMessage = data
         
         #don't send anything until the sam bridge send us its status
         self.sendable = False
Ejemplo n.º 4
0
 def connectEvent(self):
     #called when the socket connects
     assert (self.state == 'connecting' and self.direction == 'out') or (self.state == 'init' and self.direction == 'in'), 'wrong state "%s", direction "%s"' % (self.state, self.direction)
     self.state = 'connected'
     self.connected = True
     self.sendable = True
     self.inRecvLimit = self.inMaxQueueSize
     self.i2pSockStatus.setSendable(True, self.connId)
     self.sendFunc(SamMessages.streamReceiveLimitMessage(self.samId, self.inRecvLimit))
Ejemplo n.º 5
0
 def _addNameLookupQuery(self, connId, name, func, funcArgs=[], funcKw={}):
     assert not connId in self.connIdToName, 'already running a lookup?!'
     self.connIdToName[connId] = name
     
     if name in self.nameLookups:
         #already running a lookup
         self.nameLookups[name][connId] = (func, funcArgs, funcKw)
     else:
         #start a new one
         self.nameLookups[name] = {connId:(func, funcArgs, funcKw)}
         self._sendOverRealSocket(SamMessages.nameLookup(name))
Ejemplo n.º 6
0
 def recv(self, maxBytes, peekOnly):
     #called to recv data out of inbound queue
     assert self.state == 'connected' or self.state == 'failed', 'wrong state, expected "connected" or "failed", got "%s"' % (self.state,)
     availableBytes = self.inQueueSize
     
     if maxBytes == -1 or availableBytes <= maxBytes:
         #take everything available
         data = ''.join(self.inQueue)
         if not peekOnly:
             self.inQueue.clear()
             self.inQueueSize = 0
             self.i2pSockStatus.setRecvable(False, self.connId)
             
     else:
         #too much, only take a part
         data = deque()
         dataSize = 0
         count = 0
         while dataSize < maxBytes:
             #add chunks until the limit is reached
             if peekOnly:
                 dataChunk = self.inQueue[count]
                 count += 1
             else:
                 dataChunk = self.inQueue.popleft()
             dataChunkLen = len(dataChunk)
             if dataSize + dataChunkLen < maxBytes:
                 #take entire chunk
                 data.append(dataChunk)
                 dataSize += dataChunkLen
                 if not peekOnly:
                     self.inQueueSize -= dataChunkLen
             else:
                 #only take a part of the chunk
                 useableDataChunkLen = maxBytes - dataSize
                 data.append(dataChunk[:useableDataChunkLen])
                 dataSize += useableDataChunkLen
                 if not peekOnly:
                     self.inQueue.appendleft(dataChunk[useableDataChunkLen:])
                     self.inQueueSize -= useableDataChunkLen
                 
         data = ''.join(data)
     
     allowedBytes = self.inMaxQueueSize - self.inQueueSize
     if allowedBytes > 0:
         #free buffer space above threshold
         recvLimit = allowedBytes + self.inBytesReceived
         if self.samId is not None and recvLimit > (self.inRecvLimitThreshold + self.inRecvLimit):
             #new recv limit, notify sam bridge, if connected
             self.inRecvLimit = recvLimit
             self.sendFunc(SamMessages.streamReceiveLimitMessage(self.samId, recvLimit)) 
     
     return data
Ejemplo n.º 7
0
 def connect(self, remoteDest=None, samId=None):
     #called if the socket should send a connect message
     if remoteDest is not None:
         self.remoteDest = remoteDest
     if samId is not None:
         self.samId = samId
         
     assert self.remoteDest is not None, 'uhm, we need a destination ...'
     assert self.samId is not None, 'uhm, we need a id ...'
     assert self.state == 'init', 'wrong state, expected "init", got "%s"' % (self.state,)
     self.state = 'connecting'
     self.sendFunc(SamMessages.streamConnectMessage(self.samId, self.remoteDest))
Ejemplo n.º 8
0
 def send(self, target, data):
     self._sendOverRealSocket(SamMessages.datagramSendMessage(target, data))
     return len(data)
Ejemplo n.º 9
0
 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)