/// <summary> /// Handles completion of the request transmission. /// </summary> /// <param name="ar">The async result.</param> private void OnRequestSent(IAsyncResult ar) { var httpAR = (HttpAsyncResult)ar.AsyncState; using (TimedLock.Lock(this)) { try { sock.EndSendAll(ar); // The request was sent successfully so start receiving // the response. httpAR.Response = new HttpResponse(cbContentMax); httpAR.Buffer = new byte[HttpStack.BlockSize]; httpAR.Response.BeginParse(); sock.BeginReceive(httpAR.Buffer, 0, HttpStack.BlockSize, SocketFlags.None, onResponseRecv, httpAR); } catch (Exception e) { httpAR.Notify(e); } } }
/// <summary> /// Called by the socket listener when an inbound socket is accepted. /// </summary> /// <param name="sock">The accepted socket.</param> /// <param name="endPoint">The endpoint the socket was accepted from.</param> private void OnAccept(EnhancedSocket sock, IPEndPoint endPoint) { var httpState = new HttpAsyncState(); var recvBuf = new byte[RecvBlockSize]; using (TimedLock.Lock(syncLock)) { if (connections.Count >= maxConnections) { sock.AsyncSendClose(new HttpResponse(HttpStatus.ServiceUnavailable, "Server is too busy").Serialize(SendBlockSize)); return; } connections.Add(sock, sock); } httpState.FirstRequest = true; httpState.Request = new HttpRequest(); httpState.Socket = sock; httpState.Buffer = recvBuf; httpState.RecvSize = 0; httpState.Request.BeginParse(((IPEndPoint)sock.LocalEndPoint).Port); sock.BeginReceive(recvBuf, 0, recvBuf.Length, SocketFlags.None, onRecv, httpState); }
public int Receive(byte[] buf) { Reset(); sock.BeginReceive(buf, 0, buf.Length, SocketFlags.None, onRecvBuf, null); asyncEvent.WaitOne(MaxWaitTime, false); Verify(); return(cbTransfer); }
/// <summary> /// Initiates the reception of a message. /// </summary> private void BeginReceive() { try { using (TimedLock.Lock(router.SyncRoot)) { SetLastAccess(); recvHeader = true; recvBuf = new byte[MsgRouter.FrameHeaderSize]; recvPos = 0; cbRecv = MsgRouter.FrameHeaderSize; sock.BeginReceive(recvBuf, recvPos, cbRecv, SocketFlags.None, onReceive, null); } } catch (Exception e) { TraceException(e); router.OnTcpClose(this); Close(); throw; } }
private SipMessage message; // The message we're receiving contents for public Connection(SipTcpTransport transport, EnhancedSocket sock, IPEndPoint remoteEP) { this.transport = transport; this.sock = sock; this.remoteEP = remoteEP; this.sendQueue = new Queue <SipMessage>(); this.onSend = new AsyncCallback(OnSend); this.onRecv = new AsyncCallback(OnReceive); this.sendPending = false; this.headerBuf = new byte[MaxHeaderSize]; this.contentBuf = null; this.cbRecv = 0; sock.BeginReceive(headerBuf, 0, headerBuf.Length, SocketFlags.None, onRecv, null); }
/// <summary> /// Initiates reception the next chunk of received data up to a specified maxinum number of bytes. /// </summary> /// <param name="buffer">The destination buffer.</param> /// <param name="offset">Index where the first received byte is to be written.</param> /// <param name="count">Number of bytes to be received.</param> /// <param name="callback">The delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state.</param> /// <returns> /// An <see cref="IAsyncResult" /> instance to be used to track the progress of the /// operation and to eventually be passed to the <see cref="EndReceive" /> method. /// </returns> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected or if another receive operation is already pending.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="buffer" /> is <c>null</c>.</exception> /// <exception cref="IndexOutOfRangeException">Thrown if <paramref name="offset" /> and <paramref name="count" /> specify bytes outside of the <paramref name="buffer" />.</exception> /// <remarks> /// <note> /// Only one receive operation may be pending per socket for both TCP and UDP connections. /// </note> /// <note> /// All successful calls to <see cref="BeginReceive" /> must eventually be followed by a call to <see cref="EndReceive" />. /// </note> /// <note> /// For TCP connections, the operation will be considered to have completed when some number of bytes /// between one and the specified <paramref name="count" /> have been received from the remote endpoint /// or the remote endpoint has gracefully closed the connection. For UDP connections, the operation will /// be considered to be complete when the next packet is received, regardless of size. Note that the /// buffer size specified by <paramref name="count" /> must be large enough to hold the next received /// UDP packet. /// </note> /// </remarks> public IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || count < 0 || offset + count > buffer.Length + 1) { throw new IndexOutOfRangeException(string.Format("[LiteSocket.Send: offset={0}] and [count={1}] is not valid for buffer of length [{2}].", offset, count, buffer.Length)); } lock (syncLock) { if (!Connected) { throw new InvalidOperationException("Socket is not connected."); } if (receivePending) { throw new InvalidOperationException("LiteSocket.Receive: Another receive operation is already pending on this socket."); } try { receivePending = true; return(sock.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state)); } catch { receivePending = false; throw; } } }
/// <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 } }
private void OnReceive(IAsyncResult ar) { List <SipMessage> received = null; try { using (TimedLock.Lock(transport)) { int cb; int pos; int cbContents; SipHeader contentLength; byte[] packet; try { if (sock == null) { return; } if (contentBuf == null) { // We're reading a message envelope. // Read packets into headerBuf until we can find the CRLFCRLF // sequence marking the end of the message headers. cb = sock.EndReceive(ar); if (cb == 0) { // The socket has been closed on by the remote element. CloseAndRemove(); return; } cbRecv += cb; tryAgain: // Remove any leading CR or LF characters by shifting the // buffer contents. I know this isn't super efficient but // we'll probably never actually see packets with this // in the wild. for (pos = 0; pos < cbRecv; pos++) { if (headerBuf[pos] != 0x0D && headerBuf[pos] != 0x0A) { break; } } if (pos != 0) { if (pos == cbRecv) { // No data remaining in the buffer cbRecv = 0; sock.BeginReceive(headerBuf, 0, headerBuf.Length, SocketFlags.None, onRecv, null); return; } Array.Copy(headerBuf, pos, headerBuf, 0, headerBuf.Length - pos); cbRecv -= pos; } // Scan the message for the CRLFCRLF sequence terminating the // message envelope. pos = Helper.IndexOf(headerBuf, CRLFCRLF, 0, cbRecv); if (pos != -1) { // We've got the message envelope pos += 4; // Advance past the CRLFCRLF // Parse the message headers and then get the Content-Length header packet = Helper.Extract(headerBuf, 0, pos); try { message = SipMessage.Parse(packet, false); } catch (Exception e) { SipHelper.Trace(string.Format("TCP: UNPARSABLE message received from {0}: [{1}]", remoteEP, e.Message), Helper.FromUTF8(packet)); throw; } contentLength = message[SipHeader.ContentLength]; if (contentLength == null || !int.TryParse(contentLength.Text, out cbContents) || cbContents < 0) { var e = new SipException("Malformed SIP message: Invalid or missing [Content-Length] header from streaming transport."); e.Transport = "TCP"; e.BadPacket = packet; e.SourceEndpoint = remoteEP; throw e; } if (cbContents > MaxContentSize) { var e = new SipException("Invalid SIP message: [Content-Length={0}] exceeds [{1}].", cbContents, MaxContentSize); e.Transport = "TCP"; e.BadPacket = packet; e.SourceEndpoint = remoteEP; throw e; } if (pos + cbContents <= cbRecv) { // We already have the message contents, so extract the contents, // add them to the message, and then queue the message for delivery // once we leave the lock. message.Contents = Helper.Extract(headerBuf, pos, cbContents); if (received == null) { received = new List <SipMessage>(); } received.Add(message); message = null; // Shift any remaining data to the left in headerBuf, // adjust cbRecv, and the loop to look for another // message. pos += cbContents; cb = cbRecv - pos; // Bytes remaining in the buffer if (cb == 0) { // No more data left in the buffer cbRecv = 0; sock.BeginReceive(headerBuf, 0, headerBuf.Length, SocketFlags.None, onRecv, null); return; } Array.Copy(headerBuf, pos, headerBuf, 0, cb); cbRecv = cb; goto tryAgain; } // We don't have all of the message contents, so allocate a buffer for // the contents, copy what we have already into this buffer, and then // initiate a receive operation to read the remaining data. contentBuf = new byte[cbContents]; cbRecv = cbRecv - pos; // Content bytes remaining in the buffer Array.Copy(headerBuf, pos, contentBuf, 0, cbRecv); sock.BeginReceiveAll(contentBuf, cbRecv, cbContents - cbRecv, SocketFlags.None, onRecv, null); return; } // Throw an error if the header buffer is full and we still haven't // found the end of the envelope. if (cbRecv >= headerBuf.Length) { var e = new SipException("Malformed SIP message: Read [{0}] bytes and have not yet encountered end of headers.", headerBuf.Length); e.Transport = "TCP"; e.SourceEndpoint = remoteEP; throw e; } // Continue receiving header data. sock.BeginReceive(headerBuf, cbRecv, headerBuf.Length - cbRecv, SocketFlags.None, onRecv, null); } else { // We're in the process of reading the message contents. // Complete the contents receive operation and queue the // message for delivery after we leave the lock. sock.EndReceiveAll(ar); message.Contents = contentBuf; if (received == null) { received = new List <SipMessage>(); } received.Add(message); // Reset and start reading the next message envelope. message = null; contentBuf = null; cbRecv = 0; sock.BeginReceive(headerBuf, 0, headerBuf.Length, SocketFlags.None, onRecv, null); } } catch (SocketException) { CloseAndRemove(); } catch (Exception e) { SysLog.LogException(e); CloseAndRemove(); } } } finally { // Deliver any queued messages (outside of the lock) if (received != null) { foreach (var message in received) { message.SourceTransport = transport; message.RemoteEndpoint = remoteEP; if ((transport.traceMode & SipTraceMode.Receive) != 0) { SipHelper.Trace(string.Format("TCP: received from {0}", remoteEP), message); } transport.router.Route(transport, message); } } } }