Exemple #1
0
 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
Exemple #2
0
 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
Exemple #3
0
 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 = []
Exemple #4
0
 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)
Exemple #5
0
 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 = []
Exemple #6
0
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)
Exemple #7
0
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)
Exemple #8
0
 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
Exemple #9
0
        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)
Exemple #10
0
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)
Exemple #11
0
 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
Exemple #12
0
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)
Exemple #13
0
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)
Exemple #14
0
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)