GetIPEndPoint() public method

public GetIPEndPoint ( ) : IPEndPoint
return System.Net.IPEndPoint
Example #1
0
        /// <summary>
        /// Gets fired when a suspected SIP message is extracted from the TCP data stream.
        /// </summary>
        protected void SIPTCPMessageReceived(SIPChannel channel, SIPEndPoint remoteEndPoint, byte[] buffer)
        {
            if (m_connectionFailures.ContainsKey(remoteEndPoint.GetIPEndPoint().ToString()))
            {
                m_connectionFailures.Remove(remoteEndPoint.GetIPEndPoint().ToString());
            }

            if (m_connectionFailureStrikes.ContainsKey(remoteEndPoint.GetIPEndPoint().ToString()))
            {
                m_connectionFailureStrikes.Remove(remoteEndPoint.GetIPEndPoint().ToString());
            }

            SIPMessageReceived?.Invoke(channel, remoteEndPoint, buffer);
        }
Example #2
0
        /// <summary>
        /// Get the local SIPEndPoint this channel will use for communicating with the destination SIP end point.
        /// </summary>
        /// <param name="dstEndPoint">The destination SIP end point.</param>
        /// <returns>The local SIP end points this channel selects to use for connecting to the destination.</returns>
        internal virtual SIPEndPoint GetLocalSIPEndPointForDestination(SIPEndPoint dstEndPoint)
        {
            IPAddress dstAddress   = dstEndPoint.GetIPEndPoint().Address;
            IPAddress localAddress = GetLocalIPAddressForDestination(dstAddress);

            return(new SIPEndPoint(SIPProtocol, localAddress, Port, ID, null));
        }
Example #3
0
        /// <summary>
        /// This constructor is used to create non-INVITE dialogues for example the dialogues used in SIP event interactions
        /// where the dialogue is created based on a SUBSCRIBE request.
        /// </summary>
        public SIPDialogue(
            SIPRequest nonInviteRequest,
            string toTag)
        {
            Id = Guid.NewGuid();

            CallId          = nonInviteRequest.Header.CallId;
            RouteSet        = (nonInviteRequest.Header.RecordRoutes != null) ? nonInviteRequest.Header.RecordRoutes.Reversed() : null;
            RemoteUserField = nonInviteRequest.Header.From.FromUserField;
            RemoteTag       = nonInviteRequest.Header.From.FromTag;
            LocalUserField  = nonInviteRequest.Header.To.ToUserField;
            LocalUserField.Parameters.Set("tag", toTag);
            LocalTag  = toTag;
            CSeq      = nonInviteRequest.Header.CSeq;
            Inserted  = DateTime.UtcNow;
            Direction = SIPCallDirection.Out;

            // Set the dialogue remote target and take care of mangling if an upstream proxy has indicated it's required.
            RemoteTarget  = nonInviteRequest.Header.Contact[0].ContactURI;
            ProxySendFrom = nonInviteRequest.Header.ProxyReceivedOn;

            if (!nonInviteRequest.Header.ProxyReceivedFrom.IsNullOrBlank())
            {
                // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                if (RouteSet == null && IPSocket.IsPrivateAddress(RemoteTarget.Host))
                {
                    SIPEndPoint remoteUASIPEndPoint = SIPEndPoint.ParseSIPEndPoint(nonInviteRequest.Header.ProxyReceivedFrom);
                    RemoteTarget.Host = remoteUASIPEndPoint.GetIPEndPoint().ToString();
                }
            }
        }
Example #4
0
        /// <summary>
        /// Ideally sends on the web socket channel should specify the connection ID. But if there's
        /// a good reason not to we can check if there is an existing client connection with the
        /// requested remote end point and use it.
        /// </summary>
        /// <param name="destinationEndPoint">The remote destination end point to send the data to.</param>
        /// <param name="buffer">The data to send.</param>
        /// <param name="connectionIDHint">The ID of the specific web socket connection to try and send the message on.</param>
        /// <returns>If no errors SocketError.Success otherwise an error value.</returns>
        public override async Task <SocketError> SendAsync(SIPEndPoint destinationEndPoint, byte[] buffer, string connectionIDHint)
        {
            if (destinationEndPoint == null)
            {
                throw new ApplicationException("An empty destination was specified to Send in SIPWebSocketChannel.");
            }
            else if (buffer == null || buffer.Length == 0)
            {
                throw new ArgumentException("buffer", "The buffer must be set and non empty for Send in SIPWebSocketChannel.");
            }

            try
            {
                var ingressClient = GetIngressConnection(destinationEndPoint.GetIPEndPoint(), connectionIDHint);

                // And lastly if we now have a valid web socket then send.
                if (ingressClient != null)
                {
                    await Task.Run(() => ingressClient.Send(buffer, 0, buffer.Length)).ConfigureAwait(false);

                    return(SocketError.Success);
                }
                else
                {
                    return(SocketError.ConnectionReset);
                }
            }
            catch (SocketException sockExcp)
            {
                return(sockExcp.SocketErrorCode);
            }
        }
        /// <summary>
        /// Attempts to extract SIP messages from the data that has been received on the SIP stream connection.
        /// </summary>
        /// <param name="recvChannel">The receiving SIP channel.</param>
        /// <param name="buffer">The buffer holding the current data from the stream. Note that the buffer can
        /// stretch over multiple receives.</param>
        /// <param name="bytesRead">The bytes that were read by the latest receive operation (the new bytes available).</param>
        public void ExtractSIPMessages(SIPChannel recvChannel, byte[] buffer, int bytesRead)
        {
            RecvEndPosn += bytesRead;

            int bytesSkipped = 0;

            byte[] sipMsgBuffer = SIPMessageBuffer.ParseSIPMessageFromStream(buffer, RecvStartPosn, RecvEndPosn, m_sipEncoding, out bytesSkipped);

            while (sipMsgBuffer != null)
            {
                // A SIP message is available.
                if (SIPMessageReceived != null)
                {
                    LastTransmission = DateTime.Now;
                    SIPEndPoint localEndPoint  = new SIPEndPoint(ConnectionProtocol, StreamSocket.LocalEndPoint as IPEndPoint, recvChannel.ID, ConnectionID);
                    SIPEndPoint remoteEndPoint = new SIPEndPoint(ConnectionProtocol, RemoteSIPEndPoint.GetIPEndPoint(), recvChannel.ID, ConnectionID);
                    SIPMessageReceived(recvChannel, localEndPoint, remoteEndPoint, sipMsgBuffer);
                }

                RecvStartPosn += (sipMsgBuffer.Length + bytesSkipped);

                if (RecvStartPosn == RecvEndPosn)
                {
                    // All data has been successfully extracted from the receive buffer.
                    RecvStartPosn = RecvEndPosn = 0;
                    break;
                }
                else
                {
                    // Try and extract another SIP message from the receive buffer.
                    sipMsgBuffer = SIPMessageBuffer.ParseSIPMessageFromStream(buffer, RecvStartPosn, RecvEndPosn, m_sipEncoding, out bytesSkipped);
                }
            }
        }
