Exemple #1
0
def encodedecode(pkt_size, key):

    pkt = Packet()
    typ = PacketType.APP if key else PacketType.CLIENT_HELLO
    typ = PacketType.APP
    pkt.msg = os.urandom(pkt_size)
    pkt.hdr = PacketHeader.create(False, 0, typ, SeqNum(1), SeqNum(1), 0)
    pkt.hdr.length = len(pkt.msg)
    pkt.hdr.count = 1
    datagram = pkt.to_bytes(key)
    hdr = PacketHeader.from_bytes(True, datagram)
    pkt = Packet.from_bytes(hdr, key, datagram)
Exemple #2
0
    def setUp(self):
        # launch a server thread, connect one client
        self.server_sock, self.client_sock = MockUDPSocket.mkpair()
        self.client = TestClient(self.client_sock)

        self.ctxt = ServerContext(TestHandler())
        self.thread = UdpServerThread(self.server_sock, self.ctxt)

        self.thread.start()

        t0 = time.time()
        connected = False
        while not connected:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > .5:
                self.fail("failed to connect")

            # test that both sides are connected
            if self.client.conn.status == ConnectionStatus.CONNECTED:
                for addr, other in self.ctxt.connections.items():
                    if other.status == ConnectionStatus.CONNECTED:
                        self.server_client = other
                        connected = True

        self.assertEqual(self.client.conn.status, ConnectionStatus.CONNECTED)
Exemple #3
0
    def test_server_send_recv_large(self):
        # send a large payload to the server
        # send the payload back to the client
        # test sending fragmented messages in both directions

        payload = os.urandom(10 * 1024)
        self.client.send(payload)

        # TODO: investigate why this takes .5 seconds
        # it should be 10KB / MAX_PAYLOAD_SIZE ~= 8 packets
        # round tripping 18 packets should take around 16/60 ~= 0.25 seconds
        # the test contsistently takes double the expected time

        t0 = time.time()
        while not self.client.conn.incoming_messages:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > 1.0:
                self.fail("failed to receive message")

        self.assertEqual(self.client.conn.incoming_messages[0][1], payload)
    def test_conn_receive_datagram_1(self):

        key = b"0" * 16
        hdr = PacketHeader.create(True, 0, PacketType.APP, SeqNum(1),
                                  SeqNum(1), 0)
        msgs = [
            PendingMessage(SeqNum(1), PacketType.APP, b"hello world1", None, 0)
        ]

        pkt = Packet.create(hdr, msgs)

        datagram = pkt.to_bytes(key)

        conn = ConnectionBase(False, None)
        conn.session_key_bytes = key

        conn._recv_datagram(PacketHeader.from_bytes(False, datagram), datagram)
        self.assertEqual(SeqNum(1), conn.bitfield_pkt.current_seqnum)
        self.assertEqual(1, len(conn.incoming_messages))
        self.assertEqual(msgs[0].payload, conn.incoming_messages[0][1])
Exemple #5
0
    def test_server_connection_keepalive(self):

        # sleep for 1 seconds to test send/recev keep alive
        for i in range(60):
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

        self.assertTrue(self.client.conn.stats.received >= 10)
Exemple #6
0
    def test_server_connect_invalid_key(self):
        # test that a client does not connect if the public key does
        # not match the server public key
        server_sock, client_sock = MockUDPSocket.mkpair()
        client = TestClient(client_sock)
        key = EllipticCurvePrivateKey.new()
        key2 = EllipticCurvePrivateKey.new().getPublicKey()

        client.conn.setServerPublicKey(key2)

        ctxt = ServerContext(TestHandler(), key)
        thread = UdpServerThread(server_sock, ctxt)

        thread.start()

        timedout=None
        def callback(success):
            nonlocal timedout
            timedout = not success

        client.conn.outgoing_timeout = .25
        client.conn.connection_callback = callback

        t0 = time.time()
        connected = False

        with self.assertRaises(EllipticCurvePublicKey.InvalidSignature):

            while not connected:
                datagram, addr = server_sock.recvfrom(Packet.RECV_SIZE)
                if datagram:
                    hdr = PacketHeader.from_bytes(True, datagram)
                    thread.append(addr, hdr, datagram)
                client.update()
                time.sleep(1/60)

                if time.time() - t0 > .5:
                    self.fail("failed to connect")

                # test that both sides are connected
                if client.conn.status == ConnectionStatus.CONNECTED:
                    for addr, other in ctxt.connections.items():
                        if other.status == ConnectionStatus.CONNECTED:
                            connected = True

        self.assertEqual(client.conn.status, ConnectionStatus.DISCONNECTED)
        self.assertFalse(timedout)

        ctxt._active = False

        # append an invalid packet to wake up the server
        thread.append(("0.0.0.0", 0), None, b"")
        thread.join()
