Friday, November 19, 2010

Diameter Educational Series: Creating a "Hello World" Application with Mobicents Diameter

For some time now the Mobicents Diameter Team have been wondering how should we introduce diameter use cases to mobicents community. After some talk we decided to create series of blog posts with step by step instructions and examples.

In next posts, me and Alex will cover topics ranging from simple "Hello World Example" to prepaid billing service or some IMS components.

Some basics

As weird as it may seem in diameter domain, first example is always "hello world", so... Always simplistic, to show how to play in new environment. In this post I will describe basics of interaction in diameter world. I wont however describe protocol level details(like CER/CEA capabilities exchange).

Diameter Nodes.

Diameter node is a network entity which supports diameter protocol and certain application. Each node is identified by certain set of informations:
  • realm
  • URI

Diameter realm is simply string, for instance "".  It identifies nodes domain of responsibility.
URI identifies diameter nodes in realm. It has following form: aaa://[:port][;params]*

Nodes which has direct connection are called Diameter Peers. Diameter Peers have set of common applications. When connection is established between two diameter nodes, this set  is determined. If there are no common applications, connection is not created. This implies that peers understand all exchanged messages and AVPs. 

Messages and AVPs

All diameter data structures exchanged over wire have similar structure:
  • header
  • payload
Structure is proper word, since proper interpretation depends on metadata. Metadata is encoded in header.
Header contains following information:
  • ID
  • flags
  • length
  • (possibly additional information)

ID is a set of unique codes identifying structure. IDs include structure code and vendor ID(or application ID).
Flags are a set of bit switches. Flags carry additional information which may be helpful in proper interpretation of structure.
Payload is simply byte encoded content of structure, it may be simple data like integer number, or another set of structures. To see visualization please refer to this page. Since payload is byte[], its proper interpetation depends on type associated to ID of structure.

Diameter Session

Messages are exchanged within session. Session is a relation of exchanged messages to particular activity, for instance accounting. Each diameter application defines life cycle of session and types of messages that can be exchanged within session. This allows peers to communicate with integrity and confidentiality.
Sessions are identified by unique session id(AVP) present in each message exchanged. 

Diameter Application

Diameter Application is not a software application. It is definition of protocol based on Diameter Base Protocol(RFC3588). Protocol is correct term since Diameter Application defines new messages, session state machines and AVPs.
Step by step example
Now for purpose of this example lets define our own, private application. Our example application has to meet following requirements:

  • define new messages
  • define new AVPs
  • define very simple FSM for session to allow strict message exchange

Lets consider IDs of application as follows:
ApplicationID: 33333
VendorID : 66666

In this example we want our application to exchange text data within custom messages.
Lets consider new type of message with name: SomeApplication-Exchange with message code equal to686 and application ID set to examples application ID.

Request(SER - SomeApplication Exchange Request) is defined as follows:
SER ::=  < Diameter Header: 686, 33333, REQ, PXY > 
                                        < Session-Id >
                                        { Origin-Host }
                                        { Origin-Realm }
                                        { Destination-Realm }
                                       { Destination-Host }
                                       { Auth-Application-Id }
                                       { Exchange-Type }
                                       { Exchange-Data } 
                                       * [ Proxy-Info ] 
                                       * [ Route-Record ] 
                                       * [ AVP ]

Answer is defined as follows:
SEA ::= < Diameter Header: 686, 33333, PXY >

                                       < Session-Id > 
                                       { Result-Code } 
                                       { Origin-Host } 
                                       { Origin-Realm }
                                       { Auth-Application-Id } 
                                       { Exchange-Type }
                                       { Exchange-Data }
                                       * [ Proxy-Info ] 
                                       * [ AVP ]

Message definition contains two non standard AVPs which are crucial to example application.
Both AVPs are specific to this application and are simple, not grouped AVPs. They are defined as follows:

                                |    AVP Flag rules   |
                |  | |SHLD| MUST|MAY |
Attribute Name  Code Data Type  |MUST| MAY | NOT|  NOT|Encr|
Exchange-Type    888 Enumerated | M,V|  P  |    |    | N  |
Exchange-Data    999 UTF8String | M,V|  P  |    |    | N  |

