Hello World ser.cfg Analysis

Now that you have seen our 'Hello World' SIP proxy configuration, we'll explain each line in the file so that you can begin to understand the basics of SER.

This configuration is a complete, albeit, minimal SIP router. SIP clients can register with the SIP proxy and can call other registered users. This configuration however is far from complete in terms of functionality. For one thing, if the SIP proxy is restarted then all client registration information is lost because there was no mechanism for persisting registration information to disk. Call features are also absent as well as NAT traversal and voice mail. But don't worry as we will cover all these topics later on. For now, lets just concentrate on a bare bones SIP router.

1

SER has debug information that can be enabled or suppressed using the debug directive. A nominal value of 3 is usually specified to obtain enough debug information when errors occur. The debug directive specifies how much information to write to syslog. The higher the number, the more verbose SER becomes. The most verbose debug level is 9. When the debug level is set higher than 3 SER becomes very verbose and the start up time can take a bit longer.

2

The fork directive tells the SER daemon to run in the foreground or the background. When you are ready to operate SER as a system service, you must set this directive to yes. For now we will just operate SER as a foreground process.

NOTE: See the appendix for a SER init.d start script.

3

Since we are running SER as a foreground process we must set the log_stderror directive equal to yes in order to see the output

4

The listen directive instructs SER to listen for SIP traffic on a specific IP address. Your server must physically listen on the IP address you enter here. If you omit this directive then SER will listen on all interfaces.

NOTE: When you start SER, it will report all the interfaces that it is listening on.

5

In addition to specifying the IP address to listen on you can also specify a port. The default port used on most SIP routers is 5060. If you omit this directive then SER assumes port 5060.

6

The children directive tells SER how many processes to spawn upon server start up. A good number here is 4, however, in a production environment you may need to increase this number.

7

These lines are really to prevent SER from attempting to lookup its IP address in DNS. By adding these two lines to ser.cfg we suppress any warnings if your IP is not in your DNS server.

8

The fifo directive specifies the location of the SER FIFO. The FIFO is sort of like the Linux proc file system and can be used to examine the current SIP proxy activity. The FIFO can also be used if you want to inject a new SIP message directly in to the SIP proxy with an external application. A good example of this is the serctl utility that is usually located in /usr/local/sbin/. With this utility you can manage users, ping SIP URIs, and even email a SIP user. Serctl does all of this internally using the FIFO.

The FIFO can be located just about anywhere on disk, however, the user account that SER runs under must be able to create the FIFO in the specified directory.

9

Here we have external modules that are necessary for our 'hello world' SIP proxy to function. SER modules may be located anywhere on the disk system, but /usr/local/lib/ser/modules is the default location. Loading a module is as simple as specifying in a loadmodule directive as shown.

If you're wondering how you know which module or modules you need, well there is no clear cut way to know. In general the modules shown here will be needed by every SIP proxy configuration. When you need to add additional functionality, such as MySQL connectivity, then you will load the appropriate module, in this case the mysql.so module.

All SER modules are distributed with the source code and located at <ser-source>/modules. Every SER module has a README file that explains all the items that it exposes for use in a ser.cfg file. It is highly recommended that you spend some time familiarizing your self with the available SER modules. This document makes a valid attempt at explaining the most important SER modules and how to use them, but there is no substitute for reading the actual module README files.

Some modules have parameters that need to be set in ser.cfg in order for the module to function properly. Other modules, however, operate normally in most cases without any parameter adjustments. The next section will show our 'hello world' requirements.

10

The usrloc module is responsible for keeping track of SIP client registration locations. In other words, when a SIP client registers with the SIP proxy, SER will store the contact information, also known as the Address Of Record (AOR), in a table. This table is then queried when another SIP client makes a call. The location of this table can vary depending on the value of the usrloc db_mode parameter.

Our SIP proxy sets db_mode to zero to indicate that we do not want to persist registration data to a database. Instead we will only store this information in memory.

We will show how to persist AORs in a later example.

(11)

The rr parameter called enable_full_lr is really a work-around for older SIP clients that don't properly handle SIP record-route headers. SIP RFC3261 says that specifying loose routing by including a ;lr in the record-route header is the correct way to tell other SIP proxies that our SIP proxy is a loose router. However, some older and/or broken SIP clients incorrectly dropped the ;lr tag because it didn't have value associated with it (ie, lr=true).

