Ejemplo n.º 1
0
 def test_socket_closed(self):
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.connect((client_context.host, client_context.port))
     socket_checker = SocketChecker()
     self.assertFalse(socket_checker.socket_closed(s))
     s.close()
     self.assertTrue(socket_checker.socket_closed(s))
Ejemplo n.º 2
0
 def test_socket_closed(self):
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.connect((client_context.host, client_context.port))
     socket_checker = SocketChecker()
     self.assertFalse(socket_checker.socket_closed(s))
     s.close()
     self.assertTrue(socket_checker.socket_closed(s))
Ejemplo n.º 3
0
class Pool:
    def __init__(self, address, options, handshake=True):
        """
        :Parameters:
          - `address`: a (hostname, port) tuple
          - `options`: a PoolOptions instance
          - `handshake`: whether to call ismaster for each new SocketInfo
        """
        # Check a socket's health with socket_closed() every once in a while.
        # Can override for testing: 0 to always check, None to never check.
        self._check_interval_seconds = 1

        self.sockets = set()
        self.lock = threading.Lock()
        self.active_sockets = 0

        # Keep track of resets, so we notice sockets created before the most
        # recent reset and close them.
        self.pool_id = 0
        self.pid = os.getpid()
        self.address = address
        self.opts = options
        self.handshake = handshake

        if (self.opts.wait_queue_multiple is None or
                self.opts.max_pool_size is None):
            max_waiters = None
        else:
            max_waiters = (
                self.opts.max_pool_size * self.opts.wait_queue_multiple)

        self._socket_semaphore = thread_util.create_semaphore(
            self.opts.max_pool_size, max_waiters)
        self.socket_checker = SocketChecker()

    def reset(self):
        with self.lock:
            self.pool_id += 1
            self.pid = os.getpid()
            sockets, self.sockets = self.sockets, set()
            self.active_sockets = 0

        for sock_info in sockets:
            sock_info.close()

    def remove_stale_sockets(self):
        if self.opts.max_idle_time_ms is not None:
            with self.lock:
                for sock_info in self.sockets.copy():
                    idle_time_ms = 1000 * _time() - sock_info.last_checkin
                    if idle_time_ms > self.opts.max_idle_time_ms:
                        self.sockets.remove(sock_info)
                        sock_info.close()

        while len(
                self.sockets) + self.active_sockets < self.opts.min_pool_size:
            sock_info = self.connect()
            with self.lock:
                self.sockets.add(sock_info)

    def connect(self):
        """Connect to Mongo and return a new SocketInfo.

        Can raise ConnectionFailure or CertificateError.

        Note that the pool does not keep a reference to the socket -- you
        must call return_socket() when you're done with it.
        """
        sock = None
        try:
            sock = _configured_socket(self.address, self.opts)
            if self.handshake:
                cmd = SON([
                    ('ismaster', 1),
                    ('client', self.opts.metadata)
                ])
                ismaster = IsMaster(
                    command(sock,
                            'admin',
                            cmd,
                            False,
                            False,
                            ReadPreference.PRIMARY,
                            DEFAULT_CODEC_OPTIONS,
                            None,
                            None))
            else:
                ismaster = None
            return SocketInfo(sock, self, ismaster, self.address)
        except socket.error as error:
            if sock is not None:
                sock.close()
            _raise_connection_failure(self.address, error)

    @contextlib.contextmanager
    def get_socket(self, all_credentials, checkout=False):
        """Get a socket from the pool. Use with a "with" statement.

        Returns a :class:`SocketInfo` object wrapping a connected
        :class:`socket.socket`.

        This method should always be used in a with-statement::

            with pool.get_socket(credentials, checkout) as socket_info:
                socket_info.send_message(msg)
                data = socket_info.receive_message(op_code, request_id)

        The socket is logged in or out as needed to match ``all_credentials``
        using the correct authentication mechanism for the server's wire
        protocol version.

        Can raise ConnectionFailure or OperationFailure.

        :Parameters:
          - `all_credentials`: dict, maps auth source to MongoCredential.
          - `checkout` (optional): keep socket checked out.
        """
        # First get a socket, then attempt authentication. Simplifies
        # semaphore management in the face of network errors during auth.
        sock_info = self._get_socket_no_auth()
        try:
            sock_info.check_auth(all_credentials)
            yield sock_info
        except:
            # Exception in caller. Decrement semaphore.
            self.return_socket(sock_info)
            raise
        else:
            if not checkout:
                self.return_socket(sock_info)

    def _get_socket_no_auth(self):
        """Get or create a SocketInfo. Can raise ConnectionFailure."""
        # We use the pid here to avoid issues with fork / multiprocessing.
        # See test.test_client:TestClient.test_fork for an example of
        # what could go wrong otherwise
        if self.pid != os.getpid():
            self.reset()

        # Get a free socket or create one.
        if not self._socket_semaphore.acquire(
                True, self.opts.wait_queue_timeout):
            self._raise_wait_queue_timeout()
        with self.lock:
            self.active_sockets += 1

        # We've now acquired the semaphore and must release it on error.
        try:
            try:
                # set.pop() isn't atomic in Jython less than 2.7, see
                # http://bugs.jython.org/issue1854
                with self.lock:
                    # Can raise ConnectionFailure.
                    sock_info = self.sockets.pop()
            except KeyError:
                # Can raise ConnectionFailure or CertificateError.
                sock_info = self.connect()
            else:
                # Can raise ConnectionFailure.
                sock_info = self._check(sock_info)
        except:
            self._socket_semaphore.release()
            with self.lock:
                self.active_sockets -= 1
            raise

        return sock_info

    def return_socket(self, sock_info):
        """Return the socket to the pool, or if it's closed discard it."""
        if self.pid != os.getpid():
            self.reset()
        else:
            if sock_info.pool_id != self.pool_id:
                sock_info.close()
            elif not sock_info.closed:
                sock_info.last_checkin = _time()
                with self.lock:
                    self.sockets.add(sock_info)

        self._socket_semaphore.release()
        with self.lock:
            self.active_sockets -= 1

    def _check(self, sock_info):
        """This side-effecty function checks if this socket has been idle for
        for longer than the max idle time, or if the socket has been closed by
        some external network error, and if so, attempts to create a new
        socket. If this connection attempt fails we raise the
        ConnectionFailure.

        Checking sockets lets us avoid seeing *some*
        :class:`~pymongo.errors.AutoReconnect` exceptions on server
        hiccups, etc. We only check if the socket was closed by an external
        error if it has been > 1 second since the socket was checked into the
        pool, to keep performance reasonable - we can't avoid AutoReconnects
        completely anyway.
        """
        # How long since socket was last checked in.
        idle_time_seconds = _time() - sock_info.last_checkin
        # If socket is idle, open a new one.
        if (self.opts.max_idle_time_ms is not None and
                idle_time_seconds * 1000 > self.opts.max_idle_time_ms):
            sock_info.close()
            return self.connect()

        if (self._check_interval_seconds is not None and (
                0 == self._check_interval_seconds or
                idle_time_seconds > self._check_interval_seconds)):
            if self.socket_checker.socket_closed(sock_info.sock):
                sock_info.close()
                return self.connect()

        return sock_info

    def _raise_wait_queue_timeout(self):
        raise ConnectionFailure(
            'Timed out waiting for socket from pool with max_size %r and'
            ' wait_queue_timeout %r' % (
                self.opts.max_pool_size, self.opts.wait_queue_timeout))

    def __del__(self):
        # Avoid ResourceWarnings in Python 3
        for sock_info in self.sockets:
            sock_info.close()