Exchange-Type is simple enumerated AVP. Its code is 888 with Vendor ID equal to our examples vendor ID.
There are three possible values that this AVP may carry:
  • 0: INITIAL - indicates start of data session exchange
  • 1: INTERMEDIATE - indicates follow up exchange(consequent exchange)
  • 2: TERMINATING - indicates last exchange, after answer is sent, session is terminated

Exchange-Data is simple UTF8String AVP. Its code is 999 with Vendor ID equal to our examples vendor ID. It contains data that has to be exchanged.

Since AVPs and messages are defined we need to define session FSM, so we know how to code exchange of messages. Since it has to be simple, lets consider such scenario:
  1. client sends SAR with Exchange-Type set to INITIAL, server resonds with SAA
  2. session starts
  3. it can be followed by number of SAR with Exchange-Type set to INTERMEDIATE
  4. session continues
  5. client sends SAR with Exchange-Type set to TERMINATING
  6. session ends
Diagram below depicts messages exchange:

Since application logic and message flow has been defined, we can start creating client and server code. However to do that we need to understand how stack interacts with network.
For this example two types of listeners used by stack are relevant to us:

  • NetworkReqListener
  • EventListener
NetworkReqListener is very simple one. It is invoked for requests incoming from network layer. It has single method "processRequest". It is defined as follows:
public interface NetworkReqListener {
        Answer processRequest(Request request);
Instances of this listener type are registered in stack. With registration, stack is given information which applications are of interest for particular listener. That is, listener method is invoked for messages which belong to specific application.
Single method defined in this interface has return type of "Answer". Implementation of this interface may return non null value, in such case its sent as answer to request, for which method is invoked. However if method invocation does not return value, nothing bad happens. In such case, user code has to call session object to send answer explicitly.

Registration of this listener type looks as follows:
Stack stack;
 ApplicationId authAppId = ApplicationId.createByAuthAppId(....);

