def _opt_reconnect(self): ''' Check that connection is alive using low-level recv from libc(ctypes) **Due to bug in python - timeout is internal python construction. ''' if not self._socket: return self.connect() def check(): # Check that connection is alive buf = ctypes.create_string_buffer(2) try: sock_fd = self._socket.fileno() except socket.error as e: if e.errno == errno.EBADF: return errno.ECONNRESET else: if os.name == 'nt': flag = socket.MSG_PEEK self._socket.setblocking(False) else: flag = socket.MSG_DONTWAIT | socket.MSG_PEEK self._sys_recv(sock_fd, buf, 1, flag) if ctypes.get_errno() == errno.EAGAIN: ctypes.set_errno(0) return errno.EAGAIN return (ctypes.get_errno() if ctypes.get_errno() else errno.ECONNRESET) last_errno = check() if self.connected and last_errno == errno.EAGAIN: return attempt = 0 last_errno = errno.ECONNRESET while True: time.sleep(self.reconnect_delay) try: self.connect_basic() except NetworkError: pass else: if self.connected: break warn( "Reconnect attempt %d of %d" % (attempt, self.reconnect_max_attempts), NetworkWarning) if attempt == self.reconnect_max_attempts: raise NetworkError( socket.error(last_errno, errno.errorcode[last_errno])) attempt += 1 self.handshake() # It is important to set socket timeout *after* connection. # Otherwise the timeout exception will be raised, even when # the connection fails because the server is simply # not bound to port self._socket.settimeout(self.socket_timeout)
def handshake(self): greeting_buf = self._recv(IPROTO_GREETING_SIZE) greeting = greeting_decode(greeting_buf) if greeting.protocol != "Binary": raise NetworkError("Unsupported protocol: " + greeting.protocol) self.version_id = greeting.version_id self.uuid = greeting.uuid self._salt = greeting.salt if self.user: self.authenticate(self.user, self.password)
def _recv(self, to_read): buf = '' while to_read > 0: try: tmp = self._socket.recv(to_read) except socket.error: raise NetworkError( socket.error(errno.ECONNRESET, "Lost connection to server during query")) else: to_read -= len(tmp) buf += tmp return buf
def _recv(self, to_read): buf = b"" while to_read > 0: try: tmp = self._socket.recv(to_read) except OverflowError: self._socket.close() err = socket.error( errno.ECONNRESET, "Too big packet. Closing connection to server") raise NetworkError(err) except socket.error: err = socket.error(errno.ECONNRESET, "Lost connection to server during query") raise NetworkError(err) else: if len(tmp) == 0: err = socket.error( errno.ECONNRESET, "Lost connection to server during query") raise NetworkError(err) to_read -= len(tmp) buf += tmp return buf
def connect(self): ''' Create connection to the host and port specified in __init__(). Usually there is no need to call this method directly, since it is called when you create an `Connection` instance. :raise: `NetworkError` ''' try: self.connect_basic() self.handshake() self.load_schema() except Exception as e: self.connected = False raise NetworkError(e)
def _response_reader(self): # handshake greeting = yield from self._reader.read(IPROTO_GREETING_SIZE) self._salt = base64.decodestring(greeting[64:])[:20] self._greeting_event.set() buf = b"" while not self._reader.at_eof(): tmp_buf = yield from self._reader.read(self.aiobuffer_size) if not tmp_buf: yield from self._do_close( NetworkError(socket.error(errno.ECONNRESET, "Lost connection to server during query"))) buf += tmp_buf len_buf = len(buf) curr = 0 while len_buf - curr >= 5: length_pack = buf[curr:curr + 5] length = msgpack.unpackb(length_pack) if len_buf - curr < 5 + length: break body = buf[curr + 5:curr + 5 + length] curr += 5 + length response = Response(self, body) # unpack response sync = response.sync if sync not in self._waiters: logger.error("aio git happens: {r}", response) continue waiter = self._waiters[sync] if not waiter.cancelled(): if response.return_code != 0: waiter.set_exception(DatabaseError(response.return_code, response.return_message)) else: waiter.set_result(response) del self._waiters[sync] # one cut for buffer if curr: buf = buf[curr:] yield from self._do_close(None)
def connect_basic(self): ''' Create connection to the host and port specified in __init__(). :raise: `NetworkError` ''' try: # If old socket already exists - close it and re-create self.connected = True if self._socket: self._socket.close() self._socket = socket.create_connection((self.host, self.port)) self._socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) except socket.error as e: self.connected = False raise NetworkError(e)
def connect_unix(self): ''' Create connection to the host and port specified in __init__(). :raise: `NetworkError` ''' try: # If old socket already exists - close it and re-create self.connected = True if self._socket: self._socket.close() self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._socket.connect(self.port) except socket.error as e: self.connected = False raise NetworkError(e)
def connect(self): ''' Create connection to the host and port specified in __init__(). Usually there is no need to call this method directly, since it is called when you create an `Connection` instance. :raise: `NetworkError` ''' try: self.connect_basic() self.handshake() # It is important to set socket timeout *after* connection. # Otherwise the timeout exception will be raised, even when # the connection fails because the server is simply # not bound to port self._socket.settimeout(self.socket_timeout) except socket.error as e: self.connected = False raise NetworkError(e)
async def _response_reader(self): # handshake greeting = await self._reader.read(IPROTO_GREETING_SIZE) self._salt = base64.decodestring(greeting[64:])[:20] self._greeting_event.set() buf = b"" while not self._reader.at_eof(): tmp_buf = await self._reader.read(self.aiobuffer_size) if not tmp_buf: await self._do_close( NetworkError( socket.error(errno.ECONNRESET, "Lost connection to server during query")) ) buf += tmp_buf len_buf = len(buf) curr = 0 while len_buf - curr >= 5: length_pack = buf[curr:curr + 5] length = msgpack.unpackb(length_pack) if len_buf - curr < 5 + length: break body = buf[curr + 5:curr + 5 + length] curr += 5 + length try: response = Response(self, body) # unpack response except SchemaReloadException as exp: if self.encoding is not None: unpacker = msgpack.Unpacker(use_list=True, encoding=self.encoding) else: unpacker = msgpack.Unpacker(use_list=True) unpacker.feed(body) header = unpacker.unpack() sync = header.get(IPROTO_SYNC, 0) waiter = self._waiters[sync] if not waiter.cancelled(): waiter.set_exception(exp) del self._waiters[sync] self.schema.flush() self.schema_version = exp.schema_version continue sync = response.sync if sync not in self._waiters: logger.error("aio git happens: {r}", response) continue waiter = self._waiters[sync] if not waiter.cancelled(): if response.return_code != 0: waiter.set_exception( DatabaseError(response.return_code, response.return_message)) else: waiter.set_result(response) del self._waiters[sync] # one cut for buffer if curr: buf = buf[curr:] await self._do_close(None)
def _opt_reconnect(self): ''' Check that connection is alive using low-level recv from libc(ctypes) **Due to bug in python - timeout is internal python construction. ''' if not self._socket: return self.connect() def check(): # Check that connection is alive buf = ctypes.create_string_buffer(2) try: sock_fd = self._socket.fileno() except socket.error as e: if e.errno == errno.EBADF: return errno.ECONNRESET else: if os.name == 'nt': flag = socket.MSG_PEEK self._socket.setblocking(False) else: flag = socket.MSG_DONTWAIT | socket.MSG_PEEK retbytes = self._sys_recv(sock_fd, buf, 1, flag) err = 0 if os.name != 'nt': err = ctypes.get_errno() else: err = ctypes.get_last_error() self._socket.setblocking(True) WWSAEWOULDBLOCK = 10035 if (retbytes < 0) and (err == errno.EAGAIN or err == errno.EWOULDBLOCK or err == WWSAEWOULDBLOCK): ctypes.set_errno(0) return errno.EAGAIN else: return errno.ECONNRESET last_errno = check() if self.connected and last_errno == errno.EAGAIN: return attempt = 0 last_errno = errno.ECONNRESET while True: time.sleep(self.reconnect_delay) try: self.connect_basic() except NetworkError: pass else: if self.connected: break warn( "Reconnect attempt %d of %d" % (attempt, self.reconnect_max_attempts), NetworkWarning) if attempt == self.reconnect_max_attempts: raise NetworkError( socket.error(last_errno, errno.errorcode[last_errno])) attempt += 1 self.handshake()