Ejemplo n.º 4
0
class Pool:
    def __init__(self, address, options, handshake=True):
        """
        :Parameters:
          - `address`: a (hostname, port) tuple
          - `options`: a PoolOptions instance
          - `handshake`: whether to call ismaster for each new SocketInfo
        """
        # Check a socket's health with socket_closed() every once in a while.
        # Can override for testing: 0 to always check, None to never check.
        self._check_interval_seconds = 1
        # LIFO pool. Sockets are ordered on idle time. Sockets claimed
        # and returned to pool from the left side. Stale sockets removed
        # from the right side.
        self.sockets = collections.deque()
        self.lock = threading.Lock()
        self.active_sockets = 0
        # Monotonically increasing connection ID required for CMAP Events.
        self.next_connection_id = 1
        self.closed = False
        # Track whether the sockets in this pool are writeable or not.
        self.is_writable = None

        # Keep track of resets, so we notice sockets created before the most
        # recent reset and close them.
        self.pool_id = 0
        self.pid = os.getpid()
        self.address = address
        self.opts = options
        self.handshake = handshake
        # Don't publish events in Monitor pools.
        self.enabled_for_cmap = (self.handshake
                                 and self.opts.event_listeners is not None and
                                 self.opts.event_listeners.enabled_for_cmap)

        if (self.opts.wait_queue_multiple is None
                or self.opts.max_pool_size is None):
            max_waiters = None
        else:
            max_waiters = (self.opts.max_pool_size *
                           self.opts.wait_queue_multiple)

        self._socket_semaphore = thread_util.create_semaphore(
            self.opts.max_pool_size, max_waiters)
        self.socket_checker = SocketChecker()
        if self.enabled_for_cmap:
            self.opts.event_listeners.publish_pool_created(
                self.address, self.opts.non_default_options)

    def _reset(self, close):
        with self.lock:
            if self.closed:
                return
            self.pool_id += 1
            self.pid = os.getpid()
            sockets, self.sockets = self.sockets, collections.deque()
            self.active_sockets = 0
            if close:
                self.closed = True

        listeners = self.opts.event_listeners
        # CMAP spec says that close() MUST close sockets before publishing the
        # PoolClosedEvent but that reset() SHOULD close sockets *after*
        # publishing the PoolClearedEvent.
        if close:
            for sock_info in sockets:
                sock_info.close_socket(ConnectionClosedReason.POOL_CLOSED)
            if self.enabled_for_cmap:
                listeners.publish_pool_closed(self.address)
        else:
            if self.enabled_for_cmap:
                listeners.publish_pool_cleared(self.address)
            for sock_info in sockets:
                sock_info.close_socket(ConnectionClosedReason.STALE)

    def update_is_writable(self, is_writable):
        """Updates the is_writable attribute on all sockets currently in the
        Pool.
        """
        self.is_writable = is_writable
        with self.lock:
            for socket in self.sockets:
                socket.update_is_writable(self.is_writable)

    def reset(self):
        self._reset(close=False)

    def close(self):
        self._reset(close=True)

    def remove_stale_sockets(self):
        """Removes stale sockets then adds new ones if pool is too small."""
        if self.opts.max_idle_time_seconds is not None:
            with self.lock:
                while (self.sockets and self.sockets[-1].idle_time_seconds() >
                       self.opts.max_idle_time_seconds):
                    sock_info = self.sockets.pop()
                    sock_info.close_socket(ConnectionClosedReason.IDLE)
        while True:
            with self.lock:
                if (len(self.sockets) + self.active_sockets >=
                        self.opts.min_pool_size):
                    # There are enough sockets in the pool.
                    break

            # We must acquire the semaphore to respect max_pool_size.
            if not self._socket_semaphore.acquire(False):
                break
            try:
                sock_info = self.connect()
                with self.lock:
                    self.sockets.appendleft(sock_info)
            finally:
                self._socket_semaphore.release()

    def connect(self):
        """Connect to Mongo and return a new SocketInfo.

        Can raise ConnectionFailure or CertificateError.

        Note that the pool does not keep a reference to the socket -- you
        must call return_socket() when you're done with it.
        """
        with self.lock:
            conn_id = self.next_connection_id
            self.next_connection_id += 1

        listeners = self.opts.event_listeners
        if self.enabled_for_cmap:
            listeners.publish_connection_created(self.address, conn_id)

        sock = None
        try:
            sock = _configured_socket(self.address, self.opts)
        except socket.error as error:
            if sock is not None:
                sock.close()

            if self.enabled_for_cmap:
                listeners.publish_connection_closed(
                    self.address, conn_id, ConnectionClosedReason.ERROR)

            _raise_connection_failure(self.address, error)

        sock_info = SocketInfo(sock, self, self.address, conn_id)
        if self.handshake:
            sock_info.ismaster(self.opts.metadata, None)
            self.is_writable = sock_info.is_writable

        return sock_info

    @contextlib.contextmanager
    def get_socket(self, all_credentials, checkout=False):
        """Get a socket from the pool. Use with a "with" statement.

        Returns a :class:`SocketInfo` object wrapping a connected
        :class:`socket.socket`.

        This method should always be used in a with-statement::

            with pool.get_socket(credentials, checkout) as socket_info:
                socket_info.send_message(msg)
                data = socket_info.receive_message(op_code, request_id)

        The socket is logged in or out as needed to match ``all_credentials``
        using the correct authentication mechanism for the server's wire
        protocol version.

        Can raise ConnectionFailure or OperationFailure.

        :Parameters:
          - `all_credentials`: dict, maps auth source to MongoCredential.
          - `checkout` (optional): keep socket checked out.
        """
        listeners = self.opts.event_listeners
        if self.enabled_for_cmap:
            listeners.publish_connection_check_out_started(self.address)
        # First get a socket, then attempt authentication. Simplifies
        # semaphore management in the face of network errors during auth.
        sock_info = self._get_socket_no_auth()
        checked_auth = False
        try:
            sock_info.check_auth(all_credentials)
            checked_auth = True
            if self.enabled_for_cmap:
                listeners.publish_connection_checked_out(
                    self.address, sock_info.id)
            yield sock_info
        except:
            # Exception in caller. Decrement semaphore.
            self.return_socket(sock_info, publish_checkin=checked_auth)
            if self.enabled_for_cmap and not checked_auth:
                self.opts.event_listeners.publish_connection_check_out_failed(
                    self.address, ConnectionCheckOutFailedReason.CONN_ERROR)
            raise
        else:
            if not checkout:
                self.return_socket(sock_info)

    def _get_socket_no_auth(self):
        """Get or create a SocketInfo. Can raise ConnectionFailure."""
        # We use the pid here to avoid issues with fork / multiprocessing.
        # See test.test_client:TestClient.test_fork for an example of
        # what could go wrong otherwise
        if self.pid != os.getpid():
            self.reset()

        if self.closed:
            if self.enabled_for_cmap:
                self.opts.event_listeners.publish_connection_check_out_failed(
                    self.address, ConnectionCheckOutFailedReason.POOL_CLOSED)
            raise _PoolClosedError(
                'Attempted to check out a connection from closed connection '
                'pool')

        # Get a free socket or create one.
        if not self._socket_semaphore.acquire(True,
                                              self.opts.wait_queue_timeout):
            self._raise_wait_queue_timeout()
        with self.lock:
            self.active_sockets += 1

        # We've now acquired the semaphore and must release it on error.
        try:
            sock_info = None
            while sock_info is None:
                try:
                    with self.lock:
                        sock_info = self.sockets.popleft()
                except IndexError:
                    # Can raise ConnectionFailure or CertificateError.
                    sock_info = self.connect()
                else:
                    if self._perished(sock_info):
                        sock_info = None
        except Exception:
            self._socket_semaphore.release()
            with self.lock:
                self.active_sockets -= 1

            if self.enabled_for_cmap:
                self.opts.event_listeners.publish_connection_check_out_failed(
                    self.address, ConnectionCheckOutFailedReason.CONN_ERROR)
            raise

        return sock_info

    def return_socket(self, sock_info, publish_checkin=True):
        """Return the socket to the pool, or if it's closed discard it.

        :Parameters:
          - `sock_info`: The socket to check into the pool.
          - `publish_checkin`: If False, a ConnectionCheckedInEvent will not
            be published.
        """
        listeners = self.opts.event_listeners
        if self.enabled_for_cmap and publish_checkin:
            listeners.publish_connection_checked_in(self.address, sock_info.id)
        if self.pid != os.getpid():
            self.reset()
        else:
            if self.closed:
                sock_info.close_socket(ConnectionClosedReason.POOL_CLOSED)
            elif sock_info.pool_id != self.pool_id:
                sock_info.close_socket(ConnectionClosedReason.STALE)
            elif not sock_info.closed:
                sock_info.update_last_checkin_time()
                sock_info.update_is_writable(self.is_writable)
                with self.lock:
                    self.sockets.appendleft(sock_info)

        self._socket_semaphore.release()
        with self.lock:
            self.active_sockets -= 1

    def _perished(self, sock_info):
        """This side-effecty function checks if this socket has been idle for
        for longer than the max idle time, or if the socket has been closed by
        some external network error.

        Checking sockets lets us avoid seeing *some*
        :class:`~pymongo.errors.AutoReconnect` exceptions on server
        hiccups, etc. We only check if the socket was closed by an external
        error if it has been > 1 second since the socket was checked into the
        pool, to keep performance reasonable - we can't avoid AutoReconnects
        completely anyway.
        """
        idle_time_seconds = sock_info.idle_time_seconds()
        # If socket is idle, open a new one.
        if (self.opts.max_idle_time_seconds is not None
                and idle_time_seconds > self.opts.max_idle_time_seconds):
            sock_info.close_socket(ConnectionClosedReason.IDLE)
            return True

        if (self._check_interval_seconds is not None
                and (0 == self._check_interval_seconds
                     or idle_time_seconds > self._check_interval_seconds)):
            if self.socket_checker.socket_closed(sock_info.sock):
                sock_info.close_socket(ConnectionClosedReason.ERROR)
                return True

        return False

    def _raise_wait_queue_timeout(self):
        listeners = self.opts.event_listeners
        if self.enabled_for_cmap:
            listeners.publish_connection_check_out_failed(
                self.address, ConnectionCheckOutFailedReason.TIMEOUT)
        raise ConnectionFailure(
            'Timed out while checking out a connection from connection pool '
            'with max_size %r and wait_queue_timeout %r' %
            (self.opts.max_pool_size, self.opts.wait_queue_timeout))

    def __del__(self):
        # Avoid ResourceWarnings in Python 3
        # Close all sockets without calling reset() or close() because it is
        # not safe to acquire a lock in __del__.
        for sock_info in self.sockets:
            sock_info.close_socket(None)
