1# Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
2# Copyright (c) 2006-2014 Sippy Software, Inc. All rights reserved.
3#
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without modification,
7# are permitted provided that the following conditions are met:
8#
9# 1. Redistributions of source code must retain the above copyright notice, this
10# list of conditions and the following disclaimer.
11#
12# 2. Redistributions in binary form must reproduce the above copyright notice,
13# this list of conditions and the following disclaimer in the documentation and/or
14# other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27def extract_to_next_token(s, match, invert = False):
28    i = 0
29    while i < len(s):
30        if (not invert and s[i] not in match) or \
31          (invert and s[i] in match):
32            break
33        i += 1
34    if i == 0:
35        return ('', s)
36    if i == len(s):
37        return (s, '')
38    return (s[:i], s[i:])
39
40class UpdateLookupOpts(object):
41    destination_ip = None
42    local_ip = None
43    codecs = None
44    otherparams = None
45    remote_ip = None
46    remote_port = None
47    from_tag = None
48    to_tag = None
49    notify_socket = None
50    notify_tag = None
51
52    def __init__(self, s = None, *params):
53        if s == None:
54            self.destination_ip, self.local_ip, self.codecs, self.otherparams = params
55            return
56        self.otherparams = ''
57        while len(s) > 0:
58            if s[0] == 'R':
59                val, s = extract_to_next_token(s[1:], ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'))
60                val = val.strip()
61                if len(val) > 0:
62                    self.destination_ip = val
63            if s[0] == 'L':
64                val, s = extract_to_next_token(s[1:], ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'))
65                val = val.strip()
66                if len(val) > 0:
67                    self.local_ip = val
68            elif s[0] == 'c':
69                val, s = extract_to_next_token(s[1:], ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ','))
70                val = val.strip()
71                if len(val) > 0:
72                    self.codecs = [int(x) for x in val.split(',')]
73            else:
74                val, s = extract_to_next_token(s, ('c', 'R'), True)
75                if len(val) > 0:
76                    self.otherparams += val
77
78    def getstr(self, call_id, swaptags = False):
79        s = ''
80        if self.destination_ip != None:
81            s += 'R%s' % (self.destination_ip,)
82        if self.local_ip != None:
83            s += 'L%s' % (self.local_ip,)
84        if self.codecs != None:
85            s += 'c'
86            for codec in self.codecs:
87                s += '%s,' % (codec,)
88            s = s[:-1]
89        if self.otherparams != None and len(self.otherparams) > 0:
90            s += self.otherparams
91        s = '%s %s' % (s, call_id)
92        if self.remote_ip != None:
93            s = '%s %s' % (s, self.remote_ip)
94        if self.remote_port != None:
95            s = '%s %s' % (s, self.remote_port)
96        if not swaptags:
97            from_tag, to_tag = (self.from_tag, self.to_tag)
98        else:
99            if self.to_tag == None:
100                raise Exception('UpdateLookupOpts::getstr(swaptags = True): to_tag is not set')
101            to_tag, from_tag = (self.from_tag, self.to_tag)
102        if self.from_tag != None:
103            s = '%s %s' % (s, self.from_tag)
104        if self.to_tag != None:
105            s = '%s %s' % (s, self.to_tag)
106        if self.notify_socket != None:
107            s = '%s %s' % (s, self.notify_socket)
108        if self.notify_tag != None:
109            s = '%s %s' % (s, self.notify_tag)
110        return s
111
112class Rtp_proxy_cmd(object):
113    type = None
114    ul_opts = None
115    command_opts = None
116    call_id = None
117    args = None
118    nretr = None
119
120    def __init__(self, cmd):
121        self.type = cmd[0].upper()
122        if self.type in ('U', 'L', 'D', 'P', 'S', 'R', 'C', 'Q'):
123            command_opts, self.call_id, args = cmd.split(None, 2)
124            if self.type in ('U', 'L'):
125                self.ul_opts = UpdateLookupOpts(command_opts[1:])
126                self.ul_opts.remote_ip, self.ul_opts.remote_port, args = args.split(None, 2)
127                args = args.split(None, 1)
128                self.ul_opts.from_tag = args[0]
129                if len(args) > 1:
130                    args = args[1].split(None, 2)
131                    if len(args) == 1:
132                        self.ul_opts.to_tag = args[0]
133                    elif len(args) == 2:
134                        self.ul_opts.notify_socket, self.ul_opts.notify_tag = args
135                    else:
136                        self.ul_opts.to_tag, self.ul_opts.notify_socket, self.ul_opts.notify_tag = args
137            else:
138                self.args = args
139                self.command_opts = command_opts[1:]
140        elif self.type in ('G',):
141            if not cmd[1].isspace():
142                cparts = cmd[1:].split(None, 1)
143                if len(cparts) > 1:
144                    self.command_opts, self.args = cparts
145                else:
146                    self.command_opts = cparts[0]
147            else:
148                self.args = cmd[1:].strip()
149        else:
150            self.command_opts = cmd[1:]
151
152    def __str__(self):
153        s = self.type
154        if self.ul_opts != None:
155            s += self.ul_opts.getstr(self.call_id)
156        else:
157            if self.command_opts != None:
158                s += self.command_opts
159            if self.call_id != None:
160                s = '%s %s' % (s, self.call_id)
161        if self.args != None:
162            s = '%s %s' % (s, self.args)
163        return s
164
165class Rtpp_stats(object):
166    spookyprefix = ''
167    verbose = False
168
169    def __init__(self, snames):
170        all_types = []
171        for sname in snames:
172            if sname != 'total_duration':
173                stype = int
174            else:
175                stype = float
176            self.__dict__[self.spookyprefix + sname] = stype()
177            all_types.append(stype)
178        self.all_names = tuple(snames)
179        self.all_types = tuple(all_types)
180
181    def __iadd__(self, other):
182        for sname in self.all_names:
183            aname = self.spookyprefix + sname
184            self.__dict__[aname] += other.__dict__[aname]
185        return self
186
187    def parseAndAdd(self, rstr):
188        rparts = rstr.split(None, len(self.all_names) - 1)
189        for i in range(0, len(self.all_names)):
190            stype = self.all_types[i]
191            rval = stype(rparts[i])
192            aname = self.spookyprefix + self.all_names[i]
193            self.__dict__[aname] += rval
194
195    def __str__(self):
196        aname = self.spookyprefix + self.all_names[0]
197        if self.verbose:
198            rval = '%s=%s' % (self.all_names[0], str(self.__dict__[aname]))
199        else:
200            rval = str(self.__dict__[aname])
201        for sname in self.all_names[1:]:
202            aname = self.spookyprefix + sname
203            if self.verbose:
204                rval += ' %s=%s' % (sname, str(self.__dict__[aname]))
205            else:
206                rval += ' %s' % str(self.__dict__[aname])
207        return rval
208
209if __name__ == '__main__':
210    rc = Rtp_proxy_cmd('G nsess_created total_duration')
211    print rc
212    print rc.args
213    print rc.command_opts
214    rc = Rtp_proxy_cmd('Gv nsess_created total_duration')
215    print rc
216    print rc.args
217    print rc.command_opts
218