static IEnumerator<Int32> HandleClient(AsyncEnumerator ae, ServerState server, ClientState client, TcpClient tcpRecv, TcpClient tcpSend, BufferWrapper bw, FilterFunc filterFunc) { // add the client to the clients list { server.clientsMutex.BeginRegion(SyncGateMode.Exclusive, ae.End()); yield return 1; var mutexResult = ae.DequeueAsyncResult(); { if (!server.clients.ContainsKey(client.localtcp)) { server.clients[client.localtcp] = client; } } server.clientsMutex.EndRegion(mutexResult); } Socket sockRecv = tcpRecv.Client; Socket sockSend = tcpSend.Client; bool wantDisconnect = false; int len = 0; while (true) { // read message try { // resize buffer if needed so that it has initialbuffersize spaces at the end if((bw.buffer.Length - len) < server.settings.initialbuffersize) { Array.Resize(ref bw.buffer, len + server.settings.initialbuffersize); } sockRecv.BeginReceive(bw.buffer, len, server.settings.initialbuffersize, SocketFlags.None, ae.End(), null); } catch (Exception) { break; } yield return 1; try { int tmplen = sockRecv.EndReceive(ae.DequeueAsyncResult()); if (tmplen == 0) { break; } else { len += tmplen; } } catch (Exception) { break; } // filter the packets here switch (filterFunc(client, bw.buffer, len)) { case FilterIntent.Buffer: break; case FilterIntent.Accept: int sent = 0; while(sent < len) { // echo the data back to the client try { sockSend.BeginSend(bw.buffer, sent, len-sent, SocketFlags.None, ae.End(), null); } catch (Exception) { wantDisconnect = true; break; } yield return 1; try { sent += sockSend.EndSend(ae.DequeueAsyncResult()); } catch (Exception) { wantDisconnect = true; break; } } len = 0; break; case FilterIntent.Drop: len = 0; break; case FilterIntent.Disconnect: wantDisconnect = true; break; } if(wantDisconnect) break; } // remove the client from the list { server.clientsMutex.BeginRegion(SyncGateMode.Exclusive, ae.End()); yield return 1; var mutexResult = ae.DequeueAsyncResult(); { if (server.clients.ContainsKey(client.localtcp)) { var removed = server.clients.Remove(client.localtcp); Console.WriteLine("Client disconnected {0} - {1}", client.localtcp.Client.RemoteEndPoint, removed); // dont forget to dispose it tcpRecv.Close(); tcpSend.Close(); } } server.clientsMutex.EndRegion(mutexResult); } }
static IEnumerator<Int32> ServerConnectRemote(AsyncEnumerator ae, ServerState server, IPEndPoint ipe, TcpClient local) { // establish a client proxy -> real server connection var remote = new TcpClient(ipe.AddressFamily); var settings = server.settings; remote.NoDelay = true; remote.LingerState.Enabled = false; remote.BeginConnect(IPAddress.Parse(settings.addressforward), settings.portforward, ae.End(), ae); yield return 1; try { remote.EndConnect(ae.DequeueAsyncResult()); } catch (SocketException) { Console.WriteLine("A client failed to connect, has the real server started?"); local.Close(); remote.Close(); remote = null; } if(remote != null) { var bufParam = new ClientBufferParam(); { server.bufferPoolMutex.BeginRegion(SyncGateMode.Exclusive, ae.End()); yield return 1; var res = ae.DequeueAsyncResult(); server.AllocBuffer(ae, bufParam); server.bufferPoolMutex.EndRegion(res); } { var newClientState = new ClientState(local, remote); var remoteAe = new AsyncEnumerator(); var localAe = new AsyncEnumerator(); var bw1 = new BufferWrapper(bufParam.sendbuffer); var bw2 = new BufferWrapper(bufParam.recvbuffer); localAe.BeginExecute(HandleClient(localAe, server, newClientState, local, remote, bw1, server.filterSend), ae.End(), localAe); remoteAe.BeginExecute(HandleClient(remoteAe, server, newClientState, remote, local, bw2, server.filterRecv), ae.End(), remoteAe); Console.WriteLine("Client Connected {0}", local.Client.RemoteEndPoint); yield return 2; for (int x = 0; x < 2; x++) { IAsyncResult ar = ae.DequeueAsyncResult(); ((AsyncEnumerator)ar.AsyncState).EndExecute(ar); } bufParam.sendbuffer = bw1.buffer; bufParam.recvbuffer = bw2.buffer; } { server.bufferPoolMutex.BeginRegion(SyncGateMode.Exclusive, ae.End()); yield return 1; var res = ae.DequeueAsyncResult(); server.FreeBuffer(ae, bufParam); server.bufferPoolMutex.EndRegion(res); } } }