Example #1
0
        /// <summary>
        /// Completes the reception of bytes on a TCP connection.
        /// </summary>
        /// <param name="ar">The <see cref="IAsyncResult" /> instance returned by the initiating <see cref="BeginReceiveAll" /> call.</param>
        /// <exception cref="SocketException">Thrown if the was an network error.</exception>
        /// <exception cref="SocketClosedException">Thrown if the socket has been closed.</exception>
        /// <remarks>
        /// <note>
        /// All successful calls to <see cref="BeginReceiveAll" /> must eventually be followed by a call to <see cref="EndReceiveAll" />.
        /// </note>
        /// </remarks>
        public void EndReceiveAll(IAsyncResult ar)
        {
            lock (syncLock)
            {
                if (!isTcp)
                {
                    throw new InvalidOperationException("[LiteSocket.EndReceiveAll] is not supported on UDP connections.");
                }

                try
                {
                    sock.EndReceiveAll(ar);
                }
                finally
                {
                    receivePending = false;
                }
            }
        }
Example #2
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);
                        }
                    }
                }
            }