Example #6
0
        /// <summary>
        /// Attempts to send data to the remote end point over a reliable connection. If an existing
        /// connection exists it will be used otherwise an attempt will be made to establish a new connection.
        /// </summary>
        /// <param name="dstSIPEndPoint">The remote SIP end point to send the reliable data to.</param>
        /// <param name="buffer">The data to send.</param>
        /// <param name="serverCertificateName">Optional. Only relevant for SSL streams. The common name
        /// that is expected for the remote SSL server.</param>
        /// <param name="connectionIDHint">Optional. The ID of the specific TCP connection to try and the send the message on.</param>
        /// <returns>If no errors SocketError.Success otherwise an error value.</returns>
        public override Task <SocketError> SendSecureAsync(SIPEndPoint dstSIPEndPoint, byte[] buffer, string serverCertificateName, string connectionIDHint)
        {
            try
            {
                IPEndPoint dstEndPoint = dstSIPEndPoint?.GetIPEndPoint();

                if (dstEndPoint == null)
                {
                    throw new ArgumentException("dstEndPoint", "An empty destination was specified to Send in SIPTCPChannel.");
                }
                if (buffer == null || buffer.Length == 0)
                {
                    throw new ApplicationException("An empty buffer was specified to Send in SIPTCPChannel.");
                }
                else if (DisableLocalTCPSocketsCheck == false && m_localTCPSockets.Contains(dstEndPoint.ToString()))
                {
                    logger.LogWarning($"SIP {ProtDescr} Channel blocked Send to {dstEndPoint} as it was identified as a locally hosted {ProtDescr} socket.\r\n" + Encoding.UTF8.GetString(buffer));
                    throw new ApplicationException($"A Send call was blocked in SIP {ProtDescr} Channel due to the destination being another local TCP socket.");
                }
                else
                {
                    // Lookup a client socket that is connected to the destination. If it does not exist attempt to connect a new one.
                    SIPStreamConnection sipStreamConn = null;

                    if (connectionIDHint != null)
                    {
                        m_connections.TryGetValue(connectionIDHint, out sipStreamConn);
                    }

                    if (sipStreamConn == null && HasConnection(dstSIPEndPoint))
                    {
                        sipStreamConn = m_connections.Where(x => x.Value.RemoteEndPoint.Equals(dstEndPoint)).First().Value;
                    }

                    if (sipStreamConn != null)
                    {
                        SendOnConnected(sipStreamConn, buffer);
                        return(Task.FromResult(SocketError.Success));
                    }
                    else
                    {
                        return(ConnectClientAsync(dstEndPoint, buffer, serverCertificateName));
                    }
                }
            }
            catch (SocketException sockExcp)
            {
                return(Task.FromResult(sockExcp.SocketErrorCode));
            }
            catch (ApplicationException)
            {
                throw;
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception SIPTCPChannel Send (sendto=> {dstSIPEndPoint}. {excp.Message}");
                throw;
            }
        }
Example #7
0
        private void SIPTCPMessageReceived(SIPChannel channel, SIPEndPoint remoteEndPoint, byte[] buffer)
        {
            if (m_connectionFailures.ContainsKey(remoteEndPoint.GetIPEndPoint().ToString()))
            {
                m_connectionFailures.Remove(remoteEndPoint.GetIPEndPoint().ToString());
            }

            if (m_connectionFailureStrikes.ContainsKey(remoteEndPoint.GetIPEndPoint().ToString()))
            {
                m_connectionFailureStrikes.Remove(remoteEndPoint.GetIPEndPoint().ToString());
            }

            if (SIPMessageReceived != null)
            {
                SIPMessageReceived(channel, remoteEndPoint, buffer);
            }
        }
        /// <summary>
        /// Get the local SIPEndPoint this channel will use for communicating with the destination SIP end point.
        /// </summary>
        /// <param name="dstEndPoint">The destination SIP end point.</param>
        /// <returns>The local SIP end points this channel selects to use for connecting to the destination.</returns>
        internal override SIPEndPoint GetLocalSIPEndPointForDestination(SIPEndPoint dstEndPoint)
        {
            IPAddress dstAddress   = dstEndPoint.GetIPEndPoint().Address;
            IPAddress localAddress = GetLocalIPAddressForDestination(dstAddress);

            // Need to return ws or wss to match the destination.
            return(new SIPEndPoint(dstEndPoint.Protocol, localAddress, Port, ID, null));
        }
Example #9
0
        /// <summary>
        /// Checks whether the client web socket SIP channel has a connection to the requested server end point.
        /// </summary>
        public override bool HasConnection(SIPEndPoint serverEndPoint)
        {
            string uriPrefix    = (serverEndPoint.Protocol == SIPProtocolsEnum.wss) ? WEB_SOCKET_SECURE_URI_PREFIX : WEB_SOCKET_URI_PREFIX;
            var    serverUri    = new Uri($"{uriPrefix}{serverEndPoint.GetIPEndPoint()}");
            string connectionID = GetConnectionID(serverUri);

            return(m_egressConnections.ContainsKey(connectionID));
        }
Example #10
0
        /// <summary>
        /// This constructor is used by client user agents or SIP elements acting in a client user agent role. When
        /// acting as a client user agent the local fields are contained in the From header and the remote fields are
        /// in the To header.
        /// </summary>
        public SIPDialogue(
            UACInviteTransaction uacInviteTransaction,
            string owner,
            string adminMemberId)
        {
            Id = Guid.NewGuid();

            CallId   = uacInviteTransaction.TransactionRequest.Header.CallId;
            RouteSet =
                (uacInviteTransaction.TransactionFinalResponse != null &&
                 uacInviteTransaction.TransactionFinalResponse.Header.RecordRoutes != null)
                    ? uacInviteTransaction.TransactionFinalResponse.Header.RecordRoutes.Reversed()
                    : null;
            LocalUserField  = uacInviteTransaction.TransactionFinalResponse.Header.From.FromUserField;
            LocalTag        = uacInviteTransaction.TransactionFinalResponse.Header.From.FromTag;
            RemoteUserField = uacInviteTransaction.TransactionFinalResponse.Header.To.ToUserField;
            RemoteTag       = uacInviteTransaction.TransactionFinalResponse.Header.To.ToTag;
            CSeq            = uacInviteTransaction.TransactionRequest.Header.CSeq;
            CDRId           = (uacInviteTransaction.CDR != null) ? uacInviteTransaction.CDR.CDRId : Guid.Empty;
            Owner           = owner;
            AdminMemberId   = adminMemberId;
            ContentType     = uacInviteTransaction.TransactionRequest.Header.ContentType;
            SDP             = uacInviteTransaction.TransactionRequest.Body;
            RemoteSDP       = uacInviteTransaction.TransactionFinalResponse.Body;
            Inserted        = DateTimeOffset.UtcNow;
            Direction       = SIPCallDirection.Out;

            // Set the dialogue remote target and take care of mangling if an upstream proxy has indicated it's required.
            if (uacInviteTransaction.TransactionFinalResponse != null)
            {
                RemoteTarget = new SIPURI(uacInviteTransaction.TransactionRequest.URI.Scheme,
                                          uacInviteTransaction.TransactionFinalResponse.RemoteSIPEndPoint.CopyOf());
            }
            else
            {
                RemoteTarget = new SIPURI(uacInviteTransaction.TransactionRequest.URI.Scheme,
                                          uacInviteTransaction.TransactionRequest.RemoteSIPEndPoint.CopyOf());
            }

            ProxySendFrom = uacInviteTransaction.TransactionFinalResponse.Header.ProxyReceivedOn;
            if (uacInviteTransaction.TransactionFinalResponse.Header.Contact != null &&
                uacInviteTransaction.TransactionFinalResponse.Header.Contact.Count > 0)
            {
                RemoteTarget = uacInviteTransaction.TransactionFinalResponse.Header.Contact[0].ContactURI.CopyOf();
                if (!uacInviteTransaction.TransactionFinalResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                {
                    // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                    // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                    if (RouteSet == null && IPSocket.IsPrivateAddress(RemoteTarget.Host))
                    {
                        SIPEndPoint remoteUASSIPEndPoint =
                            SIPEndPoint.ParseSIPEndPoint(uacInviteTransaction.TransactionFinalResponse.Header
                                                         .ProxyReceivedFrom);
                        RemoteTarget.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                    }
                }
            }
        }
Example #11
0
        public SIPURI(SIPSchemesEnum scheme, SIPEndPoint sipEndPoint)
        {
            Scheme = scheme;
            Host   = sipEndPoint.GetIPEndPoint().ToString();

            if (sipEndPoint.Protocol != SIPProtocolsEnum.udp && scheme != SIPSchemesEnum.sips)
            {
                Parameters.Set(m_uriParamTransportKey, sipEndPoint.Protocol.ToString());
            }
        }
Example #12
0
        private void UACInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                // BranchId for 2xx responses needs to be a new one, non-2xx final responses use same one as original request.
                SIPRequest ackRequest = null;
                if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode < 299)
                {
                    if (sipResponse.Header.To != null)
                    {
                        m_remoteTag = sipResponse.Header.To.ToTag;
                    }

                    SIPURI ackURI = m_transactionRequest.URI;
                    if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
                    {
                        ackURI = sipResponse.Header.Contact[0].ContactURI;
                        // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                        if ((sipResponse.Header.RecordRoutes == null || sipResponse.Header.RecordRoutes.Length == 0) &&
                            IPSocket.IsPrivateAddress(ackURI.Host) && !sipResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                        {
                            // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                            SIPEndPoint remoteUASSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(sipResponse.Header.ProxyReceivedFrom);
                            ackURI.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                        }
                    }

                    // ACK for 2xx response needs to be a new transaction and gets routed based on SIP request fields.
                    ackRequest = GetNewTransactionACKRequest(sipResponse, ackURI, LocalSIPEndPoint);
                    base.SendRequest(ackRequest);
                }
                else
                {
                    // ACK for non 2xx response is part of the INVITE transaction and gets routed to the same endpoint as the INVITE.
                    ackRequest = GetInTransactionACKRequest(sipResponse, m_transactionRequest.URI, LocalSIPEndPoint);
                    base.SendRequest(RemoteEndPoint, ackRequest);
                }

                if (UACInviteTransactionFinalResponseReceived != null)
                {
                    UACInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Answered(sipResponse.StatusCode, sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception UACInviteTransaction_TransactionFinalResponseReceived. " + excp.Message);
            }
        }
        public override Task <SocketError> SendAsync(SIPEndPoint dstEndPoint, byte[] buffer, string connectionIDHint)
        {
            if (dstEndPoint == null)
            {
                throw new ArgumentException("dstEndPoint",
                                            "An empty destination was specified to Send in SIPUDPChannel.");
            }
            else if (buffer == null || buffer.Length == 0)
            {
                throw new ArgumentException("buffer",
                                            "The buffer must be set and non empty for Send in SIPUDPChannel.");
            }

            try
            {
                IPEndPoint dstIPEndPoint = dstEndPoint.GetIPEndPoint();

                if (m_sendFailures.ContainsKey(dstEndPoint.GetIPEndPoint()))
                {
                    return(Task.FromResult(SocketError.ConnectionRefused));
                }
                else
                {
                    m_udpSocket.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, dstIPEndPoint, EndSendTo,
                                            dstEndPoint);
                    return(Task.FromResult(SocketError.Success));
                }
            }
            catch (ObjectDisposedException) // Thrown when socket is closed. Can be safely ignored.
            {
                return(Task.FromResult(SocketError.Disconnecting));
            }
            catch (SocketException sockExcp)
            {
                return(Task.FromResult(sockExcp.SocketErrorCode));
            }
            catch (Exception excp)
            {
                Logger.Logger.Error($"Exception SIPUDPChannel.SendAsync. ->{excp}");
                return(Task.FromResult(SocketError.Fault));
            }
        }
