/// <summary> /// Sends data via the socket asynchronously /// </summary> /// <param name="Message">Data to transmit</param> public void Send(ResponseData Message) { IBuffer sendBuffer = null; //TODO: ENHANCEMENT: Log consecutive bad request response types and use that information to disconnect socket after 3 try { lock (syncSocket) { if (sentMsgs.Count > 1) { sentMsgs.Dequeue(); } sentMsgs.Enqueue(Message); //Log error if .Data is null -- this will help raise a flag if the message is being resent after .ClearData was called Diags.Assert(Message.Data != null, "ASSERTION FAILED: Message Data is null", new System.Diagnostics.StackTrace().ToString()); sendBuffer = bufferPool.GetBuffer(Message.Data.LongLength); sendBuffer.CopyFrom(Message.Data); socket.BeginSend(sendBuffer.GetSegments(), SocketFlags.None, CompleteSend, sendBuffer); Message.ClearData(); //free some memory } } catch (Exception ex) { Diags.LogSocketException(ex); if (sendBuffer != null) { sendBuffer.Dispose(); sendBuffer = null; } } }
/// <summary> /// Completes an asynchronous send /// </summary> /// <param name="ar">AsyncResul obtained from BeginSend</param> private void CompleteSend(IAsyncResult ar) { // Complete asynchronous send IBuffer sendBuffer = (IBuffer)ar.AsyncState; try { if (!socket.Connected) { return; } lock (syncSocket) { socket.EndSend(ar); } sendBuffer.Dispose(); sendBuffer = null; } catch (Exception ex) { Diags.LogSocketException(ex); if (sendBuffer != null) { sendBuffer.Dispose(); sendBuffer = null; } } }
/// <summary> /// Closes the socket gracefully /// </summary> public void Close() { //TODO: ENHANCEMENT: Seems like the graceful shutdown process in this method is not working well //Is it because of the 1 ms timeout? //I see a lot more stale Peer connections than stale web server connections, so it looks like //Thw web server connections are closing better than the peer connections. Investigate this. try { lock (syncSocket) { if (socket.Connected) { socket.Shutdown(SocketShutdown.Both); } isClosing = true; socket.Close(1); } if (recvBuffer != null) { recvBuffer.Dispose(); } } catch (Exception ex) { Diags.LogSocketException(ex); } }
/// <summary> /// Begins an asynchronous receive /// </summary> /// <param name="Buffer">Buffer to store received data</param> /// <param name="ReadCallBack">Method to call on receiving data</param> /// <param name="StateObject">State object to be passed to ReadCallBack</param> /// <returns>AsyncResult for the asynchronous operation</returns> public IAsyncResult BeginReceive(int BufferLength, AsyncCallback ReadCallBack, object StateObject) { try { if (recvBuffer == null || recvBuffer.IsDisposed) { recvBuffer = bufferPool.GetBuffer(BufferLength); } else if (recvBuffer.Size < BufferLength) { recvBuffer.Dispose(); recvBuffer = bufferPool.GetBuffer(BufferLength); } lock (syncSocket) { return(socket.BeginReceive(recvBuffer.GetSegments(), SocketFlags.None, ReadCallBack, StateObject)); } } catch (Exception ex) { Diags.LogSocketException(ex); return(null); } }
/// <summary> /// Ends an asynchronous Receive /// </summary> /// <param name="ar">AsyncResult obtained from BeginReive</param> /// <param name="Error">Indicates an error occured while receiving data</param> /// <returns>Received Data</returns> public byte[] EndReceive(IAsyncResult ar, out bool Error) { Error = false; int bytesRead = 0; try { lock (syncSocket) { bytesRead = socket.EndReceive(ar); } } catch (ObjectDisposedException ex) { if (!isClosing) { Diags.LogSocketException(ex); } Error = true; } catch (Exception ex) { Diags.LogSocketException(ex); Error = true; } byte[] readData; if (Error || bytesRead < 0) { readData = new byte[0]; } else { readData = new byte[bytesRead]; } if (recvBuffer != null && !recvBuffer.IsDisposed) { if (!Error && bytesRead > 0) { recvBuffer.CopyTo(readData, 0, bytesRead); } //Dispose buffer if it's greater than a specified threshold if (recvBuffer.Size > BufferRenewalSizeThreshold) { recvBuffer.Dispose(); } } return(readData); }
/// <summary> /// Ends an asynchronous Connect /// </summary> /// <param name="ar">AsyncResult obtained from BeginConnect</param> public void EndConnect(IAsyncResult ar) { try { lock (syncSocket) { isOutbound = true; socket.EndConnect(ar); } } catch (Exception ex) { Diags.LogSocketException(ex); } }
/// <summary> /// Begins an asynchronous Connect /// </summary> /// <param name="Host">Host to connect to</param> /// <param name="Port">Port number to connect to</param> /// <param name="ConnectCallBack">Callback to call on connecting</param> /// <param name="StateObject">State object to pass to ConnectCallback</param> /// <returns>AsyncResult for the asynchronous operation</returns> public IAsyncResult BeginConnect(string Host, int Port, AsyncCallback ConnectCallBack, object StateObject) { try { lock (syncSocket) { return(socket.BeginConnect(Host, Port, ConnectCallBack, StateObject)); } } catch (Exception ex) { Diags.LogSocketException(ex); return(null); } }
/// <summary> /// Listens on a specified port on the machine /// </summary> /// <param name="Port">Port number</param> /// <param name="AcceptCallback">Callback for accepting new connections</param> /// <returns>.NET Socket if successful, Null if not</returns> public static Socket Listen(int Port, AsyncCallback AcceptCallback) { Socket listener; // Start Listening on Web Server Socket IPEndPoint wsEndPoint = new IPEndPoint(IPAddress.Any, Port); listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { listener.Bind(wsEndPoint); listener.Listen(MaxConnections); listener.BeginAccept(AcceptCallback, listener); } catch (Exception ex) { Diags.LogSocketException(ex); return(null); } return(listener); }
/// <summary> /// Terminates a connection /// </summary> public void Abort() { try { lock (syncSocket) { if (socket.Connected) { socket.Shutdown(SocketShutdown.Send); } isClosing = true; socket.Close(); } if (recvBuffer != null) { recvBuffer.Dispose(); } } catch (Exception ex) { Diags.LogSocketException(ex); } }