Example #1
0
    def _protocol_client_hello_server_reply(self, item):
        """
        Received a hello reply
        :param item: Received server reply ("C.HI.REPLY PID=...")

        """

        with self._protocol_lock:
            # Parse it
            self._server_pid = item.replace("C.HI.REPLY PID=", "")

            # Unschedule timeout
            self._unschedule_client_helloservertimeout()

            # Stats
            Meters.aii("ping.client.client_hello_server_reply")

            # Delay
            ms = SolBase.datediff(self.dt_hello_send)

            # Stats
            Meters.dtci("ping.client.delay_client_hello_toserver_reply", ms)

            # Initiate the ping loop, with random start
            self._schedule_clientping(True)
Example #2
0
    def send_binary_to_socket_with_signal(self, signaled_buffer):
        """
        Send to socket, asynch.
        Upon completion, signaled_buffer.send_event is set.
        Caution : Caller MUST check the boolean returned. If False, the event will NOT be set.
        :param signaled_buffer: A signaled_buffer instance.
        :type signaled_buffer: pysoltcp.tcpbase.SignaledBuffer.SignaledBuffer
        :return: True is send has been scheduled, false otherwise.
        :rtype bool
        """

        # Check
        if not isinstance(signaled_buffer, SignaledBuffer):
            logger.error("signaled_buffer not a SignaledBuffer, class=%s, self=%s", SolBase.get_classname(signaled_buffer), self)
            return False

            # Check
        if not isinstance(signaled_buffer.binary_buffer, binary_type):
            logger.error("binary_buffer not a binary, class=%s, self=%s", SolBase.get_classname(signaled_buffer.binary_buffer), self)
            return False

        # Check
        if not self.__is_running():
            logger.debug(
                "not connected, returning false, self=%s",
                self)
            return False

        # Enqueue
        self.__send_queue.put(signaled_buffer)

        # Stats
        Meters.aii("tcp.server.server_bytes_send_pending", len(signaled_buffer.binary_buffer))

        return True
Example #3
0
    def _protocol_server_ping_send(self):
        """
        Must send a client ping

        """
        with self._protocolLock:
            # Reset (we are called by it)
            self._pingGreenlet = None

            # Schedule a timeout
            self._schedule_server_ping_client_timeout()

            # Timestamp
            self.dtLastPingSend = SolBase.datecurrent()

            # Send a ping
            b = self.send_unicode_to_socket("S.PING")
            if not b:
                # Stat
                logger.error("send failed, fatal, disconnecting")
                Meters.aii("ping.server.serverSendError")
                # Disconnect
                self.stop_asynch()
            else:
                # Stats
                Meters.aii("ping.server.serverPingSent")
Example #4
0
    def _protocol_client_ping_send(self):
        """
        Must send a client ping

        """
        with self._protocol_lock:
            # Reset (we are called by it)
            self._ping_greenlet = None

            # Schedule a timeout
            self._schedule_client_pingservertimeout()

            # Timestamp
            self.dt_last_ping_send = SolBase.datecurrent()

            # Send a ping
            b = self.send_unicode_to_socket("C.PING")
            if not b:
                # Stat
                logger.error("send failed, fatal, disconnecting")
                Meters.aii("ping.client.client_send_error")
                # Disconnect
                self.disconnect()
            else:
                # Stats
                Meters.aii("ping.client.client_ping_sent")
Example #5
0
    def __on_ssl_timeout(self):
        """
        Called when SSL timeout.
        """

        # Reset first (in LOCK)
        with self.__ssl_locker:
            self.__ssl_timeout_greenlet = None

        # Process (outside of LOCK, high level may call _unschedule_ssl_handshake_timeout in lock)
        logger.debug("__on_ssl_timeout, self=%s", self)

        # Check
        if not self.__ssl_handshake_pending:
            # Done, exit
            return
        elif not self.__is_running():
            # Not connected, exit
            return

        # Not done, FATAL
        logger.warning("handshake timeout, fatal, ms=%s, self=%s", self.__ssl_handshake_timeout_ms, self)

        # Stat
        Meters.aii("tcp.server.ssl_handshake_timeout_count")

        # Timeout, Fatal, exit now
        self._disconnect_helper("__on_ssl_timeout")
