/// <summary> /// Handle an InitialPacket to create a new QuicConnection related to this packet. /// </summary> /// <param name="packet">The packet received</param> /// <param name="client">The client that sent the packet</param> private void HandleInitialPacket(InitialPacket packet, IPEndPoint client) { InitialPacket incomingPacket = packet as InitialPacket; incomingPacket.DecodeFrames(); // Create random connection ID and use it as SCID for server -> client communications // Make sure it's not already in use byte[] connID = new byte[8]; do { RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(connID); } while (_connectionPool.Find(connID) != null); QuicConnection qc = new QuicConnection(_server, client, connID, incomingPacket.SCID); _connectionPool.AddConnection(qc, connID); InitialPacket responsePacket = new InitialPacket(incomingPacket.SCID, connID, 0); responsePacket.AddFrame(new PaddingFrame()); byte[] b = responsePacket.Encode(); _server.Send(b, b.Length, client); Logger.Write($"Connection established. This is server {BitConverter.ToString(connID)} connected to client {BitConverter.ToString(incomingPacket.SCID)}"); }
/// <summary> /// Connect to a remote server. /// </summary> /// <param name="ip">Ip of the remote server</param> /// <param name="port">Port of the remote server</param> public void Connect(string ip, int port) { // Create random DCID and SCID byte[] DCID = new byte[8]; byte[] SCID = new byte[8]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(DCID); rng.GetBytes(SCID); // Create and send an InitialPacket to open a connection with the remote server InitialPacket initialPacket = new InitialPacket(DCID, SCID, _packetNumber++); byte[] byteInitialPacket = initialPacket.Encode(); _client.Send(byteInitialPacket, byteInitialPacket.Length, ip, port); IPEndPoint server = null; Packet packet = Packet.Unpack(_client.Receive(ref server)); // Start the connection with an InitialPacket if (packet.GetType() == typeof(InitialPacket)) { packet.DecodeFrames(); Logger.Write($"Data received from server {server.Address}:{server.Port}"); InitialPacket initPack = packet as InitialPacket; Logger.Write($"Connection established. This is client {BitConverter.ToString(initPack.DCID)} connected to server {BitConverter.ToString(initPack.SCID)}"); _connection = new QuicConnection(_client, server, initPack.DCID, initPack.SCID); } // Background task to receive packets from the remote server _receiveToken = new CancellationTokenSource(); _receiveTask = Task.Run(() => Receive(server), _receiveToken.Token); }
private static int _packetHeaderSize = 4; // In bytes /// <summary> /// Factory that creates the correct Packet type according to the payload /// Decode the received payload /// </summary> /// <param name="data">The raw packet received</param> /// <returns>The decoded packet</returns> public static Packet Unpack(byte[] data) { if (data.Length < _packetHeaderSize) { throw new CorruptedPacketException("Wrong header size"); } Packet p; // Short header packets starts with the bits | 0 | 1 | if (!BitUtils.ReadBit(0, data)) { // Short Header Packet p = new ShortHeaderPacket(); if (!BitUtils.ReadBit(1, data)) { throw new CorruptedPacketException("Wrong second bit when decoding a ShortHeaderPacket"); } p.Decode(data); } // Long header packets starts with the bits | 1 | 1 | else { // Long Header Packet if (!BitUtils.ReadBit(1, data)) { throw new CorruptedPacketException("Undefined packet header"); } // The two next bits describe the type of the Long Header Packet switch (BitUtils.ReadNBits(2, data, 2)) { case 0: p = new InitialPacket(); break; case 1: p = new RTTPacket(); break; case 2: p = new HandshakePacket(); break; case 3: p = new RetryPacket(); break; default: throw new ArgumentException("2 Bit-encoded uint is not amongst {0, 1, 2, 3}"); } p.Decode(data); } return(p); }