Course 2 / Lecture 7

How to build a VoIP PBX in C#

How to connect two PBX systems to work as one?

Download: pbx-database.zip

Ozeki VoIP SIP SDK saves you a great deal of effort by providing professional background for PBX development. This article presents how you connect two SIP PBX systems in order to make them work as one PBX using Ozeki SIP SDK.
You can also learn how to build a PBX cluster to have a redundant VoIP system. You can use clustering to be prepared for hardware failures.

connecting two pbx systems
Figure 1 - Connecting two PBX systems to work as one

Why should be PBXes connected together?

PBX systems are basically for establishing phone lines for VoIP clients. These systems need to provide great reliability and stability. The expected reliability of a PBX system is five 9s that means that the system has to be reachable in 99,999% of time excluding planned shutdowns.

You can provide this great reliability by using more PBX systems at the same time. This does not necessarily means that your system will look like using more PBXs as you can config them to look like a single one with the help of Ozeki VoIP SIP SDK (Figure 1).

You would also need to connect two PBX systems together when you have more office departments where you want to use separate PBXs. In this case the office PBXs are connected to each other and the inter-office calls are made by having only one line established between the PBX systems. This allows the usage of only one port for internal calls.

Creating redundancy in a VoIP network increases the reliability and the performance of the system. The PBX system reliability should be five nines (99.999%) that means that the network downtime cannot exceed 5 minutes in a year except for the planned system shutdown. When you use more PBX systems as one, if one of them goes down for any reason, the other can take over and handle the calls so the users do not notice the problem at all.

Using more PBX systems in a network can also handle the case when the company has more than one offices in different locations and they want to use a connected VoIP communication network. In this case the PBX systems handle the subnetworks and they are connected to each other in order to assure the communication between the far away employees like they were in the same office.

Building a PBX cluster, you can achieve higher availability to your PBX. The aim of a highly available system is to provide continuous VoIP service.

How to implement PBX cluster using C#?

A PBX (created with Ozeki VoIP SIP SDK) cluster is based on the Microsoft Cluster Server technology. This means that if a failure occurs on a server that is a member of the cluster (for example on PBX 1 or PBX 2), the VoIP service that the failing server was hosting will automatically restart itself on another server that is a member of the same cluster.

connecting two pbx systems
Figure 2 - Connecting two PBX systems using Microsoft Cluster Service

To build an Ozeki VoIP SIP SDK PBX cluster you need to have Windows Server (2003 Enterprise Edition or Datacenter Edition, 2008 Enterprise Edition or Datacenter Edition or Windows Server 2012) installed on all computers in the cluster. We recommend you to use the latest service packs for Windows Server, but it is important to install the same service pack on all computers in the cluster.

All nodes in the cluster must be in the same architecture. This means that if you use x86-based Windows Server on one node, you need to use the same on the other node, as well.

Important: Microsoft supports a failover cluster solution only if all the hardware components are certified for Windows Server. In addition, the complete configuration (servers, network, and storage) must pass all tests in the Validate a Configuration Wizard, which is included in the Failover Cluster Manager snap-in. Concerning hardware, please refer to the Microsoft Cluster Server Administrator's Guide for a list of supported hardware configurations and hardware configuration information.

The VoIP SIP SDK PBX service that the cluster runs uses resources of the cluster nodes. The VoIP service running on the cluster has its own Hard drive assigned to it (which is shared with the other failover cluster nodes), it has its own IP Address and it has its own Network name. All of the resources that a clustered VoIP SIP SDK PBX service uses are called a Resource Group. The Resource group contains the basic resources that the VoIP SIP SDK PBX service needs, Disk Drive, IP Address, and the service itself. All of these together form a virtual server that can be moved from one server to another in a matter of seconds (Failover) without any dependence on a specific server. The user that accesses this virtual VoIP SIP SDK PBX server will be exposed to it like to any other VoIP SIP SDK PBX installation.

What is shared storage? How does it work?

To setup a fault tolerant PBX cluster, the first thing to do, is to build a shared storage facility. This facility should have a disk subsystem that uses RAID (Redundant Array of Independent Disks).

