Microsoft Lync and Skype for Business have a rich set of .NET APIs which make it easy to extend the platform and integrate it with other applications. This blog helps explain how to use those APIs.

Forking SIP requests in an MSPL script

Posted: January 17th, 2012 | Author: | Filed under: Lync Development, MSPL | Tags: , | 10 Comments »

In previous blog posts on Microsoft SIP Processing Language (MSPL), I’ve explained how to essentially intercept SIP requests, such as the INVITE message that initiates a call, and pass them along to a UCMA application for handling by passing a parameter to the ProxyRequest method. In this post, I want to discuss what you can do if you want to “fork” a request, which means you are sending it to multiple endpoints simultaneously.

Generally, an application forks a request because one of a number of endpoints may need or choose to answer it, and the application doing the routing (in this case, your MSPL script) does not have a way of knowing in advance which one it is. Now, in the vast majority of cases where you would want to fork a request, Lync already takes care of it for you. The routing behavior built into Lync forks new SIP INVITEs sent to a user among all the active endpoints for that user. For load balancing and resiliency, you don’t need to create your own forking behavior; instead, you should create a trusted application pool with multiple computers. However, occasionally you may run into a situation where your MSPL script needs to send a request to multiple endpoints, and let the endpoints themselves decide who accepts.

To fork a request in MSPL, you basically need to replace the call to ProxyRequest (which you would normally use to proxy the message to a single destination) with three things, in order:

  • BeginFork
  • Fork (repeated once for each destination)
  • EndFork

It’s a sort of triple-decker sandwich of Fork commands. Here’s an example of what this looks like:

BeginFork(false, 0);
Fork("sip:appserver.domain.local@domain.local;gruu;opaque=srvr:fork:saLA7P02gZi2Ho78Ix_w2AA");
Fork("sip:appserver.domain.local@domain.local;gruu;opaque=srvr:spoon:saLA7P02gZi2Ho78Ix_w2AA");
EndFork();

You’ll notice that the BeginFork command takes two parameters, and you may be wondering what these do. The answer is a mystery; according to the official documentation, both parameters are “reserved,” and they must be set to false and 0, respectively. I haven’t tested to see what happens if you set them to, say, true and 98, and I’m not responsible for any painful consequences if you try it yourself.

You have to call BeginFork first, to start the forking operation. Once you’ve done so, you can then call Fork as many times as you want to, passing in a destination URI each time. In the example above, I’ve used two UCMA application GRUUs.

Last but not least, you need to call EndFork to finish the forking. EndFork does not take any parameters, reserved or otherwise.

As with ProxyRequest, when you fork messages you need to be careful and have at least a general understanding of what you are doing. Usually forking makes the most sense with INVITE requests. What you don’t want to do, for the most part, is fork a message within a SIP dialog that has already been established with the INVITE / 200 OK / ACK handshake. Once the session is established, it’s understood that messages within the session (such as MESSAGE requests that carry IM text) will continue to be routed to the same endpoints, so changing this can lead to some pretty weird reactions. You also shouldn’t be messing with the routing for requests that have a Route header (a so-called “strict route”) pre-defining where the request should go; this is naughty behavior and against the rules, and from what I understand Lync will not allow you to do this in your script.

I’ve only come across a very few cases where forking in an MSPL script was necessary, but in those cases it was the only way to solve the problem. If anyone has any interesting use cases for forking to share, I’d be very curious to hear about them. Feel free to comment also if you have questions about implementation.


10 Comments on “Forking SIP requests in an MSPL script”

  1. 1 Stanky said at 2:55 pm on May 20th, 2012:

    Hello Michael,
    You wrote that “What you don’t want to do, for the most part, is fork a message within a SIP dialog that has already been established with the INVITE / 200 OK / ACK handshake”. How to determine that “INVITE” message is from established session? By analyzing “Session-Expires” and searching a “refresher” in it?

    foreach (SessionExpires in GetHeaderValues("Session-Expires")) {
    if (ContainsString(SessionExpires, "refresher", true)) {
    return;
    }
    }

    P. S. Sorry for my English.

  2. 2 Michael said at 8:25 pm on May 24th, 2012:

    If you want to exclude re-INVITEs (INVITEs that are sent to renegotiate media in an established session), what I usually do is check the CSEQ header. If the value is greater than 1, it’s a re-INVITE.
    Does that answer your question?

  3. 3 Stanky said at 2:48 pm on May 25th, 2012:

    Yes, Michael, thank you a lot!

  4. 4 Claudiu said at 10:59 am on November 28th, 2013:

    Hi – I need a piece of advice. Is this forking working with SIP NOTIFY messages in order to send the MWI coming from Exchange UM to an external IP-PBX in a modified format ?

    Thanks
    Claudiu

  5. 5 Michael said at 1:44 pm on December 3rd, 2013:

    Claudiu,
    I haven’t tried that, but you can definitely pick up NOTIFY requests in an MSPL script, so it’s worth a try.
    Michael

  6. 6 Keut said at 11:18 am on December 4th, 2013:

    Hi Michael,
    I’m trying to make a simple MSPL fork but can’t get it to work. Here’s my AM :

    On the client I receive “Operation was unsuccessful”… Am I missing something?
    Do you think this should work?

    Thanks

    Keut

  7. 7 Jon said at 5:13 pm on January 30th, 2014:

    Hi Michael,

    I am trying to perform the Fork operation using two sip addresses. I can call each of these addresses through my Lync client fine, but as soon as I try to Fork the message I get an error, “Peer server pool is out of service”.

    This is basically what my script looks like:

    if(sipRequest)
    {
    if(ContainsString(sipRequest.To, “sip:originaladdress@company.com”, true)
    {
    BeginFork(false, 0);
    Fork(“originaladdress@company.com”);
    Fork(“otheraddress@company.com”);
    EndFork();
    }
    }

    I am sure I am missing something as I am new to Lync and UCMA, but any help would be appreciated.

  8. 8 Michael said at 2:08 pm on February 16th, 2014:

    Hi Jon,

    You can’t fork to an address of record (AOR) like you are trying to do. The destination has to represent a unique endpoint and is the actual location to which the message will be routed (i.e., a request URI).

    You would need to look up the endpoints for each of those AORs using the QueryEndpoints function and then fork to all the resulting endpoints. There’s a good code example you can check out on MSDN at http://msdn.microsoft.com/en-us/library/office/dn439076.aspx.

    Hope this helps.

    Michael

  9. 9 Jon said at 12:35 pm on February 25th, 2014:

    Thanks Michael,

    I was able to figure this out after a few days of experimenting. The key to this was to enable the “IsDefaultRoutingEndpoint” option on the Application Endpoint Settings.

    On another note, I attended both of your sessions last week at Lync Conf ’14, and I had 2 requests…

    1. Could you please post the code from your “Advanced UCMA” session?
    2. You had mentioned during your “MSPL/Routing” session that there were PowerShell commands that you could use to publish your script-only .am file to your frontend server – are you able to provide some guidance on where to find these?

    Best regards,
    Jon

  10. 10 Anthony said at 12:36 pm on March 24th, 2015:

    I was wondering what you would do to split out a message that come in to have 2 people receive the message instead of the original one? Would you use forking for this?


Leave a Reply

  • Note: Comment moderation is in use because of excessive spam. Your comment may not appear immediately.

  •