Example #6
0
    def send_binary_to_socket(self, buffer_to_send):
        """
        Send to socket, asynch.
        :param buffer_to_send: The localBuffer to send (bytes)
        :type buffer_to_send: bytes
        :return: True is send has been scheduled, false otherwise.
        :rtype bool
        """

        # Check
        if not isinstance(buffer_to_send, binary_type):
            logger.error("buffer_to_send not a binary, class=%s, self=%s", SolBase.get_classname(buffer_to_send), self)
            return False

        # Check
        if not self.__is_running():
            logger.debug("not connected, returning false, self=%s", self)
            return False

        # Enqueue
        self.__send_queue.put(buffer_to_send)

        # Stats
        Meters.aii("tcp.server.server_bytes_send_pending", len(buffer_to_send))

        return True
Example #7
0
    def _connection_ping(self, conn):
        """
        Ping connection

        This send a ping, write/read toward mysql.

        :param conn: pymysql.connections.Connection
        :type conn: pymysql.connections.Connection
        :return bool
        :rtype bool
        """

        Meters.aii("k.db_pool.mysql.call._connection_ping")

        # noinspection PyBroadException
        try:
            # TODO : PING MODE MUST BE CONFIGURABLE
            conn.ping(reconnect=False)
        except Exception as e:
            Meters.aii("k.db_pool.mysql.ex_ping")
            logger.debug("Ping failed, obj=%s, ex=%s", conn,
                         SolBase.extostr(e))
            return False
        else:
            return True
Example #8
0
    def _schedule_clientping(self, randomize_delay=False):
        """
        Schedule a ping
        :param randomize_delay: Randomize delay if true.

        """
        with self._protocol_lock:
            # Check
            if self._ping_greenlet:
                logger.warning(
                    "PingSimpleClient : _schedule_clientping : _ping_greenlet is not None, killing"
                )
                Meters.aii("ping.client.schedule_client_ping_error")
                self._unschedule_client_ping()

            # Go
            if not randomize_delay:
                self._ping_greenlet = gevent.spawn_later(
                    self._ping_interval_ms * 0.001,
                    self._protocol_client_ping_send)
            else:
                # Randomize delay
                vmin = self._ping_interval_ms / 2
                vmax = self._ping_interval_ms
                ms = randint(vmin, vmax)
                self._ping_greenlet = gevent.spawn_later(
                    ms * 0.001, self._protocol_client_ping_send)
Example #9
0
    def __init__(self, conf_dict):
        """
        Init
        :param conf_dict: dict
        :type conf_dict: dict
        """

        Meters.aii("k.db_pool.mysql.call.__init")

        # Base
        super(MysqlConnectionPool, self).__init__(conf_dict)

        # Init us
        self.host_status = dict()

        # Check
        if "hosts" not in self.conf_dict and "host" not in self.conf_dict and "unix" not in self.conf_dict:
            raise Exception(
                "No server specified (hosts, host, unix not found in conf_dict"
            )

        # Init, "hosts" first
        if "hosts" in self.conf_dict:
            for host in self.conf_dict["hosts"]:
                self.host_status[host] = 0.0
        elif "host" in self.conf_dict:
            logger.warning(
                "Using deprecated entry, prefer using 'hosts', got host=%s",
                self.conf_dict["host"])
            for host in self.conf_dict["host"].split(","):
                self.host_status[host] = 0.0
        elif "unix" in self.conf_dict:
            for host in self.conf_dict["unix"].split(","):
                self.host_status[host] = 0.0
Example #10
0
    def setUp(self):
        """
        Setup
        """

        MysqlApi.reset_pools()
        Meters.reset()

        d_conf_root = {
            "host": "localhost",
            "port": 3306,
            "database": None,
            "user": "******",
            "password": "******",
            "autocommit": True,
        }

        # exec_n
        try:
            ar = MysqlApi.exec_n(d_conf_root,
                                 "DROP DATABASE IF EXISTS pysolmysql_test;")
            logger.info("ar=%s", ar)
        except Exception as e:
            logger.debug("Ex=%s", SolBase.extostr(e))
        MysqlApi.exec_n(d_conf_root,
                        "CREATE DATABASE IF NOT EXISTS pysolmysql_test;")

        # Full reset
        MysqlApi.reset_pools()
        Meters.reset()
