def _test_complete_exchange(self, client_handshaker_class, client_failure=False, server_failure=False): tcli = StringTransport() tsrv = StringTransport() p_cli = TestHandshakeProtocol() p_srv = TestHandshakeProtocol() now = time.time() hs_cli = client_handshaker_class(p_cli, now - 0.001, is_client=True) hs_srv = CryptoHandshaker(p_srv, now - 0.042) p_srv.init_handler(hs_srv.gen_handler()) p_cli.init_handler(hs_cli.gen_handler(), do_init=False) p_srv.makeConnection(tsrv) self.assertEquals(tsrv.value(), '') p_cli.makeConnection(tcli) self.assertEquals(tcli.value(), '') p_cli.init_handler() # self.assertEquals(len(tcli.value()), 1 + 1536) err = p_srv.dataReceived(tcli.value()) tcli.clear() # self.assertEquals(len(tsrv.value()), 1 + 1536 + 1536) self.assertIdentical(err, None) self.assertEquals(p_cli.handshake_status, None) err = p_cli.dataReceived(tsrv.value() + '\x00') tsrv.clear() if client_failure: self.assertIsInstance(err, failure.Failure) self.assertIsInstance(err.value, HandshakeFailedError) self.assertFalse(tcli.disconnecting, 'should not be disconnecting') self.assertEquals(p_cli.handshake_status, 'fail') self.assertEquals(p_srv.handshake_status, None) else: self.assertIdentical(err, None) self.assertFalse(tcli.disconnecting, 'disconnecting') self.assertEquals(p_cli.handshake_status, 'ok') self.assertEquals(p_srv.handshake_status, None) err = p_srv.dataReceived(tcli.value() + '\x00') tcli.clear() if server_failure: self.assertIsInstance(err, failure.Failure) self.assertIsInstance(err.value, HandshakeFailedError) self.assertFalse(tsrv.disconnecting, 'should not be disconnecting') self.assertEquals(p_srv.handshake_status, 'fail') else: self.assertIdentical(err, None) self.assertFalse(tsrv.disconnecting, 'disconnecting') self.assertEquals(p_srv.handshake_status, 'ok')
def test_complete_exchange_plus(self): # almost exactly the same test as above except writing some # additional (garbage) data immediately (as in the same # "socket.read()") after the handshake data tcli = StringTransport() tsrv = StringTransport() p_cli = TestHandshakeProtocol() p_srv = TestHandshakeProtocol() now = time.time() hs_cli = Handshaker(p_cli, now - 0.001, is_client=True) hs_srv = Handshaker(p_srv, now - 0.042) p_srv.init_handler(hs_srv.gen_handler()) p_cli.init_handler(hs_cli.gen_handler(), do_init=False) p_srv.makeConnection(tsrv) self.assertEquals(tsrv.value(), '') p_cli.makeConnection(tcli) self.assertEquals(tcli.value(), '') p_cli.init_handler() # self.assertEquals(len(tcli.value()), 1 + 1536) err = p_srv.dataReceived(tcli.value()) tcli.clear() # self.assertEquals(len(tsrv.value()), 1 + 1536 + 1536) self.assertIdentical(err, None) self.assertEquals(p_cli.handshake_status, None) err = p_cli.dataReceived(tsrv.value() + '\x00') tsrv.clear() self.assertIdentical(err, None) self.assertEquals(p_cli.handshake_status, 'ok') self.assertEquals(p_srv.handshake_status, None) err = p_srv.dataReceived(tcli.value() + '\x00') tcli.clear() self.assertIdentical(err, None) self.assertFalse(tsrv.disconnecting, 'disconnecting') self.assertFalse(tcli.disconnecting, 'disconnecting') self.assertEquals(p_srv.handshake_status, 'ok')
def test_server_side_invalid_2(self): t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = Handshaker(p, now) p.init_handler(hs.gen_handler()) p.makeConnection(t) self.assertEquals(t.value(), '') ver_pkt = struct.pack('B', self.protocol_version) invalid_hs_data = (('abcdefg' * int(self.handshake_length * 2 / 7)) + 'abcdefg'[:int(self.handshake_length * 2 % 7)]) # version is ok err = p.dataReceived(ver_pkt) self.assertIdentical(err, None) # ... but the rest is just (the right amount of) rubbish err = p.dataReceived(invalid_hs_data) self.assertIsInstance(err, failure.Failure) self.assertIsInstance(err.value, HandshakeFailedError) self.assertFalse(t.disconnecting, 'should not be disconnecting') self.assertEquals(p.handshake_status, 'fail')
def test_server_side_invalid_2(self): t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = CryptoHandshaker(p, now) p.init_handler(hs.gen_handler()) p.makeConnection(t) self.assertEquals(t.value(), '') ver_pkt = struct.pack('B', self.protocol_version) invalid_hs_data = (('abcdefg' * int(self.handshake_length * 2 / 7)) + 'abcdefg'[:int(self.handshake_length * 2 % 7)]) # version is ok err = p.dataReceived(ver_pkt) self.assertIdentical(err, None) # ... but the rest is just (the right amount of) rubbish err = p.dataReceived(invalid_hs_data) self.assertIsInstance(err, failure.Failure) self.assertIsInstance(err.value, HandshakeFailedError) self.assertFalse(t.disconnecting, 'should not be disconnecting') self.assertEquals(p.handshake_status, 'fail')
def test_many_headers(self): # OK, this test is a bit brittle, as we assume the following # properties of the encoder/muxer: # * it will allocate new chunk stream ids as long as we # provide it with unseen combinations of type and message # stream id # * the allocated ids will be consecutive numbers # * given the exactly same args to sendMessage the second call # will produce a bitstream of a message with completely # compressed header # # At the moment that seems the only reasonable way to force # muxer to use higher chunk stream ids, with different levels # of header compression, using only the public API... # for now, make sure we're using SimpleChunkProducer: class LocalTestMuxer(Muxer): chunk_producer_class = chunks.SimpleChunkProducer # first, generate and mux a whole bunch of messages tm = StringTransport() mux = LocalTestMuxer(tm) for i in range(256 + 64 + 1): mux.sendMessage(0, chunks.MSG_DATA, i, VecBuf([''])) mux.sendMessage(0, chunks.MSG_DATA, i, VecBuf([''])) # ... now demux the resulting binary data td = StringTransport() p = TestDemuxerProtocol() dmx = MessagePassingDemuxer(p) p.init_handler(dmx.gen_handler()) p.makeConnection(td) p.dataReceived(tm.value()) demuxed = p.pop_messages() # ... and check it maches the result we expect based on the # above assumptions first_csid = demuxed[0][0].cs_id for i in range(256 + 64 + 1): h, body = demuxed[2 * i] self.assertEquals((h.cs_id, h.real_time, h.real_size, h.real_type, h.real_ms_id), (i + first_csid, 0, 0, 18, i)) self.assertEquals((h.cs_id, h.time, h.size, h.type, h.ms_id), (i + first_csid, 0, 0, 18, i)) self.assertEquals(len(body), 0) h, body = demuxed[2 * i + 1] self.assertEquals((h.cs_id, h.real_time, h.real_size, h.real_type, h.real_ms_id), (i + first_csid, None, None, None, None)) self.assertEquals((h.cs_id, h.time, h.size, h.type, h.ms_id), (i + first_csid, 0, 0, 18, i)) self.assertEquals(len(body), 0)
def test_complete_exchange(self): tcli = StringTransport() tsrv = StringTransport() p_cli = TestHandshakeProtocol() p_srv = TestHandshakeProtocol() now = time.time() hs_cli = Handshaker(p_cli, now - 0.001, is_client=True) hs_srv = Handshaker(p_srv, now - 0.042) p_srv.init_handler(hs_srv.gen_handler()) p_cli.init_handler(hs_cli.gen_handler(), do_init=False) p_srv.makeConnection(tsrv) self.assertEquals(tsrv.value(), '') p_cli.makeConnection(tcli) self.assertEquals(tcli.value(), '') p_cli.init_handler() # self.assertEquals(len(tcli.value()), 1 + 1536) err = p_srv.dataReceived(tcli.value()) tcli.clear() # self.assertEquals(len(tsrv.value()), 1 + 1536 + 1536) self.assertIdentical(err, None) self.assertEquals(p_cli.handshake_status, None) err = p_cli.dataReceived(tsrv.value()) tsrv.clear() self.assertIdentical(err, None) self.assertEquals(p_cli.handshake_status, 'ok') self.assertEquals(p_srv.handshake_status, None) err = p_srv.dataReceived(tcli.value()) tcli.clear() self.assertIdentical(err, None) self.assertFalse(tsrv.disconnecting, 'disconnecting') self.assertFalse(tcli.disconnecting, 'disconnecting') self.assertEquals(p_srv.handshake_status, 'ok')
def test_combined(self): d_in = {} d_out = {} type_reverse = { 1: chunks.PROTO_SET_CHUNK_SIZE, 4: chunks.PROTO_USER_CONTROL, 5: chunks.PROTO_WINDOW_SIZE, 6: chunks.PROTO_SET_BANDWIDTH, 8: chunks.MSG_AUDIO, 9: chunks.MSG_VIDEO, 20: chunks.MSG_COMMAND } # for now, make sure we're using SimpleChunkProducer: class LocalTestMuxer(Muxer): chunk_producer_class = chunks.SimpleChunkProducer # mux messages first tm = StringTransport() mux = LocalTestMuxer(tm) for msg in messages: if not msg: continue head, body = msg msg_type = type_reverse[head[4]] mux.sendMessage(head[1], msg_type, head[5], VecBuf([body])) if msg_type == chunks.PROTO_SET_CHUNK_SIZE: mux.set_chunk_size(int(body.encode('hex'), 16)) d_in.setdefault(head[4], []).append((head[1], head[4], head[5], body)) # ... now try to demux the resulting binary data td = StringTransport() p = TestDemuxerProtocol() dmx = MessagePassingDemuxer(p) p.init_handler(dmx.gen_handler()) p.makeConnection(td) p.dataReceived(tm.value()) demuxed = p.pop_messages() # we can't rely on the received messages to be in the exact # same order as the sent ones... for head, body in demuxed: d_out.setdefault(head.type, []).append((head.abs_time, head.type, head.ms_id, body.read(len(body)))) self.assertEquals(d_in, d_out)
def test_server_side_ok_plus(self): # similar as with test_complete_exchange_plus() - feeding some # additional data immediately following handshake data t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = Handshaker(p, now) p.init_handler(hs.gen_handler()) p.makeConnection(t) # server shouldn't respond before spoken to self.assertEquals(t.value(), '') ver_pkt = struct.pack('B', self.protocol_version) err = p.dataReceived(ver_pkt) self.assertIdentical(err, None) # server may wait until it receives handshake packet before # responding, so not testing here hs_rand_data = '.' * (self.handshake_length - 8) timestamp = 42 hs_pkt = struct.pack('>LL', timestamp, 0) + hs_rand_data err = p.dataReceived(hs_pkt) self.assertIdentical(err, None) # ... and here the server might send all the packets already, # and our implementation should do so, so that's what we test self.assert_( len(t.value()) == 1 + self.handshake_length * 2, 'Response too short (%d)' % len(t.value())) self.assertEquals( struct.unpack_from('B', t.value(), 0)[0], self.protocol_version) srv_hs_pkt = t.value()[1:1 + self.handshake_length] hs_pkt_echo = t.value()[1 + self.handshake_length:1 + self.handshake_length * 2] self.assertEquals( struct.unpack_from('>L', hs_pkt_echo, 0)[0], timestamp) self.assertEquals(hs_pkt_echo[8:], hs_rand_data) # server response ok, let's finish the server side, and # pretend client starts sending more data err = p.dataReceived(srv_hs_pkt + '\x00') self.assertIdentical(err, None) self.assertFalse(t.disconnecting, 'disconnecting') self.assertEquals(p.handshake_status, 'ok')
def test_server_side_ok_plus(self): # similar as with test_complete_exchange_plus() - feeding some # additional data immediately following handshake data t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = Handshaker(p, now) p.init_handler(hs.gen_handler()) p.makeConnection(t) # server shouldn't respond before spoken to self.assertEquals(t.value(), '') ver_pkt = struct.pack('B', self.protocol_version) err = p.dataReceived(ver_pkt) self.assertIdentical(err, None) # server may wait until it receives handshake packet before # responding, so not testing here hs_rand_data = '.' * (self.handshake_length - 8) timestamp = 42 hs_pkt = struct.pack('>LL', timestamp, 0) + hs_rand_data err = p.dataReceived(hs_pkt) self.assertIdentical(err, None) # ... and here the server might send all the packets already, # and our implementation should do so, so that's what we test self.assert_(len(t.value()) == 1 + self.handshake_length * 2, 'Response too short (%d)' % len(t.value())) self.assertEquals(struct.unpack_from('B', t.value(), 0)[0], self.protocol_version) srv_hs_pkt = t.value()[1:1+self.handshake_length] hs_pkt_echo = t.value()[1+self.handshake_length: 1+self.handshake_length*2] self.assertEquals(struct.unpack_from('>L', hs_pkt_echo, 0)[0], timestamp) self.assertEquals(hs_pkt_echo[8:], hs_rand_data) # server response ok, let's finish the server side, and # pretend client starts sending more data err = p.dataReceived(srv_hs_pkt + '\x00') self.assertIdentical(err, None) self.assertFalse(t.disconnecting, 'disconnecting') self.assertEquals(p.handshake_status, 'ok')
def test_client_side_ok(self): t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = Handshaker(p, now, is_client=True) # can't initiate client handler before making connection p.init_handler(hs.gen_handler(), do_init=False) p.makeConnection(t) # client side is the active one self.assertEquals(t.value(), '') # ... once initiated p.init_handler() # after that the handling is almost identical to the server side... ver_pkt = struct.pack('B', self.protocol_version) err = p.dataReceived(ver_pkt) self.assertIdentical(err, None) hs_rand_data = '.' * (self.handshake_length - 8) timestamp = 42 hs_pkt = struct.pack('>LL', timestamp, 0) + hs_rand_data err = p.dataReceived(hs_pkt) self.assertIdentical(err, None) self.assert_(len(t.value()) == 1 + self.handshake_length * 2, 'Response too short (%d)' % len(t.value())) self.assertEquals(struct.unpack_from('B', t.value(), 0)[0], self.protocol_version) cli_hs_pkt = t.value()[1:1+self.handshake_length] hs_pkt_echo = t.value()[1+self.handshake_length: 1+self.handshake_length*2] self.assertEquals(struct.unpack_from('>L', hs_pkt_echo, 0)[0], timestamp) self.assertEquals(hs_pkt_echo[8:], hs_rand_data) err = p.dataReceived(cli_hs_pkt) self.assertIdentical(err, None) self.assertFalse(t.disconnecting, 'disconnecting') self.assertEquals(p.handshake_status, 'ok')
def test_client_side_ok(self): t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = Handshaker(p, now, is_client=True) # can't initiate client handler before making connection p.init_handler(hs.gen_handler(), do_init=False) p.makeConnection(t) # client side is the active one self.assertEquals(t.value(), '') # ... once initiated p.init_handler() # after that the handling is almost identical to the server side... ver_pkt = struct.pack('B', self.protocol_version) err = p.dataReceived(ver_pkt) self.assertIdentical(err, None) hs_rand_data = '.' * (self.handshake_length - 8) timestamp = 42 hs_pkt = struct.pack('>LL', timestamp, 0) + hs_rand_data err = p.dataReceived(hs_pkt) self.assertIdentical(err, None) self.assert_( len(t.value()) == 1 + self.handshake_length * 2, 'Response too short (%d)' % len(t.value())) self.assertEquals( struct.unpack_from('B', t.value(), 0)[0], self.protocol_version) cli_hs_pkt = t.value()[1:1 + self.handshake_length] hs_pkt_echo = t.value()[1 + self.handshake_length:1 + self.handshake_length * 2] self.assertEquals( struct.unpack_from('>L', hs_pkt_echo, 0)[0], timestamp) self.assertEquals(hs_pkt_echo[8:], hs_rand_data) err = p.dataReceived(cli_hs_pkt) self.assertIdentical(err, None) self.assertFalse(t.disconnecting, 'disconnecting') self.assertEquals(p.handshake_status, 'ok')
def test_server_side_invalid_1(self): t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = Handshaker(p, now) p.init_handler(hs.gen_handler()) p.makeConnection(t) self.assertEquals(t.value(), '') # sending version different from the server's version ver_pkt = struct.pack('B', self.protocol_version + 1) err = p.dataReceived(ver_pkt) self.assertIsInstance(err, failure.Failure) self.assertIsInstance(err.value, HandshakeFailedError) self.assertFalse(t.disconnecting, 'should not be disconnecting') self.assertEquals(p.handshake_status, 'fail')
def test_server_side_invalid_1(self): t = StringTransport() p = TestHandshakeProtocol() now = time.time() hs = CryptoHandshaker(p, now) p.init_handler(hs.gen_handler()) p.makeConnection(t) self.assertEquals(t.value(), '') # sending version different from the server's version ver_pkt = struct.pack('B', self.protocol_version + 1) err = p.dataReceived(ver_pkt) self.assertIsInstance(err, failure.Failure) self.assertIsInstance(err.value, HandshakeFailedError) self.assertFalse(t.disconnecting, 'should not be disconnecting') self.assertEquals(p.handshake_status, 'fail')