CSS-CII Servers

Module: dvbcss.protocol.server.cii

The CIIServer class implements a CII server that can be plugged into the cherrypy web server engine.

To create a CII Server, first create and mount the server in a cherrypy web server. Then you can start the cherrypy server and the CII server will start to accept connections from clients. While the server is running, update the CII state maintained by that server and instruct it when to push updates to all connected clients.

An example server is provided in this package.

Using CII Server

1. Imports and initialisation

To run a CII server, you must import both ws4py’s cherrypy server and the dvbcss.protocol.server.cii module. When the dvbcss.protocol.server.cii module is imported, it will register as a “tool” with cherrypy, so it must be imported after cherrypy is imported.

Next, subscribe the ws4py websocket plugin to cherrypy.

import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin
from dvbcss.protocol.server.cii import CIIServer

# initialise the ws4py websocket plugin
WebSocketPlugin(cherrypy.engine).subscribe()

2. Create and mount the CII server

You can now create an instance of a CIIServer and mount it into the cherrypy server at a path of your choosing.

The configuration for that path must turn on the “dvb_cii” tool and pass a “handler_cls” argument whose value is the handler class that the CIIServer instance provides via the CIIServer.handler attribute.

For example, to create a CIIServer mounted at the URL path “/cii”:

# create CII Server
ciiServer = CIIServer(maxConnectionsAllowed=2)

# bind it to the URL path /cii in the cherrypy server
class Root(object):
    @cherrypy.expose
    def cii(self):
        pass

# construct the configuration for this path, providing the handler and turning on the tool hook
cfg = {"/cii": {'tools.dvb_cii.on': True,
                'tools.dvb_cii.handler_cls': ciiServer.handler
               }
      }

cherrypy.tree.mount(Root(), "/", config=cfg)    

3. Start cherrypy running

Start cherrypy running and our CII server will start to accept connections from clients:

# configure cherrypy to serve on port 7681
cherrypy.config.update({"server.socket_port":7681})

# activate cherrypy web server (non blocking)
cherrypy.engine.start()

The cherrypy engine runs in a background thread when the cherrypy engine is started.

4. Setting CII state and pushing it to connected clients

The CIIServer.cii is a CII message object representing the CII state. Your code can read and alter the attributes of this message object to update the server side state.

When a client first connects, a CII message object will automatically be sent to that client to send it the current CII state. Your code does not need to do this.

If you update the CII state then you need to ask the CII server to push a change to all connected clients. To do this call the CIIServer.updateClients() method. By default this will only push changes to CII state, and will not send a message at all if there is no change. However this behaviour can be overridden.

ciiServer.cii.contentId = "dvb://233a.1004.1080"
ciiServer.cii.contentIdStatus = "partial"
ciiServer.updateClients()

...

ciiServer.cii.contentId = "dvb://233a.1004.1080;21af~20131004T1015Z--PT01H00M"
ciiServer.cii.contentIdStatus = "final"
ciiServer.updateClients()

Intelligently setting the host and port in tsUrl, teUrl and wcUrl properties

CIIServer has built in support to help in situations where it is difficult to determine the host and port to which clients are connecting in order to contact the CII Server, or where CIIServer might be contacted via more than one network interface.

At initialisation, pass the optional rewriteHostPort argument, setting it to a list of properties for which you want it to fix the host/port in URLs. Then within the CII, put {{host}} and {{port}} in place of the host and port number. The CIIServer will then automatically substitute this in the properties you have listed.

For example:

ciiServer = CIIServer(rewriteHostPort=['tsUrl','wcUrl'])
ciiServer.cii = CII(
    tsUrl='ws://{{host}}:{{port}}/ts',
    wcUrl='udp://{{host}}:6677'
)

This will be done transparently and individually for each connected client. The cii property of the CII server will contain the {{host}} and {{port}} patterns before the substitution takes place.

What does CIIServer do for you and what does it not?

CIIServer handles the connection and disconnection of clients without requiring any further intervention. It ensure the current state in its cii property is sent, in a CII message, to the client as soon as it connects.

The role of your code is to update the cii object as state changes, and to inform the CIIServer when it is time to update any connected clients by informing them of the changes to state by calling the updateClients() method.