Example #14
0
        public SIPUDPChannel(IPEndPoint endPoint)
        {
            m_localSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, endPoint);

            m_sipConn = new UdpClient(m_localSIPEndPoint.GetIPEndPoint());
            if (m_localSIPEndPoint.Port == 0)
            {
                m_localSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, (IPEndPoint)m_sipConn.Client.LocalEndPoint);
            }
            logger.LogDebug("SIPUDPChannel listener created " + m_localSIPEndPoint.GetIPEndPoint() + ".");

            m_mainLoop = Task.Run(Listen);
        }
Example #15
0
        /// <summary>
        /// Sends the ACK request as a new transaction. This is required for 2xx responses.
        /// </summary>
        /// <param name="content">The optional content body for the ACK request.</param>
        /// <param name="contentType">The optional content type.</param>
        private SIPRequest Get2xxAckRequest(string content, string contentType)
        {
            try
            {
                var sipResponse = m_transactionFinalResponse;

                if (sipResponse.Header.To != null)
                {
                    m_remoteTag = sipResponse.Header.To.ToTag;
                }

                SIPURI ackURI = m_transactionRequest.URI;
                if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
                {
                    ackURI = sipResponse.Header.Contact[0].ContactURI;
                    // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                    if ((sipResponse.Header.RecordRoutes == null || sipResponse.Header.RecordRoutes.Length == 0) &&
                        IPSocket.IsPrivateAddress(ackURI.Host) &&
                        !sipResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                    {
                        // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                        SIPEndPoint remoteUASSIPEndPoint =
                            SIPEndPoint.ParseSIPEndPoint(sipResponse.Header.ProxyReceivedFrom);
                        ackURI.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                    }
                }

                // ACK for 2xx response needs to be a new transaction and gets routed based on SIP request fields.
                var ackRequest = GetNewTransactionAcknowledgeRequest(SIPMethodsEnum.ACK, sipResponse, ackURI);

                if (content.NotNullOrBlank())
                {
                    ackRequest.Body = content;
                    ackRequest.Header.ContentLength = ackRequest.Body.Length;
                    ackRequest.Header.ContentType   = contentType;
                }

                return(ackRequest);
            }
            catch (Exception excp)
            {
                Logger.Logger.Error($"Exception Get2xxAckRequest. ->{excp.Message}");
                throw excp;
            }
        }
Example #16
0
        /// <summary>
        /// This constructor is used by server user agents or SIP elements acting in a server user agent role. When
        /// acting as a server user agent the local fields are contained in the To header and the remote fields are
        /// in the From header.
        /// </summary>
        public SIPDialogue(
            UASInviteTransaction uasInviteTransaction)
        {
            Id = Guid.NewGuid();

            CallId = uasInviteTransaction.TransactionRequest.Header.CallId;
            //RouteSet = (uasInviteTransaction.TransactionFinalResponse != null && uasInviteTransaction.TransactionFinalResponse.Header.RecordRoutes != null) ? uasInviteTransaction.TransactionFinalResponse.Header.RecordRoutes.Reversed() : null;
            RouteSet        = (uasInviteTransaction.TransactionFinalResponse != null && uasInviteTransaction.TransactionFinalResponse.Header.RecordRoutes != null) ? uasInviteTransaction.TransactionFinalResponse.Header.RecordRoutes : null;
            LocalUserField  = uasInviteTransaction.TransactionFinalResponse.Header.To.ToUserField;
            LocalTag        = uasInviteTransaction.TransactionFinalResponse.Header.To.ToTag;
            RemoteUserField = uasInviteTransaction.TransactionFinalResponse.Header.From.FromUserField;
            RemoteTag       = uasInviteTransaction.TransactionFinalResponse.Header.From.FromTag;
            CSeq            = uasInviteTransaction.TransactionRequest.Header.CSeq;
            CDRId           = uasInviteTransaction.CDR != null ? uasInviteTransaction.CDR.CDRId : Guid.Empty;
            ContentType     = uasInviteTransaction.TransactionFinalResponse.Header.ContentType;
            SDP             = uasInviteTransaction.TransactionFinalResponse.Body;
            RemoteSDP       = uasInviteTransaction.TransactionRequest.Body ?? uasInviteTransaction.AckRequest.Body;
            Inserted        = DateTime.UtcNow;
            Direction       = SIPCallDirection.In;

            if (uasInviteTransaction.m_gotPrack)
            {
                CSeq++;
            }

            RemoteTarget  = new SIPURI(uasInviteTransaction.TransactionRequest.URI.Scheme, uasInviteTransaction.TransactionRequest.RemoteSIPEndPoint.CopyOf());
            ProxySendFrom = uasInviteTransaction.TransactionRequest.Header.ProxyReceivedOn;
            if (uasInviteTransaction.TransactionRequest.Header.Contact != null && uasInviteTransaction.TransactionRequest.Header.Contact.Count > 0)
            {
                RemoteTarget = uasInviteTransaction.TransactionRequest.Header.Contact[0].ContactURI.CopyOf();
                if (!uasInviteTransaction.TransactionRequest.Header.ProxyReceivedFrom.IsNullOrBlank())
                {
                    // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                    // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                    if (RouteSet == null && IPSocket.IsPrivateAddress(RemoteTarget.Host))
                    {
                        SIPEndPoint remoteUASSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(uasInviteTransaction.TransactionRequest.Header.ProxyReceivedFrom);
                        RemoteTarget.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                    }
                }
            }
        }
        public void Send2xxAckRequest(string content, string contentType)
        {
            var sipResponse = m_transactionFinalResponse;

            if (sipResponse.Header.To != null)
            {
                m_remoteTag = sipResponse.Header.To.ToTag;
            }

            SIPURI ackURI = m_transactionRequest.URI;

            if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
            {
                ackURI = sipResponse.Header.Contact[0].ContactURI;
                // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                if ((sipResponse.Header.RecordRoutes == null || sipResponse.Header.RecordRoutes.Length == 0) &&
                    IPSocket.IsPrivateAddress(ackURI.Host) && !sipResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                {
                    // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                    SIPEndPoint remoteUASSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(sipResponse.Header.ProxyReceivedFrom);
                    ackURI.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                }
            }

            // ACK for 2xx response needs to be a new transaction and gets routed based on SIP request fields.
            var ackRequest = GetNewTransactionACKRequest(sipResponse, ackURI, LocalSIPEndPoint);

            if (content.NotNullOrBlank())
            {
                ackRequest.Body = content;
                ackRequest.Header.ContentLength = ackRequest.Body.Length;
                ackRequest.Header.ContentType   = contentType;
            }

            base.SendRequest(ackRequest);
        }
