Skip to content

Add async methods and examples #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions QuicNet.Tests.ConsoleClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@ namespace QuicNet.Tests.ConsoleClient
{
class Program
{
static void Main(string[] args)
static async Task Main(string[] args)
{
//Example();
await ExampleAsync();
Console.ReadKey();
}

private static void Example()
{
Console.WriteLine("Starting client.");
QuicClient client = new QuicClient();
Console.WriteLine("Connecting to server.");
QuicConnection connection = client.Connect("127.0.0.1", 11000); // Connect to peer (Server)
Console.WriteLine("Connected");

QuicStream stream = connection.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional); // Create a data stream
Console.WriteLine("Create stream with id: " + stream.StreamId.IntegerValue.ToString());

Expand Down Expand Up @@ -48,8 +55,45 @@ static void Main(string[] args)
{
Console.WriteLine(e.Message);
}
}

Console.ReadKey();
private static async Task ExampleAsync()
{
Console.WriteLine("Starting client.");
QuicClient client = new QuicClient();
Console.WriteLine("Connecting to server.");
QuicConnection connection = await client.ConnectAsync("127.0.0.1", 11000); // Connect to peer (Server)
Console.WriteLine("Connected");

QuicStream stream = connection.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional); // Create a data stream
Console.WriteLine("Create stream with id: " + stream.StreamId.IntegerValue.ToString());

Console.WriteLine("Send 'Hello From Client!'");
await stream.SendAsync(Encoding.UTF8.GetBytes("Hello from Client!")); // Send Data

stream = connection.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional); // Create a data stream
await stream.SendAsync(Encoding.UTF8.GetBytes("Hello from Client2!"));

Console.WriteLine("Waiting for message from the server");
try
{
byte[] data = await stream.ReceiveAsync(); // Receive from server
Console.WriteLine("Received: " + Encoding.UTF8.GetString(data));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}

try
{
byte[] data = await stream.ReceiveAsync(); // Receive from server
Console.WriteLine("Received: " + Encoding.UTF8.GetString(data));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
91 changes: 90 additions & 1 deletion QuicNet/Connections/QuicConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace QuicNet.Connections
{
Expand Down Expand Up @@ -74,6 +76,41 @@ public void ProcessFrames(List<Frame> frames)
}
}

public async Task ProcessFramesAsync(List<Frame> frames)
{
foreach (Frame frame in frames)
{
switch (frame.Type)
{
case 0x01:
case 0x04:
OnRstStreamFrame(frame);
break;
case byte type when type >= 0x08 && frame.Type <= 0x0f:
await OnStreamFrameAsync(frame);
break;
case 0x10:
OnMaxDataFrame(frame);
break;
case 0x11:
OnMaxStreamDataFrame(frame);
break;
case 0x12:
case 0x13:
OnMaxStreamFrame(frame);
break;
case 0x14:
OnDataBlockedFrame(frame);
break;
case 0x1c:
OnConnectionCloseFrame(frame);
break;
default:
break;
}
}
}

public void IncrementRate(int length)
{
_currentTransferRate += (UInt32)length;
Expand Down Expand Up @@ -128,6 +165,26 @@ private void OnStreamFrame(Frame frame)
}
}

private async Task OnStreamFrameAsync(Frame frame)
{
StreamFrame sf = (StreamFrame)frame;
if (_streams.ContainsKey(sf.ConvertedStreamId.Id) == false)
{
QuicStream stream = new QuicStream(this, sf.ConvertedStreamId);
await stream.ProcessDataAsync(sf);

if ((UInt64)_streams.Count < MaxStreams)
_streams.Add(sf.ConvertedStreamId.Id, stream);
else
SendMaximumStreamReachedError();
}
else
{
QuicStream stream = _streams[sf.ConvertedStreamId.Id];
await stream.ProcessDataAsync(sf);
}
}

private void OnMaxDataFrame(Frame frame)
{
MaxDataFrame sf = (MaxDataFrame)frame;
Expand Down Expand Up @@ -177,7 +234,7 @@ private void OnStreamDataBlockedFrame(Frame frame)
}

#region Internal

internal QuicConnection(ConnectionData connection)
{
_currentTransferRate = 0;
Expand Down Expand Up @@ -221,11 +278,43 @@ internal void ReceivePacket()

}

/// <summary>
/// Client async only!
/// </summary>
/// <returns></returns>
internal async Task ReceivePacketAsync()
{
Packet packet = await _pwt.ReadPacketAsync();

if (packet is ShortHeaderPacket)
{
ShortHeaderPacket shp = (ShortHeaderPacket)packet;
await ProcessFramesAsync(shp.GetFrames());
}

// If the connection has been closed
if (_state == ConnectionState.Draining)
{
if (string.IsNullOrWhiteSpace(_lastError))
_lastError = "Protocol error";

TerminateConnection();

throw new QuicConnectivityException(_lastError);
}

}

internal bool SendData(Packet packet)
{
return _pwt.SendPacket(packet);
}

internal async Task<bool> SendDataAsync(Packet packet)
{
return await _pwt.SendPacketAsync(packet);
}

internal void DataReceived(QuicStream context)
{
OnDataReceived?.Invoke(context);
Expand Down
23 changes: 23 additions & 0 deletions QuicNet/InternalInfrastructure/PacketWireTransfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ public Packet ReadPacket()
return packet;
}

public async Task<Packet> ReadPacketAsync()
{
// Await response for sucessfull connection creation by the server
var udpReceiveResult = await _client.ReceiveAsync();
_peerEndpoint = udpReceiveResult.RemoteEndPoint;
byte[] peerData = udpReceiveResult.Buffer;
if (peerData == null)
throw new QuicConnectivityException("Server did not respond properly.");

Packet packet = _unpacker.Unpack(peerData);

return packet;
}

public bool SendPacket(Packet packet)
{
byte[] data = packet.Encode();
Expand All @@ -46,6 +60,15 @@ public bool SendPacket(Packet packet)
return sent > 0;
}

public async Task<bool> SendPacketAsync(Packet packet)
{
byte[] data = packet.Encode();

var sent = _client.SendAsync(data, data.Length, _peerEndpoint);

return await sent > 0;
}

public IPEndPoint LastTransferEndpoint()
{
return _peerEndpoint;
Expand Down
29 changes: 29 additions & 0 deletions QuicNet/QuicClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ public QuicConnection Connect(string ip, int port)
return _connection;
}

/// <summary>
/// Connect to a remote server.
/// </summary>
/// <param name="ip">Ip Address</param>
/// <param name="port">Port</param>
/// <returns></returns>
public async Task<QuicConnection> ConnectAsync(string ip, int port)
{
// Establish socket connection
_peerIp = new IPEndPoint(IPAddress.Parse(ip), port);

// Initialize packet reader
_pwt = new PacketWireTransfer(_client, _peerIp);

// Start initial protocol process
InitialPacket connectionPacket = _packetCreator.CreateInitialPacket(0, 0);

// Send the initial packet
await _pwt.SendPacketAsync(connectionPacket);

// Await response for sucessfull connection creation by the server
InitialPacket packet = (InitialPacket)await _pwt.ReadPacketAsync();

HandleInitialFrames(packet);
EstablishConnection(packet.SourceConnectionId, packet.SourceConnectionId);

return _connection;
}

/// <summary>
/// Handles initial packet's frames. (In most cases protocol frames)
/// </summary>
Expand Down
Loading