def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock'): self.active = [] self.pending = [] if len(address) == 2: self.ccm = Udp_server(address, self.up_command_udp) else: self.ccm = Cli_server_local(self.up_command, address, (80, 80)) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address
def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock'): self.active = [] self.pending = [] if len(address) == 2: self.ccm = Udp_server(global_config, address, self.up_command_udp) else: self.ccm = Cli_server_local(self.up_command, address, (80, 80)) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address
def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock'): self.active = [] self.pending = [] if len(address) == 2: self.ccm = Udp_server(global_config, address, self.up_command_udp) else: sown = global_config.get('_rtpc_sockowner', None) self.ccm = Cli_server_local(self.up_command, address, sown) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address self.commands_inflight = []
def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock', dry_run = False): self.active = [] self.pending = [] self.l1rcache = {} self.l2rcache = {} if len(address) == 2: if not dry_run: uopts = Udp_server_opts(address, self.up_command_udp) self.ccm = Udp_server(global_config, uopts) else: sown = global_config.get('_rtpc_sockowner', None) if not dry_run: self.ccm = Cli_server_local(self.up_command, address, sown) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address self.commands_inflight = [] self.cache_purge_el = Timeout(self.rCachePurge, 10, -1)
def __init__(self, global_config, name, address='/var/run/rtpproxy.sock', dry_run=False): self.active = [] self.pending = [] if len(address) == 2: if not dry_run: self.ccm = Udp_server(global_config, address, self.up_command_udp) else: sown = global_config.get('_rtpc_sockowner', None) if not dry_run: self.ccm = Cli_server_local(self.up_command, address, sown) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address self.commands_inflight = []
class Rtp_cluster(object): global_config = None address = None name = None active = None pending = None ccm = None commands_inflight = None def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock', dry_run = False): self.active = [] self.pending = [] if len(address) == 2: if not dry_run: self.ccm = Udp_server(global_config, address, self.up_command_udp) else: sown = global_config.get('_rtpc_sockowner', None) if not dry_run: self.ccm = Cli_server_local(self.up_command, address, sown) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address self.commands_inflight = [] def add_member(self, member): member.on_state_change = self.rtpp_status_change if member.online: self.active.append(member) else: self.pending.append(member) def up_command_udp(self, data, address, server): dataparts = data.split(None, 1) if len(dataparts) == 1: return cookie, cmd = dataparts if cookie in self.commands_inflight: return self.commands_inflight.append(cookie) clim = UdpCLIM(address, cookie, server) return self.up_command(clim, cmd) def up_command(self, clim, orig_cmd): #print 'up_command', orig_cmd cmd = Rtp_proxy_cmd(orig_cmd) #print cmd if len(self.active) == 0: self.down_command('E999', clim, cmd, None) return if cmd.type in ('U', 'L', 'D', 'P', 'S', 'R', 'C', 'Q'): #print 'up', cmd.call_id, str(cmd) for rtpp in self.active: if rtpp.isYours(cmd.call_id): if cmd.type == 'D': rtpp.unbind_session(cmd.call_id) break else: rtpp = None if rtpp == None and cmd.type == 'U' and cmd.ul_opts.to_tag == None: # New session rtpp = self.pick_proxy(cmd.call_id) rtpp.bind_session(cmd.call_id, cmd.type) elif rtpp == None: # Existing session we know nothing about if cmd.type == 'U': # Do a forced lookup orig_cmd = 'L%s' % cmd.ul_opts.getstr(cmd.call_id, swaptags = True) active = [x for x in self.active if x.online] br = Broadcaster(len(active), clim, cmd) for rtpp in active: if cmd.type in ('U', 'L') and rtpp.lan_address != None: out_cmd = Rtp_proxy_cmd(orig_cmd) out_cmd.ul_opts.local_ip = rtpp.lan_address out_cmd = str(out_cmd) else: out_cmd = orig_cmd rtpp.send_command(out_cmd, self.merge_results, br, rtpp) return elif cmd.type == 'I' and cmd.command_opts == 'b': active = [x for x in self.active if x.online] sessions_created = active_sessions = active_streams = preceived = ptransmitted = 0 for rtpp in active: if rtpp.active_sessions == None: # There might be some time between "online" and heartbeat reply, # when stats are still empty, or when proxy goes from offline # to online, skip it continue sessions_created += rtpp.sessions_created active_sessions += rtpp.active_sessions active_streams += rtpp.active_streams preceived += rtpp.preceived ptransmitted += rtpp.ptransmitted reply = 'sessions created: %d\nactive sessions: %d\nactive streams: %d\npackets received: %d\npackets transmitted: %d' % \ (sessions_created, active_sessions, active_streams, preceived, ptransmitted) self.down_command(reply, clim, cmd, None) return else: rtpp = self.active[0] #print 'up', cmd #print 'rtpp.send_command' if cmd.type in ('U', 'L') and rtpp.lan_address != None: out_cmd = Rtp_proxy_cmd(orig_cmd) out_cmd.ul_opts.local_ip = rtpp.lan_address out_cmd = str(out_cmd) else: out_cmd = orig_cmd rtpp.send_command(out_cmd, self.down_command, clim, cmd, rtpp) def down_command(self, result, clim, cmd, rtpp): if isinstance(clim, UdpCLIM) and clim.cookie in self.commands_inflight: self.commands_inflight.remove(clim.cookie) #print 'down', result if result == None: result = 'E999' elif cmd.type in ('U', 'L') and not result[0].upper() == 'E' and \ rtpp.wan_address != None: #print 'down', cmd.ul_opts.destination_ip, rtpp.wan_address req_dip = cmd.ul_opts.destination_ip req_lip = cmd.ul_opts.local_ip if req_dip != None and not is_dst_local(req_dip) and \ req_lip != rtpp.lan_address: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) elif req_lip == None: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) # result = '%s %s' % (result_parts[0], '192.168.1.22') #print 'down clim.send', result clim.send(result + '\n') clim.close() def merge_results(self, result, br, rtpp): if result == None: result = 'E999' if br != None and not result[0].upper() == 'E' and not \ (br.cmd.type in ('U', 'L') and result == '0'): br.results.append(result) br.bcount -= 1 if br.bcount > 0: # More results to come return if len(br.results) == 1: rtpp.bind_session(br.cmd.call_id, br.cmd.type) self.down_command(br.results[0], br.clim, br.cmd, rtpp) else: # No results or more than one proxy returns positive # XXX: more than one result can probably be handled if br.cmd.type in ('U', 'L'): self.down_command('0', br.clim, br.cmd, rtpp) else: self.down_command('E999', br.clim, br.cmd, rtpp) def pick_proxy(self, call_id): active = [(rtpp, rtpp.weight * (1 - rtpp.get_caputil())) \ for rtpp in self.active if rtpp.status == 'ACTIVE' and rtpp.online] available = [(rtpp, weight) for rtpp, weight in active if weight > 0] if len(available) > 0: # Normal case, there are some proxies that are loaded below their capacities total_weight = sum([x[1] for x in available]) thr_weight = (random() * total_weight) % total_weight #print total_weight, thr_weight for rtpp, weight in available: thr_weight -= weight if thr_weight < 0: break #print 'pick_proxyNG: picked up %s for the call %s (normal)' % (rtpp.name, call_id) return rtpp elif len(active) > 0: max_rtpp, max_weight = active[0] for rtpp, weight in active[1:]: if weight > max_weight: max_rtpp, max_weight = rtpp, weight #print 'pick_proxyNG: picked up %s for the call %s (overload)' % (max_rtpp.name, call_id) return max_rtpp print 'pick_proxyNG: OUCH, no proxies to pickup from for the call %s' % (call_id,) return None def rtpp_status_change(self, rtpp, online): #print 'rtpp_status_change', self, rtpp, online if online and rtpp in self.pending: self.pending.remove(rtpp) self.active.append(rtpp) if not online and rtpp in self.active: self.active.remove(rtpp) self.pending.append(rtpp) def bring_down(self, rtpp): if rtpp in self.active: if rtpp.active_sessions in (0, None): self.active.remove(rtpp) return rtpp.status = 'DRAINING' rtpp.on_active_update = self.rtpp_active_change return self.pending.remove(rtpp) def rtpp_active_change(self, rtpp, active_sessions): if rtpp.status == 'DRAINING' and active_sessions == 0: if rtpp in self.pending: self.pending.remove(rtpp) else: self.active.remove(rtpp) rtpp.shutdown = True def rtpp_by_name(self, name): idx = 0 for rtpp in self.active + self.pending: if rtpp.name == name: return (rtpp, idx) idx += 1 return (None, None) def shutdown(self): for rtpp in self.active + self.pending: rtpp.shutdown = True if self.ccm != None: self.ccm.shutdown() self.active = None self.pending = None self.ccm = None def all_members(self): return tuple(self.active + self.pending)
def main_func(): global_config = MyConfigParser() global_config['digest_auth'] = True global_config['start_acct_enable'] = False global_config['keepalive_ans'] = 0 global_config['keepalive_orig'] = 0 global_config['auth_enable'] = True global_config['acct_enable'] = True global_config['_pass_headers'] = [] global_config['_orig_argv'] = sys.argv[:] global_config['_orig_cwd'] = os.getcwd() try: opts, args = getopt.getopt(sys.argv[1:], 'fDl:p:d:P:L:s:a:t:T:k:m:A:ur:F:R:h:c:M:HC:W:', global_config.get_longopts()) except getopt.GetoptError: usage(global_config) global_config['foreground'] = False global_config['pidfile'] = '/var/run/b2bua.pid' global_config['logfile'] = '/var/log/b2bua.log' global_config['b2bua_socket'] = '/var/run/b2bua.sock' global_config['_sip_address'] = SipConf.my_address global_config['_sip_port'] = SipConf.my_port rtp_proxy_clients = [] writeconf = None for o, a in opts: if o == '-f': global_config['foreground'] = True continue if o == '-l': global_config.check_and_set('sip_address', a) continue if o == '-p': global_config.check_and_set('sip_port', a) continue if o == '-P': global_config.check_and_set('pidfile', a) continue if o == '-L': global_config.check_and_set('logfile', a) continue if o == '-s': global_config.check_and_set('static_route', a) continue if o == '-a': global_config.check_and_set('accept_ips', a) continue if o == '-D': global_config['digest_auth'] = False continue if o == '-A': acct_level = int(a.strip()) if acct_level == 0: global_config['acct_enable'] = False global_config['start_acct_enable'] = False elif acct_level == 1: global_config['acct_enable'] = True global_config['start_acct_enable'] = False elif acct_level == 2: global_config['acct_enable'] = True global_config['start_acct_enable'] = True else: sys.__stderr__.write('ERROR: -A argument not in the range 0-2\n') usage(global_config, True) continue if o == '-t': global_config.check_and_set('static_tr_in', a) continue if o == '-T': global_config.check_and_set('static_tr_out', a) continue if o == '-k': ka_level = int(a.strip()) if ka_level == 0: pass elif ka_level == 1: global_config['keepalive_ans'] = 32 elif ka_level == 2: global_config['keepalive_orig'] = 32 elif ka_level == 3: global_config['keepalive_ans'] = 32 global_config['keepalive_orig'] = 32 else: sys.__stderr__.write('ERROR: -k argument not in the range 0-3\n') usage(global_config, True) if o == '-m': global_config.check_and_set('max_credit_time', a) continue if o == '-u': global_config['auth_enable'] = False continue if o == '-r': global_config.check_and_set('rtp_proxy_client', a) continue if o == '-F': global_config.check_and_set('allowed_pts', a) continue if o == '-R': global_config.check_and_set('radiusclient.conf', a) continue if o == '-h': for a in a.split(','): global_config.check_and_set('pass_header', a) continue if o == '-c': global_config.check_and_set('b2bua_socket', a) continue if o == '-M': global_config.check_and_set('max_radiusclients', a) continue if o == '-H': global_config['hide_call_id'] = True continue if o in ('-C', '--config'): global_config.read(a.strip()) continue if o.startswith('--'): global_config.check_and_set(o[2:], a) continue if o == '-W': writeconf = a.strip() continue if global_config.has_key('_rtp_proxy_clients'): for a in global_config['_rtp_proxy_clients']: if a.startswith('udp:'): a = a.split(':', 2) if len(a) == 2: rtp_proxy_address = (a[1], 22222) else: rtp_proxy_address = (a[1], int(a[2])) rtp_proxy_clients.append(rtp_proxy_address) else: rtp_proxy_clients.append(a) if not global_config['auth_enable'] and not global_config.has_key('static_route'): sys.__stderr__.write('ERROR: static route should be specified when Radius auth is disabled\n') usage(global_config, True) if writeconf != None: global_config.write(open(writeconf, 'w')) if not global_config['foreground']: daemonize(logfile = global_config['logfile']) global_config['_sip_logger'] = SipLogger('b2bua') if len(rtp_proxy_clients) > 0: global_config['_rtp_proxy_clients'] = [] for address in rtp_proxy_clients: global_config['_rtp_proxy_clients'].append(Rtp_proxy_client(global_config, address)) if global_config['auth_enable'] or global_config['acct_enable']: global_config['_radius_client'] = RadiusAuthorisation(global_config) SipConf.my_uaname = 'Sippy B2BUA (RADIUS)' global_config['_cmap'] = CallMap(global_config) if global_config.has_key('sip_proxy'): host_port = global_config['sip_proxy'].split(':', 1) if len(host_port) == 1: global_config['_sip_proxy'] = (host_port[0], 5060) else: global_config['_sip_proxy'] = (host_port[0], int(host_port[1])) global_config['_cmap'].proxy = StatefulProxy(global_config, global_config['_sip_proxy']) if global_config.getdefault('xmpp_b2bua_id', None) != None: global_config['_xmpp_mode'] = True global_config['_sip_tm'] = SipTransactionManager(global_config, global_config['_cmap'].recvRequest) global_config['_sip_tm'].nat_traversal = global_config.getdefault('nat_traversal', False) cmdfile = global_config['b2bua_socket'] if cmdfile.startswith('unix:'): cmdfile = cmdfile[5:] cli_server = Cli_server_local(global_config['_cmap'].recvCommand, cmdfile) if not global_config['foreground']: file(global_config['pidfile'], 'w').write(str(os.getpid()) + '\n') Signal(SIGUSR1, reopen, SIGUSR1, global_config['logfile']) reactor.suggestThreadPoolSize(50) reactor.run(installSignalHandlers = True)
def __init__(self, global_config, address = '/var/run/rtp_cluster.sock'): self.ccm = Cli_server_local(self.receive_command, address, (80, 80)) self.rtp_clusters = [] self.global_config = global_config
os.dup2(fd, sys.__stderr__.fileno()) os.close(fd) global_config['_sip_logger'] = SipLogger('b2bua') if len(rtp_proxy_clients) > 0: global_config['_rtp_proxy_clients'] = [] for address in rtp_proxy_clients: global_config['_rtp_proxy_clients'].append( Rtp_proxy_client(global_config, address)) if global_config['auth_enable'] or global_config['acct_enable']: global_config['_radius_client'] = RadiusAuthorisation(global_config) SipConf.my_uaname = 'Sippy B2BUA (RADIUS)' global_config['_cmap'] = CallMap(global_config) global_config['_sip_tm'] = SipTransactionManager( global_config, global_config['_cmap'].recvRequest) cmdfile = global_config['b2bua_socket'] if cmdfile.startswith('unix:'): cmdfile = cmdfile[5:] cli_server = Cli_server_local(global_config['_cmap'].recvCommand, cmdfile) if not global_config['foreground']: file(global_config['pidfile'], 'w').write(str(os.getpid()) + '\n') Signal(SIGUSR1, reopen, SIGUSR1, global_config['logfile']) reactor.run(installSignalHandlers=True)
class Rtp_cluster(object): global_config = None address = None name = None active = None pending = None ccm = None def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock'): self.active = [] self.pending = [] if len(address) == 2: self.ccm = Udp_server(global_config, address, self.up_command_udp) else: self.ccm = Cli_server_local(self.up_command, address, (80, 80)) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address def add_member(self, member): member.on_state_change = self.rtpp_status_change if member.online: self.active.append(member) else: self.pending.append(member) def up_command_udp(self, data, address, server): dataparts = data.split(None, 1) if len(dataparts) == 1: return cookie, cmd = dataparts clim = UdpCLIM(address, cookie, server) return self.up_command(clim, cmd) def up_command(self, clim, orig_cmd): #print 'up_command', orig_cmd cmd = Rtp_proxy_cmd(orig_cmd) #print cmd if len(self.active) == 0: self.down_command('E999', clim, cmd, None) return if cmd.type in ('U', 'L', 'D', 'P', 'S', 'R', 'C', 'Q'): #print 'up', cmd.call_id, str(cmd) for rtpp in self.active: if rtpp.isYours(cmd.call_id): if cmd.type == 'D': rtpp.unbind_session(cmd.call_id) break else: rtpp = None if rtpp == None and cmd.type == 'U' and len(cmd.args.split()) == 3: # New session rtpp = self.pick_proxy(cmd.call_id) rtpp.bind_session(cmd.call_id, cmd.type) elif rtpp == None: # Existing session we know nothing about if cmd.type == 'U': # Do a forced lookup orig_cmd = 'L%s %s' % (cmd.ul_opts, cmd.call_id) u_args = cmd.args.split(None, 4) from_tag = u_args[2] u_args[2] = u_args[3] u_args[3] = from_tag if len(u_args) == 4: orig_cmd += '%s %s %s %s' % tuple(u_args) else: orig_cmd += '%s %s %s %s %s' % tuple(u_args) active = [x for x in self.active if x.online] br = Broadcaster(len(active), clim, cmd) for rtpp in active: rtpp.send_command(orig_cmd, self.merge_results, br, rtpp) return elif cmd.type == 'I' and cmd.command_opts == 'b': active = [x for x in self.active if x.online] sessions_created = active_sessions = active_streams = preceived = ptransmitted = 0 for rtpp in active: if rtpp.sessions_created == None: # There might be some time between "online" and heartbeat reply, # when stats are still empty, skip it continue sessions_created += rtpp.sessions_created active_sessions += rtpp.active_sessions active_streams += rtpp.active_streams preceived += rtpp.preceived ptransmitted += rtpp.ptransmitted reply = 'sessions created: %d\nactive sessions: %d\nactive streams: %d\npackets received: %d\npackets transmitted: %d' % \ (sessions_created, active_sessions, active_streams, preceived, ptransmitted) self.down_command(reply, clim, cmd, None) return else: rtpp = self.active[0] #print 'up', cmd #print 'rtpp.send_command' rtpp.send_command(orig_cmd, self.down_command, clim, cmd, rtpp) def down_command(self, result, clim, cmd, rtpp): #print 'down', result if result == None: result = 'E999' elif cmd.type in ('U', 'L') and not result[0].upper() == 'E': #print 'down', cmd.ul_opts.destination_ip, rtpp.wan_address if cmd.ul_opts.destination_ip != None and rtpp.wan_address != None: if not is_dst_local(cmd.ul_opts.destination_ip): result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) elif cmd.ul_opts.destination_ip == None and rtpp.wan_address != None: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) # result = '%s %s' % (result_parts[0], '192.168.1.22') #print 'down clim.send', result clim.send(result + '\n') clim.close() def merge_results(self, result, br, rtpp): if result == None: result = 'E999' if br != None and not result[0].upper() == 'E' and not \ (br.cmd.type in ('U', 'L') and result == '0'): br.results.append(result) br.bcount -= 1 if br.bcount > 0: # More results to come return if len(br.results) == 1: rtpp.bind_session(br.cmd.call_id, br.cmd.type) self.down_command(br.results[0], br.clim, br.cmd, rtpp) else: # No results or more than one proxy returns positive # XXX: more than one result can probably be handled if br.cmd.type in ('U', 'L'): self.down_command('0', br.clim, br.cmd, rtpp) else: self.down_command('E999', br.clim, br.cmd, rtpp) def pick_proxy(self, call_id): active = list(self.active) call_id_hash = hash(call_id) while len(active) > 1: total_weight = sum([x.weight for x in active]) idx = call_id_hash % total_weight for rtpp in active: idx -= rtpp.weight if idx < 0: break if rtpp.status == 'ACTIVE' and rtpp.online and rtpp.capacity > rtpp.active_sessions: return rtpp active.remove(rtpp) return active[0] def rtpp_status_change(self, rtpp, online): #print 'rtpp_status_change', self, rtpp, online if online and rtpp in self.pending: self.pending.remove(rtpp) self.active.append(rtpp) if not online and rtpp in self.active: self.active.remove(rtpp) self.pending.append(rtpp) def bring_down(self, rtpp): if rtpp in self.active: if rtpp.active_sessions in (0, None): self.active.remove(rtpp) return rtpp.status = 'DRAINING' rtpp.on_active_update = self.rtpp_active_change return self.pending.remove(rtpp) def rtpp_active_change(self, rtpp, active_sessions): if rtpp.status == 'DRAINING' and active_sessions == 0: if rtpp in self.pending: self.pending.remove(rtpp) else: self.active.remove(rtpp) rtpp.shutdown = True def rtpp_by_name(self, name): idx = 0 for rtpp in self.active + self.pending: if rtpp.name == name: return (rtpp, idx) idx += 1 return (None, None) def shutdown(self): for rtpp in self.active + self.pending: rtpp.shutdown = True self.ccm.shutdown() self.active = None self.pending = None self.ccm = None def all_members(self): return tuple(self.active + self.pending)
def __init__(self, global_config, address): sown = global_config.get('_rtpc_sockowner', None) self.ccm = Cli_server_local(self.receive_command, address, sown) self.rtp_clusters = [] self.global_config = global_config
class Rtp_cluster(object): global_config = None address = None name = None active = None pending = None ccm = None commands_inflight = None def __init__(self, global_config, name, address='/var/run/rtpproxy.sock', dry_run=False): self.active = [] self.pending = [] if len(address) == 2: if not dry_run: self.ccm = Udp_server(global_config, address, self.up_command_udp) else: sown = global_config.get('_rtpc_sockowner', None) if not dry_run: self.ccm = Cli_server_local(self.up_command, address, sown) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address self.commands_inflight = [] def add_member(self, member): member.on_state_change = self.rtpp_status_change if member.online: self.active.append(member) else: self.pending.append(member) def up_command_udp(self, data, address, server): dataparts = data.split(None, 1) if len(dataparts) == 1: return cookie, cmd = dataparts if cookie in self.commands_inflight: return self.commands_inflight.append(cookie) clim = UdpCLIM(address, cookie, server) return self.up_command(clim, cmd) def up_command(self, clim, orig_cmd): #print 'up_command', orig_cmd cmd = Rtp_proxy_cmd(orig_cmd) #print cmd if len(self.active) == 0: self.down_command('E999', clim, cmd, None) return if cmd.type in ('U', 'L', 'D', 'P', 'S', 'R', 'C', 'Q'): #print 'up', cmd.call_id, str(cmd) for rtpp in self.active: if rtpp.isYours(cmd.call_id): if cmd.type == 'D': rtpp.unbind_session(cmd.call_id) break else: rtpp = None if rtpp == None and cmd.type == 'U' and cmd.ul_opts.to_tag == None: # New session rtpp = self.pick_proxy(cmd.call_id) rtpp.bind_session(cmd.call_id, cmd.type) elif rtpp == None: # Existing session we know nothing about if cmd.type == 'U': # Do a forced lookup orig_cmd = 'L%s' % cmd.ul_opts.getstr(cmd.call_id, swaptags=True) active = [x for x in self.active if x.online] br = Broadcaster(len(active), clim, cmd) for rtpp in active: if cmd.type in ('U', 'L') and rtpp.lan_address != None: out_cmd = Rtp_proxy_cmd(orig_cmd) out_cmd.ul_opts.local_ip = rtpp.lan_address out_cmd = str(out_cmd) else: out_cmd = orig_cmd rtpp.send_command(out_cmd, self.merge_results, br, rtpp) return elif cmd.type == 'I' and cmd.command_opts == 'b': active = [x for x in self.active if x.online] sessions_created = active_sessions = active_streams = preceived = ptransmitted = 0 for rtpp in active: if rtpp.active_sessions == None: # There might be some time between "online" and heartbeat reply, # when stats are still empty, or when proxy goes from offline # to online, skip it continue sessions_created += rtpp.sessions_created active_sessions += rtpp.active_sessions active_streams += rtpp.active_streams preceived += rtpp.preceived ptransmitted += rtpp.ptransmitted reply = 'sessions created: %d\nactive sessions: %d\nactive streams: %d\npackets received: %d\npackets transmitted: %d' % \ (sessions_created, active_sessions, active_streams, preceived, ptransmitted) self.down_command(reply, clim, cmd, None) return else: rtpp = self.active[0] #print 'up', cmd #print 'rtpp.send_command' if cmd.type in ('U', 'L') and rtpp.lan_address != None: out_cmd = Rtp_proxy_cmd(orig_cmd) out_cmd.ul_opts.local_ip = rtpp.lan_address out_cmd = str(out_cmd) else: out_cmd = orig_cmd rtpp.send_command(out_cmd, self.down_command, clim, cmd, rtpp) def down_command(self, result, clim, cmd, rtpp): if isinstance(clim, UdpCLIM) and clim.cookie in self.commands_inflight: self.commands_inflight.remove(clim.cookie) #print 'down', result if result == None: result = 'E999' elif cmd.type in ('U', 'L') and not result[0].upper() == 'E' and \ rtpp.wan_address != None: #print 'down', cmd.ul_opts.destination_ip, rtpp.wan_address req_dip = cmd.ul_opts.destination_ip req_lip = cmd.ul_opts.local_ip if req_dip != None and not is_dst_local(req_dip) and \ req_lip != rtpp.lan_address: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) elif req_lip == None: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) # result = '%s %s' % (result_parts[0], '192.168.1.22') #print 'down clim.send', result clim.send(result + '\n') clim.close() def merge_results(self, result, br, rtpp): if result == None: result = 'E999' if br != None and not result[0].upper() == 'E' and not \ (br.cmd.type in ('U', 'L') and result == '0'): br.results.append(result) br.bcount -= 1 if br.bcount > 0: # More results to come return if len(br.results) == 1: rtpp.bind_session(br.cmd.call_id, br.cmd.type) self.down_command(br.results[0], br.clim, br.cmd, rtpp) else: # No results or more than one proxy returns positive # XXX: more than one result can probably be handled if br.cmd.type in ('U', 'L'): self.down_command('0', br.clim, br.cmd, rtpp) else: self.down_command('E999', br.clim, br.cmd, rtpp) def pick_proxy(self, call_id): active = [(rtpp, rtpp.weight * (1 - rtpp.get_caputil())) \ for rtpp in self.active if rtpp.status == 'ACTIVE' and rtpp.online] available = [(rtpp, weight) for rtpp, weight in active if weight > 0] if len(available) > 0: # Normal case, there are some proxies that are loaded below their capacities total_weight = sum([x[1] for x in available]) thr_weight = (random() * total_weight) % total_weight #print total_weight, thr_weight for rtpp, weight in available: thr_weight -= weight if thr_weight < 0: break #print 'pick_proxyNG: picked up %s for the call %s (normal)' % (rtpp.name, call_id) return rtpp elif len(active) > 0: max_rtpp, max_weight = active[0] for rtpp, weight in active[1:]: if weight > max_weight: max_rtpp, max_weight = rtpp, weight #print 'pick_proxyNG: picked up %s for the call %s (overload)' % (max_rtpp.name, call_id) return max_rtpp print 'pick_proxyNG: OUCH, no proxies to pickup from for the call %s' % ( call_id, ) return None def rtpp_status_change(self, rtpp, online): #print 'rtpp_status_change', self, rtpp, online if online and rtpp in self.pending: self.pending.remove(rtpp) self.active.append(rtpp) if not online and rtpp in self.active: self.active.remove(rtpp) self.pending.append(rtpp) def bring_down(self, rtpp): if rtpp in self.active: if rtpp.active_sessions in (0, None): self.active.remove(rtpp) return rtpp.status = 'DRAINING' rtpp.on_active_update = self.rtpp_active_change return self.pending.remove(rtpp) def rtpp_active_change(self, rtpp, active_sessions): if rtpp.status == 'DRAINING' and active_sessions == 0: if rtpp in self.pending: self.pending.remove(rtpp) else: self.active.remove(rtpp) rtpp.shutdown = True def rtpp_by_name(self, name): idx = 0 for rtpp in self.active + self.pending: if rtpp.name == name: return (rtpp, idx) idx += 1 return (None, None) def shutdown(self): for rtpp in self.active + self.pending: rtpp.shutdown = True if self.ccm != None: self.ccm.shutdown() self.active = None self.pending = None self.ccm = None def all_members(self): return tuple(self.active + self.pending)
class Rtp_cluster(object): global_config = None address = None name = None active = None pending = None ccm = None def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock'): self.active = [] self.pending = [] if len(address) == 2: self.ccm = Udp_server(address, self.up_command_udp) else: self.ccm = Cli_server_local(self.up_command, address, (80, 80)) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address def add_member(self, member): member.on_state_change = self.rtpp_status_change if member.online: self.active.append(member) else: self.pending.append(member) def up_command_udp(self, data, address, server): dataparts = data.split(None, 1) if len(dataparts) == 1: return cookie, cmd = dataparts clim = UdpCLIM(address, cookie, server) return self.up_command(clim, cmd) def up_command(self, clim, orig_cmd): #print 'up_command', orig_cmd cmd = Rtp_proxy_cmd(orig_cmd) #print cmd if len(self.active) == 0: self.down_command('E999', clim, cmd, None) return if cmd.type in ('U', 'L', 'D', 'P', 'S', 'R', 'C', 'Q'): #print 'up', cmd.call_id, str(cmd) for rtpp in self.active: if rtpp.isYours(cmd.call_id): if cmd.type == 'D': rtpp.unbind_session(cmd.call_id) break else: rtpp = None if rtpp == None and cmd.type == 'U' and len(cmd.args.split()) == 3: # New session rtpp = self.pick_proxy(cmd.call_id) rtpp.bind_session(cmd.call_id, cmd.type) elif rtpp == None: # Existing session we know nothing about if cmd.type == 'U': # Do a forced lookup orig_cmd = 'L%s %s' % (cmd.ul_opts, cmd.call_id) u_args = cmd.args.split(None, 4) from_tag = u_args[2] u_args[2] = u_args[3] u_args[3] = from_tag if len(u_args) == 4: orig_cmd += '%s %s %s %s' % tuple(u_args) else: orig_cmd += '%s %s %s %s %s' % tuple(u_args) active = [x for x in self.active if x.online] br = Broadcaster(len(active), clim, cmd) for rtpp in active: rtpp.send_command(orig_cmd, self.merge_results, br, rtpp) return else: rtpp = self.active[0] #print 'up', cmd #print 'rtpp.send_command' rtpp.send_command(orig_cmd, self.down_command, clim, cmd, rtpp) def down_command(self, result, clim, cmd, rtpp): #print 'down', result if result == None: result = 'E999' elif cmd.type in ('U', 'L') and not result[0].upper() == 'E': #print 'down', cmd.ul_opts.destination_ip, rtpp.wan_address if cmd.ul_opts.destination_ip != None and rtpp.wan_address != None: if not is_dst_local(cmd.ul_opts.destination_ip): result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) # result = '%s %s' % (result_parts[0], '192.168.1.22') #print 'down clim.send', result clim.send(result + '\n') clim.close() def merge_results(self, result, br, rtpp): if br != None and not result[0].upper() == 'E' and not \ (br.cmd.type in ('U', 'L') and result == '0'): br.results.append(result) br.bcount -= 1 if br.bcount > 0: # More results to come return if len(br.results) == 1: rtpp.bind_session(br.cmd.call_id, br.cmd.type) self.down_command(br.results[0], br.clim, br.cmd, rtpp) else: # No results or more than one proxy returns positive # XXX: more than one result can probably be handled if br.cmd.type in ('U', 'L'): self.down_command('0', br.clim, br.cmd, rtpp) else: self.down_command('E999', br.clim, br.cmd, rtpp) def pick_proxy(self, call_id): active = list(self.active) call_id_hash = hash(call_id) while len(active) > 1: total_weight = sum([x.weight for x in active]) idx = call_id_hash % total_weight for rtpp in active: idx -= rtpp.weight if idx < 0: break if rtpp.status == 'ACTIVE' and rtpp.online and rtpp.capacity > rtpp.active_sessions: return rtpp active.remove(rtpp) return active[0] def rtpp_status_change(self, rtpp, online): #print 'rtpp_status_change', self, rtpp, online if online and rtpp in self.pending: self.pending.remove(rtpp) self.active.append(rtpp) if not online and rtpp in self.active: self.active.remove(rtpp) self.pending.append(rtpp) def bring_down(self, rtpp): if rtpp in self.active: if rtpp.active_sessions in (0, None): self.active.remove(rtpp) return rtpp.status = 'DRAINING' rtpp.on_active_update = self.rtpp_active_change return self.pending.remove(rtpp) def rtpp_active_change(self, rtpp, active_sessions): if rtpp.status == 'DRAINING' and active_sessions == 0: if rtpp in self.pending: self.pending.remove(rtpp) else: self.active.remove(rtpp) rtpp.shutdown = True def rtpp_by_name(self, name): idx = 0 for rtpp in self.active + self.pending: if rtpp.name == name: return (rtpp, idx) idx += 1 return (None, None) def shutdown(self): for rtpp in self.active + self.pending: rtpp.shutdown = True self.ccm.shutdown() self.active = None self.pending = None self.ccm = None def all_members(self): return tuple(self.active + self.pending)
class Rtp_cluster(object): global_config = None address = None name = None active = None pending = None ccm = None commands_inflight = None l1rcache = None l2rcache = None cache_purge_el = None dnrelay = None capacity_limit_soft = True def __init__(self, global_config, name, address = '/var/run/rtpproxy.sock', \ dnconfig = None, dry_run = False): self.active = [] self.pending = [] self.l1rcache = {} self.l2rcache = {} if len(address) == 2: if not dry_run: uopts = Udp_server_opts(address, self.up_command_udp) self.ccm = Udp_server(global_config, uopts) else: sown = global_config.get('_rtpc_sockowner', None) if not dry_run: self.ccm = Cli_server_local(self.up_command, address, sown) self.ccm.protocol.expect_lf = False self.global_config = global_config self.name = name self.address = address self.commands_inflight = [] self.cache_purge_el = Timeout(self.rCachePurge, 10, -1) self.update_dnrelay(dnconfig) def update_dnrelay(self, dnconfig): if self.dnrelay != None: if dnconfig != None and self.dnrelay.cmpconfig(dnconfig): return allow_from = self.dnrelay.get_allow_list() self.dnrelay.shutdown() self.dnrelay = None else: allow_from = None if dnconfig == None: return self.dnrelay = DNRelay(dnconfig) if allow_from != None: self.dnrelay.set_allow_list(allow_from) def add_member(self, member): member.on_state_change = self.rtpp_status_change if member.online: self.active.append(member) else: self.pending.append(member) if not member.is_local and self.dnrelay != None: self.dnrelay.allow_from(member.address) def up_command_udp(self, data, address, server, rtime): dataparts = data.split(None, 1) if len(dataparts) == 1: return cookie, cmd = dataparts if cookie in self.commands_inflight: return cresp = self.l1rcache.get(cookie, self.l2rcache.get(cookie, None)) if cresp != None: response = '%s %s' % (cookie, cresp) server.send_to(response, address) print('Rtp_cluster.up_command_udp(): sending cached response "%s" to %s' % \ (response[:-1], address)) return self.commands_inflight.append(cookie) clim = UdpCLIM(address, cookie, server) return self.up_command(clim, cmd) def up_command(self, clim, orig_cmd): #print 'up_command', orig_cmd cmd = Rtp_proxy_cmd(orig_cmd) #print cmd if len(self.active) == 0: self.down_command('E999', clim, cmd, None) return if cmd.type in ('U', 'L', 'D', 'P', 'S', 'R', 'C', 'Q'): #print 'up', cmd.call_id, str(cmd) for rtpp in self.active: if rtpp.isYours(cmd.call_id): break else: rtpp = None if cmd.type == 'U' and cmd.ul_opts.to_tag == None: new_session = True else: new_session = False if rtpp == None and not new_session: # Existing session, also check if it exists on any of the offline # members and try to relay it there, it makes no sense to broadcast # the call to every other node in that case for rtpp in self.pending: if rtpp.isYours(cmd.call_id): break else: rtpp = None if rtpp != None and cmd.type == 'D': rtpp.unbind_session(cmd.call_id) if rtpp == None and new_session: # New session rtpp = self.pick_proxy(cmd.call_id) if rtpp == None: self.down_command('E9989', clim, cmd, None) return rtpp.bind_session(cmd.call_id, cmd.type) if rtpp != None and cmd.type in ('U', 'L') and cmd.ul_opts.notify_socket != None: if rtpp.wdnt_supported and self.dnrelay != None and not rtpp.is_local and \ cmd.ul_opts.notify_socket.startswith(self.dnrelay.dest_sprefix): pref_len = len(self.dnrelay.dest_sprefix) dnstr = '%s %s' % (cmd.ul_opts.notify_socket[pref_len:], \ unquote(cmd.ul_opts.notify_tag)) cmd.ul_opts.notify_tag = quote(dnstr) cmd.ul_opts.notify_socket = 'tcp:%%%%CC_SELF%%%%:%d' % self.dnrelay.in_address[1] orig_cmd = str(cmd) elif not rtpp.is_local: cmd.ul_opts.notify_tag = None cmd.ul_opts.notify_socket = None orig_cmd = str(cmd) if rtpp == None: # Existing session we know nothing about if cmd.type == 'U': # Do a forced lookup orig_cmd = 'L%s' % cmd.ul_opts.getstr(cmd.call_id, swaptags = True) active = [x for x in self.active if x.online] br = Broadcaster(len(active), clim, cmd) for rtpp in active: if cmd.type in ('U', 'L') and rtpp.lan_address != None: out_cmd = Rtp_proxy_cmd(orig_cmd) out_cmd.ul_opts.local_ip = rtpp.lan_address out_cmd = str(out_cmd) else: out_cmd = orig_cmd rtpp.send_command(out_cmd, self.merge_results, br, rtpp) return elif cmd.type == 'I' and cmd.command_opts == 'b': active = [x for x in self.active if x.online] sessions_created = active_sessions = active_streams = preceived = ptransmitted = 0 for rtpp in active: if rtpp.active_sessions == None: # There might be some time between "online" and heartbeat reply, # when stats are still empty, or when proxy goes from offline # to online, skip it continue sessions_created += rtpp.sessions_created active_sessions += rtpp.active_sessions active_streams += rtpp.active_streams preceived += rtpp.preceived ptransmitted += rtpp.ptransmitted reply = 'sessions created: %d\nactive sessions: %d\nactive streams: %d\npackets received: %d\npackets transmitted: %d' % \ (sessions_created, active_sessions, active_streams, preceived, ptransmitted) self.down_command(reply, clim, cmd, None) return elif cmd.type == 'G': active = [x for x in self.active if x.online] br = Broadcaster(len(active), clim, cmd) br.sobj = Rtpp_stats(cmd.args.split()) if cmd.command_opts != None and cmd.command_opts.lower() == 'v': cmd.command_opts = None br.sobj.verbose = True cmd.nretr = 0 for rtpp in active: rtpp.send_command(cmd, self.merge_stats_results, br, rtpp) return else: rtpp = self.active[0] #print 'up', cmd #print 'rtpp.send_command' if cmd.type in ('U', 'L') and rtpp.lan_address != None: out_cmd = Rtp_proxy_cmd(orig_cmd) out_cmd.ul_opts.local_ip = rtpp.lan_address out_cmd = str(out_cmd) else: out_cmd = orig_cmd rtpp.send_command(out_cmd, self.down_command, clim, cmd, rtpp) def down_command(self, result, clim, cmd, rtpp): if isinstance(clim, UdpCLIM) and clim.cookie in self.commands_inflight: self.commands_inflight.remove(clim.cookie) #print 'down', result if result == None: result = 'E999' elif cmd.type in ('U', 'L') and not result[0].upper() == 'E' and \ rtpp.wan_address != None: #print 'down', cmd.ul_opts.destination_ip, rtpp.wan_address req_dip = cmd.ul_opts.destination_ip req_lip = cmd.ul_opts.local_ip if req_dip != None and not is_dst_local(req_dip) and \ req_lip != rtpp.lan_address: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) elif req_lip == None: result_parts = result.strip().split() result = '%s %s' % (result_parts[0], rtpp.wan_address) # result = '%s %s' % (result_parts[0], '192.168.1.22') #print 'down clim.send', result response = result + '\n' clim.send(response) if isinstance(clim, UdpCLIM): self.l1rcache[clim.cookie] = response clim.close() def merge_results(self, result, br, rtpp): if result == None: result = 'E999' if br != None and not result[0].upper() == 'E' and not \ (br.cmd.type in ('U', 'L') and result == '0'): br.results.append(result) br.bcount -= 1 if br.bcount > 0: # More results to come return if len(br.results) == 1: rtpp.bind_session(br.cmd.call_id, br.cmd.type) self.down_command(br.results[0], br.clim, br.cmd, rtpp) else: # No results or more than one proxy returns positive # XXX: more than one result can probably be handled if br.cmd.type in ('U', 'L'): self.down_command('0', br.clim, br.cmd, rtpp) else: self.down_command('E999', br.clim, br.cmd, rtpp) def merge_stats_results(self, result, br, rtpp): #print 'merge_stats_results, result', result if result == None: result = rtpp.stats_cache.get(br.sobj.all_names, 'E999') print 'merge_stats_results: getting from the cache %s' % result elif result[0].upper() != 'E': rtpp.stats_cache[br.sobj.all_names] = result if br != None and not result[0].upper() == 'E': try: br.sobj.parseAndAdd(result) br.ecount -= 1 except: pass br.bcount -= 1 if br.bcount > 0: # More results to come return #print 'merge_stats_results, br.sobj', br.sobj if br.ecount == br.nparts: rval = 'E999' else: rval = str(br.sobj) self.down_command(rval, br.clim, br.cmd, rtpp) def pick_proxy(self, call_id): active = [(rtpp, rtpp.weight * (1 - rtpp.get_caputil())) \ for rtpp in self.active if rtpp.status == 'ACTIVE' and rtpp.online] available = [(rtpp, weight) for rtpp, weight in active if weight > 0] if len(available) > 0: # Normal case, there are some proxies that are loaded below their capacities total_weight = sum([x[1] for x in available]) thr_weight = (random() * total_weight) % total_weight #print total_weight, thr_weight for rtpp, weight in available: thr_weight -= weight if thr_weight < 0: break #print 'pick_proxyNG: picked up %s for the call %s (normal)' % (rtpp.name, call_id) return rtpp elif len(active) > 0 and self.capacity_limit_soft: max_rtpp, max_weight = active[0] for rtpp, weight in active[1:]: if weight > max_weight: max_rtpp, max_weight = rtpp, weight #print 'pick_proxyNG: picked up %s for the call %s (overload)' % (max_rtpp.name, call_id) return max_rtpp print 'pick_proxyNG: OUCH, no proxies to pickup from for the call %s' % (call_id,) return None def rtpp_status_change(self, rtpp, online): #print 'rtpp_status_change', self, rtpp, online if online and rtpp in self.pending: self.pending.remove(rtpp) self.active.append(rtpp) if not online and rtpp in self.active: self.active.remove(rtpp) self.pending.append(rtpp) def bring_down(self, rtpp): if not rtpp.is_local and self.dnrelay != None: self.dnrelay.disallow_from(rtpp.address) if rtpp in self.active: if rtpp.active_sessions in (0, None): self.active.remove(rtpp) return rtpp.status = 'DRAINING' rtpp.on_active_update = self.rtpp_active_change return self.pending.remove(rtpp) def rtpp_active_change(self, rtpp, active_sessions): if rtpp.status == 'DRAINING' and active_sessions == 0: if rtpp in self.pending: self.pending.remove(rtpp) else: self.active.remove(rtpp) rtpp.shutdown() def rtpp_by_name(self, name): idx = 0 for rtpp in self.active + self.pending: if rtpp.name == name: return (rtpp, idx) idx += 1 return (None, None) def shutdown(self): for rtpp in self.active + self.pending: rtpp.shutdown() if self.ccm != None: self.ccm.shutdown() if self.cache_purge_el != None: self.cache_purge_el.cancel() self.active = None self.pending = None self.ccm = None self.cache_purge_el = None if self.dnrelay != None: self.dnrelay.shutdown() def all_members(self): return tuple(self.active + self.pending) def rCachePurge(self): self.l2rcache = self.l1rcache self.l1rcache = {}
continue if o == '-S': sippy_path = a.strip() continue if o == '-o': fname = a.strip() if fname == '-': file_out = sys.stdout else: file_out = file(fname, 'w') if o == '-t': timeout = float(a.strip()) continue if sippy_path != None: sys.path.insert(0, sippy_path) from sippy.Cli_server_local import Cli_server_local from sippy.Cli_server_tcp import Cli_server_tcp from sippy.Timeout import Timeout ch = cli_handler(file_out) if stype == 'unix': cs = Cli_server_local(ch.command_received, spath) else: cs = Cli_server_tcp(ch.command_received, spath) if timeout != None: Timeout(ch.done, timeout) reactor.run(installSignalHandlers=1) sys.exit(ch.rval)