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
}
}