Ejemplo n.º 5
0
class Pool:
    def __init__(self, address, options, handshake=True):
        """
        :Parameters:
          - `address`: a (hostname, port) tuple
          - `options`: a PoolOptions instance
          - `handshake`: whether to call ismaster for each new SocketInfo
        """
        # Check a socket's health with socket_closed() every once in a while.
        # Can override for testing: 0 to always check, None to never check.
        self._check_interval_seconds = 1

        self.sockets = set()
        self.lock = threading.Lock()
        self.active_sockets = 0

        # Keep track of resets, so we notice sockets created before the most
        # recent reset and close them.
        self.pool_id = 0
        self.pid = os.getpid()
        self.address = address
        self.opts = options
        self.handshake = handshake

        if (self.opts.wait_queue_multiple is None or
                self.opts.max_pool_size is None):
            max_waiters = None
        else:
            max_waiters = (
                self.opts.max_pool_size * self.opts.wait_queue_multiple)

        self._socket_semaphore = thread_util.create_semaphore(
            self.opts.max_pool_size, max_waiters)
        self.socket_checker = SocketChecker()

    def reset(self):
        with self.lock:
            self.pool_id += 1
            self.pid = os.getpid()
            sockets, self.sockets = self.sockets, set()
            self.active_sockets = 0

        for sock_info in sockets:
            sock_info.close()

    def remove_stale_sockets(self):
        """Removes stale sockets then adds new ones if pool is too small."""
        if self.opts.max_idle_time_seconds is not None:
            with self.lock:
                for sock_info in self.sockets.copy():
                    if (sock_info.idle_time_seconds() >
                            self.opts.max_idle_time_seconds):
                        self.sockets.remove(sock_info)
                        sock_info.close()

        while True:
            with self.lock:
                if (len(self.sockets) + self.active_sockets >=
                        self.opts.min_pool_size):
                    # There are enough sockets in the pool.
                    break

            # We must acquire the semaphore to respect max_pool_size.
            if not self._socket_semaphore.acquire(False):
                break
            try:
                sock_info = self.connect()
                with self.lock:
                    self.sockets.add(sock_info)
            finally:
                self._socket_semaphore.release()

    def connect(self):
        """Connect to Mongo and return a new SocketInfo.

        Can raise ConnectionFailure or CertificateError.

        Note that the pool does not keep a reference to the socket -- you
        must call return_socket() when you're done with it.
        """
        sock = None
        try:
            sock = _configured_socket(self.address, self.opts)
        except socket.error as error:
            if sock is not None:
                sock.close()
            _raise_connection_failure(self.address, error)

        sock_info = SocketInfo(sock, self, self.address)
        if self.handshake:
            sock_info.ismaster(self.opts.metadata, None)
        return sock_info

    @contextlib.contextmanager
    def get_socket(self, all_credentials, checkout=False):
        """Get a socket from the pool. Use with a "with" statement.

        Returns a :class:`SocketInfo` object wrapping a connected
        :class:`socket.socket`.

        This method should always be used in a with-statement::

            with pool.get_socket(credentials, checkout) as socket_info:
                socket_info.send_message(msg)
                data = socket_info.receive_message(op_code, request_id)

        The socket is logged in or out as needed to match ``all_credentials``
        using the correct authentication mechanism for the server's wire
        protocol version.

        Can raise ConnectionFailure or OperationFailure.

        :Parameters:
          - `all_credentials`: dict, maps auth source to MongoCredential.
          - `checkout` (optional): keep socket checked out.
        """
        # First get a socket, then attempt authentication. Simplifies
        # semaphore management in the face of network errors during auth.
        sock_info = self._get_socket_no_auth()
        try:
            sock_info.check_auth(all_credentials)
            yield sock_info
        except:
            # Exception in caller. Decrement semaphore.
            self.return_socket(sock_info)
            raise
        else:
            if not checkout:
                self.return_socket(sock_info)

    def _get_socket_no_auth(self):
        """Get or create a SocketInfo. Can raise ConnectionFailure."""
        # We use the pid here to avoid issues with fork / multiprocessing.
        # See test.test_client:TestClient.test_fork for an example of
        # what could go wrong otherwise
        if self.pid != os.getpid():
            self.reset()

        # Get a free socket or create one.
        if not self._socket_semaphore.acquire(
                True, self.opts.wait_queue_timeout):
            self._raise_wait_queue_timeout()
        with self.lock:
            self.active_sockets += 1

        # We've now acquired the semaphore and must release it on error.
        try:
            try:
                # set.pop() isn't atomic in Jython less than 2.7, see
                # http://bugs.jython.org/issue1854
                with self.lock:
                    # Can raise ConnectionFailure.
                    sock_info = self.sockets.pop()
            except KeyError:
                # Can raise ConnectionFailure or CertificateError.
                sock_info = self.connect()
            else:
                # Can raise ConnectionFailure.
                sock_info = self._check(sock_info)
        except:
            self._socket_semaphore.release()
            with self.lock:
                self.active_sockets -= 1
            raise

        return sock_info

    def return_socket(self, sock_info):
        """Return the socket to the pool, or if it's closed discard it."""
        if self.pid != os.getpid():
            self.reset()
        else:
            if sock_info.pool_id != self.pool_id:
                sock_info.close()
            elif not sock_info.closed:
                sock_info.update_last_checkin_time()
                with self.lock:
                    self.sockets.add(sock_info)

        self._socket_semaphore.release()
        with self.lock:
            self.active_sockets -= 1

    def _check(self, sock_info):
        """This side-effecty function checks if this socket has been idle for
        for longer than the max idle time, or if the socket has been closed by
        some external network error, and if so, attempts to create a new
        socket. If this connection attempt fails we raise the
        ConnectionFailure.

        Checking sockets lets us avoid seeing *some*
        :class:`~pymongo.errors.AutoReconnect` exceptions on server
        hiccups, etc. We only check if the socket was closed by an external
        error if it has been > 1 second since the socket was checked into the
        pool, to keep performance reasonable - we can't avoid AutoReconnects
        completely anyway.
        """
        idle_time_seconds = sock_info.idle_time_seconds()
        # If socket is idle, open a new one.
        if (self.opts.max_idle_time_seconds is not None and
                idle_time_seconds > self.opts.max_idle_time_seconds):
            sock_info.close()
            return self.connect()

        if (self._check_interval_seconds is not None and (
                0 == self._check_interval_seconds or
                idle_time_seconds > self._check_interval_seconds)):
            if self.socket_checker.socket_closed(sock_info.sock):
                sock_info.close()
                return self.connect()

        return sock_info

    def _raise_wait_queue_timeout(self):
        raise ConnectionFailure(
            'Timed out waiting for socket from pool with max_size %r and'
            ' wait_queue_timeout %r' % (
                self.opts.max_pool_size, self.opts.wait_queue_timeout))

    def __del__(self):
        # Avoid ResourceWarnings in Python 3
        for sock_info in self.sockets:
            sock_info.close()