Exemple #7
0
    def update(self, delta_t=0):

        self.conn.update()

        datagram, addr = self.sock.recvfrom(Packet.RECV_SIZE)
        if datagram:
            hdr = PacketHeader.from_bytes(False, datagram)
            self.conn._recv_datagram(hdr, datagram)

        pkt = self.conn._build_packet()
        if pkt:
            datagram = self.conn._encode_packet(pkt)
            self.sock.sendto(datagram, self.addr)
Exemple #8
0
    def test_server_send_recv(self):

        self.client.send(b"hello")

        t0 = time.time()
        while not self.client.conn.incoming_messages:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > .5:
                self.fail("failed to receive")
Exemple #9
0
    def test_server_connect(self):
        # test that a client can connect to the server
        server_sock, client_sock = MockUDPSocket.mkpair()
        client = TestClient(client_sock)

        ctxt = ServerContext(TestHandler())
        thread = UdpServerThread(server_sock, ctxt)

        thread.start()

        timedout = None

        def callback(success):
            nonlocal timedout
            timedout = not success

        client.conn.outgoing_timeout = .25
        client.conn.connection_callback = callback

        t0 = time.time()
        connected = False
        while not connected:
            datagram, addr = server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                thread.append(addr, hdr, datagram)
            client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > .5:
                self.fail("failed to connect")

            # test that both sides are connected
            if client.conn.status == ConnectionStatus.CONNECTED:
                for addr, other in ctxt.connections.items():
                    if other.status == ConnectionStatus.CONNECTED:
                        connected = True

        self.assertEqual(client.conn.status, ConnectionStatus.CONNECTED)
        self.assertFalse(timedout)

        ctxt._active = False

        # append an invalid packet to wake up the server
        thread.append(("0.0.0.0", 0), None, b"")
        thread.join()
    def test_conn_send_datagram_simple(self):
        """
        """
        payload = b"hello world"
        conn = ConnectionBase(False, None)
        conn._send_type(PacketType.CLIENT_HELLO, payload, RetryMode.NONE, None)

        pkt = conn._build_packet()
        datagram = conn._encode_packet(pkt)

        self.assertEqual(
            PacketHeader.SIZE + PacketHeader.CRC_SIZE + Packet.overhead(1) +
            len(payload), len(datagram))

        hdr = PacketHeader.from_bytes(True, datagram)
        pkt = Packet.from_bytes(hdr, None, datagram)
        self.assertEqual(pkt.msg[2:], payload)
    def test_packet_max_size(self):
        # test that forming a packet of max payload size
        # correctly builds a packet with the maximum number of
        # bytes for the default MTU size (1500)

        hdr = PacketHeader()
        dat = os.urandom(Packet.MAX_PAYLOAD_SIZE)

        msg = PendingMessage(SeqNum(1), PacketType.APP, dat, None, 0)

        pkt = Packet.create(hdr, [msg])

        datagram = pkt.to_bytes(b"0" * 16)
        self.assertEqual(len(datagram), Packet.MAX_SIZE)
        self.assertEqual(len(datagram), 1472)  # mtu - 28

        datagram = pkt.to_bytes(None)
        self.assertEqual(len(datagram), Packet.MAX_SIZE_CRC)
Exemple #12
0
    def test_server_datagram_corrupt(self):

        self.client.send(b"hello1")

        t0 = time.time()
        while self.server_client.stats.dropped == 0:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                # valid header, invalid tag
                datagram = datagram[:-16] + b'0' * 16
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > .5:
                self.fail("failed to receive")
        self.assertEqual(self.server_client.stats.dropped, 1)
Exemple #13
0
    def test_server_duplicate_datagram(self):

        self.client.send(b"hello1")
        self.client.send(b"hello2")
        self.client.send(b"hello3")

        t0 = time.time()
        while self.server_client.stats.dropped == 0:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > .5:
                self.fail("failed to receive")
        self.assertEqual(self.server_client.stats.dropped, 1)
Exemple #14
0
    def test_server_disconnect(self):

        # in the real world the client is not guaranteed to
        # receive the reply from the server.
        disconnected = False
        def onDisconnectCallback(success):
            nonlocal disconnected
            disconnected = True
        self.client.conn.disconnect(onDisconnectCallback)

        t0 = time.time()
        while not disconnected:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1/60)

            if time.time() - t0 > .5:
                self.fail("failed to receive disconnect")