Therefore, by setting enable_full_lr to one, SER will write all ;lr tags as ;lr=on to avoid this problem.

(12)

This is the beginning of the SIP processing logic. This line defines the main route block. A route block must have a beginning and ending curly bracket.

The main route block is where all received SIP messages are sent. From the main route block you can call other route blocks, test the message for certain conditions, reject the message, relay the message, and basically do anything you need to fit your business needs.

Here is a main overview of what happens:

  1. A message enters the main route and we do some checks

  2. We determine if the message is for us, if not we just send it to where it belongs (route[1])

  3. If its for us, we explicitly handle REGISTER messages (a message from a phone asking to register itself). Route[2] handles REGISTERs by saving where we can reach the phone, while route[1] is a default handler for all other messages.

NOTE: It may appear odd to present such simple functionality this way, but we will use this structure as the basis for a much more complex ser.cfg which is presented step-by-step in following sections.

The details are below.

(13)

mf_process_maxfwd_header is a safety check that you should always include as the first line of your main route block. This function is exposed in the mf.so module and is used to keep track of how many times a SIP message has passed through SER. Erroneous ser.cfg files can send a SIP message to the wrong location and cause looping conditions. Also other SIP proxies that SER interacts with can do the same thing.

The basic rule here is that if this function ever returns 'true' then you need to stop processing the problematic message to avoid endless looping.

(14)

If a looping situation is detected then SER needs a way to tell the SIP client that an error has occurred. The sl_send_reply() function performs this job. sl_send_reply() is exposed in the sl.so module and all it does is sends a stateless message to the SIP client. This means that SER will send the message and forget about it. It will not try to resend if it does not reach the recipient or expect a reply.

You can specify an appropriate error message as shown. The error message can only selected by the defined SIP error codes and messages. Many IP phones will show the text message to the user.

(15)

The break statement tells SER to stop processing the SIP message and exit from the route block that it is currently executing. Since we are calling break in the main route block, SER will completely stop processing the current message.

(16)

msg:len is a core SER function that returns the length in bytes of the current SIP message. This, like mf_process_maxfwd_header() should be called at the beginning of the main route block in all ser.cfg files.

This statement simply tests the length of the SIP message against the maximum length allowed. If the SIP message is too large, then we stop processing because a potential buffer overflow has been detected.

(17)

Here we look to see if the SIP message that was received is a REGISTER message. If it is not a register message then we must record-route the message to ensure that upstream and/or downstream SIP proxies that we may interact with keep our SIP proxy informed of all SIP state changes. By doing so, we can be certain that SER has a chance to process all SIP messages for the conversation.

The keyword 'method' is provided by the SER core and allows you to find out what type of SIP message you are dealing with.

(18)

The record_route() function simply adds a Record-Route header field to the current SIP message. The inserted field will be inserted before any other Record-Route headers that may already be present in the SIP message. Other SIP servers or clients will use this header to know where to send an answer or a new message in a SIP dialog.

(19)

loose_route() tests to see if the current SIP message should be loose routed or not. If the message should be loose routed then SER should simply relay the message to the next destination as specified in the top-most Record-Route header field.

In all ser.cfg files you should call loose_route() after the record_route() function.

This is the basic definition of loose routing. Refer to RFC3261 for a complete explanation of loose routing.

Note for interested readers:

# RFC3261 states that a SIP proxy is said to be "loose routing" if it

# follows the procedures defined in this specification for processing of

# the Route header field. These procedures separate the destination of the

# request (present in the Request-URI) from the set of proxies that need to

# be visited along the way (present in the Route header field). A proxy

# compliant to these mechanisms is also known as a "loose router".

#

# SER is a loose router, therefore you do not need to do anything aside

# from calling loose_route() in order to implement this functionality.

#

# A note on SIP message dialogs (contributed by Jan Janak):

#When it comes to SIP messages, you can classify them as those that

#create a dialog and those that are within a dialog. A message within

#a dialog (ACK, BYE, NOTIFY) typically requires no processing on the

