/// <summary> /// Invoke when a datagram is received from a socket. /// </summary> /// <param name="receive"></param> /// <param name="respond"></param> /// <param name="args"></param> public void OnReceive(Socket receive, Socket respond, SocketAsyncEventArgs args) { var source = new KIpEndpoint((IPEndPoint)args.RemoteEndPoint); logger.LogTrace("Received incoming packet of {Length} from {Endpoint}.", args.BytesTransferred, source); try { // no data found if (args.BytesTransferred == 0) { return; } // some error occurred? if (args.SocketError != SocketError.Success) { logger.LogError("Socket error while receiving UDP data: {SocketError}.", args.SocketError); return; } // we only care about receive from events if (args.LastOperation != SocketAsyncOperation.ReceiveFrom && args.LastOperation != SocketAsyncOperation.ReceiveMessageFrom) { logger.LogError("Unxpected operation while receiving UDP data: {LastOperation}.", args.LastOperation); return; } // deserialize message sequence var packet = serializer.Read(new ReadOnlyMemory <byte>(args.Buffer, args.Offset, args.BytesTransferred), new KMessageContext <TNodeId>(formats.Select(i => i.ContentType))); if (packet.Format == null || packet.Sequence == null) { logger.LogWarning("Invalid or empty packet."); return; } Task.Run(async() => { try { logger.LogTrace("Decoded packet as {Format} from {Endpoint}.", packet.Format, source); await OnReceiveAsync(receive, respond, source, packet, CancellationToken.None); } catch (Exception e) { logger.LogError(e, "Unhandled exception receiving UDP packet."); } }); } catch (Exception e) { logger.LogError(e, "Exception during UDP receive."); } }
/// <summary> /// Invoked when a receive operation completes. /// </summary> /// <param name="socket"></param> /// <param name="args"></param> void RecvArgs_Completed(Socket socket, SocketAsyncEventArgs args) { // extract source endpoint var source = new KIpEndpoint((IPEndPoint)args.RemoteEndPoint); var length = args.BytesTransferred; logger.LogTrace("Received incoming UDP packet of {Length} from {Endpoint}.", length, source); // should only be receiving packets from our message loop if (args.LastOperation != SocketAsyncOperation.ReceiveMessageFrom) { logger.LogTrace("Unexpected packet operation {Operation}.", args.LastOperation); return; } // some error occurred? if (args.SocketError != SocketError.Success) { return; } // we only care about receive from events if (args.LastOperation != SocketAsyncOperation.ReceiveMessageFrom && args.LastOperation != SocketAsyncOperation.ReceiveFrom) { return; } // no data found if (args.BytesTransferred == 0) { return; } // socket is unbound, ignore if (socket.IsBound == false) { return; } // deserialize message sequence var packet = serializer.Read(new ReadOnlyMemory <byte>(args.Buffer, args.Offset, args.BytesTransferred), new KMessageContext <TNodeId>(formats.Select(i => i.ContentType))); if (packet.Format == null || packet.Sequence == null) { return; } Task.Run(async() => { try { logger.LogTrace("Decoded packet as {Format} from {Endpoint}.", packet.Format, source); await OnReceiveAsync(socket, source, packet, CancellationToken.None); } catch (Exception e) { logger.LogError(e, "Unhandled exception dispatching incoming packet."); } }); // continue receiving if socket still available // this lock is blocking, but should be okay since this event handler can stall using (sync.LockAsync().GetAwaiter().GetResult()) { // reset remote endpoint args.RemoteEndPoint = source.Protocol switch { KIpAddressFamily.IPv4 => new IPEndPoint(IPAddress.Any, 0), KIpAddressFamily.IPv6 => new IPEndPoint(IPAddress.IPv6Any, 0), _ => throw new InvalidOperationException(), }; try { socket.ReceiveMessageFromAsync(args); } catch (ObjectDisposedException) { // we must have been terminated, ignore } } }