Exemple #15
0
    def test_server_send_recv_multi(self):

        self.client.send(b"hello1")
        self.client.send(b"hello2")
        self.client.send(b"hello3")

        received = 0
        t0 = time.time()
        while len(self.client.conn.incoming_messages) < 3:
            datagram, addr = self.server_sock.recvfrom(Packet.RECV_SIZE)
            if datagram:
                received += 1
                hdr = PacketHeader.from_bytes(True, datagram)
                self.thread.append(addr, hdr, datagram)
            self.client.update()
            time.sleep(1 / 60)

            if time.time() - t0 > .5:
                self.fail("failed to receive")

        self.assertEqual(received, 1)
        self.assertEqual(len(self.client.conn.incoming_messages), 3)
    def test_packet_set_max_size(self):
        # test that forming a packet of max payload size
        # correctly builds a packet with the maximum number of
        # bytes for a custom MTU size.
        #
        Packet.setMTU(512)

        hdr = PacketHeader()
        dat = os.urandom(Packet.MAX_PAYLOAD_SIZE)

        msg = PendingMessage(SeqNum(1), PacketType.APP, dat, None, 0)

        pkt = Packet.create(hdr, [msg])

        datagram1 = pkt.to_bytes(b"0" * 16)
        datagram2 = pkt.to_bytes(None)

        self.assertEqual(len(datagram1), 484)  # mtu - 28
        self.assertEqual(len(datagram1), Packet.MAX_SIZE)
        self.assertEqual(len(datagram2), Packet.MAX_SIZE_CRC)
        # reset mtu for subsequent tests
        Packet.setMTU(1500)
    def test_conn_sendrecv_datagram_encrypted(self):
        """
        """
        key = b"0" * 16

        payload = b"hello world"
        client = ConnectionBase(False, None)
        client.session_key_bytes = key
        client.status = ConnectionStatus.CONNECTED

        server = ConnectionBase(True, None)
        server.session_key_bytes = key

        client.send(payload)

        pkt = client._build_packet()
        datagram = client._encode_packet(pkt)

        hdr = PacketHeader.from_bytes(True, datagram)
        server._recv_datagram(hdr, datagram)

        self.assertEqual(1, len(server.incoming_messages))
        self.assertEqual(payload, server.incoming_messages[0][1])
    def test_conn_handshake(self):
        """
        run through the entire handshake

        happy path integration test
        """
        current_time = 0

        def clock():
            nonlocal current_time
            current_time += 1
            return current_time

        client = ClientServerConnection(('0.0.0.0', 1234))
        client.clock = clock
        #client.status = ConnectionStatus.CONNECTED

        ctxt = ServerContext(EventHandler(), None)
        server = ServerClientConnection(ctxt, ('0.0.0.0', 1235))
        server.clock = clock
        #server.status = ConnectionStatus.CONNECTED

        #with self.subTest(mode='send client hello'):
        client._sendClientHello()
        datagram = client._encode_packet(client._build_packet())

        self.assertEqual(len(datagram),
                         Packet.MAX_PAYLOAD_SIZE + PacketHeader.CRC_SIZE)
        hdr = PacketHeader.from_bytes(True, datagram)

        # update the context with a reference to the server side client connection
        # user later to finalize the connection
        ctxt.temp_connections[server.addr] = server
        server._recv_datagram(hdr, datagram)
        datagram = server._encode_packet(server._build_packet())

        with self.subTest(mode='recv server hello'):
            hdr = PacketHeader.from_bytes(False, datagram)
            client._recv_datagram(hdr, datagram)

        with self.subTest(mode='recv challenge response'):
            datagram = client._encode_packet(client._build_packet())
            hdr = PacketHeader.from_bytes(True, datagram)
            server._recv_datagram(hdr, datagram)

        self.assertEqual(ConnectionStatus.CONNECTED, server.status)
        self.assertEqual(ConnectionStatus.CONNECTED, client.status)

        with self.subTest(mode='server send test'):
            greeting = b"hello client"
            server.send(greeting)
            datagram = server._encode_packet(server._build_packet())
            hdr = PacketHeader.from_bytes(False, datagram)
            client._recv_datagram(hdr, datagram)
            self.assertEqual(1, len(client.incoming_messages))
            self.assertEqual(b"hello client", client.incoming_messages[0][1])

        with self.subTest(mode='client send test'):

            greeting = b"hello server"
            client.send(greeting)
            datagram = client._encode_packet(client._build_packet())
            hdr = PacketHeader.from_bytes(True, datagram)
            server._recv_datagram(hdr, datagram)
            self.assertEqual(1, len(server.incoming_messages))
            self.assertEqual(greeting, server.incoming_messages[0][1])

        self.assertTrue(server.latency > 0)
Exemple #19
0
def recvinto(sock, thread):
    r, w, x = select.select([sock], [], [], 0)
    if r:
        datagram, addr = sock.recvfrom(Packet.RECV_SIZE)
        hdr = PacketHeader.from_bytes(True, datagram)
        thread.append(addr, hdr, datagram)