Example #11
0
    def test_basic_ttl(self):
        """
        Test
        :return:
        """

        # Alloc
        self.redis_cache = RedisCache()

        # Put
        self.redis_cache.put(self.key_prefix + "keyA", b"valA", 60000)
        self.redis_cache.put(self.key_prefix + "keyB", b"valB", 1000)
        logger.info("ms cur=%s", SolBase.mscurrent())
        logger.info("A : %s", self.redis_cache.get(self.key_prefix + "keyA"))
        logger.info("B : %s", self.redis_cache.get(self.key_prefix + "keyB"))

        # Wait a bit
        SolBase.sleep(2000)
        logger.info("ms after sleep=%s", SolBase.mscurrent())

        # A : must be present
        # B : must be evicted (TTL elapsed)
        self.assertEqual(self.redis_cache.get(self.key_prefix + "keyA"),
                         b"valA")
        self.assertIsNone(self.redis_cache.get(self.key_prefix + "keyB"))

        self.assertEqual(Meters.aig("rcs.cache_put"), 2)
        self.assertEqual(Meters.aig("rcs.cache_get_hit"), 3)
        self.assertEqual(Meters.aig("rcs.cache_get_miss"), 1)

        # Stop
        self.redis_cache.stop_cache()
        self.redis_cache = None
Example #12
0
    def start(self):
        """
        Connect to server.
        :return Return true upon success.
        """

        # Timestamp
        self.dtClientConnect = SolBase.datecurrent()

        # Call base
        b = TcpServerQueuedClientContext.start(self)
        if not b:
            # Stat
            logger.error("start failed, fatal, exiting")
            Meters.aii("ping.server.serverStartError")

            # Exit
            return False

        # Stat
        Meters.aii("ping.server.serverStartCount")

        # Schedule an hello timeout
        self._schedule_client_hello_timeout()
        return True
Example #13
0
    def test_max_item_size(self):
        """
        Test
        :return:
        """

        # Alloc
        self.redis_cache = RedisCache(max_single_item_bytes=2)

        # Put
        self.assertTrue(
            self.redis_cache.put(self.key_prefix + "keyA", b"aa", 60000))
        self.assertFalse(
            self.redis_cache.put(self.key_prefix + "keyB", b"aaa", 60000))
        logger.info("ms cur=%s", SolBase.mscurrent())
        logger.info("A : %s", self.redis_cache.get(self.key_prefix + "keyA"))
        logger.info("B : %s", self.redis_cache.get(self.key_prefix + "keyB"))

        # A : must be present
        # B : must be out of cache
        self.assertEqual(self.redis_cache.get(self.key_prefix + "keyA"), b"aa")
        self.assertIsNone(self.redis_cache.get(self.key_prefix + "keyB"))

        self.assertEqual(Meters.aig("rcs.cache_put"), 1)
        self.assertEqual(Meters.aig("rcs.cache_get_hit"), 2)
        self.assertEqual(Meters.aig("rcs.cache_get_miss"), 2)

        # Stop
        self.redis_cache.stop_cache()
        self.redis_cache = None
Example #14
0
    def tearDown(self):
        """
        Setup (called on destroy)
        """

        SolBase.logging_init(log_level='DEBUG', force_reset=True)
        Meters.write_to_logger()
        SolBase.logging_init(log_level='INFO', force_reset=True)
Example #15
0
    def _internal_test(self,
                       client_count,
                       ping_interval_ms,
                       my_run_time_ms=20000):
        """
        Test.
        :param client_count: Client count.
        :param ping_interval_ms: Ping interval in millis.
        :param my_run_time_ms: Run time in millis.
        :return: nothing.
        """
        try:
            # Overrides statics (beuuurk but so gooood)
            self.clientMaxCount = client_count
            self.serverPingIntervalMs = ping_interval_ms
            self.clientPingIntervalMs = ping_interval_ms
            self.runTimeMs = my_run_time_ms

            # Expected server and client ping/src
            self.expectedPps = (float(self.clientMaxCount) /
                                float(self.serverPingIntervalMs)) * 1000.0

            logger.info("starting, client=%s, ping.ms=%s, expected.pps=%s",
                        client_count, ping_interval_ms, self.expectedPps)

            # Instance
            self.tcp_server = None

            try:
                # Start server
                self._start_server_and_check()

                # Start client, check and stop client
                self._start_multi_client_checkallping_stop()

                # Stop server
                self._stop_server_and_check()

            except Exception as e:
                logger.error("Exception in test, ex=%s", SolBase.extostr(e))
                raise
            finally:
                if self.tcp_server:
                    self.tcp_server.stop_server()
        finally:
            # Final stats
            logger.info("Finished, final stats bellow")
            Meters.write_to_logger()

            # Reset
            self.tcp_server = None

            # Sleep
            Utility.test_wait()
