Пример #1
0
    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)
Пример #2
0
 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)
Пример #3
0
 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
Пример #4
0
 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
Пример #5
0
    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)
Пример #6
0
    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)
Пример #7
0
    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)
Пример #8
0
    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)
Пример #9
0
    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)
Пример #10
0
    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)
Пример #11
0
    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()