Wednesday 14 December 2011

A Very Basic Mobicents Diameter Receiver

I've been playing with Mobicents JAIN SLEE for a while now, to add some Diameter functionality to our product range.
Initially, I've been hacking some of the provided example code to prove the concepts, but now it's time to get a clean sheet of paper and implement a product. Getting all this clever Java Application Server stuff into my poor old Embedded C mind has been a bit of a struggle.

What follows pulls together several existing tutorials, and then goes on to add a Diameter Base Protocol RA.

I'm not going to explain terminology as I go, but I will put some links at the end (if I'm still awake, and remember to do so).

Create a clean machine

I'm not going to go into details here as this should be Operating System agnostic, there are detailed instructions elsewhere and anything I write here will be out-of-date in hours.

However for the record, my clean machine is as follows:
  1. I'm running it as a virtual machine under VMWare Player 4.0.1
  2. I've created a new virtual machine and installed CentOS 6.0 (32-bit due to virtualisation limitations on my laptop)
  3. Applied updates (yum update)
  4. Installed Java JDK. I've gone for 1.7.
Installed a Mobicents SLEE developement environment.

I've followed Eduardo Martins Mobicents JAIN SLEE Development Environment Setup, except that for the EclipSLEE I've done the following:
  1. Open Eclipse
  2. Go to Help | Install New Software...
  3. Click Add... and enter name EclipSLEE and URL http://hudson.jboss.org/hudson/view/Mobicents/job/Mobicents-EclipSLEE/lastSuccessfulBuild/artifact/
  4. Select the appropriate EclipSLEE version, click Next and follow the instructions in the Eclipse Wizard
  5. Allow Eclipse to restart
Which I took from Ibrahima Gaye's post on Mobicents Google Group

This fixes an issue with service creation. If you are using a later version of Mobicents, then this fix will have made it into the release.
Again, for the record, I am using
Build a SLEE application.