Example #16
0
    def close_all(self):
        """
        Close all connections
        """
        n = 0
        while not self.pool.empty():
            conn = self.pool.get_nowait()
            self._connection_close(conn)
            n += 1

        Meters.aii("k.db_pool.base.cur_size", increment_value=-n)
        Meters.ai("k.db_pool.base.max_size").set(max(Meters.aig("k.db_pool.base.max_size"), Meters.aig("k.db_pool.base.cur_size")))
        self.size = 0
Example #17
0
    def connect(self):
        """
        Connect to server.
        :return Return true upon success.
        """

        # Stats
        Meters.aii("ping.client.client_connect_count")

        # Call base
        dt_start = SolBase.datecurrent()
        b = TcpSimpleClient.connect(self)
        if not b:
            # Stat
            logger.error("PingSimpleClient : connect failed, fatal, exiting")
            Meters.aii("ping.client.client_connect_error")

            # Exit
            return False

        # Stat
        Meters.dtci("ping.client.delay_client_connect",
                    SolBase.datediff(dt_start))

        # SSL stats
        ms = self._get_ssl_handshake_ms()
        if ms:
            Meters.dtci("ping.client.delay_client_sslhandshake", ms)

        # Send hello
        self._protocol_client_hello_send()
        return True
Example #18
0
    def test_pool_basic_x2(self):
        """
        Test pool, basic
        """

        MysqlApi.reset_pools()
        Meters.reset()

        d_conf = {
            "hosts": ["localhost", "127.0.0.1"],
            "port": 3306,
            "database": None,
            "user": "******",
            "password": "******",
            "autocommit": True,
        }

        for _ in range(0, 10):
            MysqlApi.exec_1(d_conf,
                            "SELECT user, host FROM mysql.user LIMIT 1;")

        d_conf = {
            "hosts": ["localhost", "localhost"],
            "port": 3306,
            "database": None,
            "user": "******",
            "password": "******",
            "autocommit": True,
        }

        for _ in range(0, 10):
            MysqlApi.exec_1(d_conf,
                            "SELECT user, host FROM mysql.user LIMIT 1;")

        # Check it
        self.assertEquals(Meters.aig("k.db_pool.hash.cur"), 1 * 2)

        self.assertEquals(Meters.aig("k.db_pool.base.cur_size"), 1 * 2)
        self.assertEquals(Meters.aig("k.db_pool.base.call.connection_acquire"),
                          10 * 2)
        self.assertEquals(Meters.aig("k.db_pool.base.call.connection_release"),
                          10 * 2)

        self.assertEquals(Meters.aig("k.db_pool.mysql.call.__init"), 1 * 2)
        self.assertEquals(
            Meters.aig("k.db_pool.mysql.call._connection_create"), 1 * 2)
        self.assertEquals(Meters.aig("k.db_pool.mysql.call._get_connection"),
                          1 * 2)
        self.assertEquals(Meters.aig("k.db_pool.mysql.call._connection_ping"),
                          10 * 2)
Example #19
0
    def _protocol_client_hello_received(self):
        """
        Must send a hello

        """
        with self._protocolLock:
            # Un-schedule hello timeout
            self._unschedule_client_hello_timeout()

            # Stats
            Meters.aii("ping.server.clientHelloReceived")

            # Delay
            Meters.aii("ping.server.delayClientConnectToClientHello",
                       SolBase.datediff(self.dtClientConnect))

            # Send a reply
            b = self.send_unicode_to_socket("C.HI.REPLY PID={0}".format(
                os.getpid()))
            if not b:
                # Stat
                logger.error("send failed, fatal, disconnecting")
                Meters.aii("ping.server.serverSendError")

                # Disconnect
                self.stop_asynch()
            else:
                # Now connected, schedule a ping
                self._schedule_server_ping()

                # Stats
                Meters.aii("ping.server.client_hello_server_reply")