Example #18
0
        /// <summary>
        /// Generates the ACK or PRACK request to acknowledge a response. This method generates the ACK requests
        /// for INVITE 2xx and PRACK for 1xx responses. The request needs to be sent as part of a new transaction.
        /// Note for constructing the ACK for INVITE >= 300 responses is <seealso cref="GetInTransactionACKRequest"/>.
        /// </summary>
        /// <param name="ackResponse">The response being acknowledged.</param>
        /// <param name="ackMethod">The acknowledgement request method, either ACK or PRACK.</param>
        /// <param name="cseq">The SIP CSeq header value to set on the acknowledge request.</param>
        /// <param name="content">The optional content body for the ACK request.</param>
        /// <param name="contentType">The optional content type.</param>
        private SIPRequest GetAcknowledgeRequest(SIPResponse ackResponse, SIPMethodsEnum ackMethod, int cseq, string content, string contentType)
        {
            if (ackResponse.Header.To != null)
            {
                m_remoteTag = ackResponse.Header.To.ToTag;
            }

            SIPURI requestURI = m_transactionRequest.URI.CopyOf();

            if (ackResponse.Header.Contact?.Count > 0)
            {
                requestURI = ackResponse.Header.Contact[0].ContactURI;
                // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's
                // in a Record-Route header that's its problem.
                if ((ackResponse.Header.RecordRoutes == null || ackResponse.Header.RecordRoutes.Length == 0) &&
                    IPSocket.IsPrivateAddress(requestURI.Host) && !ackResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                {
                    // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should
                    // mangle the contact.
                    SIPEndPoint remoteUASSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(ackResponse.Header.ProxyReceivedFrom);
                    requestURI.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                }
            }

            // ACK for 2xx response needs to be a new transaction and gets routed based on SIP request fields.
            var ackRequest = GetNewTxACKRequest(ackMethod, cseq, ackResponse, requestURI);

            if (content.NotNullOrBlank())
            {
                ackRequest.Body = content;
                ackRequest.Header.ContentLength = ackRequest.Body.Length;
                ackRequest.Header.ContentType   = contentType;
            }

            return(ackRequest);
        }
            public void AckRecognitionUnitTest()
            {
                SIPTransport clientTransport = null;
                SIPTransport serverTransport = null;

                try
                {
                    SIPTransactionEngine clientEngine = new SIPTransactionEngine();     // Client side of the INVITE.
                    SIPEndPoint clientEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(IPAddress.Loopback, 12013));
                    clientTransport = new SIPTransport(MockSIPDNSManager.Resolve, clientEngine, new SIPUDPChannel(clientEndPoint.GetIPEndPoint()), false);
                    SetTransportTraceEvents(clientTransport);

                    SIPTransactionEngine serverEngine = new SIPTransactionEngine();     // Server side of the INVITE.
                    UASInviteTransaction serverTransaction = null;
                    SIPEndPoint serverEndPoint = new SIPEndPoint(new IPEndPoint(IPAddress.Loopback, 12014));
                    serverTransport = new SIPTransport(MockSIPDNSManager.Resolve, serverEngine, new SIPUDPChannel(serverEndPoint.GetIPEndPoint()), false);
                    SetTransportTraceEvents(serverTransport);
                    serverTransport.SIPTransportRequestReceived += (localEndPoint, remoteEndPoint, sipRequest) =>
                    {
                        Console.WriteLine("Server Transport Request In: " + sipRequest.Method + ".");
                        serverTransaction = serverTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localEndPoint, null);
                        SetTransactionTraceEvents(serverTransaction);
                        serverTransaction.GotRequest(localEndPoint, remoteEndPoint, sipRequest);
                    };

                    SIPURI dummyURI = SIPURI.ParseSIPURI("sip:dummy@" + serverEndPoint);
                    SIPRequest inviteRequest = GetDummyINVITERequest(dummyURI);
                    inviteRequest.LocalSIPEndPoint = clientTransport.GetDefaultTransportContact(SIPProtocolsEnum.udp);

                    // Send the invite to the server side.
                    UACInviteTransaction clientTransaction = new UACInviteTransaction(clientTransport, inviteRequest, serverEndPoint, clientEndPoint, null);
                    SetTransactionTraceEvents(clientTransaction);
                    clientEngine.AddTransaction(clientTransaction);
                    clientTransaction.SendInviteRequest(serverEndPoint, inviteRequest);

                    Thread.Sleep(500);

                    Assert.IsTrue(clientTransaction.TransactionState == SIPTransactionStatesEnum.Completed, "Client transaction in incorrect state.");
                    Assert.IsTrue(serverTransaction.TransactionState == SIPTransactionStatesEnum.Confirmed, "Server transaction in incorrect state.");
                }
                finally
                {
                    if (clientTransport != null)
                    {
                        clientTransport.Shutdown();
                    }

                    if (serverTransport != null)
                    {
                        serverTransport.Shutdown();
                    }
                }
            }
Example #20
0
 /// <summary>
 /// Checks whether there is an existing client web socket connection for a remote end point.
 /// </summary>
 /// <param name="remoteEndPoint">The remote end point to check for an existing connection.</param>
 /// <returns>True if there is a connection or false if not.</returns>
 public override bool HasConnection(SIPEndPoint remoteEndPoint)
 {
     return(m_ingressConnections.Any(x => x.Value.Context.UserEndPoint.Equals(remoteEndPoint.GetIPEndPoint())));
 }
Example #21
0
        private void SIPTCPMessageReceived(SIPChannel channel, SIPEndPoint remoteEndPoint, byte[] buffer)
        {
            if (m_connectionFailures.ContainsKey(remoteEndPoint.GetIPEndPoint().ToString()))
            {
                m_connectionFailures.Remove(remoteEndPoint.GetIPEndPoint().ToString());
            }

            if (m_connectionFailureStrikes.ContainsKey(remoteEndPoint.GetIPEndPoint().ToString()))
            {
                m_connectionFailureStrikes.Remove(remoteEndPoint.GetIPEndPoint().ToString());
            }

            if (SIPMessageReceived != null)
            {
                SIPMessageReceived(channel, remoteEndPoint, buffer);
            }
        }
Example #22
0
        public SIPURI(SIPSchemesEnum scheme, SIPEndPoint sipEndPoint)
        {
            Scheme = scheme;
            Host = sipEndPoint.GetIPEndPoint().ToString();

            if (sipEndPoint.Protocol != SIPProtocolsEnum.udp)
            {
                Parameters.Set(m_uriParamTransportKey, sipEndPoint.Protocol.ToString());
            }
        }
Example #23
0
        /// <summary>
        /// Used to create a SIP response when it was not possible to parse the incoming SIP request.
        /// </summary>
        public SIPResponse GetResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponseStatusCodesEnum responseCode, string reasonPhrase)
        {
            try
            {
                if (localSIPEndPoint == null)
                {
                    localSIPEndPoint = GetDefaultSIPEndPoint();
                }

                SIPResponse response = new SIPResponse(responseCode, reasonPhrase, localSIPEndPoint);
                SIPSchemesEnum sipScheme = (localSIPEndPoint.Protocol == SIPProtocolsEnum.tls) ? SIPSchemesEnum.sips : SIPSchemesEnum.sip;
                SIPFromHeader from = new SIPFromHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                SIPToHeader to = new SIPToHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                int cSeq = 1;
                string callId = CallProperties.CreateNewCallId();
                response.Header = new SIPHeader(from, to, cSeq, callId);
                response.Header.CSeqMethod = SIPMethodsEnum.NONE;
                response.Header.Vias.PushViaHeader(new SIPViaHeader(new SIPEndPoint(localSIPEndPoint.Protocol, remoteEndPoint.GetIPEndPoint()), CallProperties.CreateBranchId()));
                response.Header.MaxForwards = Int32.MinValue;
                response.Header.Allow = ALLOWED_SIP_METHODS;

                return response;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPTransport GetResponse. " + excp.Message);
                throw;
            }
        }
