def _reader (self, number): # The function must not be called if it does not return with no data with a smaller size as parameter if not self.io: self.close() raise NotConnected('Trying to read on a closed TCP connection') if number == 0: yield b'' return while not self.reading(): yield b'' data = b'' reported = '' while True: try: while True: if self.defensive and random.randint(0,2): raise socket.error(errno.EAGAIN,'raising network error on purpose') read = self.io.recv(number) if not read: self.close() self.logger.wire("%s %s lost TCP session with peer" % (self.name(),self.peer),source=self.session()) raise LostConnection('the TCP connection was closed by the remote end') data += read number -= len(read) if not number: self.logger.wire( LazyFormat( "%s %-32s RECEIVED " % ( self.name(), '%s / %s' % (self.local,self.peer) ), read ), source=self.session() ) yield data return yield b'' except socket.timeout as exc: self.close() self.logger.wire("%s %s peer is too slow" % (self.name(),self.peer),source=self.session()) raise TooSlowError('Timeout while reading data from the network (%s)' % errstr(exc)) except socket.error as exc: if exc.args[0] in error.block: message = "%s %s blocking io problem mid-way through reading a message %s, trying to complete" % (self.name(),self.peer,errstr(exc)) if message != reported: reported = message self.logger.wire(message,'debug',self.session()) yield b'' elif exc.args[0] in error.fatal: self.close() raise LostConnection('issue reading on the socket: %s' % errstr(exc)) # what error could it be ! else: self.logger.wire("%s %s undefined error reading on socket" % (self.name(),self.peer),source=self.session()) raise NetworkError('Problem while reading data from the network (%s)' % errstr(exc))
def _reader (self,number): # The function must not be called if it does not return with no data with a smaller size as parameter if not self.io: self.close() raise NotConnected('Trying to read on a close TCP conncetion') if number == 0: yield '' return # XXX: one of the socket option is to recover the size of the buffer # XXX: we could use it to not have to put together the string with multiple reads # XXX: and get rid of the self.read_timeout option while not self.reading(): yield '' data = '' while True: try: while True: if self._reading is None: self._reading = time.time() elif time.time() > self._reading + self.read_timeout: self.close() self.logger.wire("%s %s peer is too slow (we were told there was data on the socket but we can not read up to what should be there)" % (self.name(),self.peer)) raise TooSlowError('Waited to read for data on a socket for more than %d second(s)' % self.read_timeout) if self.defensive and random.randint(0,2): raise socket.error(errno.EAGAIN,'raising network error in purpose') read = self.io.recv(number) if not read: self.close() self.logger.wire("%s %s lost TCP session with peer" % (self.name(),self.peer)) raise LostConnection('the TCP connection was closed by the remote end') data += read number -= len(read) if not number: self.logger.wire(LazyFormat("%s %-32s RECEIVED " % (self.name(),'%s / %s' % (self.local,self.peer)),od,read)) self._reading = None yield data return except socket.timeout,e: self.close() self.logger.wire("%s %s peer is too slow" % (self.name(),self.peer)) raise TooSlowError('Timeout while reading data from the network (%s)' % errstr(e)) except socket.error,e: if e.args[0] in error.block: self.logger.wire("%s %s blocking io problem mid-way through reading a message %s, trying to complete" % (self.name(),self.peer,errstr(e)),'debug') elif e.args[0] in error.fatal: self.close() raise LostConnection('issue reading on the socket: %s' % errstr(e)) # what error could it be ! else: self.logger.wire("%s %s undefined error reading on socket" % (self.name(),self.peer)) raise NetworkError('Problem while reading data from the network (%s)' % errstr(e))
def writer(self, data): if not self.io: # XXX: FIXME: Make sure it does not hold the cleanup during the closing of the peering session yield True return while not self.writing(): yield False self.logger.debug(LazyFormat('sending TCP payload', data), self.session()) # The first while is here to setup the try/catch block once as it is very expensive while True: try: while True: if self.defensive and random.randint(0, 2): raise socket.error(errno.EAGAIN, 'raising network error on purpose') # we can not use sendall as in case of network buffer filling # it does raise and does not let you know how much was sent number = self.io.send(data) if not number: self.close() self.logger.warning( '%s %s lost TCP connection with peer' % (self.name(), self.peer), self.session()) raise LostConnection('lost the TCP connection') data = data[number:] if not data: yield True return yield False except socket.error as exc: if exc.args[0] in error.block: self.logger.debug( '%s %s blocking io problem mid-way through writing a message %s, trying to complete' % (self.name(), self.peer, errstr(exc)), self.session()) yield False elif exc.errno == errno.EPIPE: # The TCP connection is gone. self.close() raise NetworkError('Broken TCP connection') elif exc.args[0] in error.fatal: self.close() self.logger.critical( '%s %s problem sending message (%s)' % (self.name(), self.peer, errstr(exc)), self.session()) raise NetworkError( 'Problem while writing data to the network (%s)' % errstr(exc)) # what error could it be ! else: self.logger.critical( '%s %s undefined error writing on socket' % (self.name(), self.peer), self.session()) yield False
def writer (self,data): if not self.io: # XXX: FIXME: Make sure it does not hold the cleanup during the closing of the peering session yield True return if not self.writing(): yield False return self.logger.wire(LazyFormat("%s %-32s SENDING " % (self.name(),'%s / %s' % (self.local,self.peer)),od,data)) # The first while is here to setup the try/catch block once as it is very expensive while True: try: while True: if self._writing is None: self._writing = time.time() elif time.time() > self._writing + self.read_timeout: self.close() self.logger.wire("%s %s peer is too slow" % (self.name(),self.peer)) raise TooSlowError('Waited to write for data on a socket for more than %d second(s)' % self.read_timeout) if self.defensive and random.randint(0,2): raise socket.error(errno.EAGAIN,'raising network error in purpose') # we can not use sendall as in case of network buffer filling # it does raise and does not let you know how much was sent nb = self.io.send(data) if not nb: self.close() self.logger.wire("%s %s lost TCP connection with peer" % (self.name(),self.peer)) raise LostConnection('lost the TCP connection') data = data[nb:] if not data: self._writing = None yield True return yield False except socket.error,e: if e.args[0] in error.block: self.logger.wire("%s %s blocking io problem mid-way through writing a message %s, trying to complete" % (self.name(),self.peer,errstr(e)),'debug') elif e.errno == errno.EPIPE: # The TCP connection is gone. self.close() raise NetworkError('Broken TCP connection') elif e.args[0] in error.fatal: self.close() self.logger.wire("%s %s problem sending message (%s)" % (self.name(),self.peer,errstr(e))) raise NetworkError('Problem while writing data to the network (%s)' % errstr(e)) # what error could it be ! else: self.logger.wire("%s %s undefined error writing on socket" % (self.name(),self.peer)) yield False