RAID refers to the grouping of individual hard disks in a way that provides continued operation in the event of a disk failure. The shared storage you setup for a PBX cluster can be both hardware RAID (e.g., a RAID controller is used) and software RAID (e.g., the functionality is provided by an operating system or application). There are many forms (levels) of RAID:

  • RAID-0: Stripe set without parity. Stripe sets work well with databases due to the usually random I/O nature of database transactions. In RAID-0, data is divided into blocks and spread (in a fixed order) across all of the disks in an array. RAID-0 improves read/write performance by spreading operations across multiple disks, so that operations can be performed independently and simultaneously. While RAID-0 provides the highest performance, it does not provide any fault tolerance. If a drive in a RAID-0 array fails, all of the data within the stripe set becomes inaccessible.
  • RAID-1: Mirroring. Disk mirroring provides a redundant, identical copy of a disk. Data written to the primary disk is also written to a mirror disk. RAID-1 provides fault tolerance and generally improves read performance, but it may also degrade write performance. Because dual-write operations can degrade system performance, many mirror set implementations use duplexing, where each mirror drive has its own disk controller. While the mirror approach provides good fault tolerance, it is relatively expensive to implement. In addition, only half of the available disk space can be used for storage. The other half is needed for mirroring.
  • RAID-5: Stripe set with parity. RAID-5 provides redundancy of all data on the array, allowing a single disk to fail and be replaced, in most cases, without system downtime. RAID-5 offers lower performance than RAID-0 or RAID-1 but higher reliability and faster recovery. RAID-5 uses the equivalent of one disk for storing the parity strips, but distributes the parity strips across all the drives in the array. The data and parity information are arranged on the disk array so that they are always on different disks.

There are other implementations of RAID, such as RAID-0+1 (aka RAID-10), RAID-2, RAID-3, etc., but these are typically proprietary implementations unique to the hardware manufacturer that support them.

