private void ProcessInitialPacket(Packet packet, IPEndPoint endPoint) { byte[] data; // Unsupported version. Version negotiation packet is sent only on initial connection. All other packets are dropped. (5.2.2 / 16th draft) if (packet.Version != QuicVersion.CurrentVersion || !QuicVersion.SupportedVersions.Contains(packet.Version)) { VersionNegotiationPacket vnp = _packetCreator.CreateVersionNegotiationPacket(); data = vnp.Encode(); _client.Send(data, data.Length, endPoint); return; } InitialPacket cast = packet as InitialPacket; InitialPacket ip = _packetCreator.CreateInitialPacket(0, cast.SourceConnectionId); // Protocol violation if the initial packet is smaller than the PMTU. (pt. 14 / 16th draft) if (cast.Encode().Length < QuicSettings.PMTU) { ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, "PMTU have not been reached.")); } else if (ConnectionPool.AddConnection(cast.SourceConnectionId) == true) { // We're including the maximum possible stream id during the connection handshake. (4.5 / 16th draft) ip.AttachFrame(new MaxStreamIdFrame(QuicSettings.MaximumStreamId, StreamType.ServerBidirectional)); } else { // Not accepting connections. Send initial packet with CONNECTION_CLOSE frame. // TODO: Buffering. The server might buffer incomming 0-RTT packets in anticipation of late delivery InitialPacket. // Maximum buffer size should be set in QuicSettings. ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.SERVER_BUSY, "The server is too busy to process your request.")); } data = ip.Encode(); int dataSent = _client.Send(data, data.Length, endPoint); if (dataSent > 0) { // Create a QuicContext to represent the connected client. QuicContext context = new QuicContext(_client, endPoint); ConnectionPool.AttachContext(cast.SourceConnectionId, context); OnClientConnected?.Invoke(context); } }