Classes

CIIServer - CII Server handler for cherrypy

class dvbcss.protocol.server.cii.CIIServer(maxConnectionsAllowed=-1, enabled=True, initialCII=CII(protocolVersion='1.1'), rewriteHostPort=[])[source]

The CIIServer class implements a server for the CSS-CII protocol. It transparently manages the connection and disconnection of clients and provides an interface for simply setting the CII state and requesting that it be pushed to any connected clients.

Must be used in conjunction with a cherrypy web server:

  1. Ensure the ws4py WebSocketPlugin is subscribed, to the cherrypy server. E.g.

    WebSocketPlugin(cherrypy.engine).subscribe()
    
  2. Mount the instance onto a particular URL path on a cherrypy web server. Set the config properties for the URL it is to be mounted at as follows:

    { 'tools.dvb_cii.on'         : True,
      'tools.dvb_cii.handler_cls': myCiiServerInstance.handler }
    

Update the cii property with the CII state information and call the updateClients() method to propagate state changes to any connected clients.

When the server is “disabled” it will refuse attempts to connect by sending the HTTP status response 403 “Forbidden”.

When the server has reached its connection limit, it will refuse attempts to connect by sending the HTTP status response 503 “Service unavailable”.

This object provides properties:

  • enabled (read/write) controls whether this server is enabled or not
  • cii (read/write) the CII state that is being shared to connected clients

To allow for servers serving multiple network interfaces, or where the IP address of the interface is not easy to determine, CII Server can be asked to automatically substitute the host and port with the one that the client connected to. Specify the list of property names for which this shoud happen as an optional rewritheostPort argument when intialising the CIIServer, then use {{host}} {{port}} within those properties.

Initialisation takes the following parameters:

Parameters:
  • maxConnectionsAllowed – (int, default=-1) Maximum number of concurrent connections to be allowed, or -1 to allow as many connections as resources allow.
  • enabled – (bool, default=True) Whether the endpoint is initially enabled (True) or disabled (False)
  • initialCII – (dvbcss.protocol.cii.CII, default=CII(protocolVersion=”1.1”)) Initial value of CII state.
  • rewriteHostPort – (list) List of CII property names for which the sub-string ‘{{host}}’ ‘{{port}}’ will be replaced with the host and port that the client connected to.
cii[source]
handler[source]

Handler class for new connections.

When mounting the CII server with cherrypy, include in the config dict a key ‘tools.dvb_cii.handler_cls’ with this handler class as the value.

enabled[source]

(read/write bool) Whether this server endpoint is enabled (True) or disabled (False).

Set this property enable or disable the endpoint.

When disabled, existing connections are closed with WebSocket closure reason code 1001 and new attempts to connect will be refused with HTTP response status code 403 “Forbidden”.

getConnections()[source]
Returns dict:mapping a WebSocket object to connection related data for all connections to this server. This is a snapshot of the connections at the moment the call is made. The dictionary is not updated later if new clients connect or existing ones disconnect.
onClientConnect(webSock)[source]

If you override this method you must call the base class implementation.

onClientDisconnect(webSock, connectionData)[source]

If you override this method you must call the base class implementation.

onClientMessage(webSock, message)[source]

If you override this method you must call the base class implementation.

updateClients(sendOnlyDiff=True, sendIfEmpty=False)[source]

Send update of current CII state from the CIIServer.cii object to all connected clients.

Parameters:
  • sendOnlyDiff – (bool, default=True) Send only the properties in the CII state that have changed since last time a message was sent. Set to False to send the entire message.
  • sendIfEmpty – (bool, default=False) Set to True to force that a CII message be sent, even if it will be empty (e.g. no change since last time)

By default this method will only send a CII message to clients informing them of the differencesin state since last time a message was sent to them. If no properties have changed at all, then no message will be sent.

The two optional arguments allow you to change this behaviour. For example, to force the messages sent to include all properties, even if they have not changed:

myCiiServer.updateClients(sendOnlyDiff=False)

To additionally force it to send even if the CII state held at this server has no values for any of the properties:

myCiiServer.updateClients(sendOnlyDiff=False, sendIfEmpty=True)