def __on_exit(self): if self._pidfile: try: os.unlink(self._pidfile) except OSError as e: log.warning('unable to delete pidfile %s: %s' % (self._pidfile, e))
def _NH_SIPApplicationDidEnd(self, notification): self.trace_manager.stop() log.msg('SIP application ended') if not self.stopping_event.is_set(): log.warning('SIP application ended without stopping all subsystems') self.stopping_event.set() self.stop_event.set()
def _save_calls(self, result): if self.calls: log.info('Saving calls') calls_file = process.runtime.file(backup_calls_file) try: f = open(calls_file, 'wb') except: pass else: for call in list(self.calls.values()): call.application = None # we will mark timers with 'running' or 'idle', depending on their current state, # to be able to correctly restore them later (Timer objects cannot be pickled) if call.timer is not None: if call.inprogress: call.timer.cancel() call.timer = 'running' # temporary mark that this timer was running else: call.timer = 'idle' # temporary mark that this timer was not running failed_dump = False try: try: pickle.dump(self.calls, f) except Exception as e: log.warning('Failed to dump call list: %s', e) failed_dump = True finally: f.close() if failed_dump: unlink(calls_file) else: log.info("Saved calls: %s" % str(list(self.calls.keys()))) self.calls = {}
def refresh_file_sizes(): """Computes & stores the 'length_aggregate_in_bytes' fields of all files.""" from application.modules import file_storage matched = 0 unmatched = 0 total_size = 0 files_collection = app.data.driver.db['files'] for file_doc in files_collection.find(): file_storage.compute_aggregate_length(file_doc) length = file_doc['length_aggregate_in_bytes'] total_size += length result = files_collection.update_one({'_id': file_doc['_id']}, {'$set': {'length_aggregate_in_bytes': length}}) if result.matched_count != 1: log.warning('Unable to update document %s', file_doc['_id']) unmatched += 1 else: matched += 1 log.info('Updated %i file documents.', matched) if unmatched: log.warning('Unable to update %i documents.', unmatched) log.info('%i bytes (%.3f GiB) storage used in total.', total_size, total_size / 1024 ** 3)
def read(cls, cfgfile=None, section=None): """Read the settings from the given file and section""" cfgfile = cfgfile or cls.__cfgfile__ section = section or cls.__section__ if None in (cfgfile, section): raise ValueError( "A config file and section are required for reading settings") if isinstance(cfgfile, ConfigFile): config_file = cfgfile else: config_file = cls.__cfgtype__(cfgfile) if isinstance(section, basestring): section_list = (section, ) else: section_list = section for section in section_list: for name, value in config_file.get_section(section, filter=cls.__settings__, default=[]): try: setattr(cls, name, value) except Exception as e: log.warning( 'ignoring invalid config value: %s.%s=%s (%s).' % (section, name, value, e))
def start(self): for app in ApplicationRegistry(): try: app().start() except Exception, e: log.warning('Error starting application: %s' % e) log.err()
def _PE_debitbalance(self, line): valid_answers = ('Ok', 'Failed', 'Not prepaid') lines = line.splitlines() try: result = lines[0].strip().capitalize() except IndexError: raise ValueError( "Empty reply from rating engine %s:%s", (self.transport.getPeer().host, self.transport.getPeer().port)) if result not in valid_answers: log.error("Invalid reply from rating engine: got '%s' from %s:%s" % (lines[0].strip(), self.transport.getPeer().host, self.transport.getPeer().port)) log.warning('Rating engine possible failed query: %s', self.__request) raise RatingEngineError('Invalid rating engine response') elif result == 'Failed': log.warning('Rating engine failed query: %s', self.__request) raise RatingEngineError('Rating engine failed query') else: try: timelimit = int(lines[1].split('=', 1)[1].strip()) totalcost = lines[2].strip() except: log.error( "Invalid reply from rating engine for DebitBalance on lines 2, 3: got '%s' from %s:%s" % ("', `".join(lines[1:3]), self.transport.getPeer().host, self.transport.getPeer().port)) timelimit = None totalcost = 0 return timelimit, totalcost
def refresh_file_sizes(): """Computes & stores the 'length_aggregate_in_bytes' fields of all files.""" from application.modules import file_storage matched = 0 unmatched = 0 total_size = 0 files_collection = app.data.driver.db['files'] for file_doc in files_collection.find(): file_storage.compute_aggregate_length(file_doc) length = file_doc['length_aggregate_in_bytes'] total_size += length result = files_collection.update_one( {'_id': file_doc['_id']}, {'$set': { 'length_aggregate_in_bytes': length }}) if result.matched_count != 1: log.warning('Unable to update document %s', file_doc['_id']) unmatched += 1 else: matched += 1 log.info('Updated %i file documents.', matched) if unmatched: log.warning('Unable to update %i documents.', unmatched) log.info('%i bytes (%.3f GiB) storage used in total.', total_size, total_size / 1024**3)
def __init__(self): load_applications() registry = ApplicationRegistry() self.applications = dict((app.__appname__, app) for app in registry) log.msg('Loaded applications: %s' % ', '.join(self.applications)) default_application = registry.find_application( ServerConfig.default_application) if default_application is None: log.warning( 'Default application "%s" does not exist, falling back to "conference"' % ServerConfig.default_application) ServerConfig.default_application = 'conference' else: log.msg('Default application: %s' % ServerConfig.default_application) self.application_map = dict( (item.split(':')) for item in ServerConfig.application_map) if self.application_map: txt = 'Application map:\n' invert_app_map = defaultdict(list) for url, app in self.application_map.iteritems(): invert_app_map[app].append(url) for app, urls in invert_app_map.iteritems(): txt += ' * %s:\n' % app for url in urls: txt += ' - %s\n' % url log.msg(txt[:-1]) self.authorization_handler = AuthorizationHandler()
def load_applications(self): for name in find_builtin_applications(): try: __import__('sylk.applications.{name}'.format(name=name)) except ImportError as e: log.error( 'Failed to load builtin application {name!r}: {exception!s}' .format(name=name, exception=e)) for name in find_extra_applications(): if name in sys.modules: # being able to log this is contingent on this function only executing once log.warning( 'Not loading extra application {name!r} as it would overshadow a system package/module' .format(name=name)) continue try: imp.load_module( name, *imp.find_module( name, [ServerConfig.extra_applications_dir.normalized])) except ImportError as e: log.error( 'Failed to load extra application {name!r}: {exception!s}'. format(name=name, exception=e))
def load_builtin_applications(): toplevel = os.path.dirname(__file__) app_list = [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))] for module in ['sylk.applications.%s' % item for item in set(app_list).difference(ServerConfig.disabled_applications)]: try: __import__(module) except ImportError, e: log.warning('Error loading builtin "%s" application: %s' % (module, e))
def __new__(cls, value): if isinstance(value, str): try: return X509PrivateKey(file_content(value)) except Exception, e: log.warning('Private key file %r could not be loaded: %s' % (value, e)) return None
def __new__(cls, value): if isinstance(value, str): try: return X509Certificate(file_content(value)) except Exception, e: log.warning('Certificate file %r could not be loaded: %s' % (value, e)) return None
def _NH_SIPApplicationDidEnd(self, notification): log.info('SIP application ended') tracelog_manager = TraceLogManager() tracelog_manager.stop() if not self.stopping_event.is_set(): log.warning('SIP application ended without shutting down all subsystems') self.stopping_event.set() self.stopped_event.set()
def load_applications(): load_builtin_applications() load_extra_applications() for app in ApplicationRegistry(): try: app() except Exception, e: log.warning('Error loading application: %s' % e) log.err()
def __new__(cls, value): if isinstance(value, str): try: return X509PrivateKey(file_content(value)) except Exception as e: log.warning("Private key file '%s' could not be loaded: %s" % (value, e)) return None else: raise TypeError('value should be a string')
def load_extra_applications(): if ServerConfig.extra_applications_dir: toplevel = os.path.realpath(os.path.abspath(ServerConfig.extra_applications_dir.normalized)) if os.path.isdir(toplevel): app_list = [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))] sys.path.append(toplevel) for module in (item for item in set(app_list).difference(ServerConfig.disabled_applications)): try: __import__(module) except ImportError, e: log.warning('Error loading extra "%s" application: %s' % (module, e))
def __init__(self): self.engine = Engine() self.engine.start( ip_address=None if ServerConfig.address == '0.0.0.0' else ServerConfig.address, user_agent="OpenXCAP %s" % xcap.__version__, ) self.sip_prefix_re = re.compile('^sips?:') try: self.outbound_proxy = SIPProxyAddress.from_description(Config.outbound_sip_proxy) except ValueError: log.warning('Invalid SIP proxy address specified: %s' % Config.outbound_sip_proxy) self.outbound_proxy = None
def set_loggers(self): debug = self.debug if self.debug else False loggers = {} config = configparser.ConfigParser() default_path = '/var/log/sylk-pushserver/push.log' log_path = '' if not self.file['error']: config.read(self.file['path']) try: log_to_file = f"{config['server']['log_to_file']}" log_to_file = True if log_to_file.lower() == 'true' else False except KeyError: pass else: if log_to_file: try: log_path = f"{config['server']['log_file']}" except KeyError: log_path = default_path try: str_debug = config['server']['debug'].lower() except KeyError: str_debug = False debug = True if str_debug == 'true' else False debug = debug or self.debug formatter = logging.Formatter( '%(asctime)s [%(levelname)-8s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S') logger_journal = logging.getLogger() loggers['to_journal'] = logger_journal if log_path: try: hdlr = logging.FileHandler(log_path) hdlr.setFormatter(formatter) hdlr.setLevel(logging.DEBUG) logger_journal.addHandler(hdlr) except PermissionError: log.warning(f'Permission denied for log file: {log_path}, ' \ f'logging will only be in the journal or foreground') debug = debug or self.debug loggers['debug'] = debug if debug: logger_journal.setLevel(logging.DEBUG) return loggers
def session_expired(self, session): connector = self.dispatcher_connectors.get(session.dispatcher) if connector is None: connector = self.old_connectors.get(session.dispatcher) if connector and connector.state == 'connected': connector.transport.write(' '.join( ['expired', cjson.encode(session.statistics)]) + connector.factory.protocol.delimiter) else: log.warning( 'dispatcher for expired session is no longer online, statistics are lost!' )
def __init__(self): main_config_file = process.configuration.file(RadiusConfig.config_file) if main_config_file is None: raise RuntimeError( 'Cannot find the radius configuration file: %r' % RadiusConfig.config_file) try: config = dict( line.rstrip('\n').split(None, 1) for line in open(main_config_file) if len(line.split(None, 1)) == 2 and not line.startswith('#')) secrets = dict( line.rstrip('\n').split(None, 1) for line in open(config['servers']) if len(line.split(None, 1)) == 2 and not line.startswith('#')) server = config['acctserver'] try: server, acctport = server.split(':') acctport = int(acctport) except ValueError: log.info( 'Could not load additional RADIUS dictionary file: %r' % RadiusConfig.additional_dictionary) acctport = 1813 log.info('Using RADIUS server at %s:%d' % (server, acctport)) secret = secrets[server] log.info("Using RADIUS dictionary file %s" % config['dictionary']) dicts = [RadiusDictionaryFile(config['dictionary'])] if RadiusConfig.additional_dictionary: additional_dictionary = process.configuration.file( RadiusConfig.additional_dictionary) if additional_dictionary: log.info("Using additional RADIUS dictionary file %s" % RadiusConfig.additional_dictionary) dicts.append(RadiusDictionaryFile(additional_dictionary)) else: log.warning( 'Could not load additional RADIUS dictionary file: %r' % RadiusConfig.additional_dictionary) raddict = pyrad.dictionary.Dictionary(*dicts) timeout = int(config['radius_timeout']) retries = int(config['radius_retries']) except Exception: log.critical('cannot read the RADIUS configuration file %s' % RadiusConfig.config_file) raise pyrad.client.Client.__init__(self, server, 1812, acctport, 3799, secret, raddict) self.timeout = timeout self.retries = retries if 'bindaddr' in config and config['bindaddr'] != '*': self.bind((config['bindaddr'], 0)) EventQueue.__init__(self, self.do_accounting)
def stop(self): self.authorization_handler.stop() notification_center = NotificationCenter() notification_center.remove_observer(self, name='SIPSessionNewIncoming') notification_center.remove_observer(self, name='SIPIncomingSubscriptionGotSubscribe') notification_center.remove_observer(self, name='SIPIncomingReferralGotRefer') notification_center.remove_observer(self, name='SIPIncomingRequestGotRequest') for app in ApplicationRegistry(): try: app().stop() except Exception, e: log.warning('Error stopping application: %s' % e) log.err()
def _remove_expired_sessions(self): now, limit = time(), DispatcherConfig.cleanup_expired_sessions_after obsolete = [ k for k, s in ifilter( lambda (k, s): s.expire_time and (now - s.expire_time >= limit), self.sessions.iteritems()) ] if obsolete: [self.sessions.pop(call_id) for call_id in obsolete] log.warning( 'found %d expired sessions which were not removed during the last %d hours' % (len(obsolete), round(limit / 3600.0))) return KeepRunning
def session_expired(self, call_id, from_tag): key = (call_id, from_tag) try: session = self.sessions[key] except KeyError: log.warning( 'A session expired but is no longer present on the relay') return session.logger.info('expired') session.cleanup() self.closed_byte_counter += session.relayed_bytes del self.sessions[key] self.relay.session_expired(session) self.relay.remove_session(session.dispatcher)
def remove_session(self, call_id, from_tag, to_tag=None, **kw): key = self._find_session_key(call_id, from_tag, to_tag) try: session = self.sessions[key] except KeyError: log.warning( 'The dispatcher tried to remove a session which is no longer present on the relay' ) return None session.logger.info('removed') session.cleanup() self.closed_byte_counter += session.relayed_bytes del self.sessions[key] reactor.callLater(0, self.relay.remove_session, session.dispatcher) return session
def __init__(self): self.engine = Engine() self.engine.start( ip_address=None if ServerConfig.address == '0.0.0.0' else ServerConfig.address, user_agent="OpenXCAP %s" % xcap.__version__, ) self.sip_prefix_re = re.compile('^sips?:') try: self.outbound_proxy = SIPProxyAddress.from_description( Config.outbound_sip_proxy) except ValueError: log.warning('Invalid SIP proxy address specified: %s' % Config.outbound_sip_proxy) self.outbound_proxy = None
def _measure_speed(self): start_time = time() current_byte_counter = sum(session.relayed_bytes for session in self.sessions.itervalues()) self.bps_relayed = 8 * ( current_byte_counter + self.closed_byte_counter - self.active_byte_counter) / RelayConfig.traffic_sampling_period self.active_byte_counter = current_byte_counter self.closed_byte_counter = 0 us_taken = int((time() - start_time) * 1000000) if us_taken > 10000: log.warning( 'Aggregate speed calculation time exceeded 10ms: %d us for %d sessions' % (us_taken, len(self.sessions))) return KeepRunning
def stop(self): self.authorization_handler.stop() notification_center = NotificationCenter() notification_center.remove_observer(self, name='SIPSessionNewIncoming') notification_center.remove_observer( self, name='SIPIncomingSubscriptionGotSubscribe') notification_center.remove_observer(self, name='SIPIncomingReferralGotRefer') notification_center.remove_observer( self, name='SIPIncomingRequestGotRequest') for app in ApplicationRegistry(): try: app().stop() except Exception, e: log.warning('Error stopping application: %s' % e) log.err()
def load_builtin_applications(): toplevel = os.path.dirname(__file__) app_list = [ 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)) ] for module in [ 'sylk.applications.%s' % item for item in set(app_list).difference( ServerConfig.disabled_applications) ]: try: __import__(module) except ImportError, e: log.warning('Error loading builtin "%s" application: %s' % (module, e))
def get_setting(self, section, setting, type=str, default=''): """Get a setting from a given section using type, or default if missing""" try: value = self.parser.get(section, setting) except Exception: return default else: try: if type is bool: return datatypes.Boolean(value) else: return type(value) except Exception as e: log.warning('ignoring invalid config value: %s.%s=%s (%s).' % (section, setting, value, e)) return default
def __new__(cls, description): if isinstance(description, (list, tuple)): return [Hostname(x) for x in description] elif not isinstance(description, basestring): raise TypeError("value must be a string, list or tuple") if description.lower() == 'none': return [] lst = re.split(r'\s*,\s*', description) hosts = [] for x in lst: try: host = Hostname(x) except ValueError as e: log.warning('%s (ignored)' % e) else: hosts.append(host) return hosts
def load_extra_applications(): if ServerConfig.extra_applications_dir: toplevel = os.path.realpath( os.path.abspath(ServerConfig.extra_applications_dir.normalized)) if os.path.isdir(toplevel): app_list = [ 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)) ] sys.path.append(toplevel) for module in (item for item in set(app_list).difference( ServerConfig.disabled_applications)): try: __import__(module) except ImportError, e: log.warning('Error loading extra "%s" application: %s' % (module, e))
def end(self, calltime=None, reason=None, sendbye=False): if sendbye and self.dialogid is not None: ManagementInterface().end_dialog(self.dialogid) if self.timer: self.timer.cancel() self.timer = None fullreason = '%s%s' % (self.inprogress and 'disconnected' or 'canceled', reason and (' by %s' % reason) or '') if self.inprogress: self.endtime = time.time() duration = self.endtime - self.starttime if calltime: ## call did timeout and was ended by external means (like mediaproxy). ## we were notified of this and we have the actual call duration in `calltime' #self.endtime = self.starttime + calltime self.duration = calltime log.info( "Call from %s to %s was already disconnected (ended or did timeout) after %s seconds (%s)" % (self.user, self.ruri, self.duration, self.callid)) elif self.expired: self.duration = self.timelimit if duration > self.timelimit + 10: log.warning( 'Time difference between sending BYEs and actual closing is > 10 seconds' ) else: self.duration = duration if not self.timelimit: self.timelimit = 0 if self.prepaid and not self.locked and self.timelimit > 0: ## even if call was not started we debit 0 seconds anyway to unlock the account rating = RatingEngineConnections.getConnection(self) rating.debitBalance(self).addCallbacks( callback=self._end_finish, errback=self._end_error, callbackArgs=[reason and fullreason or None]) elif reason is not None: log.info( "Call from %s to %s %s%s (%s)" % (self.user, self.ruri, fullreason, self.duration and (' after %d seconds' % self.duration) or '', self.callid))
def __new__(cls, description): if description is None: return description elif isinstance(description, (list, tuple)): return [NetworkRange(x) for x in description] or None elif not isinstance(description, basestring): raise TypeError('value must be a string, list, tuple or None') if description.lower() == 'none': return None lst = re.split(r'\s*,\s*', description) ranges = [] for x in lst: try: network_range = NetworkRange(x) except NameError: log.warning('Could not resolve hostname: %r (ignored)' % x) except ValueError: log.warning('Invalid network specification: %r (ignored)' % x) else: ranges.append(network_range) return ranges or None
def on_startup(self): # First set up listening on the unix socket try: gid = grp.getgrnam(self.group)[2] mode = 0o660 except (KeyError, IndexError): gid = -1 mode = 0o666 self.listening = reactor.listenUNIX(address=self.path, factory=CallControlFactory(self)) # Make it writable only to the SIP proxy group members try: os.chown(self.path, -1, gid) os.chmod(self.path, mode) except OSError: log.warning("Couldn't set access rights for %s" % self.path) log.warning("OpenSIPS may not be able to communicate with us!") # Then setup the CallsMonitor self.monitor = CallsMonitor(CallControlConfig.checkInterval, self) # Open the connection to the rating engines self.engines = RatingEngineConnections()
def lineReceived(self, line): log.debug( 'Received response from rating engine %s:%s: %s' % (self.transport.getPeer().host, self.transport.getPeer().port, line.strip().replace("\n", " "))) if not line: return if self.__timeout_call is not None: self.__timeout_call.cancel() if self.__request is None: log.warning('Got reply for non-existing request: %s' % line) return try: self._respond( getattr(self, '_PE_%s' % self.__request.command.lower())(line)) except AttributeError: self._respond( "Unknown command in request. Cannot handle reply. Reply is: %s" % line, success=False) except Exception as e: self._respond(str(e), success=False)
def __init__(self): load_applications() registry = ApplicationRegistry() self.applications = dict((app.__appname__, app) for app in registry) log.msg('Loaded applications: %s' % ', '.join(self.applications.keys())) default_application = registry.find_application(ServerConfig.default_application) if default_application is None: log.warning('Default application "%s" does not exist, falling back to "conference"' % ServerConfig.default_application) ServerConfig.default_application = 'conference' else: log.msg('Default application: %s' % ServerConfig.default_application) self.application_map = dict((item.split(':')) for item in ServerConfig.application_map) if self.application_map: txt = 'Application map:\n' invert_app_map = defaultdict(list) for url, app in self.application_map.iteritems(): invert_app_map[app].append(url) for app, urls in invert_app_map.iteritems(): txt += ' * %s:\n' % app for url in urls: txt += ' - %s\n' % url log.msg(txt[:-1]) self.authorization_handler = AuthorizationHandler()
class TLSSettingsExtension(TLSSettings): ca_list = Setting(type=Path, default=ca_file, nillable=True) def sip_port_validator(port, sibling_port): if port == sibling_port != 0: raise ValueError("the TCP and TLS ports must be different") transport_list = [] if SIPConfig.local_udp_port is not None: transport_list.append('udp') if SIPConfig.local_tcp_port is not None: transport_list.append('tcp') tls_port = SIPConfig.local_tls_port if tls_port is not None and None in (ca_file, account_cert): log.warning('Cannot enable TLS because the CA or the certificate are not specified') tls_port = None if tls_port is not None: transport_list.append('tls') class SIPSettingsExtension(SIPSettings): udp_port = Setting(type=Port, default=SIPConfig.local_udp_port, nillable=True) tcp_port = CorrelatedSetting(type=Port, sibling='tls_port', validator=sip_port_validator, default=SIPConfig.local_tcp_port, nillable=True) tls_port = CorrelatedSetting(type=Port, sibling='tcp_port', validator=sip_port_validator, default=tls_port, nillable=True) transport_list = Setting(type=SIPTransportList, default=transport_list) class SylkServerSettingsExtension(SettingsObjectExtension): user_agent = Setting(type=str, default='SylkServer-%s' % server_version) audio = AudioSettingsExtension
def warning(self, message, **context): log.warning(self.prefix+message, **context)