Example #20
0
    def get(self, key):
        """
        Get from cache.
        :param key: Any key
        :type key: str
        :return An obj or null if not in cache
        :rtype bytes, None
        """

        ms_start = SolBase.mscurrent()
        try:
            if not isinstance(key, (bytes, str)):
                raise Exception("Key must be (bytes, str)")

            # Use read redis
            v = self._read_redis.get(key)
            if v:
                Meters.aii(self.meters_prefix + "rcs.cache_get_hit")
            else:
                Meters.aii(self.meters_prefix + "rcs.cache_get_miss")
            return v
        except Exception as e:
            logger.warning("Exception, ex=%s", SolBase.extostr(e))
            Meters.aii(self.meters_prefix + "rcs.cache_ex")
            return None
        finally:
            Meters.dtci(self.meters_prefix + "rcs.cache_dtc_read",
                        SolBase.msdiff(ms_start))
Example #21
0
    def __str__(self):
        """
        Str override
        :return str
        :rtype: str
        """

        return "id={0}*put/bypass/hit/miss={1}/{2}/{3}/{4}*ex={5}".format(
            id(self),
            Meters.aig(self.meters_prefix + "rcs.cache_put"),
            Meters.aig(self.meters_prefix + "rcs.cache_put_too_big"),
            Meters.aig(self.meters_prefix + "rcs.cache_get_hit"),
            Meters.aig(self.meters_prefix + "rcs.cache_get_miss"),
            Meters.aig(self.meters_prefix + "rcs.cache_ex"),
        )
Example #22
0
    def _schedule_client_pingservertimeout(self):
        """
        Schedule a ping timeout

        """

        with self._protocol_lock:
            # Check
            if self._ping_timeout_greenlet:
                logger.warning("_ping_timeout_greenlet is not None, killing")
                Meters.aii("ping.client.schedule_client_pingtimeouterror")
                self._unschedule_client_pingservertimeout()
                # Go
            self._ping_timeout_greenlet = gevent.spawn_later(
                self._ping_timeout_ms * 0.001,
                self._protocol_client_pingserver_timeout)
Example #23
0
    def test_basic_eviction_max_capacity_lru(self):
        """
        Test
        :return:
        """

        # Alloc
        self.mem_cache = MemoryCache(max_item=3,
                                     cb_evict=self.eviction_callback)

        # Put
        self.mem_cache.put("keyA", b"valA", 60000)
        self.mem_cache.put("keyB", b"valB", 60000)
        self.mem_cache.put("keyC", b"valC", 60000)

        # Use A and C => B becomes the older to be used
        self.mem_cache.get("keyA")
        self.mem_cache.get("keyC")

        # We are maxed (3 items)
        # Add D => B must be kicked
        self.mem_cache.put("keyD", b"valD", 60000)
        self.assertEqual(self.mem_cache.get("keyA"), b"valA")
        self.assertEqual(self.mem_cache.get("keyC"), b"valC")
        self.assertEqual(self.mem_cache.get("keyD"), b"valD")
        self.assertIsNone(self.mem_cache.get("keyB"))
        self.assertEqual(self.evict_count, 1)
        self.assertEqual(self.evict_last_key, "keyB")
        self.assertEqual(self.evict_last_value, b"valB")
        self.assertEqual(Meters.aig("mcs.cache_evict_lru_put"), 1)

        # Stop
        self.mem_cache.stop_cache()
        self.mem_cache = None
Example #24
0
    def test_basic_eviction_with_get_ttl(self):
        """
        Test
        :return:
        """

        # Alloc
        self.mem_cache = MemoryCache(cb_evict=self.eviction_callback)

        # Put
        self.mem_cache.put("keyA", b"valA", 60000)
        self.mem_cache.put("keyB", b"valB", 500)
        logger.info("ms cur=%s", SolBase.mscurrent())
        logger.info("A : %s", self.mem_cache.get_raw("keyA"))
        logger.info("B : %s", self.mem_cache.get_raw("keyB"))

        # Wait a bit
        SolBase.sleep(600)
        logger.info("ms after sleep=%s", SolBase.mscurrent())

        # A : must be present
        # B : must be evicted (TTL elapsed)
        self.assertEqual(self.mem_cache.get("keyA"), b"valA")
        self.assertIsNone(self.mem_cache.get("keyB"))
        self.assertEqual(self.evict_count, 1)
        self.assertEqual(self.evict_last_key, "keyB")
        self.assertEqual(self.evict_last_value, b"valB")
        self.assertEqual(Meters.aig("mcs.cache_evict_ttl_get"), 1)

        # Stop
        self.mem_cache.stop_cache()
        self.mem_cache = None