Again I've followed Eduardo Martins. This time his Hello SLEE World Service JAIN SLEE Tutorial
This time I've followed it completely, not even changing the names.
Note that if you have used the version of EclipSLEE shipped with 2.5.0 you will have problems. Use the nightly build until 2.6.0 ships...
    Add an RA

    At last we are into new ground.
    I'm going to add a Diameter Base RA, and handle the receipt of  the Accounting Request (ACR). Again, I'm not going to go into the details of Diameter Base Accounting, but I might link to some other posts at the end.

    First we need to add a Maven Dependency on the Diameter Base RA Type.

    Open up the SBB in Package Explorer, right click and select Add Maven Dependency




    From the Components Drop down box, choose Mobicents Diameter Base


    And the plug-in will fill things in for you:


    Now we are going to bind the Resource Adaptor to the SBB. In Package Explorer, find the sbb-jar.xml, right click on it and select Modify Service Building Block (SBB) > Hello SLEE World 1.0 org.mobicents > Resource Adaptor Bindings




    A Wizard should appear and offer you a Base RA.


    Click on the Base RA, and then on Select RA Type



    Before we finish here, we are going to add some bindings (about which I am going to be deliberately vague at the moment.
    Click the Edit Bindings... button in the table row that starts Diameter Base.


    Click Add,
    Click on the First Question Mark and set the Object Name to "slee/ra/jdbc/1.0/sbbinterface".
    Click on the second Question Mark and set the Entity Link to "JDBCRA". 
    Click OK.


    Now click on the table under ACI Factory Name and enter "slee/ra/jdbc/1.0/acifactory"


    You should now have:


    Click OK.

    If we go and have a look in sbb-jar.xml we should now find a stanza like this:
    <resource-adaptor-type-binding>
        <resource-adaptor-type-ref>
          <resource-adaptor-type-name>JDBCResourceAdaptorType</resource-adaptor-type-name>
          <resource-adaptor-type-vendor>org.mobicents</resource-adaptor-type-vendor>
          <resource-adaptor-type-version>1.0</resource-adaptor-type-version>
        </resource-adaptor-type-ref>
        <activity-context-interface-factory-name>slee/ra/jdbc/1.0/acifactory</activity-context-interface-factory-name>
        <resource-adaptor-entity-binding>
          <resource-adaptor-object-name>slee/ra/jdbc/1.0/sbbinterface</resource-adaptor-object-name>
          <resource-adaptor-entity-link>JDBCRA</resource-adaptor-entity-link>
        </resource-adaptor-entity-binding>
      </resource-adaptor-type-binding>
    

    Finally, we are going to handle an Event from the RA.  In Package Explorer, find the sbb-jar.xml again, right click on it and select Modify Service Building Block (SBB) > Hello SLEE World 1.0 org.mobicents >  Events...




     You should get a Wizard that lists all the basic SLEE events, and the events defined in the RA. Notice that we have already selected the ServiceStartedEvent (we did this in Eduardo's tutorial).

     Click on the AccountingRequestEvent and then on Select Event














    and finally click on Modify... and make this an Initial Event



    Now we just need to add some code. If you have a look in HelloSleeWorldSbb.java, you will see that the Wizard has created a function called onAccountingRequest for you. We're going to return a Accounting Answer (ACA) from this. Add the following code to the stub function.

    public void onAccountingRequest(net.java.slee.resource.diameter.base.events.AccountingRequest event, ActivityContextInterface aci) {
        if (aci.getActivity() instanceof AccountingServerSessionActivity) {
            AccountingServerSessionActivity assa = (AccountingServerSessionActivity) aci.getActivity();
    
            AccountingAnswer ans = assa.createAccountingAnswer(event);
            ans.setResultCode(2001); // 2001 = SUCCESS
    
            try {
                assa.sendAccountingAnswer(ans);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    

    This checks that we are doing the correct activity, and if so it creates an answer, sets the result code to 2001 (=> Success) and sends it. We haven't actually done anything with the data, but I'm going to leave that as an exercise for the student.

    Deploying the Service


    To do anything useful we are going to have to deploy the service. To do this successfully we also have to deploy the Mobicents provided components that it uses. These are

    • Diameter MUX - This is a routing layer that distributes Diameter messages to all the different Resource Adaptors we may have deployed.
    • Diameter Base RA - This is the Resource Adaptor for the Diameter service we are implementing.
    These can't be hot deployed, so stop the JBoss server before deploying them.
    The MUX is implemented in .SAR. You will find it in MOBICENTS_HOME/slee/binary/2.5.0.FINAL/extra/mobicents-diameter/. If you read the README.TXT it says to drop the SAR into deploy directory. As we are all using the directory structure that Eduardo used in his first tutorial, we can do this from the command line as follows:

    cp -r $MOBICENTS_HOME/slee/binary/2.5.0.FINAL/extra/mobicents-diameter/mobicents-diameter-mux-1.4.0.CR1.sar $JBOSS_HOME/server/default/deploy/
    

    The RA is a JAR file and can be found at MOBICENTS_HOME/slee/binary/2.5.0.FINAL/resources/diameter-base. Again we can deploy it using the command line:

    cp $MOBICENTS_HOME/slee/binary/2.5.0.FINAL/resources/diameter-base/diameter-base-ra-DU-2.5.0.FINAL.jar $JBOSS_HOME/server/default/deploy/
    

    You can restart JBoss now, or you can wait until we have done some configuration.

    I'm going to leave the configuration for another post - otherwise I will never get this posted (I've been working on it for a month now !)

    Saturday 5 March 2011

    Record-route and route fun in SIPp

    We've found a problem with SIPp's handling of Record-route and route headers. Specifically, it inserts the correct Routes for "client scripts" requests, but gets them wrong in "server scripts" requests. (Note that here I am using "server" and "client" as SIPp does...)

    This is what I did:

    I started with the two default scenarios from SIPP ("sipp -sd uac > uac.xml" and "sipp -sd uas > uas.xml"). Using two terminals, I ran these back-to-back ("sipp -sf uas.xml -m 1" then "sipp -sf uac.xml -m 1 localhost:5061"). [The "-m 1" makes sure both sipp scripts do a single call. If I don't put one on the server script, I forget to restart it when I edit the script, and wonder why my changes take no effect....]

    Assuming this works OK, we can go on to add some Record-Route headers. I'm going to use the pair from RFC3261 § 16.12.1.1 Basic SIP Trapezoid to avoid any confusion.

    Modify uac.xml at the following points:
      1) Add the lines "Record-Route: <sip:p2.domain.com;lr>" and "Record-Route: <sip:p1.example.com;lr>"
    to the INVITE
      2) Add 'rrs="true"' to the 'recv response="200"' command.
      3) Add a '[routes]' line to both the ACK and the BYE

    Modify uas.xml at the following points:
      1) Add 'rrs="true"' to the 'recv request="INVITE"' command
      2) Add a '[last_Record-route]' line to both the 180 and 200

    Now if you re-run the test you should see:
     In the INVITE:
    Record-Route: <sip:p2.domain.com;lr>
      Record-Route: <sip:p1.example.com;lr>

     In the 180 and the 200:
       Record-Route: <sip:p2.domain.com;lr>, <sip:p1.example.com;lr>

     In the ACK and the BYE
       Route:  <sip:p1.example.com;lr>,<sip:p2.domain.com;lr>

    So, SIPp has choosen to put both the Record-route and Route headers on the same line, but that's absolutlely fine. What is important is the order, and this is correct. So far, so good.

    OK, so lets try this in the opposite direction. Copy uac.xml and uas.xml to uac1.xml and uas1.xml. Cut the BYE and the 200 out of the UAS and paste them into the UAC; cut the PAUSE, the BYE and 200 out of the UAC and paste them UAS. Remove the 'optional="true"' parameter from the ACK in the UAS (ACKs are not optional....).

    Re-run using these new scripts. All the Record-route and Route headers are the same. This is a shame as the Route header in the BYE should be "Route:  <sip:p2.domain.com;lr>,<sip:p1.example.com;lr>".

    There are some other signalling errors in the traces as well, but I'm going to ignore these right now.
    For now, here is my finely crafted fix. (AKA boadge).

    In the UAS script (uas1.xml that is) make the following changes.
      1) Add an action to the recv INVITE command to extract and store the content of the two Record-Route headers.
    <action>
      <ereg regexp=".*" search_in="hdr" header="Record-Route:" occurence="1" assign_to="1"/>
      <ereg regexp=".*" search_in="hdr" header="Record-Route:" occurence="2" assign_to="2"/>
    </action>
      2) Replace the '[routes]' line in the BYE with two lines to insert them back
    Route: [$1]
      Route: [$2]
          
    Re-run it (there is no need to change the uac1.xml script), and you should find that you have Route: headers in the right order!

    This bodge has one draw-backs. You have to handle each Record-route individually, if you have more headers, you need to add more lines. However, it does cope with the Record-Route headers being on the same line. However, you could use it to get strict routing right (if you feel the urge).

    More on SIPp when I get some spare time, or maybe I'll patch the code..(Don't hold your breath folks).

    Monday 7 February 2011

    Coming out

    Having returned from FOSDEM I've decided it's probably time I entered this 21st Century with its blogs and tweets. So I've signed up for Twitter and started this blog.

    To Do:
    • Find something interesting to say
    • Remain sober so I don't commit any malapropisms or other indiscretions
    Hopefully some witty and pithy out-pourings on work, kids, Morris Dancing and cheese will appear here. Failing that I'll have to write something.