Example #24
0
        /// <summary>
        /// Allows raw bytes to be sent from one of the SIPTransport sockets. This should not be used for SIP payloads and instead is
        /// provided to allow other types of payloads to be multi-plexed on the SIP socket. Examples are sending NAT keep alives and
        /// STUN responses where it's useful to use the same socket as the SIP packets.
        /// </summary>
        public void SendRaw(SIPEndPoint localSIPEndPoint, SIPEndPoint destinationEndPoint, byte[] buffer)
        {
            if (destinationEndPoint != null && destinationEndPoint.Address.Equals(BlackholeAddress))
            {
                // Ignore packet, it's destined for the blackhole.
                return;
            }

            if (m_sipChannels.Count == 0)
            {
                throw new ApplicationException("No channels are configured in the SIP transport layer. The data could not be sent.");
            }

            SIPChannel sendSIPChannel = FindSIPChannel(localSIPEndPoint);
            if (sendSIPChannel != null)
            {
                sendSIPChannel.Send(destinationEndPoint.GetIPEndPoint(), buffer);
            }
            else
            {
                logger.Warn("No SIPChannel could be found for " + localSIPEndPoint + " in SIPTransport.SendRaw, sending to " + destinationEndPoint.ToString() + ".");
                //logger.Warn(Encoding.UTF8.GetString(buffer));
            }
        }
Example #25
0
        private void SendResponse(SIPChannel sipChannel, SIPEndPoint dstEndPoint, SIPResponse sipResponse)
        {
            try
            {
                if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress))
                {
                    // Ignore packet, it's destined for the blackhole.
                    return;
                }

                if (m_sipChannels.Count == 0)
                {
                    throw new ApplicationException("No channels are configured in the SIP transport layer. The response could not be sent.");
                }

                sipResponse.Header.ContentLength = (sipResponse.Body.NotNullOrBlank()) ? Encoding.UTF8.GetByteCount(sipResponse.Body) : 0;
                sipChannel.Send(dstEndPoint.GetIPEndPoint(), Encoding.UTF8.GetBytes(sipResponse.ToString()));

                if (SIPRequestOutTraceEvent != null)
                {
                    FireSIPResponseOutTraceEvent(sipChannel.SIPChannelEndPoint, dstEndPoint, sipResponse);
                }
            }
            catch (ApplicationException appExcp)
            {
                logger.Warn("ApplicationException SIPTransport SendResponse. " + appExcp.Message);
            }
        }