Example #25
0
    def disconnect(self):
        """
        Disconnect from server.
        :return Return true upon success.
        """

        # Stat
        Meters.aii("ping.client.client_disconnect_count")

        # Clean
        self._unschedule_client_helloservertimeout()
        self._unschedule_client_ping()
        self._unschedule_client_pingservertimeout()

        # Base
        return TcpSimpleClient.disconnect(self)
Example #26
0
    def _schedule_client_hello_timeout(self):
        """
        Schedule a ping timeout

        """

        with self._protocolLock:
            # Check
            if self._helloTimeOutGreenlet:
                logger.warning("_helloTimeOutGreenlet is not None, killing")
                Meters.aii("ping.server.scheduleClientHelloTimeOutError")
                self._unschedule_client_hello_timeout()
                # Go
            self._helloTimeOutGreenlet = gevent.spawn_later(
                self._helloTimeOutMs * 0.001,
                self._protocol_context_client_hello_timeout)
Example #27
0
    def _schedule_server_ping_client_timeout(self):
        """
        Schedule a ping timeout

        """

        with self._protocolLock:
            # Check
            if self._pingTimeOutGreenlet:
                logger.warning("_ping_timeout_greenlet is not None, killing")
                Meters.aii("ping.server.scheduleServerPingTimeOutError")
                self._unschedule_server_ping_client_timeout()
                # Go
            self._pingTimeOutGreenlet = gevent.spawn_later(
                self._pingTimeOutMs * 0.001,
                self._protocol_server_ping_client_timeout)
Example #28
0
    def _read_from_socket(self):
        """
        Read from the socket. Return a local_buf or None.
        """

        # Check
        if not self.__is_running():
            logger.debug("not connected, doing nothing, self=%s", self)
            return None

        try:
            # TODO : Socket local_buf size
            # TODO : Socket, upon server closure, will BLOCK on recv. Upon time, auto disconnect the client.

            # Try to read
            local_buf = self.current_socket.recv(1024)

            # If local_buf is empty string, socket is disconnected.
            if local_buf and len(local_buf) == 0:
                # Disconnect
                logger.debug("empty string received, disconnecting ourselves, self=%s", self)
                self._disconnect_helper("_read_from_socket : Empty string")
                return None

            # Stats
            Meters.aii("tcp.server.server_bytes_received", len(local_buf))

            # Ok
            return local_buf
        except error as e:
            # [Errno 11] Resource temporarily unavailable
            # Means that nothing is available to read.
            # If not this, we raise.
            if e.args[0] != EWOULDBLOCK:
                # Raise :)
                logger.debug("_tryReadWrite : _read_from_socket : error, ex=%s, self=%s", SolBase.extostr(e), self)
                self._disconnect_helper("_read_from_socket : error / No EWOULDBLOCK")
                return None
            else:
                # Normal
                logger.debug("_tryReadWrite : _read_from_socket : normal exception/EWOULDBLOCK, ex=%s, self=%s", e,
                             self)
                return None
        except Exception as e:
            logger.debug("_tryReadWrite : _read_from_socket : Exception, ex=%s, self=%s", SolBase.extostr(e), self)
            self._disconnect_helper("_read_from_socket : Exception / No EWOULDBLOCK")
            return None
Example #29
0
    def setUp(self):
        """
        Setup (called before each test)
        """

        # Initialize asap
        SolBase.voodoo_init()
        SolBase.set_compo_name("CompoNotSet")
        self.assertTrue(SolBase._voodoo_initialized)
        self.assertTrue(SolBase._logging_initialized)

        # Reset
        Meters.reset()

        # Bench
        self.per_loop = 10000
        self.max_ms = 2000
Example #30
0
    def _protocol_client_hello_server_timeout(self):
        """
        Hello timeout

        """

        with self._protocol_lock:
            logger.error("timeout, fatal, disconnecting")

            # Reset (we are called by it)
            self._hello_timeout_greenlet = None

            # Stats
            Meters.aii("ping.client.client_hello_server_timeout")

            # Disconnect ourselves (this is fatal)
            self.disconnect()