Messages

From Yate Documentation
Revision as of 17:16, 26 March 2013 by Andrei (Talk | contribs)

Jump to: navigation, search

Messages are the main piece of Yate. We use them between modules insted of using functions. We do this mainly because if one module is changing we don't have to change all the other modules that are dependent, and also because we can debug what's happening in the engine much easier since we know which module passes which data to another module.

Contents

Components of a message

A message is a holder for several components:

  • name - identifies the message type and allows matching it against the possible handlers
  • return value - a string that is used as returned value by the emitter of the message
  • time - the time the message was created. This is important if the messages are queued for an indefinite amount of time
  • parameters - an arbitrary number (including zero) of string values, each having a name. Each handler can take action based on specific parameters and/or modify them. Unknown parameters must be ignored.

All the messages are binary inside of Yate. However you can use Rmanager to get them out in a human readable form.

The messages are passed using memory sharing. In this way we have a pretty optimized system. Other options like pipes or sockets have been considered, but failed to give us the flexibility and speed needed. When passed to external modules the messages are converted to an escaped string encoding that allows handling any special characters that may be present in the message's components.

How messages are processed

Message Handlers

Messages can be processed by message handlers. These receive messages whose names match the handler's name. They can freely modify the message's components (parameters, returned value, even the name) and finally they can stop processing the message or let it slip to the next handler.

The order in which handlers are called to attempt to process a message is established when the handlers are inserted in the dispatcher. The ordering of handlers is by their priority, a handler with a lower numerical priority is inserted earlier in list and receives the message before a handler with a higher numerical priority.

There is NO GUARANTEE about the order between handlers of equal priority although currently the following rules apply:

  • The order this does not change between messages.
  • To avoid uncertainity and preserve order if a handler is removed and reinserted handlers of equal priority are sorted by their address.

Message Queue

Message Queues provides a mechanism for using a separate message queue for a message type. When you create a MessageQueue instance you need to specify the number of workers to use for message processing. A message queue is populated by Engine::enqueue() method, if the queued message matches the queue filters. A message queue can have multiple filters, but it can serve only one message type; e.g.: you can not create a message queue for call.route and call.preroute messages but you can create multiple queues for one message e.g.: call.route, caller=123 and call.route, caller=124. A message queue can be identified by the message name that it serves, and, a list of filters. The filters represent a name value pair. When a message is added to a queue only if the message name equals the queue name and, the message has identical fields in his body as the message queue filters. The method received can be re-implemented in this way a direct processing can be made for the message. Re-implementing received method can be sometimes be risky, because the messages will not be processed by the installed MessageHandlers; so if you are sure that the messages from the queue should only be processed by you than that's the reason the MessageQueue was implemented for. But if you want that the message to be processed by installed engine's handlers than you may want to call Engine::dispatch() method after you had finished pre-processing the message. A JavaScript API exists for MessageQueue and it can be found here.


Example of call.route message

A very good example about how the message system works is the "call.route" message.

Generate the message

When a call comes in at some point, a messages is generated like this:

  Message *m = new Message("call.route"); 
 m->addParam("driver","iax"); 
 if (e->ies.calling_name) 
     m->addParam("callername",e->ies.calling_name); 
 else 
   m->addParam("callername",e->session->callerid); 
 if (e->ies.called_number) 
   m->addParam("called",e->ies.called_number); 
 else 
   m->addParam("called",e->session->dnid);

Send the message to engine

Then we send the message to the Engine and we find out if some module did actually accept to handle it. We must also destruct the message.

  if (Engine::dispatch(m))
    Output("Routing returned: %s",m->retValue().c_str());
  else
    Output("Nobody routed the call!");
  m->destruct();

The Engine is getting the above message and is sending it to all the modules that have registered a "route" handler.

Fire-and-forget messages

It is also possible to fire-and-forget messages. They are stored in a queue in the engine and dispatched later in threads that belong to the engine. Once such a message is dispatched it is destroyed by the engine.

  Message *m = new Message("alert");
  m->addParam("reason","Hardware malfunction");
  Engine::enqueue(m);

Handle a route request

To handle a route request (probably in another module) we first have to declare a class RouteHandler derived from MessageHandler.

class RouteHandler : public MessageHandler
{
public:
    RouteHandler(int prio)
        : MessageHandler("call.route",prio) { }
    virtual bool received(Message &msg);
};

Then, because the received method is a pure virtual in the MessageHandler class, we must override it.

bool RouteHandler::received(Message &msg)
{
   const char *driver = msg.getValue("driver")
   Debug(DebugInfo,"Route for driver %s",driver);
   // don't actually route anything, let message continue
   return false;
}

Install the handler

And finally, in the plugin initialized method we can install the handler.

 m_route = new RouteHandler(priority);
   Engine::install(m_route); 

To get more references about messages read the Message class documentation at API::Message.


See also

Personal tools
Namespaces

Variants
Actions
Preface
Configuration
Administrators
Developers