Example #26
0
        private void SIPMessageReceived(SIPChannel sipChannel, SIPEndPoint remoteEndPoint, byte[] buffer)
        {
            string rawSIPMessage = null;

            try
            {
                if (buffer != null && buffer.Length > 0)
                {
                    if ((buffer[0] == 0x0 || buffer[0] == 0x1) && buffer.Length >= 20)
                    {
                        // Treat any messages that cannot be SIP as STUN requests.
                        if (STUNRequestReceived != null)
                        {
                            STUNRequestReceived(sipChannel.SIPChannelEndPoint.GetIPEndPoint(), remoteEndPoint.GetIPEndPoint(), buffer, buffer.Length);

            #if !SILVERLIGHT
                            if (PerformanceMonitorPrefix != null)
                            {
                                SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_STUN_REQUESTS_PER_SECOND_SUFFIX);
                            }
            #endif
                        }
                    }
                    else
                    {
                        // Treat all messages that don't match STUN requests as SIP.
                        if (buffer.Length > SIPConstants.SIP_MAXIMUM_RECEIVE_LENGTH)
                        {
                            string rawErrorMessage = Encoding.UTF8.GetString(buffer, 0, 1024) + "\r\n..truncated";
                            FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "SIP message too large, " + buffer.Length + " bytes, maximum allowed is " + SIPConstants.SIP_MAXIMUM_RECEIVE_LENGTH + " bytes.", SIPValidationFieldsEnum.Request, rawErrorMessage);
                            SIPResponse tooLargeResponse = GetResponse(sipChannel.SIPChannelEndPoint, remoteEndPoint, SIPResponseStatusCodesEnum.MessageTooLarge, null);
                            SendResponse(tooLargeResponse);

            #if !SILVERLIGHT
                            if (PerformanceMonitorPrefix != null)
                            {
                                SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_BAD_MESSAGES_PER_SECOND_SUFFIX);
                            }
            #endif
                        }
                        else
                        {
                            rawSIPMessage = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
                            if (rawSIPMessage.IsNullOrBlank())
                            {
                                // An emptry transmission has been received. More than likely this is a NAT keep alive and can be disregarded.
                                //FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "No printable characters, length " + buffer.Length + " bytes.", SIPValidationFieldsEnum.Unknown, null);

            #if !SILVERLIGHT
                                if (PerformanceMonitorPrefix != null)
                                {
                                    // SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_BAD_MESSAGES_PER_SECOND_SUFFIX);
                                }
            #endif

                                return;
                            }
                            else if (!rawSIPMessage.Contains("SIP"))
                            {
                                FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "Missing SIP string.", SIPValidationFieldsEnum.NoSIPString, rawSIPMessage);

            #if !SILVERLIGHT
                                if (PerformanceMonitorPrefix != null)
                                {
                                    SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_BAD_MESSAGES_PER_SECOND_SUFFIX);
                                }
            #endif

                                return;
                            }

                            SIPMessage sipMessage = SIPMessage.ParseSIPMessage(rawSIPMessage, sipChannel.SIPChannelEndPoint, remoteEndPoint);

                            if (sipMessage != null)
                            {
                                if (sipMessage.SIPMessageType == SIPMessageTypesEnum.Response)
                                {
                                    #region SIP Response.

                                    try
                                    {
            #if !SILVERLIGHT
                                        if (PerformanceMonitorPrefix != null)
                                        {
                                            SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_RESPONSES_PER_SECOND_SUFFIX);
                                        }
            #endif

                                        SIPResponse sipResponse = SIPResponse.ParseSIPResponse(sipMessage);

                                        if (SIPResponseInTraceEvent != null)
                                        {
                                            FireSIPResponseInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipResponse);
                                        }

                                        if (m_transactionEngine != null && m_transactionEngine.Exists(sipResponse))
                                        {
                                            SIPTransaction transaction = m_transactionEngine.GetTransaction(sipResponse);

                                            if (transaction.TransactionState != SIPTransactionStatesEnum.Completed)
                                            {
                                                transaction.DeliveryPending = false;
                                                if (m_reliableTransmissions.ContainsKey(transaction.TransactionId))
                                                {
                                                    lock (m_reliableTransmissions)
                                                    {
                                                        m_reliableTransmissions.Remove(transaction.TransactionId);
                                                    }
                                                }
                                            }

                                            transaction.GotResponse(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipResponse);
                                        }
                                        else if (SIPTransportResponseReceived != null)
                                        {
                                            SIPTransportResponseReceived(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipResponse);
                                        }
                                    }
                                    catch (SIPValidationException sipValidationException)
                                    {
                                        //logger.Warn("Invalid SIP response from " + sipMessage.ReceivedFrom + ", " + sipResponse.ValidationError + " , ignoring.");
                                        //logger.Warn(sipMessage.RawMessage);
                                        FireSIPBadResponseInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipMessage.RawMessage, sipValidationException.SIPErrorField, sipMessage.RawMessage);
                                    }

                                    #endregion
                                }
                                else
                                {
                                    #region SIP Request.

            #if !SILVERLIGHT
                                    if (PerformanceMonitorPrefix != null)
                                    {
                                        SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_REQUESTS_PER_SECOND_SUFFIX);
                                    }
            #endif

                                    try
                                    {
                                        SIPRequest sipRequest = SIPRequest.ParseSIPRequest(sipMessage);

                                        SIPValidationFieldsEnum sipRequestErrorField = SIPValidationFieldsEnum.Unknown;
                                        string sipRequestValidationError = null;
                                        if (!sipRequest.IsValid(out sipRequestErrorField, out sipRequestValidationError))
                                        {
                                            throw new SIPValidationException(sipRequestErrorField, sipRequestValidationError);
                                        }

                                        if (SIPRequestInTraceEvent != null)
                                        {
                                            FireSIPRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipRequest);
                                        }

                                        // Stateful cores will create transactions once they get the request and the transport layer will use those transactions.
                                        // Stateless cores will not be affected by this step as the transaction layer will always return false.
                                        SIPTransaction requestTransaction = (m_transactionEngine != null) ? m_transactionEngine.GetTransaction(sipRequest) : null;
                                        if (requestTransaction != null)
                                        {
                                            if (requestTransaction.TransactionState == SIPTransactionStatesEnum.Completed && sipRequest.Method != SIPMethodsEnum.ACK)
                                            {
                                                logger.Warn("Resending final response for " + sipRequest.Method + ", " + sipRequest.URI.ToString() + ", cseq=" + sipRequest.Header.CSeq + ".");
                                                requestTransaction.RetransmitFinalResponse();
                                            }
                                            else if (sipRequest.Method == SIPMethodsEnum.ACK)
                                            {
                                                //logger.Debug("ACK received for " + requestTransaction.TransactionRequest.URI.ToString() + ".");

                                                if (requestTransaction.TransactionState == SIPTransactionStatesEnum.Completed)
                                                {
                                                    //logger.Debug("ACK received for INVITE, setting state to Confirmed, " + sipRequest.URI.ToString() + " from " + sipRequest.Header.From.FromURI.User + " " + remoteEndPoint + ".");
                                                    //requestTransaction.UpdateTransactionState(SIPTransactionStatesEnum.Confirmed);
                                                    requestTransaction.ACKReceived(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipRequest);
                                                }
                                                else if (requestTransaction.TransactionState == SIPTransactionStatesEnum.Confirmed)
                                                {
                                                    // ACK retransmit, ignore as a previous ACK was received and the transaction has already been confirmed.
                                                }
                                                else
                                                {
                                                    //logger.Warn("ACK recieved from " + remoteEndPoint.ToString() + " on " + requestTransaction.TransactionState + " transaction, ignoring.");
                                                    FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "ACK recieved on " + requestTransaction.TransactionState + " transaction, ignoring.", SIPValidationFieldsEnum.Request, null);
                                                }
                                            }
                                            else
                                            {
                                                logger.Warn("Transaction already exists, ignoring duplicate request, " + sipRequest.Method + " " + sipRequest.URI.ToString() + ".");
                                                //FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "Transaction already exists, ignoring duplicate request, " + sipRequest.Method + " " + sipRequest.URI.ToString() + " from " + remoteEndPoint + ".", SIPValidationFieldsEnum.Request);
                                            }
                                        }
                                        else if (SIPTransportRequestReceived != null)
                                        {
                                            // This is a new SIP request and if the validity checks are passed it will be handed off to all subscribed new request listeners.

                                            #region Check for invalid SIP requests.

                                            if (sipRequest.Header.MaxForwards == 0 && sipRequest.Method != SIPMethodsEnum.OPTIONS)
                                            {
                                                // Check the MaxForwards value, if equal to 0 the request must be discarded. If MaxForwards is -1 it indicates the
                                                // header was not present in the request and that the MaxForwards check should not be undertaken.
                                                //logger.Warn("SIPTransport responding with TooManyHops due to 0 MaxForwards.");
                                                FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "Zero MaxForwards on " + sipRequest.Method + " " + sipRequest.URI.ToString() + " from " + sipRequest.Header.From.FromURI.User + " " + remoteEndPoint.ToString(), SIPValidationFieldsEnum.Request, sipRequest.ToString());
                                                SIPResponse tooManyHops = GetResponse(sipRequest, SIPResponseStatusCodesEnum.TooManyHops, null);
                                                SendResponse(sipChannel, tooManyHops);
                                                return;
                                            }
                                            /*else if (sipRequest.IsLoop(sipChannel.SIPChannelEndPoint.SocketEndPoint.Address.ToString(), sipChannel.SIPChannelEndPoint.SocketEndPoint.Port, sipRequest.CreateBranchId()))
                                            {
                                                //logger.Warn("SIPTransport Dropping looped request.");
                                                FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "Dropping looped request, " + sipRequest.Method + " " + sipRequest.URI.ToString() + " from " + sipRequest.Header.From.FromURI.User + " " + IPSocket.GetSocketString(remoteEndPoint), SIPValidationFieldsEnum.Request);
                                                SIPResponse loopResponse = GetResponse(sipRequest, SIPResponseStatusCodesEnum.LoopDetected, null);
                                                SendResponse(loopResponse);
                                                return;
                                            }*/

                                            #endregion

                                            #region Route pre-processing.

                                            if (sipRequest.Header.Routes.Length > 0)
                                            {
                                                PreProcessRouteInfo(sipRequest);
                                            }

                                            #endregion

                                            // Request has passed validity checks, adjust the client Via header to reflect the socket the request was received on.
                                            //SIPViaHeader originalTopViaHeader = sipRequest.Header.Via.TopViaHeader;
                                            sipRequest.Header.Vias.UpateTopViaHeader(remoteEndPoint.GetIPEndPoint());

                                            // Stateful cores should create a transaction once they receive this event, stateless cores should not.
                                            SIPTransportRequestReceived(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipRequest);
                                        }
                                    }
                                    catch (SIPValidationException sipRequestExcp)
                                    {
                                        FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipRequestExcp.Message, sipRequestExcp.SIPErrorField, sipMessage.RawMessage);
                                        SIPResponse errorResponse = GetResponse(sipChannel.SIPChannelEndPoint, remoteEndPoint, sipRequestExcp.SIPResponseErrorCode, sipRequestExcp.Message);
                                        SendResponse(sipChannel, errorResponse);
                                    }

                                    #endregion
                                }
                            }
                            else
                            {
                                FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "Not parseable as SIP message.", SIPValidationFieldsEnum.Unknown, rawSIPMessage);

            #if !SILVERLIGHT
                                if (PerformanceMonitorPrefix != null)
                                {
                                    SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_BAD_MESSAGES_PER_SECOND_SUFFIX);
                                }
            #endif
                            }
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                FireSIPBadRequestInTraceEvent(sipChannel.SIPChannelEndPoint, remoteEndPoint, "Exception SIPTransport. " + excp.Message, SIPValidationFieldsEnum.Unknown, rawSIPMessage);

            #if !SILVERLIGHT
                if (PerformanceMonitorPrefix != null)
                {
                    SIPSorceryPerformanceMonitor.IncrementCounter(PerformanceMonitorPrefix + SIPSorceryPerformanceMonitor.SIP_TRANSPORT_SIP_BAD_MESSAGES_PER_SECOND_SUFFIX);
                }
            #endif
            }
        }
Example #27
0
        private void EndReceiveFrom(IAsyncResult ar)
        {
            EndPoint remoteEP = (ListeningIPAddress.AddressFamily == AddressFamily.InterNetwork) ? new IPEndPoint(IPAddress.Any, 0) : new IPEndPoint(IPAddress.IPv6Any, 0);

            try
            {
                if (!Closed)
                {
                    SocketFlags flags = SocketFlags.None;

                    int bytesRead = m_udpSocket.EndReceiveFrom(ar, ref remoteEP);

                    if (flags == SocketFlags.Truncated)
                    {
                        logger.LogWarning($"The message was too large to fit into the specified buffer and was truncated.");
                    }

                    if (bytesRead > 0)
                    {
                        // In addition to the note in the RTPChannel class about IPPacketInformation some versions of the mono runtime
                        // on Android are unable to use Begin/EndReceiveMessageFrom.
                        // See https://github.com/sipsorcery/sipsorcery/issues/302.
                        // Those specific Begin/End calls were being used to get the packet information and identify which local
                        // IP address a receive occurred on. Upon investigation it does not seem that the local IP address is
                        // required on incoming SIP packets. The outgoing socket was previously chosen based on this address but
                        // subsequent to https://github.com/sipsorcery/sipsorcery/issues/97 the mechanism has changed.
                        // The calls have been changed to Begin/EndReceiveFrom in order to support Android. The consequence is the localEndPoint
                        // parameter for the SIPMessageReceived will have an IP address of 0.0.0.0 or [::0] if wildcard addresses are in use.

                        SIPEndPoint remoteEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, remoteEP as IPEndPoint, ID, null);
                        //SIPEndPoint localEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(packetInfo.Address, Port), ID, null);
                        SIPEndPoint localEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(ListeningIPAddress, Port), ID, null);
                        byte[]      sipMsgBuffer  = new byte[bytesRead];
                        Buffer.BlockCopy(m_recvBuffer, 0, sipMsgBuffer, 0, bytesRead);
                        SIPMessageReceived?.Invoke(this, localEndPoint, remoteEndPoint, sipMsgBuffer);
                    }
                }
            }
            catch (SocketException sockExcp)
            {
                if (remoteEP != null)
                {
                    // Note the SIPEndPoint is being used to take care of any IPv4 mapped to IPv6 addresses.
                    SIPEndPoint remSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, remoteEP as IPEndPoint);

                    // This exception can occur as the result of a Send operation. It's caused by an ICMP packet from a remote host
                    // rejecting an incoming UDP packet. If that happens we want to stop further sends to the socket for a short period.
                    logger.LogWarning(sockExcp, $"SocketException SIPUDPChannel EndReceiveFrom from {remSIPEndPoint} ({sockExcp.ErrorCode}). {sockExcp.Message}");

                    m_sendFailures.TryAdd(remSIPEndPoint.GetIPEndPoint(), DateTime.Now);
                }
                else
                {
                    logger.LogError($"SocketException SIPUDPChannel EndReceiveFrom. {sockExcp}");
                }
            }
            catch (ObjectDisposedException) // Thrown when socket is closed. Can be safely ignored.
            { }
            catch (Exception excp)
            {
                logger.LogError($"Exception SIPUDPChannel EndReceiveFrom. {excp}");
            }
            finally
            {
                if (!Closed)
                {
                    Receive();
                }
            }
        }