 Network network = stack.unwrap(Network.class);
    network.addNetworkReqListener(new NetworkReqListener() {
     public Answer processRequest(Request request) {
      //this wontbe called.
      return null;
    }, authAppId);
EventListener is a bit more complicated. It is used to inform application on result of request send operation. It is defined as follows:

public interface EventListener { 
     void receivedSuccessMessage(R request, A answer);
     void timeoutExpired(R request);
It is invoked in two cases:

  • there has been no answer to request: timeoutExpired(R request)
  • answer has been received for request send from this stack: receivedSuccessMessage(R request, A answer)

Instance of this listener type is passed to session object when new request is sent through it.
Sessions and messages exchange
Messages can be exchanged between peers by means of Session objects(RawSession or Session). In our example we will use Session object. Each object of this type represents single diameter session(identified by session-id AVP present in messages). Session object is very basic one. Session object may be in two states: valid and invalid. It is invalidated explicitly by user. Once invalidated, it is not eligible for further use.
Session objects can be obtained from SessionFactory in following way:

SessionFactory factory = stack.getSessionFactory();
 //create new session, with auto generated Session-Id
 Session session = factory.getNewSession(); 

Stack configuration
Stack is configured with instance of "Configuration" object. Current implementation provides instance of this interface which parses XML configuration file. For detailed description of XML tags used in this file please refer to stack guide. Below there is quick guide to essentials we need to make our example application work.
Definition of configuration file looks as follows:

<xsi:element name="Configuration">
            <xsi:documentation>JDiameter configuration&lt/xsi:documentation>
                <xsi:element ref="LocalPeer" minOccurs="1" maxOccurs="1"/>
                <xsi:element ref="Parameters" minOccurs="1" maxOccurs="1"/>
                <xsi:element ref="Network" minOccurs="1" maxOccurs="1"/>
                <xsi:element ref="Security" minOccurs="0" maxOccurs="1"/>
                <xsi:element ref="Extensions" minOccurs="0" maxOccurs="1"/>

To our example only two are relevant(Parameters are of no interest for now):

  • LocalPeer
  • Network
LocalPeer contains configuration options for local diameter node. It includes information like:

    • local peer URI( like aaa://our.localhost:34200 )
    • IP addresses
    • Realm name to which local peer belongs to
    • overload monitor and applications configuration

Network tag contains configuration information concerning network environment:

    • Realms to which local peer is connected
    • Remote peers to which local peer is connected

Below is example configuration file for stack which:

  • identifies itself as, bound to port 13868
  • bound to two NICs
  • belongs to "billing" domain.
  • supports one realm: "service"
  • is connected to single remote peer

<?xml version="1.0"?>
<Configuration xmlns="">

                <URI value="aaa://" />

                        <IPAddress value="" />
                        <IPAddress value="" />
                <Realm value="billing" />
                <VendorID value="0" />
                <ProductName value="jDiameter" />
                <FirmwareRevision value="1" />
                        <Entry index="1" lowThreshold="0.5" highThreshold="0.6">
                                        <VendorId value="0" />
                                        <AuthApplId value="333333" />
                                        <AcctApplId value="0" />


                        <Peer name="aaa://" attempt_connect="true" rating="1" />
                        <Realm name="service" peers="" local_action="LOCAL" dynamic="false" exp_time="1">
                                        <VendorId value="0" />
                                        <AuthApplId value="333333" />
                                        <AcctApplId value="0" />
        <Extensions />

Application Client
Since now we know some basics, we can start creating our client code. Step by step, we should be able to create simple source which will act according to our application FSM.
First we need definition of some static fields, with some values relevant to our application and configuration. Static definition may look as follows:
//configuration files
 private static final String configFile = "org/example/client/client-jdiameter-config.xml";
 private static final String dictionaryFile = "org/example/client/dictionary.xml";
 //our destination
 private static final String serverHost = "";
 private static final String serverPort = "3868";
 private static final String serverURI = "aaa://" + serverHost + ":" + serverPort;
 //our realm
 private static final String realmName = "";
 // definition of codes, IDs
 private static final int commandCode = 686;
 private static final long vendorID = 66666;
 private static final long applicationID = 33333;
 private ApplicationId authAppId = ApplicationId.createByAuthAppId(applicationID);
        //avp codes
 private static final int exchangeTypeCode = 888;
 private static final int exchangeDataCode = 999;
 // enum values for Exchange-Type AVP
 private static final int EXCHANGE_TYPE_INITIAL = 0;
 private static final int EXCHANGE_TYPE_INTERMEDIATE = 1;
 private static final int EXCHANGE_TYPE_TERMINATING = 2;
 //list of data we want to exchange.
 private static final String[] TO_SEND = new String[] { "I want to get 3 answers", "This is second message", "Bye bye" };

Secondly, we require definition of some objects, like stack, session etc. It could look as follows:

//Dictionary, for informational purposes.
 private AvpDictionary dictionary = AvpDictionary.INSTANCE;
 private Stack stack;
 private SessionFactory factory;
        // ////////////////////////////////////////
 // Objects which will be used in action //
 // ////////////////////////////////////////
 private Session session;  // session used as handle for communication
 private int toSendIndex = 0;  //index in TO_SEND table
 private boolean finished = false;  //boolean telling if we finished our interaction

Thirdly, we need code which will initialize stack, session factory and register us as dummy listener for network requests. It could look as follows:

private void initStack() {
  if (log.isInfoEnabled()) {"Initializing Stack...");
  InputStream is = null;
  try {
   //Parse dictionary, it is used for user friendly info.
   dictionary.parseDictionary(this.getClass().getClassLoader().getResourceAsStream(dictionaryFile));"AVP Dictionary successfully parsed.");
   this.stack = new StackImpl();
   //Parse stack configuration
   is = this.getClass().getClassLoader().getResourceAsStream(configFile);
   Configuration config = new XMLConfiguration(is);
   factory = stack.init(config);
   if (log.isInfoEnabled()) {"Stack Configuration successfully loaded.");
   //Print info about applicatio
   Set<org.jdiameter.api.ApplicationId> appIds = stack.getMetaData().getLocalPeer().getCommonApplications();"Diameter Stack  :: Supporting " + appIds.size() + " applications.");
   for (org.jdiameter.api.ApplicationId x : appIds) {"Diameter Stack  :: Common :: " + x);
   //Register network req listener, even though we wont receive requests
   //this has to be done to inform stack that we support application
   Network network = stack.unwrap(Network.class);
   network.addNetworkReqListener(new NetworkReqListener() {
    public Answer processRequest(Request request) {
     //this wontbe called.
     return null;
   }, this.authAppId); //passing our example app id.
  } catch (Exception e) {
   if (this.stack != null) {

   if (is != null) {
    try {
    } catch (IOException e1) {
     // TODO Auto-generated catch block

  MetaData metaData = stack.getMetaData();
  //ignore for now.
  if (metaData.getStackType() != StackType.TYPE_SERVER || metaData.getMinorVersion() <= 0) {
   if (log.isEnabledFor(org.apache.log4j.Level.ERROR)) {
    log.error("Incorrect driver");

  try {
   if (log.isInfoEnabled()) {"Starting stack");
   if (log.isInfoEnabled()) {"Stack is running.");
  } catch (Exception e) {
  if (log.isInfoEnabled()) {"Stack initialization successfully completed.");
Finally we need three more pieces of code to handle initialization of whole procedure, request send and answer handling.
Initialization part could be straightforward and could look as follows:

private void start() {
  try {
   //wait for connection to peer
   try {
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
   //do send
   this.session = this.factory.getNewSession("BadCustomSessionId;YesWeCanPassId;" + System.currentTimeMillis());
  } catch (InternalException e) {
   // TODO Auto-generated catch block
  } catch (IllegalDiameterStateException e) {
   // TODO Auto-generated catch block
  } catch (RouteException e) {
   // TODO Auto-generated catch block
  } catch (OverloadException e) {
   // TODO Auto-generated catch block


Part which actually creates request and sends it via session objects is also quite trivial. It could look as follows:

private void sendNextRequest(int enumType) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  Request r = this.session.createRequest(commandCode, this.authAppId, realmName, serverURI);
  // here we have all except our custom avps

  AvpSet requestAvps = r.getAvps();
  // code , value , vendor, mandatory,protected,isUnsigned32
  // (Enumerated)
  Avp exchangeType = requestAvps.addAvp(exchangeTypeCode, (long) enumType, vendorID, true, false, true); // value is set on creation
  // code , value , vendor, mandatory,protected, isOctetString
  Avp exchangeData = requestAvps.addAvp(exchangeDataCode, TO_SEND[toSendIndex++], vendorID, true, false, false); // value is set on creation
  // send, pass oursevles as EventListener object
  this.session.send(r, this);

In above code, when request is sent this is passed as argument(EventListener). So our client object, must also handle answers. Lets consider that we want to perform following:

  • Send request with some data encoded as string
  • Receive properly formatted answer, with the same data client send
  • In case of error answer, client should terminate operations
Code which does above could look as follows:
 public void receivedSuccessMessage(Request request, Answer answer) {
  if (answer.getCommandCode() != commandCode) {
   log.error("Received bad answer: " + answer.getCommandCode());
  AvpSet answerAvpSet = answer.getAvps();

  Avp exchangeTypeAvp = answerAvpSet.getAvp(exchangeTypeCode, vendorID);
  Avp exchangeDataAvp = answerAvpSet.getAvp(exchangeDataCode, vendorID);
  Avp resultAvp = answer.getResultCode();

  try {
   //for bad formatted request.
   if (resultAvp.getUnsigned32() == 5005 || resultAvp.getUnsigned32() == 5004) {
    // missing || bad value of avp
    this.session = null;
    log.error("Something wrong happened at server side!");
    finished = true;
   switch ((int) exchangeTypeAvp.getUnsigned32()) {
    // JIC check;
    String data = exchangeDataAvp.getUTF8String();
    if (data.equals(TO_SEND[toSendIndex - 1])) {
     // ok :) send next;
    } else {
     log.error("Received wrong Exchange-Data: " + data);
    // JIC check;
    data = exchangeDataAvp.getUTF8String();
    if (data.equals(TO_SEND[toSendIndex - 1])) {
     // ok :) send next;
    } else {
     log.error("Received wrong Exchange-Data: " + data);
    data = exchangeDataAvp.getUTF8String();
    if (data.equals(TO_SEND[toSendIndex - 1])) {
     // good, we reached end of FSM.
     finished = true;
     // release session and its resources.
     this.session = null;
    } else {
     log.error("Received wrong Exchange-Data: " + data);
    log.error("Bad value of Exchange-Type avp: " + exchangeTypeAvp.getUnsigned32());
  } catch (AvpDataException e) {
   // thrown when interpretation of byte[] fails
  } catch (InternalException e) {
   // TODO Auto-generated catch block
  } catch (IllegalDiameterStateException e) {
   // TODO Auto-generated catch block
  } catch (RouteException e) {
   // TODO Auto-generated catch block
  } catch (OverloadException e) {
   // TODO Auto-generated catch block


As you can see, client code is quite simple. It is not smarty-pants code, its sole purpose is to show how to interact with stack.
Server code is very similar. Whole source with configuration files and ready to run scripts can be found in our gcode svn.

Thursday, November 18, 2010

Syntax highlighter

Just testing cool tool for syntax.

class X implements{

    public void makeMyDay()

Downside of this, is that for each snippet I need to edit HTML, but still... looks a lot better.Also sometimes "Compose" will still use editor &ltpre>  to embed new content.

To use this tool add ref in head of blog template to .js and .css files:
<link href='' rel='stylesheet' type='text/css'/>
<link href='' rel='stylesheet' type='text/css'/>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script src='' type='text/javascript'></script>
<script type='text/javascript'>
  SyntaxHighlighter.config.clipboardSwf = '';
  SyntaxHighlighter.config.bloggerMode = true;
and follow instructions: found here (look for section with examples).

Monday, October 11, 2010

Mobicents Team building 2010, Antalya, Turkey

Exactly, that one event in year, when whole team is supposed to have fun and work in close quarters(yes).

Whole event has been organized by Eduardo M. M., big thanks. It was one of best events, if not THE best we had so far. We stayed in 5 start hotel & SPA center. Awesome place to chill out. Just look at pictures:

This year was actually special for two reasons. First reason is the fact that whole team has gathered for the first time. Yes, thats true. During past years we always had bad luck and someone either did not make it, or just couldnt. This year even we met all, for the first time. Even Tom, who works from Brisbane office joined us.

Second reason is fact that some community users and customers joined us on short notice. This proved to be very, very good turn of events.

Most of us arrived on 24th night or evening, so start was a bit slow - simple catching up with cold beer in hand at the bar.
Next day was strictly fun day, no work(well we talked about roadmaps on the bus, but that does not count). Rafting time! We took a bus from hotel which drove us somewhere in the mountains. Once the bus stopped we got out, our prayers have been heard, we were alive - seriously if you dont buckle up, go there, have a ride, those guys are insane.
From that spot we took huge rafts and went down the river. It was quite good fun.

Now, enough about fun. Since that point, our regular day looked more or less the same: breakfast, work, 1-2h relax time, more work, party till morning.
Total we had three and a half day for our presentations, discussions and everything related. During that period of time, as each year, we went through all projects, their achievements, shortcommings and roadmaps.
Additionally this year some other topic were brought up to attention and discussed - like Clustering or SS7 training session. 
Unfortunetly three days were not enough to go through all of our fields of interest. Certainly sign that we should extended next years event. Example topics that were discussed only with beer in hand are for instance: SIP Presence or IPBX.

Our first day started with private sessions during which we discussed some internal stuff, crucial to our future. After that plan looked as follows:

 Eduardo presented our efforts to bring best open soruce JSLEE container :). So....
We had very good year, lots of work, lots of community feedback. Extremly  successful 2.x release of container. We completly reworked 2.x core to achieve:

  • high performance - over 4x compared to 1.x generation of container
  • low latency
  • fault tolerance

His presentation covered also major features and development efforts we made, like:

  • Container's core modularization and SPI
  • Server's state replication
  • Fault Tolerant RA API
  • Congestion Control
  • Event Router Stats and Execution Mapper
  • Simplified Global Logging Configuration
  • New or Reworked RAs (JCC, ISUP, MAP, XCAP Client)
  • Jopr Web Console
  • Enhanced or simplified external SLEE Connection.

In the end he covered roadmaps for immediate release and long term efforts:

Mobicents JAIN SLEE 2.2.0

  • Part I of clustering performance enhancements (8x compared with 2.1.2)
  • Buddy groups clustering
  • Twiddle Command Line Interface (CLI), which we believe will be a major tool for developers and platform administrators
  • Part I of JAIN SLEE 1.1 Extensions, specially the one which allows JAIN SLEE Libraries to depend on other SLEE component types, such as RA Types
  • Eclipse SLEE Plugin 2.0
  • SMPP v5 Resource Adaptor
  • Misc performance optimizations on SLEE facilities, such as Tracers

Mobicents JAIN SLEE 2010/11 Roadmap Draft

  • JAIN SLEE 1.1 Extensions: Annotations & ConfigProperties
  • Jopr Web Console 2.x (or something else if we are not able to solve current version limitations)
  • EclipSLEE 2.1
  • Mobicents Cluster Framework 3.x with Advanced Buddy Groups features such as high performance intra group broadcasting of notifications
  • Second wave of SS7 RAs
  • JSR 309 RA

For detailed info follow Eduardos blog.


Diameter presentation was a first one I did this year. This was actually a crash course training and as such it can not be disclosed as other presentations. 
In crash course Ive covered following:
  • DIAMETER basics - data structures, encoding, protocol base
  • DIAMETER domains
  • Base application
  • Accounting application
  • Credit Control Application(rfc4006)
  • Ro & Rf applications

During Diameter time, Alex covered our development efforts and roadmap.
In short it was quite good year.  Roadmap was a bit packed. Only two features did not make it since there was no interest - WS Support and HSS. Major features and development efforts on diameter are as follows:
  • SOAK testing 
  • CPU and memory stability
  • XML configurable dictionary and validator
  • implementation of different applications(Cx/Dx,Sh,Ro,Rf,Cca....) along with JSLEE RAs
  • FT/HA support
  • performance improvement( over 4x )
  • documentation
  • JOPR console
  • Improved AVP handling

For next year we plan to split work in two directions. Continue 1.4.x branch with improvements and start new one. The 2.x will be testing field for next gen stack, which should be more user friendly and much more  performant.

For 1.4.x we have planned following:


  • parser separation from stack metadata
  • testing framework for application sessions
  • profiling and improving clustering code
  • improve thread management
  • IPSEC/TLS support
  • testing framework for JSLEE RAs
  • support plugable/configurable load balancing algorithm in stack
  • integration with SIP loadbalancer
  • ...
This is just a short list, full has much much more, its quite packed and scary.

For 2.x we have planed following:
  • redesign API to be user friendly
  • evaluate IoC as good approach
  • decouple sessions and message creation
  • SCTP support
  • greater perofrmance(over 1k exchanges/s)
  • ....


During one of my time slots I have conducted quick crash course about SS7 and our progress in this field.
Crash course proved to be a bit confusing for some. But it drove our community guest into discussion, in which they shared their experience, field of interest and expectations. It was quite good and valuable discussion.

SS7 progress during last year is tremendous. We have started very slow and picked up pace. 
From almost no working code and experience we finished with support for:
  • Dialogic and Intel based SS7 cards - this includes implementation of MTP levels
  • M3UA integration
  • SCCP
  • ISUP
  • TCAP
  • MAP
  • USSD Gateway
In future we plan to get SS7 training on operators side to be able to meet production quality with our code. In near future we will stabilize SS7 stack layers and test everything end to end with real hardware in our lab, which is being created.
Last but not least we plan to add more protocols to USSD Gateway we have been developing.

SS7 presentation can be found here.

Media Server

During this event Amit and Oleg presented last years achievements and problems we faced on media field.

In media processing accuracy and predictability is what counts. To address that requirement we had to give away multi threading and java timers. Our work on MMS has been centered around:
  • stability
  • predictability
  • accurate implementation of scheduler(very low overhead, with 1ms precision)
  • reducing number of active threads - MMS core and MGCP stack
  • improving performance with 3rd party libraries(like TTS, MBROLA)
The outcome is best performing server on low end machine with 300x concurrent, bidirectional connections!

Future plans for MMS are to split development in two directions. First one is to continue 2.x development and concentrate on stability and perofrmance with voice media.

Second is to start 3.x development which will include video support.

Near future roadmap(2.1.0-B1) includes following:
  • B-Channel endpoint for SS7
  • smart voice pool
  • configurable connection count for endpoints
  • RTCP support
  • Audit endpoint support

Thats it. Looking forward for next years TB event. Hope that more community users will show up.