public override void Bind(EndPoint localEP) { if (this.ActsAsServer) { throw new Exception("Cannot call {nameof(Bind)} multiple times."); } UnderlyingSocket.Bind(localEP); this.ActsAsServer = true; this.Clients = new ConcurrentDictionary <IPEndPoint, UdpSocket>(); this.ServerTaskCancellationTokenSource = new CancellationTokenSource(); // All "receives" should be handled by this "server" instance. For now, let's try one background thread. ServerTask = Task.Run(async() => { try { var buffer = new byte[4096]; while (true) { // TODO: There should be a TTL on "acting as server" sockets that are "connected" to remote endpoints, since // UDP clients won't ever request a "close". var receive = await UnderlyingSocket.ReceiveFromAsync(buffer, SocketFlags.None, new IPEndPoint(IPAddress.Any, 0 /* any */)); var read = receive.ReceivedBytes; var remoteEndpoint = (IPEndPoint)receive.RemoteEndPoint; var memory = new byte[read].AsMemory(); buffer.AsMemory().Slice(0, read).CopyTo(memory); // See if this is for a "client" socket; if so, queue up for that socket's receive. if (Clients.TryGetValue(remoteEndpoint, out UdpSocket? actualReceiver)) { await actualReceiver.AwaitingReceives.Writer.WriteAsync(memory, ServerTaskCancellationTokenSource.Token); continue; } // Otherwise, queue up for "self" in awaiting accepts. var acceptingSocket = new UdpSocket(UnderlyingSocket) { TrackedRemote = remoteEndpoint }; await acceptingSocket.AwaitingReceives.Writer.WriteAsync(memory); await this.AwaitingAccepts.Writer.WriteAsync(acceptingSocket, ServerTaskCancellationTokenSource.Token); } } catch (Exception e) { Console.WriteLine(e.Message); throw e; } }, ServerTaskCancellationTokenSource.Token); }
public override void Dispose() { if (!this.ActsAsServer) { return; // NO-OP for client sockets. } this.Disconnect(false); UnderlyingSocket.Dispose(); }
/// <summary> /// Marks a specific connection for graceful shutdown. The next receive or send to be posted /// will fail and close the connection. /// </summary> public void Shutdown(SocketShutdown socketShutdown) { try { trace.Debug("Shutting Down Socket to {0} Side = {1}", IPAddress, socketShutdown.ToString()); UnderlyingSocket.Shutdown(socketShutdown); } catch (Exception e) { trace.Error(e, "Non-fatal error shuttind down socket"); } }
private void ReceiveAsyncLoop(ReceiveAsyncState receiveState) { receiveAsyncLoopAgain: if (receiveState.countToRead > 0) { receiveEventArgs.SetBuffer(receiveState.byteBuffer.WriteOffset, receiveState.countToRead); if (UnderlyingSocket.ReceiveAsync(receiveEventArgs) == false) { // completed synchrounsly CompleteReceive(receiveEventArgs, false); goto receiveAsyncLoopAgain; } } }
private void SendAsyncLoop(SendAsyncState sendState) { sendAsyncLoopAgain: if (sendState.countToWrite > 0) { sendEventArgs.SetBuffer(sendState.byteBuffer.ReadOffset, sendState.countToWrite); if (UnderlyingSocket.SendAsync(sendEventArgs) == false) { // completed synchrounsly CompleteSend(sendEventArgs, false); goto sendAsyncLoopAgain; } } }
public override void Disconnect(bool reuseSocket) { if (!ActsAsServer) { return; // NO-OP for "client" sockets. } // Clear all clients. this.Clients?.Clear(); // Cancel listening thread. ServerTaskCancellationTokenSource?.Cancel(); // Disconnect underlying socket. UnderlyingSocket.Disconnect(reuseSocket); }
public void Close() { try { try { UnderlyingSocket.Shutdown(SocketShutdown.Both); } catch (Exception e) { trace.Error(e, "Non-fatal error shutting down socket"); } UnderlyingSocket.Close(); } finally { var onClosedEvent = OnClosed; if (onClosedEvent != null) { onClosedEvent(this, EventArgs.Empty); } } }
public bool ReceiveAsync(SocketAsyncEventArgs args) { return(UnderlyingSocket.ReceiveAsync(args)); }
public override ValueTask <int> SendAsync(ReadOnlyMemory <byte> buffer, CancellationToken cancellationToken = default) => UnderlyingSocket.SendAsync(buffer, SocketFlags.None);
public override async Task <TransportSocket> ConnectAsync(IPAddress address, int port) { await UnderlyingSocket.ConnectAsync(address, port); return(this); }
public override async Task <TransportSocket> AcceptAsync() => (await UnderlyingSocket.AcceptAsync()).ToTcpSocket();
public override ValueTask <int> ReceiveAsync(Memory <byte> buffer, CancellationToken cancellationToken = default) => UnderlyingSocket.ReceiveAsync(buffer, SocketFlags.None, cancellationToken);
public override void Bind(EndPoint localEP) => UnderlyingSocket.Bind(localEP);
public override void Disconnect(bool reuseSocket) => UnderlyingSocket.Disconnect(reuseSocket);
public bool SendAsync(SocketAsyncEventArgs args) { return(UnderlyingSocket.SendAsync(args)); }
public override void Dispose() => UnderlyingSocket.Dispose();
public override ValueTask <int> SendAsync(ReadOnlyMemory <byte> buffer, CancellationToken cancellationToken = default) { return(new ValueTask <int>(UnderlyingSocket.SendToAsync(buffer.ToArray(), SocketFlags.None, TrackedRemote))); }
public bool ConnectAsync(SocketAsyncEventArgs args) { return(UnderlyingSocket.ConnectAsync(args)); }
public void Dispose() { UnderlyingSocket.Dispose(); }
public int Receive(IList <ArraySegment <byte> > buffers) { return(UnderlyingSocket.Receive(buffers)); }
public override void Listen(int backlog) => UnderlyingSocket.Listen(backlog);
public int Send(IList <ArraySegment <byte> > buffers) { return(UnderlyingSocket.Send(buffers)); }
public override async Task <TransportSocket> ConnectAsync(string host, int port) { await UnderlyingSocket.ConnectAsync(host, port); return(this); }