public IncomingMessage(SIPChannel sipChannel, SIPEndPoint remoteEndPoint, byte[] buffer) { LocalSIPChannel = sipChannel; RemoteEndPoint = remoteEndPoint; Buffer = buffer; ReceivedAt = DateTime.Now; }
public SIPConnection(SIPChannel channel, Socket sipSocket, IPEndPoint remoteEndPoint, SIPProtocolsEnum connectionProtocol, SIPConnectionsEnum connectionType) { LastTransmission = DateTime.Now; m_owningChannel = channel; SIPSocket = sipSocket; RemoteEndPoint = remoteEndPoint; ConnectionProtocol = connectionProtocol; ConnectionType = connectionType; }
/// <summary> /// Adds an additional SIP Channel to the transport layer. /// </summary> /// <param name="localEndPoint"></param> public void AddSIPChannel(SIPChannel sipChannel) { try { m_sipChannels.Add(sipChannel.SIPChannelEndPoint.ToString(), sipChannel); // Wire up the SIP transport to the SIP channel. sipChannel.SIPMessageReceived += ReceiveMessage; if (m_queueIncoming && !m_transportThreadStarted) { StartTransportThread(); } } catch (Exception excp) { logger.Error("Exception AddSIPChannel. " + excp.Message); throw excp; } }
public SIPTransport(ResolveSIPEndPointDelegate sipResolver, SIPTransactionEngine transactionEngine, SIPChannel sipChannel, bool queueIncoming) { if (sipResolver == null) { throw new ArgumentNullException("The SIP end point resolver must be set when creating a SIPTransport object."); } ResolveSIPEndPoint_External = sipResolver; m_transactionEngine = transactionEngine; AddSIPChannel(sipChannel); m_queueIncoming = queueIncoming; }
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 } }
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); } }
private void SendResponse(SIPChannel sipChannel, SIPResponse sipResponse) { if (m_sipChannels.Count == 0) { throw new ApplicationException("No channels are configured in the SIP transport layer. The response could not be sent."); } SIPViaHeader topVia = sipResponse.Header.Vias.TopViaHeader; SIPDNSLookupResult lookupResult = GetHostEndPoint(topVia.ReceivedFromAddress, false); if (lookupResult.LookupError != null) { throw new ApplicationException("Could not resolve destination for response.\n" + sipResponse.ToString()); } else if (lookupResult.Pending) { // Ignore this response transmission and wait for the transaction retransmit mechanism to try again when DNS will have hopefully resolved the end point. return; } else { SIPEndPoint dstEndPoint = lookupResult.GetSIPEndPoint(); if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress)) { // Ignore packet, it's destined for the blackhole. return; } else if (dstEndPoint != null) { SendResponse(sipChannel, new SIPEndPoint(topVia.Transport, dstEndPoint.GetIPEndPoint()), sipResponse); } else { throw new ApplicationException("SendResponse could not send a response as no end point was resolved.\n" + sipResponse.ToString()); } } }
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); } } }
/// <summary> /// Gets fired when a suspected SIP message is extracted from the TCP data stream. /// </summary> protected void SIPTCPMessageReceived(SIPChannel channel, SIPEndPoint localEndPoint, SIPEndPoint remoteEndPoint, byte[] buffer) { SIPMessageReceived?.Invoke(channel, localEndPoint, remoteEndPoint, buffer); }
private void NatKeepAliveChannelMessageReceived(SIPChannel sipChannel, SIPEndPoint remoteEndPoint, byte[] buffer) { try { NATKeepAliveMessage keepAliveMessage = NATKeepAliveMessage.ParseNATKeepAliveMessage(buffer); if (keepAliveMessage != null) { if (keepAliveMessage.LocalSIPEndPoint.Protocol == SIPProtocolsEnum.udp) { FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.NATKeepAlive, SIPMonitorEventTypesEnum.NATKeepAliveRelay, "Relaying NAT keep-alive from proxy socket " + keepAliveMessage.LocalSIPEndPoint + " to " + keepAliveMessage.RemoteEndPoint + ".", null)); m_sipTransport.SendRaw(keepAliveMessage.LocalSIPEndPoint, new SIPEndPoint(keepAliveMessage.RemoteEndPoint), m_sendBuffer); } else { // For connection oriented protocols check whether a connection exists. NAT keep alives shouldn't cause a connection to be initiated. SIPChannel sendFromChannel = m_sipTransport.FindSIPChannel(keepAliveMessage.LocalSIPEndPoint); if (sendFromChannel != null && sendFromChannel.IsConnectionEstablished(keepAliveMessage.RemoteEndPoint)) { FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.NATKeepAlive, SIPMonitorEventTypesEnum.NATKeepAliveRelay, "Relaying NAT keep-alive from proxy socket " + keepAliveMessage.LocalSIPEndPoint + " to " + keepAliveMessage.RemoteEndPoint + ".", null)); m_sipTransport.SendRaw(keepAliveMessage.LocalSIPEndPoint, new SIPEndPoint(keepAliveMessage.RemoteEndPoint), m_sendBuffer); } else { FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.NATKeepAlive, SIPMonitorEventTypesEnum.NATKeepAliveRelay, "No established connection was found to relay NAT keep-alive from proxy socket " + keepAliveMessage.LocalSIPEndPoint + " to " + keepAliveMessage.RemoteEndPoint + ".", null)); } } } } catch (Exception excp) { logger.Error("Exception NatKeepAliveChannelMessageReceived. " + excp.Message); } }
private byte[] m_sendBuffer = new byte[] { 0x0, 0x0, 0x0, 0x0 }; // Doesn't matter what is sent since it's just to keep the NAT connection alive. /// <param name="listenerSocket">Socket to listen for NAT keepalive relay requests on.</param> public NATKeepAliveRelay(SIPTransport sipTransport, IPEndPoint listenerSocket, SIPMonitorLogDelegate sipMonitorLogDelegate) { m_sipTransport = sipTransport; m_natKeepAliveChannel = new SIPUDPChannel(listenerSocket); m_natKeepAliveChannel.SIPMessageReceived += NatKeepAliveChannelMessageReceived; SIPMonitorLog_External = sipMonitorLogDelegate; logger.Debug("NATKeepAlive Relay instantiated on " + listenerSocket + "."); }
public void ReceiveMessage(SIPChannel sipChannel, SIPEndPoint remoteEndPoint, byte[] buffer) { try { if (!m_queueIncoming) { SIPMessageReceived(sipChannel, remoteEndPoint, buffer); } else { IncomingMessage incomingMessage = new IncomingMessage(sipChannel, remoteEndPoint, buffer); m_inMessageQueue.TryAdd(incomingMessage); } } catch (Exception excp) { logger.Error("Exception SIPTransport ReceiveMessage. " + excp.Message); throw excp; } }
/// <summary> /// Gets fired when a suspected SIP message is extracted from the TCP data stream. /// </summary> protected Task SIPTCPMessageReceived(SIPChannel channel, SIPEndPoint localEndPoint, SIPEndPoint remoteEndPoint, byte[] buffer) { return(SIPMessageReceived?.Invoke(channel, localEndPoint, remoteEndPoint, buffer)); }
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); } }
public void ReceiveMessage(SIPChannel sipChannel, SIPEndPoint remoteEndPoint, byte[] buffer) { try { if (!m_queueIncoming) { SIPMessageReceived(sipChannel, remoteEndPoint, buffer); } else { IncomingMessage incomingMessage = new IncomingMessage(sipChannel, remoteEndPoint, buffer); // Keep the queue within size limits if (m_inMessageQueue.Count >= MAX_INMESSAGE_QUEUECOUNT) { logger.Warn("SIPTransport queue full new message from " + remoteEndPoint + " being discarded."); } else { lock (m_inMessageQueue) { m_inMessageQueue.Enqueue(incomingMessage); } } m_inMessageArrived.Set(); } } catch (Exception excp) { logger.Error("Exception SIPTransport ReceiveMessage. " + excp.Message); throw excp; } }
public void RemoveSIPChannel(SIPChannel sipChannel) { if (m_sipChannels.ContainsKey(sipChannel.SIPChannelEndPoint.ToString())) { m_sipChannels.Remove(sipChannel.SIPChannelEndPoint.ToString()); sipChannel.SIPMessageReceived -= ReceiveMessage; } }
private void SIPTLSMessageReceived(SIPChannel channel, SIPEndPoint remoteEndPoint, byte[] buffer) { if (SIPMessageReceived != null) { SIPMessageReceived(channel, remoteEndPoint, buffer); } }