Server Configuration File: server.rb

This Ruby file contains the custom application logic writen by the user along with programmable callbacks for OverSIP events. All those callbacks are executed within a new Ruby Fiber, allowing synchronous style coding by using em-synchrony libraries.

Example code in this page makes use of the oversip-mod-mysql MySQL driver with synchronous style coding (no callbacks for retrieving the SQL queries result).

The server.rb file is divided in the following sections:

Custom Application Logic

The top of the file is reserved for custom code writen by the user. Typicaly the user loads here external required Gems or libraries (via require "gem-name") and adds modules, classes and methods for building a custom application logic on top of OverSIP.

If the user adds a module or class here it’s useful it to include/extend the OverSIP::Logger module so the user can make use of the methods provided by OverSIP for logging into Syslog (log_debug, log_info, log_warn, etc).

Example code

require "oversip-mod-mysql"


module MyApp

  extend ::OverSIP::Logger

  # Load valid WebSocket Origin values from DB.
  def self.load_valid_websocket_origins
    log_info "loading valid origins from DB..."

    @valid_websocket_origins ||= []
    valid_websocket_origins = []

    db = OverSIP::Modules::Mysql.pool(:my_db)

    result = db.query "SELECT origin FROM websocket_origins"
    result.each do |row|
      valid_websocket_origins << row["origin"]
    end

    @valid_websocket_origins = valid_websocket_origins
  end

  # Get the Array with the loaded valid WebSocket Origins.
  def self.valid_websocket_origins
    @valid_websocket_origins
  end

  [...]
end

When the user’s custom code is too long it can be split into different files. For example, the user could create a directory /etc/oversip/my_app/ containing custom files and load them at the top of server.rb as follows:

require "/etc/oversip/my_app/file1.rb"
require "/etc/oversip/my_app/file2.rb"
require "/etc/oversip/my_app/file3.rb"
[...]

System Events

This section includes programmable callbacks for system events:

OverSIP::SystemEvents.on_initialize

This method is called by OverSIP when main configuration files have been loaded. This method is NOT executed again when OverSIP is reloaded (HUP signal or /etc/init.d/oversip reload).

This is the place for setting i.e. dabatase connections (by using existing OverSIP 3rd party modules such us oversip-mod-mysql, oversip-mod-postgresql or EventMachine libraries such as couchbase-ruby-client-em, EventMachine built-in Memcache client, or some others via em-synchrony).

NOTE: If you need to use Ruby threads within your application logic (via the EventMachine.defer() method) then this method is a good place to set the EventMachine.threadpool_size parameter.

Example code

def (OverSIP::SystemEvents).on_initialize

  log_info "setting my DB connection..."

  OverSIP::Modules::Mysql.add_pool({
    :pool_name => :my_db,
    :pool_size => 5,
    :host => "localhost",
    :username => "oversip",
    :password => "xxxxxx",
    :database => "oversip"
  })

end

OverSIP::SystemEvents.on_started

This method is called by OverSIP once the core reactor has been started. Place here code to retrieve information from i.e. a database and fill some custom variable that will be later inspected in runtime.

Example code

def (OverSIP::SystemEvents).on_started

  MyApp.load_valid_websocket_origins()

end

OverSIP::SystemEvents.on_user_reload

This method is called by OverSIP when a USR1 signal is received by the OverSIP main process (or /etc/init.d/oversip user-reload is executed) and allows the user to set custom code to be executed or reloaded.

For example, this method could be used to reload a Ruby object (i.e. a Hash) with data retrieved from a database when such an information has been modified in the database.

Example code

def (OverSIP::SystemEvents).on_user_reload

  MyApp.load_valid_websocket_origins()

end

OverSIP::SystemEvents.on_terminated(error)

This method is called after OverSIP has been terminated.

Parameters

error
true in case OverSIP has died in an unexpected way.

Example code

def (OverSIP::SystemEvents).on_terminated(error)

  if error
    log_notice "exiting with error: #{error.inspect}"
  else
    log_info "properly exiting"
  end

end

SIP Events

This section includes programmable callbacks for SIP events:

OverSIP::SipEvents.on_request(request)

This method is called when a SIP request is received.

Parameters

request
The OverSIP::SIP::Request instance.

Example code