Example #28
0
        private void SendRequest(SIPChannel sipChannel, SIPEndPoint dstEndPoint, SIPRequest sipRequest)
        {
            try
            {
                if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress))
                {
                    // Ignore packet, it's destined for the blackhole.
                    return;
                }

                if (m_sipChannels.Count == 0)
                {
                    throw new ApplicationException("No channels are configured in the SIP transport layer. The request could not be sent.");
                }

                sipRequest.Header.ContentLength = (sipRequest.Body.NotNullOrBlank()) ? Encoding.UTF8.GetByteCount(sipRequest.Body) : 0;

                if (sipChannel.IsTLS)
                {
                    sipChannel.Send(dstEndPoint.GetIPEndPoint(), Encoding.UTF8.GetBytes(sipRequest.ToString()), sipRequest.URI.Host);
                }
                else
                {
                    sipChannel.Send(dstEndPoint.GetIPEndPoint(), Encoding.UTF8.GetBytes(sipRequest.ToString()));
                }

                if (SIPRequestOutTraceEvent != null)
                {
                    FireSIPRequestOutTraceEvent(sipChannel.SIPChannelEndPoint, dstEndPoint, sipRequest);
                }
            }
            catch (ApplicationException appExcp)
            {
                logger.Warn("ApplicationException SIPTransport SendRequest. " + appExcp.Message);

                SIPResponse errorResponse = GetResponse(sipRequest, SIPResponseStatusCodesEnum.InternalServerError, appExcp.Message);

                // Remove any Via headers, other than the last one, that are for sockets hosted by this process.
                while (errorResponse.Header.Vias.Length > 0)
                {
                    if (IsLocalSIPEndPoint(SIPEndPoint.ParseSIPEndPoint(errorResponse.Header.Vias.TopViaHeader.ReceivedFromAddress)))
                    {
                        errorResponse.Header.Vias.PopTopViaHeader();
                    }
                    else
                    {
                        break;
                    }
                }

                if (errorResponse.Header.Vias.Length == 0)
                {
                    logger.Warn("Could not send error response for " + appExcp.Message + " as no non-local Via headers were available.");
                }
                else
                {
                    SendResponse(errorResponse);
                }
            }
        }
Example #29
0
            public void AckRecognitionUnitTest()
            {
                SIPTransport clientTransport = null;
                SIPTransport serverTransport = null;

                try
                {
                    SIPTransactionEngine clientEngine   = new SIPTransactionEngine();   // Client side of the INVITE.
                    SIPEndPoint          clientEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(IPAddress.Loopback, 12013));
                    clientTransport = new SIPTransport(MockSIPDNSManager.Resolve, clientEngine, new SIPUDPChannel(clientEndPoint.GetIPEndPoint()), false);
                    SetTransportTraceEvents(clientTransport);

                    SIPTransactionEngine serverEngine      = new SIPTransactionEngine(); // Server side of the INVITE.
                    UASInviteTransaction serverTransaction = null;
                    SIPEndPoint          serverEndPoint    = new SIPEndPoint(new IPEndPoint(IPAddress.Loopback, 12014));
                    serverTransport = new SIPTransport(MockSIPDNSManager.Resolve, serverEngine, new SIPUDPChannel(serverEndPoint.GetIPEndPoint()), false);
                    SetTransportTraceEvents(serverTransport);
                    serverTransport.SIPTransportRequestReceived += (localEndPoint, remoteEndPoint, sipRequest) =>
                    {
                        Console.WriteLine("Server Transport Request In: " + sipRequest.Method + ".");
                        serverTransaction = serverTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localEndPoint, null);
                        SetTransactionTraceEvents(serverTransaction);
                        serverTransaction.GotRequest(localEndPoint, remoteEndPoint, sipRequest);
                    };

                    SIPURI     dummyURI      = SIPURI.ParseSIPURI("sip:dummy@" + serverEndPoint);
                    SIPRequest inviteRequest = GetDummyINVITERequest(dummyURI);
                    inviteRequest.LocalSIPEndPoint = clientTransport.GetDefaultTransportContact(SIPProtocolsEnum.udp);

                    // Send the invite to the server side.
                    UACInviteTransaction clientTransaction = new UACInviteTransaction(clientTransport, inviteRequest, serverEndPoint, clientEndPoint, null);
                    SetTransactionTraceEvents(clientTransaction);
                    clientEngine.AddTransaction(clientTransaction);
                    clientTransaction.SendInviteRequest(serverEndPoint, inviteRequest);

                    Thread.Sleep(500);

                    Assert.IsTrue(clientTransaction.TransactionState == SIPTransactionStatesEnum.Completed, "Client transaction in incorrect state.");
                    Assert.IsTrue(serverTransaction.TransactionState == SIPTransactionStatesEnum.Confirmed, "Server transaction in incorrect state.");
                }
                finally
                {
                    if (clientTransport != null)
                    {
                        clientTransport.Shutdown();
                    }

                    if (serverTransport != null)
                    {
                        serverTransport.Shutdown();
                    }
                }
            }
Example #30
0
 /// <summary>
 /// Checks whether there is an existing connection for a remote end point. Existing connections include
 /// connections that have been accepted by this channel's listener and connections that have been initiated
 /// due to sends from this channel.
 /// </summary>
 /// <param name="remoteEndPoint">The remote end point to check for an existing connection.</param>
 /// <returns>True if there is a connection or false if not.</returns>
 public override bool HasConnection(SIPEndPoint remoteEndPoint)
 {
     return(m_connections.Any(x => x.Value.RemoteEndPoint.Equals(remoteEndPoint.GetIPEndPoint())));
 }
