diff --git a/config.ini.sample b/config.ini.sample index 6282a67..237fcc1 100644 --- a/config.ini.sample +++ b/config.ini.sample @@ -1,64 +1,67 @@ ; SylkServer configuration file [Server] ; The following settings are the default used by the software, uncomment ; them only if you want to make changes ; default_application = conference +; Map user part of the Request URI to a specific application +; application_map = 123:conference,test:irc-conference + ; trace_dir = /var/log/sylkserver ; trace_sip = False ; trace_msrp = False ; trace_notifications = False ; TLS can be used for encryption of SIP signaling and MSRP media. TLS is ; disabled by default. To enabled TLS, you must have a valid X.509 ; certificate and configure it below, then set the local_tls_port in the SIP ; section and use_tls in MSRP section ; The X.509 Certificate Authorities file ; ca_file = /etc/sylkserver/tls/ca.crt ; The file containing X.509 certificate and private key in unencrypted format ; certificate = /etc/sylkserver/tls/sylkserver.crt ; verify_server = False [SIP] ; SIP transport settings ; IP address used for SIP signaling; empty string or any means listen on interface used ; by the default route ; local_ip = ; Ports used for SIP transports, if not set to any value the transport will be disabled ; local_udp_port = 5060 ; local_tcp_port = 5060 ; local_tls_port = [MSRP] ; MSRP transport settings ; use_tls = False [RTP] ; RTP transport settings ; Allowed codec list, valid values: G722, speex, PCMU, PCMA, iLBC, GSM ; allowed_codecs = G722,speex,PCMU,PCMA ; Port range used for RTP ; port_range = 50000:50500 ; SRTP valid values: disabled, mandatory, optional ; srtp_encryption = optional ; RTP stream timeout, session will be disconnected after this value ; timeout = 30 diff --git a/sylk/applications/__init__.py b/sylk/applications/__init__.py index 5def9a5..1dd11cb 100644 --- a/sylk/applications/__init__.py +++ b/sylk/applications/__init__.py @@ -1,126 +1,130 @@ # Copyright (C) 2010-2011 AG Projects. See LICENSE for details # __all__ = ['ISylkApplication', 'ApplicationRegistry', 'sylk_application', 'IncomingRequestHandler'] import os from application import log from application.notification import IObserver, NotificationCenter from application.python.util import Null, Singleton from sipsimple.threading import run_in_twisted_thread from zope.interface import Attribute, Interface, implements from sylk.configuration import ServerConfig class ISylkApplication(Interface): """ Interface defining attributes and methods any application must implement. Each application must be a Singleton and has to be decorated with the @sylk_application decorator. """ __appname__ = Attribute("Application name") def incoming_session(self, session): pass def incoming_subscription(self, subscribe_request, data): pass def incoming_sip_message(self, message_request, data): pass class ApplicationRegistry(object): __metaclass__ = Singleton def __init__(self): self.applications = [] def __iter__(self): return iter(self.applications) def add(self, app): if app not in self.applications: self.applications.append(app) def sylk_application(cls): """Class decorator for adding applications to the ApplicationRegistry""" ApplicationRegistry().add(cls()) return cls def load_applications(): toplevel = os.path.dirname(__file__) app_list = ['sylk.applications.%s' % item for item in os.listdir(toplevel) if os.path.isdir(os.path.join(toplevel, item)) and '__init__.py' in os.listdir(os.path.join(toplevel, item))] map(__import__, app_list) class IncomingRequestHandler(object): """ Handle incoming requests and match them to applications. """ __metaclass__ = Singleton implements(IObserver) # TODO: implement a 'find_application' function which will get the appropriate application # as defined in the configuration # TODO: apply ACLs (before or after?) def __init__(self): load_applications() log.msg('Loaded applications: %s' % ', '.join([app.__appname__ for app in ApplicationRegistry()])) + self.application_map = dict((item.split(':')) for item in ServerConfig.application_map) def start(self): notification_center = NotificationCenter() notification_center.add_observer(self, name='SIPSessionNewIncoming') notification_center.add_observer(self, name='SIPIncomingSubscriptionGotSubscribe') notification_center.add_observer(self, name='SIPIncomingRequestGotRequest') def stop(self): notification_center = NotificationCenter() notification_center.remove_observer(self, name='SIPSessionNewIncoming') notification_center.remove_observer(self, name='SIPIncomingSubscriptionGotSubscribe') notification_center.remove_observer(self, name='SIPIncomingRequestGotRequest') @run_in_twisted_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPSessionNewIncoming(self, notification): session = notification.sender + application = self.application_map.get(session._invitation.request_uri.user, ServerConfig.default_application) try: - app = (app for app in ApplicationRegistry() if app.__appname__ == ServerConfig.default_application).next() + app = (app for app in ApplicationRegistry() if app.__appname__ == application).next() except StopIteration: - pass + log.error('Application %s is not loaded' % application) else: app.incoming_session(session) def _NH_SIPIncomingSubscriptionGotSubscribe(self, notification): subscribe_request = notification.sender + application = self.application_map.get(notification.data.request_uri.user, ServerConfig.default_application) try: - app = (app for app in ApplicationRegistry() if app.__appname__ == ServerConfig.default_application).next() + app = (app for app in ApplicationRegistry() if app.__appname__ == application).next() except StopIteration: - pass + log.error('Application %s is not loaded' % application) else: app.incoming_subscription(subscribe_request, notification.data) def _NH_SIPIncomingRequestGotRequest(self, notification): request = notification.sender if notification.data.method != 'MESSAGE': request.answer(405) return + application = self.application_map.get(notification.data.request_uri.user, ServerConfig.default_application) try: - app = (app for app in ApplicationRegistry() if app.__appname__ == ServerConfig.default_application).next() + app = (app for app in ApplicationRegistry() if app.__appname__ == application).next() except StopIteration: - pass + log.error('Application %s is not loaded' % application) else: app.incoming_sip_message(request, notification.data) diff --git a/sylk/configuration/__init__.py b/sylk/configuration/__init__.py index b9f53ec..b27e4f7 100644 --- a/sylk/configuration/__init__.py +++ b/sylk/configuration/__init__.py @@ -1,52 +1,54 @@ # Copyright (C) 2010-2011 AG Projects. See LICENSE for details. # from application.configuration import ConfigSection, ConfigSetting +from application.configuration.datatypes import StringList from application.system import host from sipsimple.configuration.datatypes import NonNegativeInteger, SRTPEncryption from sylk import configuration_filename from sylk.configuration.datatypes import AudioCodecs, IPAddress, Port, PortRange class ServerConfig(ConfigSection): __cfgfile__ = configuration_filename __section__ = 'Server' ca_file = ConfigSetting(type=str, value='/etc/sylkserver/tls/ca.crt') certificate = ConfigSetting(type=str, value='/etc/sylkserver/tls/sylkserver.crt') verify_server = False default_application = 'conference' + application_map = ConfigSetting(type=StringList, value='') trace_dir = ConfigSetting(type=str, value='/var/log/sylkserver') trace_sip = False trace_msrp = False trace_notifications = False class SIPConfig(ConfigSection): __cfgfile__ = configuration_filename __section__ = 'SIP' local_ip = ConfigSetting(type=IPAddress, value=host.default_ip) local_udp_port = ConfigSetting(type=Port, value=5060) local_tcp_port = ConfigSetting(type=Port, value=5060) local_tls_port = ConfigSetting(type=Port, value=None) class MSRPConfig(ConfigSection): __cfgfile__ = configuration_filename __section__ = 'MSRP' use_tls = False class RTPConfig(ConfigSection): __cfgfile__ = configuration_filename __section__ = 'RTP' audio_codecs = ConfigSetting(type=AudioCodecs, value=None) port_range = ConfigSetting(type=PortRange, value=PortRange('50000:50500')) srtp_encryption = ConfigSetting(type=SRTPEncryption, value='optional') timeout = ConfigSetting(type=NonNegativeInteger, value=30)