/// <summary> /// Gracefully stops communication on the socket and then closes it. /// </summary> /// <remarks> /// <note> /// This method is safe to call when the socket is already shut down or closed. /// </note> /// </remarks> public void ShutdownAndClose() { lock (syncLock) { if (isTcp) { sock.ShutdownAndClose(); } else { sock.Close(); } } }
/// <summary> /// Closes the channel if it's currently open. /// </summary> public void Close() { using (TimedLock.Lock(router.SyncRoot)) { try { if (sock != null) { try { if (sock.Connected) { router.Trace(2, "TCP: Close", "LocalEP=" + localEP.NetEP.ToString() + " remoteEP=" + remoteEP.NetEP.ToString(), null); } sock.ShutdownAndClose(); } catch { } connected = false; sendQueue.Clear(); sending = false; sendMsg = null; sendBuf = null; sendPos = 0; cbSend = 0; recvHeader = false; recvBuf = null; recvPos = 0; } } catch { } } }
public void Close() { if (sock == null) { return; } using (TimedLock.Lock(transport)) { sock.ShutdownAndClose(); sock = null; } }
/// <summary> /// Handles completion of the response reception. /// </summary> /// <param name="ar">The async result.</param> private void OnResponseReceived(IAsyncResult ar) { var httpAR = (HttpAsyncResult)ar.AsyncState; int cbRecv; using (TimedLock.Lock(this)) { try { // Pump the received data into the response parser, // signalling completion when we have the entire message. cbRecv = sock.EndReceive(ar); if (perfBytesRecv != null) { perfBytesRecv.IncrementBy(cbRecv); } if (httpAR.Response.Parse(httpAR.Buffer, cbRecv)) { httpAR.Response.EndParse(); httpAR.Notify(); return; } if (cbRecv == 0) { sock.ShutdownAndClose(); return; } // Continue receiving response data httpAR.Buffer = new byte[HttpStack.BlockSize]; sock.BeginReceive(httpAR.Buffer, 0, HttpStack.BlockSize, SocketFlags.None, onResponseRecv, httpAR); } catch (Exception e) { httpAR.Notify(e); } } }
/// <summary> /// Handles socket receive completions. /// </summary> /// <param name="ar"></param> private void OnReceive(IAsyncResult ar) { HttpAsyncState httpState = (HttpAsyncState)ar.AsyncState; HttpRequest request = httpState.Request; EnhancedSocket sock = httpState.Socket; byte[] recvBuf = httpState.Buffer; int cbRecv; HttpResponse response; bool closeCon; bool close; bool firstRequest; try { cbRecv = sock.EndReceive(ar); } catch { using (TimedLock.Lock(syncLock)) connections.Remove(sock); sock.Close(); return; } if (cbRecv == 0) { using (TimedLock.Lock(syncLock)) connections.Remove(sock); sock.ShutdownAndClose(); return; } if (perfBytesRecv != null) { perfBytesRecv.IncrementBy(cbRecv); } httpState.RecvSize += cbRecv; if (httpState.RecvSize > cbQueryMax) { // The request is too large so respond with a HttpStatus.RequestEntityTooLarge // and close the socket. response = new HttpResponse(HttpStatus.RequestEntityTooLarge); sock.AsyncSendClose(response.Serialize(SendBlockSize)); using (TimedLock.Lock(syncLock)) connections.Remove(sock); return; } if (!request.Parse(recvBuf, cbRecv)) { recvBuf = new byte[RecvBlockSize]; httpState.Buffer = recvBuf; sock.BeginReceive(recvBuf, 0, recvBuf.Length, SocketFlags.None, onRecv, httpState); return; } // We have a complete request so process it. request.EndParse(); firstRequest = httpState.FirstRequest; httpState.FirstRequest = false; try { sock.AppState = this; // Indicate that we're processing a request closeCon = false; for (int i = 0; i < modules.Length; i++) { response = modules[i].OnRequest(this, request, firstRequest, out close); closeCon = closeCon || close; if (response != null) { BlockArray blocks; // Make sure the response version is reasonable if (request.HttpVersion < response.HttpVersion) { response.HttpVersion = request.HttpVersion; } // Truncate any content data for HEAD requests if (request.Method == "HEAD") { response.Content = null; if (response["Content-Length"] != null) { response["Content-Length"] = "0"; } } blocks = response.Serialize(SendBlockSize); if (perfBytesSent != null) { perfBytesSent.IncrementBy(blocks.Size); } if (closeCon) { sock.AsyncSendClose(blocks); using (TimedLock.Lock(syncLock)) connections.Remove(sock); } else { sock.BeginSendAll(blocks, SocketFlags.None, onSend, httpState); } break; } } } finally { sock.AppState = null; // Indicate that we're done processing the request } }
/// <summary> /// Asynchronously transmits the message passed to the destination /// indicated by the <see paramref="remoteEP" /> parameter. /// </summary> /// <param name="remoteEP">The destination SIP endpoint's <see cref="NetworkBinding" />.</param> /// <param name="message">The <see cref="SipMessage" /> to be transmitted.</param> /// <remarks> /// Note that this method will go to some lengths to send the message /// down an existing connection to this endpoint. /// </remarks> /// <exception cref="SipTransportException">Thrown if the remote endpoint rejected the message or timed out.</exception> public void Send(NetworkBinding remoteEP, SipMessage message) { string key = remoteEP.ToString(); EnhancedSocket sock; Connection con; using (TimedLock.Lock(this)) { if (listener == null) { throw new ObjectDisposedException("Transport is closed."); } if (disabled) { return; } if ((traceMode & SipTraceMode.Send) != 0) { SipHelper.Trace(string.Format("TCP: sending to {0}", remoteEP), message); } // Send the message down an existing connection to this // endpoint (if there is one). if (connections.TryGetValue(key, out con)) { con.Send(message); return; } } // Otherwise establish a connection to the endpoint and transmit // the message. Note that I'm establishing the connection outside // of the lock so processing on other connections can continue // while the connection is established. try { sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Connect(remoteEP); } catch (SocketException e) { switch ((SocketError)e.ErrorCode) { case SocketError.ConnectionAborted: case SocketError.ConnectionRefused: case SocketError.ConnectionReset: case SocketError.HostDown: case SocketError.HostNotFound: case SocketError.HostUnreachable: throw new SipTransportException(SipTransportException.ErrorType.Rejected, e.Message, e); case SocketError.TimedOut: throw new SipTransportException(SipTransportException.ErrorType.Timeout, e.Message, e); default: throw; } } using (TimedLock.Lock(this)) { if (listener == null) { // Transport must have been closed while we were outside of the lock. sock.ShutdownAndClose(); throw new ObjectDisposedException("Transport is closed."); } if (connections.TryGetValue(key, out con)) { // Another connection to this endpoint must have been established // while we were outside of the lock. Close the new socket and // use the existing connection. sock.ShutdownAndClose(); con.Send(message); return; } // Add the new connection to the collection and then // send the message. con = new Connection(this, sock, remoteEP); connections.Add(key, con); con.Send(message); } }