/// <summary>
        /// Sends response to request maker.
        /// </summary>
        /// <param name="socket">Socket which to use to send response.</param>
        /// <param name="remoteEndPoint">Remote end point where to send response. 
        /// If this value is null, Via header is used to get remote end point.
        /// </param>
        /// <param name="response">Response to send.</param>
        public void SendResponse(SocketEx socket,IPEndPoint remoteEndPoint,SIP_Response response)
        {
            /* RFC 3581 4.  Server Behavior.
                When a server attempts to send a response, it examines the topmost
                Via header field value of that response.  If the "sent-protocol"
                component indicates an unreliable unicast transport protocol, such as
                UDP, and there is no "maddr" parameter, but there is both a
                "received" parameter and an "rport" parameter, the response MUST be
                sent to the IP address listed in the "received" parameter, and the
                port in the "rport" parameter.  The response MUST be sent from the
                same address and port that the corresponding request was received on
                in order to traverse symmetric NATs.

            */

            /* RFC 3261 18.2.2 Sending Responses.
                The server transport uses the value of the top Via header field in
                order to determine where to send a response.  It MUST follow the
                following process:

                  o  If the "sent-protocol" is a reliable transport protocol such as
                     TCP or SCTP, or TLS over those, the response MUST be sent using
                     the existing connection to the source of the original request
                     that created the transaction, if that connection is still open.
                     This requires the server transport to maintain an association
                     between server transactions and transport connections.  If that
                     connection is no longer open, the server SHOULD open a
                     connection to the IP address in the "received" parameter, if
                     present, using the port in the "sent-by" value, or the default
                     port for that transport, if no port is specified.  If that
                     connection attempt fails, the server SHOULD use the procedures
                     in [4] for servers in order to determine the IP address and
                     port to open the connection and send the response to.

                  o  Otherwise, if the Via header field value contains a "maddr"
                     parameter, the response MUST be forwarded to the address listed
                     there, using the port indicated in "sent-by", or port 5060 if
                     none is present.  If the address is a multicast address, the
                     response SHOULD be sent using the TTL indicated in the "ttl"
                     parameter, or with a TTL of 1 if that parameter is not present.

                  o  Otherwise (for unreliable unicast transports), if the top Via
                     has a "received" parameter, the response MUST be sent to the
                     address in the "received" parameter, using the port indicated
                     in the "sent-by" value, or using port 5060 if none is specified
                     explicitly.  If this fails, for example, elicits an ICMP "port
                     unreachable" response, the procedures of Section 5 of [4]
                     SHOULD be used to determine where to send the response.

                  o  Otherwise, if it is not receiver-tagged, the response MUST be
                     sent to the address indicated by the "sent-by" value, using the
                     procedures in Section 5 of [4].
            */

            // TODO: Probably we can use local endpoint instead of socket. Because then we can
            //       Search right UDP connection or TCP/TLS connection.

            try{
                SIP_t_ViaParm via = response.Via.GetTopMostValue();

                // End point not specified, get it from Via.
                if(remoteEndPoint == null){
                    string host = null;
                    int    port = 5060;

                    // Use received host.
                    if(via.Received != null){
                        host = via.Received;
                    }
                    // Get sent-by host
                    else{
                        host = via.SentBy.Split(':')[0];
                    }

                    // Use rport if recevived is specified too
                    if(via.Received != null && via.RPort > 0){
                        port = via.RPort;
                    }
                    // Get port from sent-by
                    else{
                        string[] host_port = via.SentBy.Split(':');
                        if(host_port.Length == 2){
                            port = Convert.ToInt32(host_port[1]);
                        }
                    }

                    remoteEndPoint = new IPEndPoint(System.Net.Dns.GetHostAddresses(host)[0],port);
                }

                byte[] data = response.ToByteData();

                // Log
                m_pSipStack.Logger.AddWrite(data.Length,"Sending (" + data.Length + " bytes): " + socket.LocalEndPoint.ToString() + " -> " + remoteEndPoint.ToString() + "\r\n<begin>\r\n" + System.Text.Encoding.UTF8.GetString(data) + "<end>\r\n");

                // We don't have any more that socket what accepted request which response it is.
                // There are 2 known cases when no socket:
                //   1) Stateless proxy.
                //   2) Statefull proxy, but response didn't match any transaction.
                if(socket == null){
                    // UDP Multicast
                    if(via.ProtocolTransport.ToUpper() == SIP_Transport.UDP && via.Maddr != null){
                        throw new SIP_TransportException("UDP Multicast not implemented !");
                    }
                    // UDP
                    else if(via.ProtocolTransport.ToUpper() == SIP_Transport.UDP){
                        foreach(SipListeningPoint listeningPoint in m_pListeningPoints){
                            if(listeningPoint.Protocol == BindInfoProtocol.UDP){
                                listeningPoint.Socket.SendTo(data,remoteEndPoint);
                                return;
                            }
                        }

                        throw new SIP_TransportException("No UDP transport available, this never should happen !");
                    }
                    // TCP
                    else if(via.ProtocolTransport.ToUpper() == SIP_Transport.TCP){
                        SipTcpPipe pipe = GetTcpPipe(SIP_Transport.TCP,remoteEndPoint);
                        // Not existing connection, create it.
                        if(pipe == null){
                            pipe = new SipTcpPipe(this,remoteEndPoint,true);
                        }
                        pipe.SendMessage(data);
                    }
                    // TCP TLS
                    else if(via.ProtocolTransport.ToUpper() == SIP_Transport.TLS){
                        SipTcpPipe pipe = GetTcpPipe(SIP_Transport.TLS,remoteEndPoint);
                        // Not existing connection, create it.
                        if(pipe == null){
                            pipe = new SipTcpPipe(this,remoteEndPoint,true);
                        }
                        pipe.SendMessage(data);
                    }
                }
                // We have existing socket, use it.
                else{
                    if(via.ProtocolTransport.ToUpper() == SIP_Transport.UDP){
                        socket.SendTo(data,remoteEndPoint);
                    }
                    else{
                        socket.Write(data);
                    }
                }
            }
            catch(Exception x){
                throw new SIP_TransportException(x.Message);
            }
        }
        /// <summary>
        /// Sends specified request to specified SIP server.
        /// </summary>
        /// <param name="request">SIP request to send.</param>
        /// <param name="localEndPoint">Local end point to use. Value null means first available. NOTE: This is used only if transport = UDP.</param>
        /// <param name="remoteEndPoint">Destination remote endpoint where to send request.</param>
        /// <param name="transport">SIP transport to use. Supported values are defined in SIP_Transport class.</param>
        /// <exception cref="SIP_TransportException">Is raised when sending fails.</exception>
        public void SendRequest(SIP_Request request,SIP_EndPointInfo localEndPoint,IPEndPoint remoteEndPoint,string transport)
        {
            /* RFC 3561 18.1.1 Sending Requests.
                The client side of the transport layer is responsible for sending the
                request and receiving responses.  The user of the transport layer
                passes the client transport the request, an IP address, port,
                transport, and possibly TTL for multicast destinations.

                A client that sends a request to a multicast address MUST add the
                "maddr" parameter to its Via header field value containing the
                destination multicast address, and for IPv4, SHOULD add the "ttl"
                parameter with a value of 1.

                Before a request is sent, the client transport MUST insert a value of
                the "sent-by" field into the Via header field.  This field contains
                an IP address or host name, and port.  The usage of an FQDN is RECOMMENDED.

                For reliable transports, the response is normally sent on the
                connection on which the request was received.  Therefore, the client
                transport MUST be prepared to receive the response on the same
                connection used to send the request.

                For unreliable unicast transports, the client transport MUST be
                prepared to receive responses on the source IP address from which the request is sent.

                For multicast, the client transport MUST be prepared to receive
                responses on the same multicast group and port to which the request is sent.
            */

            try{
                byte[]        data = null;
                SipTcpPipe    pipe = null;
                SIP_t_ViaParm via  = request.Via.GetTopMostValue();

                /*
                    If UDP or TCP we always can override "transport" to reuse any existing TCP/TLS connection.
                    If TLS we can reuse only existing TLS connection.
                */
                if(transport.ToUpper() == SIP_Transport.UDP || transport.ToUpper() == SIP_Transport.TCP){
                    pipe = GetTcpPipe(null,remoteEndPoint);
                    // Not existing connection.
                    if(pipe == null){
                        // Not existing connection, create it.
                        if(transport == SIP_Transport.TCP){
                            pipe = new SipTcpPipe(this,remoteEndPoint,false);
                        }
                        // Use UDP socket.
                        else{
                            foreach(SipListeningPoint listeningPoint in m_pListeningPoints){
                                if(listeningPoint.Protocol == BindInfoProtocol.UDP){
                                    if(localEndPoint == null || listeningPoint.LocalEndPoint.Equals(localEndPoint.EndPoint)){
                                        // Set sent-by value.
                                        if(!string.IsNullOrEmpty(m_pSipStack.HostName)){
                                            via.SentBy = m_pSipStack.HostName;
                                        }
                                        else if(pipe.LocalEndPoint.Address.Equals(IPAddress.Any)){
                                            // Get first IP
                                            via.SentBy = System.Net.Dns.GetHostAddresses("")[0] + ":" + pipe.LocalEndPoint.Port;
                                        }
                                        else{
                                            via.SentBy = listeningPoint.LocalEndPoint.ToString();
                                        }

                                        data = request.ToByteData();

                                        // Log
                                        m_pSipStack.Logger.AddWrite(data.Length,"Sending (" + data.Length + " bytes): " + listeningPoint.LocalEndPoint.ToString() + " -> " + remoteEndPoint.ToString() + "\r\n<begin>\r\n" + System.Text.Encoding.UTF8.GetString(data) + "<end>\r\n");

                                        listeningPoint.Socket.SendTo(data,remoteEndPoint);
                                        return;
                                    }
                                }
                            }

                            throw new SIP_TransportException("No suitable UDP socket !");
                        }
                    }
                    // We can reuse existing connection, use it.
                    // We stored pipe, we use it later.
                    //else{
                    //}
                }
                else if(transport.ToUpper() == SIP_Transport.TLS){
                    pipe = GetTcpPipe(SIP_Transport.TLS,remoteEndPoint);
                    // Not existing connection, create it.
                    if(pipe == null){
                        pipe = new SipTcpPipe(this,remoteEndPoint,true);
                    }
                }
                else{
                    throw new SIP_TransportException("No transport for protocol '" + transport + "' !");
                }

                // Set sent-by value.
                if(!string.IsNullOrEmpty(m_pSipStack.HostName)){
                    via.SentBy = m_pSipStack.HostName;
                }
                else if(pipe.LocalEndPoint.Address.Equals(IPAddress.Any)){
                    // Get first IP
                    via.SentBy = System.Net.Dns.GetHostAddresses("")[0] + ":" + pipe.LocalEndPoint.Port;
                }
                else{
                    via.SentBy = pipe.LocalEndPoint.ToString();
                }

                data = request.ToByteData();

                // Log
                m_pSipStack.Logger.AddWrite(data.Length,"Sending (" + data.Length + " bytes): " + pipe.LocalEndPoint.ToString() + " -> " + remoteEndPoint.ToString() + "\r\n<begin>\r\n" + System.Text.Encoding.UTF8.GetString(data) + "<end>\r\n");

                // Send request.
                pipe.SendMessage(data);
            }
            catch(Exception x){
                throw new SIP_TransportException(x.Message);
            }
        }