class UacStateCancelling(UaStateGeneric): sname = 'Cancelling(UAC)' def __init__(self, ua): UaStateGeneric.__init__(self, ua) ua.on_local_sdp_change = None ua.on_remote_sdp_change = None # 300 provides good estimate on the amount of time during which # we can wait for receiving non-negative response to CANCELled # INVITE transaction. self.te = Timeout(self.goIdle, 300.0) def goIdle(self): # print 'Time in Cancelling state expired, going to the Dead state' self.te = None self.ua.changeState((UaStateDead,)) def recvResponse(self, resp, tr): code, reason = resp.getSCode() if code < 200: return None if self.te != None: self.te.cancel() self.te = None # When the final response arrives make sure to send BYE # if response is positive 200 OK and move into # UaStateDisconnected to catch any in-flight BYE from the # called party. # # If the response is negative or redirect go to the UaStateDead # immediately, since this means that we won't receive any more # requests from the calling party. XXX: redirects should probably # somehow reported to the upper level, but it will create # significant additional complexity there, since after signalling # Failure/Disconnect calling party don't expect any more # events to be delivered from the called one. In any case, # this should be fine, since we are in this state only when # caller already has declared his wilingless to end the session, # so that he is probably isn't interested in redirects anymore. if code >= 200 and code < 300: if resp.countHFs('contact') > 0: self.ua.rTarget = resp.getHFBody('contact').getUrl().getCopy() self.ua.routes = [x.getCopy() for x in resp.getHFBodys('record-route')] self.ua.routes.reverse() if len(self.ua.routes) > 0: if not self.ua.routes[0].getUrl().lr: self.ua.routes.append(SipRoute(address=SipAddress(url=self.ua.rTarget))) self.ua.rTarget = self.ua.routes.pop(0).getUrl() self.ua.rAddr = self.ua.rTarget.getAddr() elif self.ua.outbound_proxy != None: self.ua.routes.append(SipRoute(address=SipAddress(url=self.ua.rTarget))) self.ua.rTarget = self.ua.routes[0].getUrl().getCopy() self.ua.rTarget.lr = False self.ua.rTarget.other = tuple() self.ua.rTarget.headers = tuple() else: self.ua.rAddr = self.ua.routes[0].getAddr() else: self.ua.rAddr = self.ua.rTarget.getAddr() self.ua.rUri.setTag(resp.getHFBody('to').getTag()) req = self.ua.genRequest('BYE') self.ua.lCSeq += 1 self.ua.global_config['_sip_tm'].newTransaction(req, \ laddress=self.ua.source_address, compact=self.ua.compact_sip) return (UaStateDisconnected,) return (UaStateDead,) def recvEvent(self, event): # print 'wrong event %s in the Cancelling state' % event return None
class RadiusAccounting(object): global_config = None drec = None crec = None iTime = None cTime = None credit_time = None sip_cid = None origin = None lperiod = None el = None send_start = None complete = False def __init__(self, global_config, origin, lperiod = None, send_start = False, itime = None): if not itime: self.iTime = time() else: self.iTime = itime self.global_config = global_config self._attributes = [('h323-call-origin', origin), ('h323-call-type', 'VoIP'), \ ('h323-session-protocol', 'sipv2'), ('h323-setup-time', ftime(self.iTime))] self.drec = False self.crec = False self.origin = origin self.lperiod = lperiod self.send_start = send_start def setParams(self, username, caller, callee, h323_cid, sip_cid, remote_ip, \ credit_time = None, h323_in_cid = None): if caller == None: caller = '' self._attributes.extend((('User-Name', username), ('Calling-Station-Id', caller), \ ('Called-Station-Id', callee), ('h323-conf-id', h323_cid), ('call-id', sip_cid), \ ('Acct-Session-Id', sip_cid), ('h323-remote-address', remote_ip))) if h323_in_cid != None and h323_in_cid != h323_cid: self._attributes.append(('h323-incoming-conf-id', h323_in_cid)) self.credit_time = credit_time self.sip_cid = str(sip_cid) self.complete = True def conn(self, ua, rtime, origin): if self.crec: return self.crec = True self.cTime = rtime if self.send_start: self.asend('Start', rtime, origin) self._attributes.extend((('h323-voice-quality', 0), ('Acct-Terminate-Cause', 'User-Request'))) if self.lperiod != None: self.el = Timeout(self.asend, self.lperiod, -1, 'Alive') def disc(self, ua, rtime, origin, result = 0): if self.drec: return self.drec = True if self.el: self.el.cancel() self.el = None self.asend('Stop', rtime, origin, result) def asend(self, type, rtime = None, origin = None, result = 0): if not self.complete: return if not rtime: rtime = time() attributes = self._attributes[:] if type != 'Start': if self.cTime: duration = rtime - self.cTime delay = self.cTime - self.iTime else: duration = 0 delay = rtime - self.iTime if self.credit_time != None and duration > self.credit_time and duration < self.credit_time + 10: duration = self.credit_time if result >= 400: try: dc = sipErrToH323Err[result][0] except: dc = '7f' elif result < 200: dc = '10' else: dc = '0' attributes.extend((('h323-disconnect-time', ftime(self.iTime + delay + duration)), \ ('h323-connect-time', ftime(self.iTime + delay)), ('Acct-Session-Time', int(duration)), \ ('h323-disconnect-cause', dc))) else: attributes.append(('h323-connect-time', ftime(self.cTime))) if type == 'Stop': if origin == 'caller': release_source = '2' elif origin == 'callee': release_source = '4' else: release_source = '8' attributes.append(('release-source', release_source)) attributes.append(('Acct-Status-Type', type)) pattributes = ['%-32s = \'%s\'\n' % (x[0], str(x[1])) for x in attributes] pattributes.insert(0, 'sending Acct %s (%s):\n' % (type, self.origin.capitalize())) self.global_config['sip_logger'].write(call_id = self.sip_cid, *pattributes) self.global_config['radius_client'].do_acct(attributes, self._process_result, self.sip_cid, time()) def _process_result(self, results, sip_cid, btime): delay = time() - btime rcode = results[1] if rcode in (0, 1): if rcode == 0: message = 'Acct/%s request accepted (delay is %.3f)\n' % (self.origin, delay) else: message = 'Acct/%s request rejected (delay is %.3f)\n' % (self.origin, delay) else: message = 'Error sending Acct/%s request (delay is %.3f)\n' % (self.origin, delay) self.global_config['sip_logger'].write(message, call_id = sip_cid)
class UacStateCancelling(UaStateGeneric): sname = 'Cancelling(UAC)' def __init__(self, ua): UaStateGeneric.__init__(self, ua) ua.on_local_sdp_change = None ua.on_remote_sdp_change = None # 300 provides good estimate on the amount of time during which # we can wait for receiving non-negative response to CANCELled # INVITE transaction. self.te = Timeout(self.goIdle, 300.0) def goIdle(self): #print 'Time in Cancelling state expired, going to the Dead state' self.te = None self.ua.changeState((UaStateDead,)) def recvResponse(self, resp): code, reason = resp.getSCode() if code < 200: return None if self.te != None: self.te.cancel() self.te = None # When the final response arrives make sure to send BYE # if response is positive 200 OK and move into # UaStateDisconnected to catch any in-flight BYE from the # called party. # # If the response is negative or redirect go to the UaStateDead # immediately, since this means that we won't receive any more # requests from the calling party. XXX: redirects should probably # somehow reported to the upper level, but it will create # significant additional complexity there, since after signalling # Failure/Disconnect calling party don't expect any more # events to be delivered from the called one. In any case, # this should be fine, since we are in this state only when # caller already has declared his wilingless to end the session, # so that he is probably isn't interested in redirects anymore. if code >= 200 and code < 300: if resp.countHFs('contact') > 0: self.ua.rTarget = resp.getHFBody('contact').getUrl().getCopy() self.ua.routes = [x.getCopy() for x in resp.getHFBodys('record-route')] self.ua.routes.reverse() if len(self.ua.routes) > 0: if not self.ua.routes[0].getUrl().lr: self.ua.routes.append(SipRoute(address = SipAddress(url = self.ua.rTarget.getCopy()))) self.ua.rTarget = self.ua.routes.pop(0).getUrl() self.ua.rAddr = self.ua.rTarget.getAddr() else: self.ua.rAddr = self.ua.routes[0].getAddr() else: self.ua.rAddr = self.ua.rTarget.getAddr() self.ua.rUri.setTag(resp.getHFBody('to').getTag()) req = self.ua.genRequest('BYE') self.ua.lCSeq += 1 self.ua.global_config['_sip_tm'].newTransaction(req, \ laddress = self.ua.source_address) return (UaStateDisconnected,) return (UaStateDead,) def recvEvent(self, event): #print 'wrong event %s in the Cancelling state' % event return None
class RadiusAccounting(object): global_config = None drec = None crec = None iTime = None cTime = None sip_cid = None origin = None lperiod = None el = None send_start = None complete = False ms_precision = False user_agent = None p1xx_ts = None p100_ts = None def __init__(self, global_config, origin, lperiod = None, send_start = False): self.global_config = global_config self._attributes = [('h323-call-origin', origin), ('h323-call-type', 'VoIP'), \ ('h323-session-protocol', 'sipv2')] self.drec = False self.crec = False self.origin = origin self.lperiod = lperiod self.send_start = send_start def setParams(self, username, caller, callee, h323_cid, sip_cid, remote_ip, \ h323_in_cid = None): if caller == None: caller = '' self._attributes.extend((('User-Name', username), ('Calling-Station-Id', caller), \ ('Called-Station-Id', callee), ('h323-conf-id', h323_cid), ('call-id', sip_cid), \ ('Acct-Session-Id', sip_cid), ('h323-remote-address', remote_ip))) if h323_in_cid != None and h323_in_cid != h323_cid: self._attributes.append(('h323-incoming-conf-id', h323_in_cid)) self.sip_cid = str(sip_cid) self.complete = True def conn(self, ua, rtime, origin): if self.crec: return self.crec = True self.iTime = ua.setup_ts self.cTime = ua.connect_ts if ua.remote_ua != None and self.user_agent == None: self.user_agent = ua.remote_ua if ua.p1xx_ts != None: self.p1xx_ts = ua.p1xx_ts if ua.p100_ts != None: self.p100_ts = ua.p100_ts if self.send_start: self.asend('Start', rtime, origin, ua) self._attributes.extend((('h323-voice-quality', 0), ('Acct-Terminate-Cause', 'User-Request'))) if self.lperiod != None and self.lperiod > 0: self.el = Timeout(self.asend, self.lperiod, -1, 'Alive') def disc(self, ua, rtime, origin, result = 0): if self.drec: return self.drec = True if self.el != None: self.el.cancel() self.el = None if self.iTime == None: self.iTime = ua.setup_ts if self.cTime == None: self.cTime = rtime if ua.remote_ua != None and self.user_agent == None: self.user_agent = ua.remote_ua if ua.p1xx_ts != None: self.p1xx_ts = ua.p1xx_ts if ua.p100_ts != None: self.p100_ts = ua.p100_ts self.asend('Stop', rtime, origin, result, ua) def asend(self, type, rtime = None, origin = None, result = 0, ua = None): if not self.complete: return if rtime == None: rtime = time() if ua != None: duration, delay, connected = ua.getAcct()[:3] else: # Alive accounting duration = rtime - self.cTime delay = self.cTime - self.iTime connected = True if not(self.ms_precision): duration = round(duration) delay = round(delay) attributes = self._attributes[:] if type != 'Start': if result >= 400: try: dc = sipErrToH323Err[result][0] except: dc = '7f' elif result < 200: dc = '10' else: dc = '0' attributes.extend((('h323-disconnect-time', self.ftime(self.iTime + delay + duration)), \ ('Acct-Session-Time', '%d' % round(duration)), ('h323-disconnect-cause', dc))) if type == 'Stop': if origin == 'caller': release_source = '2' elif origin == 'callee': release_source = '4' else: release_source = '8' attributes.append(('release-source', release_source)) attributes.extend((('h323-connect-time', self.ftime(self.iTime + delay)), ('h323-setup-time', self.ftime(self.iTime)), \ ('Acct-Status-Type', type))) if self.user_agent != None: attributes.append(('h323-ivr-out', 'sip_ua:' + self.user_agent)) if self.p1xx_ts != None: attributes.append(('Acct-Delay-Time', round(self.p1xx_ts))) if self.p100_ts != None: attributes.append(('provisional-timepoint', self.ftime(self.p100_ts))) pattributes = ['%-32s = \'%s\'\n' % (x[0], str(x[1])) for x in attributes] pattributes.insert(0, 'sending Acct %s (%s):\n' % (type, self.origin.capitalize())) self.global_config['_sip_logger'].write(call_id = self.sip_cid, *pattributes) self.global_config['_radius_client'].do_acct(attributes, self._process_result, self.sip_cid, time()) def ftime(self, t): gt = gmtime(t) day = strftime('%d', gt) if day[0] == '0': day = day[1] if self.ms_precision: msec = (t % 1) * 1000 else: msec = 0 return strftime('%%H:%%M:%%S.%.3d GMT %%a %%b %s %%Y' % (msec, day), gt) def _process_result(self, results, sip_cid, btime): delay = time() - btime rcode = results[1] if rcode in (0, 1): if rcode == 0: message = 'Acct/%s request accepted (delay is %.3f)\n' % (self.origin, delay) else: message = 'Acct/%s request rejected (delay is %.3f)\n' % (self.origin, delay) else: message = 'Error sending Acct/%s request (delay is %.3f)\n' % (self.origin, delay) self.global_config['_sip_logger'].write(message, call_id = sip_cid)