/// <summary> /// Begins the process of receiving a message from the client. /// This method must manually be called to Begin receiving data /// </summary> public void BeginReceive() { try { if (Connection != null) { // Reset Buffer offset back to the original allocated offset BufferDataToken token = ReadEventArgs.UserToken as BufferDataToken; ReadEventArgs.SetBuffer(token.BufferOffset, token.BufferBlockSize); // Begin Receiving if (!Connection.ReceiveAsync(ReadEventArgs)) { ProcessReceive(); } } } catch (ObjectDisposedException) { if (!DisconnectEventCalled) { // Disconnect user DisconnectEventCalled = true; OnDisconnect?.Invoke(this); } } catch (SocketException e) { HandleSocketError(e.SocketErrorCode); } }
public UDPPacket(SocketAsyncEventArgs e) { // Get our received bytes BytesRecieved = new byte[e.BytesTransferred]; BufferDataToken token = e.UserToken as BufferDataToken; Array.Copy(e.Buffer, token.BufferOffset, BytesRecieved, 0, e.BytesTransferred); // Set our internal variables AsyncEventArgs = e; }
/// <summary> /// Sets the contents of the SocketAsyncEventArgs buffer, /// so a reply can be sent to the remote host connection /// </summary> /// <param name="contents">The new contents to set the buffer to</param> /// <returns>The length of bytes written to the buffer</returns> public int SetBufferContents(byte[] contents) { BufferDataToken token = AsyncEventArgs.UserToken as BufferDataToken; if (contents.Length > token.BufferBlockSize) { throw new ArgumentOutOfRangeException("contents", "Contents are larger then the allocated buffer block size."); } // Copy contents to buffer, then set buffer position Array.Copy(contents, 0, AsyncEventArgs.Buffer, token.BufferOffset, contents.Length); AsyncEventArgs.SetBuffer(token.BufferOffset, contents.Length); return(contents.Length); }
/// <summary> /// Once data has been received from the client, this method is called /// to process the data. Once a message has been completed, the OnDataReceived /// event will be called /// </summary> private void ProcessReceive() { // If we do not get a success code here, we have a bad socket if (ReadEventArgs.SocketError != SocketError.Success) { HandleSocketError(ReadEventArgs.SocketError); return; } // Force disconnect (Specifically for Gpsp, whom will spam empty connections) if (ReadEventArgs.BytesTransferred == 0) { Close(); return; } else { // Fetch our message as a string from the Buffer BufferDataToken token = ReadEventArgs.UserToken as BufferDataToken; RecvMessage.Append( Encoding.UTF8.GetString( ReadEventArgs.Buffer, token.BufferOffset, ReadEventArgs.BytesTransferred ) ); // Process Message string received = RecvMessage.ToString(); if (LogWriter.Log.DebugSockets) { LogWriter.Log.Write("Received TCP data: " + received, LogLevel.Debug); } // Tell our parent that we received a message RecvMessage.Clear(); // Clear old junk DataReceived(this, received); } // Begin receiving again BeginReceive(); }
/// <summary> /// Releases Buffer space assigned to a token so that it can be assingned to a new SAEA /// </summary> /// <param name="args">The SocketEventArgs object that we are releasing buffer space from</param> public void ReleaseBuffer(SocketAsyncEventArgs args) { // Check for dispose CheckDisposed(); // Grab the SAEA user token, which should be a BufferDataToken BufferDataToken Token = args.UserToken as BufferDataToken; if (Token == null) { throw new Exception("The SocketAsyncEventArgs.UserToken was not a valid instance of BufferDataToken"); } // Add the free buffer space back FreeBufferSpace.Push(Token); // Try and reset buffer try { args.SetBuffer(null, 0, 0); } catch (ObjectDisposedException) { } }
/// <summary> /// Begins accepting a new connection asynchronously /// </summary> protected async void StartAcceptAsync() { // If we are shutting down, dont receive again if (!IsRunning) { return; } try { // Enforce max connections. If we are capped on connections, the new connection will stop here, // and retrun once a connection is opened up from the Release() method await MaxConnectionsEnforcer.WaitAsync(); // Fetch ourselves an available AcceptEventArg for the next connection SocketAsyncEventArgs AcceptEventArg = SocketReadWritePool.Pop(); AcceptEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, Port); // Reset the Async's Buffer position for the next read BufferDataToken token = AcceptEventArg.UserToken as BufferDataToken; AcceptEventArg.SetBuffer(token.BufferOffset, token.BufferBlockSize); // Begin accpetion connections bool willRaiseEvent = Listener.ReceiveFromAsync(AcceptEventArg); // If we wont raise event, that means a connection has already been accepted synchronously // and the Accept_Completed event will NOT be fired. So we manually call ProcessAccept if (!willRaiseEvent) { IOComplete(this, AcceptEventArg); } } catch (ObjectDisposedException) { // Happens when the server is shutdown } catch (Exception e) { OnException(e); } }
/// <summary> /// Sends a message Asynchronously to the client connection /// </summary> private void ProcessSend() { // Return if we are closing the socket if (SocketClosed) { return; } // Bool holder bool willRaiseEvent = true; // Prevent an connection loss exception try { // Prevent race conditions by locking here. // ** Make sure to set WaitingOnAsync Inside the LOCK! ** lock (_lockObj) { // If we are waiting on the IO operation to complete, we exit here if (WaitingOnAsync) { return; } // Get the number of bytes remaining to be sent int NumBytesToSend = SendMessage.Count - SendBytesOffset; // If there are no more bytes to send, then reset if (NumBytesToSend <= 0) { SendMessage.Clear(); SendBytesOffset = 0; WaitingOnAsync = false; return; } // Make sure we arent sending more data then what we have space for BufferDataToken Token = WriteEventArgs.UserToken as BufferDataToken; if (NumBytesToSend > Token.BufferBlockSize) { NumBytesToSend = Token.BufferBlockSize; } // Copy our message to the Write Buffer SendMessage.CopyTo(SendBytesOffset, WriteEventArgs.Buffer, Token.BufferOffset, NumBytesToSend); WriteEventArgs.SetBuffer(Token.BufferOffset, NumBytesToSend); // We have to exit the lock() before we can handle the event manually WaitingOnAsync = true; willRaiseEvent = Connection.SendAsync(WriteEventArgs); } } catch (ObjectDisposedException) { WaitingOnAsync = false; Close(); } // If we wont raise the IO event, that means a connection sent the messsage synchronously if (!willRaiseEvent) { // Remember, if we are here, data was sent synchronously... IOComplete event is not called! // First, Check for a closed conenction if (WriteEventArgs.BytesTransferred == 0 || WriteEventArgs.SocketError != SocketError.Success) { Close(); return; } // Append to the offset SendBytesOffset += WriteEventArgs.BytesTransferred; WaitingOnAsync = false; ProcessSend(); } }