Skip to main content
Version: 2.0.0

Message Dispatcher

The Message Dispatcher, or Dispatcher for short, is a component responsible for receiving messages from the EdgePort and routing them to the appropriate Processor and Middleware.

The Dispatcher is required when your deployment has more than one Processor or has at least one Middleware. If your deployment has only one Processor and no Middleware, you can skip the Dispatcher and connect the EdgePort directly to the Processor.

The following diagram shows the relation between the EdgePort, the Message Dispatcher, and the Message Processor.

┌────────┐ ┌──────────────────┐             ┌─────────────────┐
│EdgePort│ │Message Dispatcher│ │Message Processor│
└───┬────┘ └──────┬───────────┘ └────────┬────────┘
│ │ │
│gRPC request │ │
│────────────>│ │
│ │ │
│ │findProcessor() & forwardMessage()│
│ │─────────────────────────────────>│
│ │ │
│ │ Processed Message │
│ │<─────────────────────────────────│
│ │ │
│gRPC response│ │
│<────────────│ │
┌───┴────┐ ┌──────┴───────────┐ ┌────────┴────────┐
│EdgePort│ │Message Dispatcher│ │Message Processor│
└────────┘ └──────────────────┘ └─────────────────┘

Configuration Spec

To configure the Dispatcher, you must provide a YAML or JSON configuration with the following structure.

You can configure the Dispatcher using a YAML or JSON file that has the following structure:

PropertyDescriptionRequired
refReference to the DispatcherYes
spec.bindAddrIpv4 interface to accept requests onNo
spec.processorsList of ProcessorsYes
spec.processors[*].refReference to the ProcessorYes
spec.processors[*].matchFuncMatching functionYes
spec.processors[*].addrAddress of the ProcessorYes
spec.processors[*].methodsList of SIP Methods supported by the ProcessorYes
spec.middlewaresList of MiddlewaresNo
spec.middlewares[*].refReference to the MiddlewareYes
spec.middlewares[*].addrAddress of the MiddlewareYes
spec.middlewares[*].postProcessorWhether to process the SIP Message after the ProcessorYes

Here is an example of a configuration file:

Filename: dispatcher.yaml or dispatcher.json

kind: MessageDispatcher
apiVersion: v2beta1
ref: message-dispatcher
spec:
bindAddr: 0.0.0.0:51901
processors:
- ref: connect-processor
addr: connect:51904
matchFunc: req => true
methods:
- REGISTER
- MESSAGE
- INVITE
- ACK
- BYE
- CANCEL

The matching function is a Javascript function that takes the SIP Message and returns a boolean value. The Dispatcher will forward the message to the first Processor that matches the criteria. Therefore, the order of the Processors and the matching function is essential to ensure the correct routing.

The matchFunc is a javascript function that leverages the JSON representation of the SIPMessage protobuf.

This example features a Dispatcher that matches MESSAGE requests to the IM Processor and all others to the Connect Processor.

kind: MessageDispatcher
apiVersion: v2beta1
ref: message-dispatcher
spec:
bindAddr: 0.0.0.0:51901
processors:
- ref: im-processor
addr: im:51904
matchFunc: req => req.method === "MESSAGE"
methods:
- MESSAGE
- ref: connect-processor
addr: connect:51904
matchFunc: req => true
methods:
- REGISTER
- INVITE
- ACK
- BYE
- CANCEL

The following examples show typical matching functions:

Match all SIP Messages.

req => true

Match SIP Messages with a specific method.

req => req.method === "MESSAGE"

Match SIP Messages with a specific method and a specific header.

req => req.method === "MESSAGE" && req.message.from.address.uri.user === "alice"

Match SIP Messages with a specific User-Agent header.

req => req.message.extensions.find(e => e.name === "User-Agent" && e.value.includes("Zoiper"))

Communication and Protobuf Spec

The Message Dispatcher uses gRPC to communicate with the Processors and Middlewares, which happen to share the protobuf definition:

syntax = "proto3";

package fonoster.routr.processor.v2beta1;

import "common.proto";
import "sipmessage.proto";

// Processor service
service Processor {
// Process Message Request
rpc ProcessMessage (MessageRequest) returns (MessageResponse) {}
}

enum Method {
UNKNOWN = 0;
// Communicates user location (hostname, IP)
REGISTER = 1;
// Establishes a session
INVITE = 2;
// Transports Instant Messages
MESSAGE = 3;
// Publishes an event to the Server
PUBLISH = 4;
// Notifies the subscriber of a new event
NOTIFY = 5;
// Subscribes for Notification from the notifier
SUBSCRIBE = 6;
// Confirms an INVITE request
ACK = 7;
// Terminates a session
BYE = 8;
// Cancels establishing of a session
CANCEL = 9;
// Communicates information about the capabilities of the calling and receiving SIP phones
OPTIONS = 10;
// Provisional Acknowledgement
PRACK = 11;
// Sends mid-session information
INFO = 12;
// Asks the recipient to issue a call transfer
REFER = 13;
// Modifies the state of a session
UPDATE = 14;
}

message NetInterface {
string host = 1;
int32 port = 2;
fonoster.routr.common.v2beta1.Transport transport = 3;
}

message MessageRequest {
// Same as the Call-Id header
string ref = 1;
string edge_port_ref = 2;
Method method = 3;
NetInterface sender = 4;
repeated NetInterface listening_points = 5;
repeated string external_addrs = 6;
repeated string localnets = 7;
fonoster.routr.sipmessage.v2beta1.SIPMessage message = 8;
map<string, string> metadata = 9;
}

message MessageResponse {
NetInterface sender = 1;
fonoster.routr.sipmessage.v2beta1.SIPMessage message = 2;
map<string, string> metadata = 3;
}

Link to the protobuf definition.

Launching the Dispatcher with Docker

The Message Dispatcher is available as a Docker image from Docker Hub. To launch the Dispatcher with Docker, you can use the following command:

docker run -it -v $(pwd)/dispatcher.yaml:/etc/routr/dispatcher.yaml -p 51901:51901 fonoster/routr-dispatcher

The previous example will pull the latest version of the Dispatcher from Docker Hub and launch it with the default configuration. The Dispatcher will be listening on port 51901 for gRPC requests. Remember, your Docker container must expose the ports in your configuration file. By default, the Dispatcher listens on port 51901.

Quick Test with gRPCurl

One easy way to interact with the Dispatcher for testing and development is to use gRPCurl. The following example shows how to send a SIP Message to the Dispatcher.

grpcurl -plaintext \
-import-path /path/to/protos \
-proto processor.proto -d '{...}' \
localhost:51901 \
fonoster.routr.processor.v2beta1.Processor/ProcessMessage