Example #1
0
 /// <summary>
 /// Completes the reception of bytes from the remote endpoint.
 /// </summary>
 /// <param name="ar">The <see cref="IAsyncResult" /> instance returned by the initiating <see cref="BeginReceive" /> call.</param>
 /// <returns>The number of bytes received or zero if the remote endpoint has gracefully closed the connection (for TCP connections).</returns>
 /// <exception cref="SocketException">Thrown if the was an network error.</exception>
 /// <exception cref="SocketClosedException">Thrown if the socket has been closed.</exception>
 /// <remarks>
 /// <note>
 /// For TCP connections, the operation will be considered to have completed when some number of bytes
 /// between one and the specified <b>count</b> 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 <b>count</b> must be large enough to hold the next received
 /// UDP packet.
 /// </note>
 /// <note>
 /// All successful calls to <see cref="BeginReceive" /> must eventually be followed by a call to <see cref="EndReceive" />.
 /// </note>
 /// </remarks>
 public int EndReceive(IAsyncResult ar)
 {
     lock (syncLock)
     {
         try
         {
             return(sock.EndReceive(ar));
         }
         finally
         {
             receivePending = false;
         }
     }
 }
Example #2
0
 private void OnRecvBuf(IAsyncResult ar)
 {
     try
     {
         syncCompletion = ar.CompletedSynchronously;
         cbTransfer     = sock.EndReceive(ar);
     }
     catch (Exception e)
     {
         asyncException = e;
     }
     finally
     {
         asyncEvent.Set();
     }
 }
Example #3
0
        /// <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);
                }
            }
        }
Example #4
0
        /// <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
            }
        }
Example #5
0
            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);
                        }
                    }
                }
            }
Example #6
0
        /// <summary>
        /// Handles receive completions on the socket.
        /// </summary>
        /// <param name="ar">The async result.</param>
        private void OnReceive(IAsyncResult ar)
        {
            int cbRecv;

            try
            {
                using (TimedLock.Lock(router.SyncRoot))
                {
                    if (sock == null || recvBuf == null)
                    {
                        return;
                    }

                    try
                    {
                        cbRecv = sock.EndReceive(ar);
                    }
                    catch (SocketException e2)
                    {
                        if (e2.SocketErrorCode == SocketError.ConnectionReset)
                        {
                            cbRecv = 0;     // Treat connection resets as connection closure
                        }
                        else
                        {
                            throw;
                        }
                    }

                    if (cbRecv == 0)
                    {
                        sock.ShutdownAndClose();
                        return;
                    }

                    SetLastAccess();

                    recvPos += cbRecv;
                    if (recvPos < recvBuf.Length)
                    {
                        // Continue the reception

                        sock.BeginReceive(recvBuf, recvPos, recvBuf.Length - recvPos, SocketFlags.None, onReceive, null);
                        return;
                    }

                    if (recvHeader)
                    {
                        // Initiate reception of the frame payload

                        int    pos = 0;
                        int    cbFrame;
                        byte[] buf;

                        cbFrame = Helper.ReadInt32(recvBuf, ref pos);
                        buf     = new byte[MsgRouter.FrameHeaderSize + cbFrame];
                        Array.Copy(recvBuf, 0, buf, 0, MsgRouter.FrameHeaderSize);

                        recvHeader = false;
                        recvBuf    = buf;
                        recvPos    = MsgRouter.FrameHeaderSize;
                        cbRecv     = cbFrame;

                        sock.BeginReceive(recvBuf, recvPos, cbFrame, SocketFlags.None, onReceive, null);
                    }
                    else
                    {
                        // We've completed the reception of a message

                        Msg    msg;
                        byte[] msgBuf;
                        int    cbMsg;

                        msgBuf = router.DecryptFrame(recvBuf, recvBuf.Length, out cbMsg);
                        msg    = Msg.Load(new EnhancedMemoryStream(msgBuf));
                        msgBuf = null;

                        // Handle initialization messages locally and queue a
                        // notification for all other messages so that router.OnReceive()
                        // will be called on a worker thread.

                        if (!initProcessed)
                        {
                            TcpInitMsg initMsg;
                            Exception  e;

                            initMsg = msg as TcpInitMsg;
                            if (initMsg == null)
                            {
                                e = new MsgException("Invalid TCP channel protocol: TcpInitMsg expected.");
                                SysLog.LogException(e);
                                Helper.Rethrow(e);
                            }

                            initMsg._Trace(router, 2, "Receive", null);

                            // If the sender indicates that it is an uplink then we're going
                            // to use the actual remote port for the remoteEP rather than
                            // ListenPort (which should be 0).  The reason for this is that
                            // intervening routers and NATs may translate the port number
                            // reported by the child router.

                            routerEP            = initMsg.RouterEP;
                            remoteEP.NetEP.Port = initMsg.IsUplink ? ((IPEndPoint)sock.RemoteEndPoint).Port : initMsg.ListenPort;
                            isDownlink          = initMsg.IsUplink;
                            isP2P         = initMsg.RouterInfo.IsP2P;
                            initProcessed = true;

                            router.OnTcpInit(this);
                        }
                        else
                        {
                            msg._SetFromChannel(remoteEP);
                            msg._Trace(router, 2, "TCP: Recv", null);
                            msg._Trace(router, 0, "Receive", string.Empty);
                            router.OnReceive(this, msg);
                        }

                        // Initiate reception of the next message

                        BeginReceive();
                    }
                }
            }
            catch (SocketException e)
            {
                // Don't log connection resets because we see these all the
                // time when a router stops.  We're not going to consider
                // this to be an error.

                if (e.SocketErrorCode != SocketError.ConnectionReset)
                {
                    TraceException(e);
                    SysLog.LogException(e);
                }

                router.OnTcpClose(this);
                Close();
            }
            catch (Exception e)
            {
                TraceException(e);
                SysLog.LogException(e);
                router.OnTcpClose(this);
                Close();
            }
        }