/// <summary> /// Sends in initial notification request for a new subscription where it makes sense to do so. /// </summary> /// <param name="subscribeRequest">The client request that resulted in the subscription creation.</param> /// <param name="sipAccount">The authenticated SIP account that created the subscription.</param> private void SendInitialNotification(SIPRequest subscribeRequest, ISIPAccount sipAccount) { if (SIPEventPackageType.IsValid(subscribeRequest.Header.Event)) { var eventPackage = SIPEventPackageType.Parse(subscribeRequest.Header.Event); if (eventPackage == SIPEventPackagesEnum.MessageSummary) { // Send a dummy message waiting indicator message so that a client can verify a notification request can // be received. var dstUri = subscribeRequest.Header.Contact[0].ContactURI; var accountURI = new SIPURI(sipAccount.SIPUsername, sipAccount.SIPDomain, null, dstUri.Scheme, dstUri.Protocol); var notifyReq = SIPRequest.GetRequest(SIPMethodsEnum.NOTIFY, subscribeRequest.Header.Contact[0].ContactURI, new SIPToHeader(null, accountURI.CopyOf(), CallProperties.CreateNewTag()), new SIPFromHeader(null, accountURI.CopyOf(), CallProperties.CreateNewTag())); notifyReq.Header.CallId = subscribeRequest.Header.CallId; notifyReq.Header.CSeq = subscribeRequest.Header.CSeq++; notifyReq.Header.Server = m_serverAgent; notifyReq.Header.Event = SIPEventPackageType.MESSAGE_SUMMARY_EVENT_VALUE; notifyReq.Header.SubscriptionState = "active"; notifyReq.Header.SetDateHeader(); notifyReq.Header.ContentType = SIPMIMETypes.MWI_CONTENT_TYPE; notifyReq.Body = "Messages-Waiting: no"; // A little trick here is using the remote SIP end point as the destination rather than the Contact URI. // Ideally some extra logic to check for IPv4 NAT should be applied. But since this server is known to // be operating in the cloud and only send NOTIFY requests to Internet clients it should be a reasonable // option. SIPNonInviteTransaction notifyTx = new SIPNonInviteTransaction(m_sipTransport, notifyReq, subscribeRequest.RemoteSIPEndPoint); notifyTx.SendRequest(); } } }
/// <summary> /// This method handles incoming requests from the SIP transport instance. It may be working in /// conjunction with other receivers on the same SIP transport so it should filter the requests /// to identify the NOTIFY requests for this subscription. /// </summary> /// <param name="localSIPEndPoint">The local SIP end point the request was received on.</param> /// <param name="remoteEndPoint">The remote SIP end point the request was received from.</param> /// <param name="sipRequest">The SIP request.</param> private async Task GotNotificationRequest(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { if (sipRequest.Method == SIPMethodsEnum.NOTIFY && sipRequest.Header.CallId == m_subscribeCallID && SIPEventPackageType.Parse(sipRequest.Header.Event) == m_sipEventPackage && sipRequest.Body != null) { logger.LogDebug($"SIPNotifierClient GotNotificationRequest for {sipRequest.Method} {sipRequest.URI} {sipRequest.Header.CSeq}."); SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await m_sipTransport.SendResponseAsync(okResponse).ConfigureAwait(false); if (sipRequest.Header.CSeq <= m_remoteCSeq) { logger.LogWarning($"A duplicate NOTIFY request received by SIPNotifierClient for subscription Call-ID {m_subscribeCallID}."); } else { //logger.LogDebug("New dialog info notification request received."); m_remoteCSeq = sipRequest.Header.CSeq; NotificationReceived?.Invoke(m_sipEventPackage, sipRequest.Body); } } }
/// <summary> /// Initiates a SUBSCRIBE request to a notification server. /// </summary> /// <param name="subscribeURI">The SIP user that dialog notifications are being subscribed to.</param> public void Subscribe(SIPURI subscribeURI, int expiry, SIPEventPackagesEnum sipEventPackage, string subscribeCallID, SIPURI contactURI) { try { if (m_attempts >= MAX_SUBSCRIBE_ATTEMPTS) { logger.LogWarning($"Subscription to {subscribeURI} reached the maximum number of allowed attempts without a failure condition."); m_subscribed = false; SubscriptionFailed?.Invoke(subscribeURI, SIPResponseStatusCodesEnum.InternalServerError, "Subscription reached the maximum number of allowed attempts."); m_waitForSubscribeResponse.Set(); } else { m_attempts++; m_localCSeq++; SIPRequest subscribeRequest = SIPRequest.GetRequest( SIPMethodsEnum.SUBSCRIBE, m_resourceURI, new SIPToHeader(null, subscribeURI, m_subscriptionToTag), new SIPFromHeader(null, new SIPURI(m_authUsername, m_authDomain, null, m_resourceURI.Scheme, SIPProtocolsEnum.udp), m_subscriptionFromTag)); if (contactURI != null) { subscribeRequest.Header.Contact = new List <SIPContactHeader>() { new SIPContactHeader(null, contactURI) }; } else { subscribeRequest.Header.Contact = new List <SIPContactHeader>() { SIPContactHeader.GetDefaultSIPContactHeader(subscribeRequest.URI.Scheme) }; } subscribeRequest.Header.CSeq = m_localCSeq; subscribeRequest.Header.Expires = expiry; subscribeRequest.Header.Event = SIPEventPackageType.GetEventHeader(sipEventPackage); subscribeRequest.Header.CallId = subscribeCallID; if (!m_filter.IsNullOrBlank()) { subscribeRequest.Body = m_filter; subscribeRequest.Header.ContentLength = m_filter.Length; subscribeRequest.Header.ContentType = m_filterTextType; } SIPNonInviteTransaction subscribeTransaction = new SIPNonInviteTransaction(m_sipTransport, subscribeRequest, m_outboundProxy); subscribeTransaction.NonInviteTransactionFinalResponseReceived += SubscribeTransactionFinalResponseReceived; subscribeTransaction.NonInviteTransactionFailed += SubscribeTransactionFailed; LastSubscribeAttempt = DateTime.Now; subscribeTransaction.SendRequest(); } } catch (Exception excp) { logger.LogError("Exception SIPNotifierClient Subscribe. " + excp.Message); SubscriptionFailed?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception Subscribing. " + excp.Message); m_waitForSubscribeResponse.Set(); } }