When you build the shared storage facility, make sure, that all shared disks, must be physically attached to a shared bus. Verify that disks attached to the shared bus can be seen from all nodes. This can be checked at the host adapter setup level. (Please refer to the manufacturer's documentation for adapter-specific instructions.) SCSI devices must be assigned unique SCSI identification numbers and properly terminated, as per manufacturer's instructions. All shared disks must be configured as basic (not dynamic). All partitions on the disks must be formatted as NTFS.

If you study the PBX_Database example, you will see the PBX is using local (.mdf) database for the purpose to get information about extensions. You can configure the PBX to handle any database types, and if one of the PBXes wouldn't be able to functioning, the other one in the cluster would take it's position, and would start to use the set database. This way, all PBXes within the same cluster have the exact same extension information.

How to handle network connectivity?

Each node of the VoIP PBX cluster should have two network adapters - one for connection to the public network and the other for the node-to-node private cluster network. If you use only one network adapter for both connections, your PBX cluster will not work.

How to install and set up the cluster?

During the initial installation, please make sure that you install the same PBX version on both nodes of the cluster. Concerning the installation path, all files should be installed to the shared disk resource.

The following guide gives instructions about how to setup Microsoft Clustering Service using Windows Server 2003 Datacenter Edition or Enterprise Edition. If you use a newer version of Microsoft Windows Server, such as 2008 or 2012, you can use the links below under the References.

Please follow these steps to install:

  1. Check your system

    After you have installed the Windows OS on the first node and before you install Microsoft Cluster Service, you need to check your system. First click Start, select Programs and Administrative Tools, and then click Configure Your Server. Here, select Advanced \ Cluster Service, and then in the right panel click Learn More.

    In the Windows Help menu, review item 2 in the "Windows Clustering" topic to be familiar with the technology and the installation steps. Important: You must read the "Planning for Windows Clustering\Requirements" for server clusters and follow the checklist for server clusters named "Checklist: Creating a server cluster". The "Checklist: Creating a server cluster" topic is located under the "Server Clusters section\Checklist" for server clusters topic.

    To setup a cluster, you also need to check the following:

    • You need two Ethernet controllers. One of them should be connected to the Internet, while the other should be connected to a private network. For example there are two network cards in the computer: Local area connection and Local area connection 2. Suppose that the first is connected to the Internet with IP address: 192.168.90.101 and the second is connected to a private network with IP address: 10.0.0.101.
    • You need two disks: one of them will host the Windows installation, the other will be the shared (quorum) disk of the cluster. Your PBX will be installed on the shared disk to store sensitive information, such as SIP account or call logging information.
  2. Setup the cluster on Node 1

    If your hardware is ready, you can create your cluster.

    Click on Start menu and select Cluster Administrator from the Administrative Tools menu. Then follow the installation steps. Select Create new cluster, specify a unique Cluster name (e.g. "clustern1"), enter an IP address that cluster management tolls will use to connect to the cluster. Later, you need to use this IP address to connect your VoIP phones and devices to your PBX. In addition, here you need to give login information for the domain account under which the cluster service will be run. Now your cluster is ready on Node 1.

  3. Add Node 2 to the cluster

    After the cluster has been created, you should add a second computer to it.

    The name of this computer will be "clustern2". Please note that "clustern1" and "clustern2" should be the member of the same domain. In the Cluster Administrator Window, right click on the name of the cluster and select New Node. Provide a name and follow the instructions during the installation. After you have added Node 2 to this cluster, you can see both of the clusters in the list of the Cluster Administrator Window.

  4. Install PBX on Node 1

    After the cluster has been prepared, you should install your PBX to cluster Node 1.

    The installation destination directory should point to the shared disk. This means that your configurations, SIP account data, call loggings will be saved on Node 2 as well.

  5. Declare the cluster resource

    The next step is to register your PBX as a cluster resource.

    Right click on Rescource and then select New Resource in the Cluster Administrator Window. Provide a name for this Resource and select Generic Service, as a Resource type. Click on Next button, then select "clustern2" as a possible owner on which this resource can be brought online. In the Dependencies window, select Cluster IP Address and Quorum Disk in the Resource dependencies section. Finally, provide a service name and click on FInish. Then a popup window shows you to created the cluster successfully.

  6. 6. Install PBX on Node 2

    After you PBX has been registered as a cluster resource, it's service entry should be added to Node 2.

    Open Command Prompt, go to the directory of the installed PBX on the qourum disk and provide the following command to make a service for your PBX:

       inssrv.exe install "OzekiPBX" "OzekiPBX" "Q:\OzekiPBX\OzekiPBX.exe"
    

    Now, your PBX cluster is ready. If there is a hardware failure on Node 1, Node 2 can take over the control.

What common tasks should be handled?

Shutdown: To shutdown Ozeki PBX on a cluster, you need to use the "cluster.exe" command, that comes with the Windows OS. The basic syntax for this command is:

   cluster [cluster name] RESOURCE [resource name] /option

To use it in operation you should issue one of these commands:

   cluster "PBXCluster" resource "OzekiPBX" /offline
   cluster "PBXCluster" resource "OzekiPBX" /online

Version upgrade: To upgrade your PBX in your cluster to a new version in an active/passive configuration, you need to install the new version on the primary node only. The installation will update all files on the shared storage. The service registration of the old version (on the passive node) will work for the new version as well.

What alternative clustering technologies are available?

An alternative to the introduced clustering solution can be created using the followings:

For shared storage solutions:

PBX with database management example in C#

Please note that, this example does the same tasks as the VoIP PBX authentication example, the only difference is the database management instead of using the UserInfoContainer class.

This example puts the users into the database instead of adding them into the UserInfoContainer:

void SetUserInfosDB()
    {
        for (int i = 0; i < 10; i++)
        {
            var userName = string.Format("100{0}", i);
            var password = userName;
            UserInfo userInfo = new UserInfo(userName, password);
            databaseManager.AddUserInfo(userInfo);
        }
    }

When the authentication request arrives, the PBX checks if the database contains the user. If it does, it checks the user infos:

UserInfo userInfo;
if (databaseManager.TryGetUserInfo(extension.ExtensionID))
{
	userInfo = databaseManager.GetUserInfo(extension.ExtensionID);
	result = extension.CheckPassword(userInfo.UserName, userInfo.Password, authInfo);
}

To manage the database the example is using the DatabaseManager class, which creates and opens the connection with the database, than provides public methods such as:

  • AddUserInfo(): receives a UserInfo objects, and adds its values to the database, if that isn't contains that already:
  • public void AddUserInfo(UserInfo userInfo)
    {
        using (var command = _connection.CreateCommand())
        {
            if (!ContainsKey(userInfo.UserName))
            {
                command.CommandText = "INSERT INTO Table_AllowedUsers (Username, Password) values ('" + userInfo.UserName +
                                      "', '" + userInfo.Password + "')";
                command.ExecuteNonQuery();
            }
            else
                Console.WriteLine("Already inserted.");
        }
    }
    
  • TryGetUserInfo(): checks if the database contains the list, and return with a boolean value, dependant of the result:
  • public bool TryGetUserInfo(string username)
    {
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = "SELECT * FROM Table_AllowedUsers WHERE Username = '" + username + "'";
    
            using (var reader = command.ExecuteReader())
            {
                if (reader.HasRows)
                    return true;
            }
        }
        return false;
    }
    
  • GetUserInfo(): receives a username, and return with a UserInfo object, which contains the informatin about the user, set in the database. It's recommended to use the TryGetUserInfo() method before using this one, to check if the database contains the user.
  • public UserInfo GetUserInfo(string username)
    {
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = "SELECT * FROM Table_AllowedUsers WHERE Username = '" + username + "'";
    
            using (var reader = command.ExecuteReader())
            {
                if (reader.HasRows)
                {
                    reader.Read();
                    var password = reader["Password"].ToString();
                    UserInfo userInfo = new UserInfo(username, password);
                    return userInfo;
                }
            }
        }
        Console.WriteLine("Can not find user.");
        return null;
    }
    

The example is using local (.mdf) database for the purpose to introduce a simple solution of PBX database handling, but you can - of course - use any database types and your own functions. These are only for the purpose to represent a very simple PBX which can handle a database.


References

Related Pages

More information