#server and thus should be relayed at the beginning of [your ser.cfg]

#right after loose_route function.

#

#Messages creating dialogs can be further classified as those that

#belong to the server (they have the domain or IP of the server in

#the Request-URI) and those that do not. Messages that do not have a

#domain or IP of the proxy in the Request-URI should be immediately

#relayed or blocked.

(20)

If the test for loose routing returns 'true' then we must relay the message without other processing. To do so we pass execution control to route block number one (ie, route[1]). This route block is documented later but it suffices now to say that it is the default message handler.

(21)

Since loose routing was required we cannot process the message any further so we must use a break command to exit the main route block.

(22)

Now we have come to a part of the SIP configuration file were we are processing out-of-dialogue messages. In other words, we are processing either a message that will begin a new dialogue, or we are processing a SIP message that is not destined for our sip proxy (but we are relaying or proxying the message).

The keyword 'uri' is defined in the SER core and is a synonym for the request URI or R-URI for short. The 'myself' keyword is also defined in the SER core and is a synonym for the SER proxy itself.

So this line tests to see if the R-URI is the same as the SIP proxy itself. Another way to look at it is by saying that if this statement is TRUE then the SIP message is not being sent to our SIP proxy but rather to some other destination, such as a third party SIP phone.

(23)

Relay the message to the destination without further interrogation.

(24)

Stop processing the current message because we have sent it to its destination on the previous line.

(25)

ACK messages are explicitly handled, so we need to find out if we are processing an ACK request.

(26)

Relay the message to the destination without further interrogation.

(27)

Stop processing because the ACK message has already been fully processed.

(28)

REGISTER messages are explicitly handled, so we need to find out if we are processing a registration request.

(29)

All registration requests are passed to route[2] for processing. We do this to somewhat segregate the workload of the main route block. By doing so we keep our ser.cfg from becoming unmanageable.

(30)

Stop processing because the REGISTER message has already been fully processed.

(31)

Lookup(aliases) attempts to retrieve any aliases for the Requested URI. An alias is just another way to refer to a SIP destination. For example, if you have a SIP user 4075559938 and a toll free number 8885551192 that rings to 4075559938, then you can create the toll free number as an alias for 4075559938. When someone dials the toll free number the SIP client configured as 4075559938 will ring.

The lookup(aliases) function is not strictly needed for this example, however, serctl, which is a command line utility included with SER requires this line for it to operate properly.

(32)

If an alias was found and the Requested URI is no longer a locally served destination, then we relay the SIP message using our default message handler route[1]. After the message is relayed we stop processing by means of the break command.

(33)

lookup(location) attempts to retrieve the AOR for the Requested URI. In other words it tries to find out where the person you are calling is physically located. It does this by searching the location table that the save() function updates. If an AOR is located, we can complete the call, otherwise we must return an error to the caller to indicate such a condition.

(34)

If the party being called cannot be located then SER will reply with a 404 User Not Found error. This is done in a stateless fashion.

(35)

Since the user cannot be found we stop processing.

(36)

If the current SIP message is not a REGISTER request, then we just relay it to its destination without further processing. We do this by passing control to route[1], the default message handler.

(37)

Route[1] is the default message handler that is used throughout the ser.cfg file to relay messages. Notice how the route block definition uses square brackets, but to call a route block you use parenthesis.

(38)

t_relay() is a function exposed by the tm.so module and is perhaps one of the most important functions in any ser.cfg file. t_relay() is responsible for sending a message to it's destination and keep track of any re-sends or replies. If the message cannot be sent successfully, then t_relay() will return an error condition.

See section 1 for more in-depth background information on transactions.

(39)

If t_relay() cannot send the SIP message then sl_reply_error() will send the error back to the SIP client to inform it that a server error has occurred.

(40)

Route[2] is the registration message handler. This is where we store user contact data.

(41)

All REGISTER messages are happily honoured because we have not yet implemented authorization checks. The save() function is responsible for storing SIP client registration information in the location table. However, recall that the usrloc db_mode has been set to zero on line 5.1. This means that the save() function will only save the registration information to memory rather than to disk.

(42)

If SER is unable save the contact information then we just return the error to the client and return to the main route block.