For a full example code check the OverSIP::SipEvents.on_request section in the default server.rb file.

OverSIP::SipEvents.on_client_tls_handshake(connection, pems)

This method is called when a SIP client initiates a TLS handshake with OverSIP. It is not called if the SIP callback_on_client_tls_handshake parameter is not set.

Take a look to the TLS API for using the data provided by this method.

NOTE: When the SIP parameter use_tls_tunnel is enabled, incoming SIP TLS connections are handled by Stud processes and thus this method is not called.

Parameters

connection
The OverSIP::SIP::Connection instance.
pems
An Array with the chain of X509 certificates in PEM format (String) presented by the client during the TLS handshake. The first element is the most-resolved certificate, followed by the successive intermediate certificates and the root (or CA) certificate at the end. It could be empty if the client does not present a TLS certificate.

OverSIP::SipEvents.on_server_tls_handshake(connection, pems)

This method is called when OverSIP initiates a TLS handshake with a SIP server. It is not called if the callback_on_server_tls_handshake is not set for the “Proxy” instance being used for routing the SIP request.

In case the connection is not desired (after TLS certificate validation) it can be closed (and thus the SIP request not sent) by calling the close() method in the given OverSIP::SIP::Connection instance. It would generate an internal 500TLS Validation Failed” SIP response.

Take a look to the TLS API for using the data provided by this method.

Parameters

connection
The OverSIP::SIP::Connection instance.
pems
An Array with the chain of X509 certificates in PEM format (String) presented by the server during the TLS handshake. The first element is the most-resolved certificate, followed by the successive intermediate certificates and the root (or CA) certificate at the end.

WebSocket Events

This section includes programmable callbacks for WebSocket events:

OverSIP::WebSocketEvents.on_connection(connection, http_request)

This method is called when a client attempts to establish a WebSocket connection and once OverSIP has validated that the HTTP GET request is a valid WebSocket handshake request but before OverSIP replies the HTTP 101 “Switching Protocols”.

Based on the HTTP request parameters and local policy the user can decide here whether to allow or reject the WebSocket connection attempt. This can be done by inspecting specific fields of the request (i.e. Origin header, Cookie header, request URI value and parameters, etc) and data from the connection (source address, plain or secure WebSocket connection, etc). The user can reject the WebSocket connection by calling connection.http_reject (so the HTTP 101 response required for completing the WebSocket handshake wont take place).

Parameters

connection
The associated OverSIP::WebSocket::Connection instance.
request
The WebSocket handshake OverSIP::WebSocket::HttpRequest instance.

Example code

def (OverSIP::WebSocketEvents).on_connection(connection, http_request)

  # Check the Origin header against my allowed list of domains.
  if MyApp.valid_websocket_origins.include? http_request.hdr_origin
    log_info "allowed WebSocket connection"
  else
    log_warn "WebSocket connection rejected, invalid Origin: #{http_request.hdr_origin}"
    connection.http_reject 403, "Origin not allowed"
  end

end

OverSIP::WebSocketEvents.on_disconnection(connection, client_closed)

This method is called when a WebSocket connection is closed.

Parameters

connection
The associated OverSIP::WebSocket::Connection instance.
client_closed
true if the client caused the disconnection, false otherwise (OverSIP closed it).

Example code

def (OverSIP::WebSocketEvents).on_disconnection(connection, client_closed)

  if client_closed
    log_info "WebSocket connection closed by the client"
  else
    log_info "WebSocket connection closed by OverSIP"
  end

end

OverSIP::WebSocketEvents.on_client_tls_handshake(connection, pems)

This method is called when a WebSocket client initiates a TLS handshake with OverSIP. It is not called if the WebSocket callback_on_client_tls_handshake parameter is not set.

Take a look to the TLS API for using the data provided by this method.

NOTE: When the WebSocket parameter use_tls_tunnel is enabled, incoming WebSocket TLS connections are handled by Stud processes and thus this method is not called.

Parameters

connection
The OverSIP::WebSocket::Connection instance.
pems
An Array with the chain of X509 certificates in PEM format (String) presented by the client during the TLS handshake. The first element is the most-resolved certificate, followed by the successive intermediate certificates and the root (or CA) certificate at the end. It could be empty if the client does not present a TLS certificate.