Example #31
0
        /// <summary>
        /// Used to create a SIP response for a request when it was not possible to parse the incoming SIP request.
        /// The response generated by this method may or may not make it back to the requester. Because the SIP
        /// request could not be parsed there are no Via headers available and without those the return network
        /// path is missing. Instead a new Via header is generated that may get through if the requester is only
        /// one SIP hop away.
        /// </summary>
        /// <param name="localSIPEndPoint">The local SIP end point the request was received on.</param>
        /// <param name="remoteSIPEndPoint">The remote SIP end point the request was received on.</param>
        /// <param name="responseCode">The response code to set on the response.</param>
        /// <param name="reasonPhrase">Optional reason phrase to set on the response (keep short).</param>
        public static SIPResponse GetResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteSIPEndPoint, SIPResponseStatusCodesEnum responseCode, string reasonPhrase)
        {
            try
            {
                SIPResponse response = new SIPResponse(responseCode, reasonPhrase);
                response.SetSendFromHints(localSIPEndPoint);
                SIPSchemesEnum sipScheme = (localSIPEndPoint.Protocol == SIPProtocolsEnum.tls) ? SIPSchemesEnum.sips : SIPSchemesEnum.sip;
                SIPFromHeader  from      = new SIPFromHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                SIPToHeader    to        = new SIPToHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                int            cSeq      = 1;
                string         callId    = CallProperties.CreateNewCallId();
                response.Header            = new SIPHeader(from, to, cSeq, callId);
                response.Header.CSeqMethod = SIPMethodsEnum.NONE;
                response.Header.Vias.PushViaHeader(new SIPViaHeader(new SIPEndPoint(localSIPEndPoint.Protocol, remoteSIPEndPoint.GetIPEndPoint()), CallProperties.CreateBranchId()));
                response.Header.MaxForwards = Int32.MinValue;
                response.Header.Allow       = m_allowedSIPMethods;

                return(response);
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPResponse.GetResponse. " + excp.Message);
                throw;
            }
        }
        /// <summary>
        /// Attempts a send to a remote web socket server. If there is an existing connection it will be used
        /// otherwise an attempt will made to establish a new one.
        /// </summary>
        /// <param name="serverEndPoint">The remote web socket server URI to send to.</param>
        /// <param name="buffer">The data buffer to send.</param>
        /// <returns>A success value or an error for failure.</returns>
        private async Task <SocketError> SendAsync(SIPEndPoint serverEndPoint, byte[] buffer)
        {
            try
            {
                string uriPrefix = (serverEndPoint.Protocol == SIPProtocolsEnum.wss)
                    ? WEB_SOCKET_SECURE_URI_PREFIX
                    : WEB_SOCKET_URI_PREFIX;
                var serverUri = new Uri($"{uriPrefix}{serverEndPoint.GetIPEndPoint()}");

                string connectionID = GetConnectionID(serverUri);
                serverEndPoint.ChannelID    = this.ID;
                serverEndPoint.ConnectionID = connectionID;

                if (m_egressConnections.TryGetValue(connectionID, out var conn))
                {
                    Logger.Logger.Debug(
                        $"Sending {buffer.Length} bytes on client web socket connection to {conn.ServerUri}.");

                    ArraySegment <byte> segmentBuffer = new ArraySegment <byte>(buffer);
                    await conn.Client.SendAsync(segmentBuffer, WebSocketMessageType.Text, true, m_cts.Token)
                    .ConfigureAwait(false);

                    return(SocketError.Success);
                }
                else
                {
                    // Attempt a new connection.
                    ClientWebSocket clientWebSocket = new ClientWebSocket();
                    await clientWebSocket.ConnectAsync(serverUri, m_cts.Token).ConfigureAwait(false);

                    Logger.Logger.Debug($"Successfully connected web socket client to {serverUri}.");

                    ArraySegment <byte> segmentBuffer = new ArraySegment <byte>(buffer);
                    await clientWebSocket.SendAsync(segmentBuffer, WebSocketMessageType.Text, true, m_cts.Token)
                    .ConfigureAwait(false);

                    var recvBuffer = new ArraySegment <byte>(new byte[2 * SIPStreamConnection.MaxSIPTCPMessageSize]);
                    Task <WebSocketReceiveResult> receiveTask = clientWebSocket.ReceiveAsync(recvBuffer, m_cts.Token);

                    // There's currently no way to get the socket IP end point used by the client web socket to establish
                    // the connection. Instead provide a dummy local end point that has as much of the information as we can.
                    IPEndPoint localEndPoint =
                        new IPEndPoint(
                            (serverEndPoint.Address.AddressFamily == AddressFamily.InterNetwork)
                                ? IPAddress.Any
                                : IPAddress.IPv6Any, 0);
                    SIPEndPoint localSIPEndPoint =
                        new SIPEndPoint(serverEndPoint.Protocol, localEndPoint, this.ID, connectionID);

                    ClientWebSocketConnection newConn = new ClientWebSocketConnection
                    {
                        LocalEndPoint  = localSIPEndPoint,
                        ServerUri      = serverUri,
                        RemoteEndPoint = serverEndPoint,
                        ConnectionID   = connectionID,
                        ReceiveBuffer  = recvBuffer,
                        ReceiveTask    = receiveTask,
                        Client         = clientWebSocket
                    };

                    if (!m_egressConnections.TryAdd(connectionID, newConn))
                    {
                        Logger.Logger.Error(
                            $"Could not add web socket client connected to {serverUri} to channel collection, closing.");
                        await Close(connectionID, clientWebSocket).ConfigureAwait(false);
                    }
                    else
                    {
                        if (!m_isReceiveTaskRunning)
                        {
                            m_isReceiveTaskRunning = true;
                            _ = Task.Factory.StartNew(MonitorReceiveTasks, TaskCreationOptions.LongRunning);
                        }
                    }

                    return(SocketError.Success);
                }
            }
            catch (SocketException sockExcp)
            {
                return(sockExcp.SocketErrorCode);
            }
        }
Example #33
0
        /// <summary>
        /// Attempts to send data to the remote end point over a reliable connection. If an existing
        /// connection exists it will be used otherwise an attempt will be made to establish a new connection.
        /// </summary>
        /// <param name="dstSIPEndPoint">The remote SIP end point to send the reliable data to.</param>
        /// <param name="buffer">The data to send.</param>
        /// <param name="serverCertificateName">Optional. Only relevant for SSL streams. The common name
        /// that is expected for the remote SSL server.</param>
        /// <param name="canInitiateConnection">Indicates whether this send should initiate a connection if needed.
        /// The typical case is SIP requests can initiate new connections but responses should not. Responses should
        /// only be sent on the same TCP or TLS connection that the original request was received on.</param>
        /// <param name="connectionIDHint">Optional. The ID of the specific TCP connection to try and the send the message on.</param>
        /// <returns>If no errors SocketError.Success otherwise an error value.</returns>
        public override Task <SocketError> SendSecureAsync(
            SIPEndPoint dstSIPEndPoint,
            byte[] buffer,
            string serverCertificateName,
            bool canInitiateConnection,
            string connectionIDHint)
        {
            try
            {
                if (dstSIPEndPoint == null)
                {
                    throw new ArgumentException(nameof(dstSIPEndPoint), "An empty destination was specified to Send in SIPTCPChannel.");
                }
                if (buffer == null || buffer.Length == 0)
                {
                    throw new ApplicationException("An empty buffer was specified to Send in SIPTCPChannel.");
                }
                else if (!DisableLocalTCPSocketsCheck && NetServices.LocalIPAddresses.Contains(dstSIPEndPoint.Address) && Port == dstSIPEndPoint.Port)
                {
                    logger.LogWarning($"SIP {ProtDescr} Channel blocked Send to {dstSIPEndPoint} as it was identified as a locally hosted {ProtDescr} socket.\r\n" + SIPConstants.DEFAULT_ENCODING.GetString(buffer));
                    throw new ApplicationException($"A Send call was blocked in SIP {ProtDescr} Channel due to the destination being another local TCP socket.");
                }
                else
                {
                    IPEndPoint dstEndPoint = dstSIPEndPoint.GetIPEndPoint(m_isDualMode);

                    // Lookup a client socket that is connected to the destination. If it does not exist attempt to connect a new one.
                    SIPStreamConnection sipStreamConn = null;

                    if (connectionIDHint != null)
                    {
                        m_connections.TryGetValue(connectionIDHint, out sipStreamConn);
                    }

                    if (sipStreamConn == null && HasConnection(dstSIPEndPoint))
                    {
                        sipStreamConn = m_connections.Where(x => x.Value.RemoteSIPEndPoint.IsSocketEqual(dstSIPEndPoint)).First().Value;
                    }

                    if (sipStreamConn != null)
                    {
                        SendOnConnected(sipStreamConn, buffer);
                        return(Task.FromResult(SocketError.Success));
                    }
                    else if (canInitiateConnection)
                    {
                        return(ConnectClientAsync(dstEndPoint, buffer, serverCertificateName));
                    }
                    else
                    {
                        logger.LogWarning($"SIP {ProtDescr} Channel did not have an existing connection for send to {dstSIPEndPoint} and requested not to initiate a connection.");
                        return(Task.FromResult(SocketError.NotConnected));
                    }
                }
            }
            catch (SocketException sockExcp)
            {
                return(Task.FromResult(sockExcp.SocketErrorCode));
            }
            catch (ApplicationException)
            {
                throw;
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception SIPTCPChannel Send (sendto=>{dstSIPEndPoint}). {excp}");
                throw;
            }
        }