~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/tests/pjsua/inc_sip.py

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# $Id: inc_sip.py 3283 2010-08-18 07:37:29Z bennylp $
 
2
#
 
3
from socket import *
 
4
import re
 
5
import random
 
6
import time
 
7
import sys
 
8
import inc_cfg as cfg
 
9
from select import *
 
10
 
 
11
# SIP request template
 
12
req_templ = \
 
13
"""$METHOD $TARGET_URI SIP/2.0\r
 
14
Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;branch=z9hG4bK$BRANCH\r
 
15
Max-Forwards: 70\r
 
16
From: <sip:caller@pjsip.org>$FROM_TAG\r
 
17
To: <$TARGET_URI>$TO_TAG\r
 
18
Contact: <sip:$LOCAL_IP:$LOCAL_PORT;transport=udp>\r
 
19
Call-ID: $CALL_ID@pjsip.org\r
 
20
CSeq: $CSEQ $METHOD\r
 
21
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, REFER\r
 
22
Supported: replaces, 100rel, norefersub\r
 
23
User-Agent: pjsip.org Python tester\r
 
24
Content-Length: $CONTENT_LENGTH\r
 
25
$SIP_HEADERS"""
 
26
 
 
27
 
 
28
def is_request(msg):
 
29
        return msg.split(" ", 1)[0] != "SIP/2.0"
 
30
        
 
31
def is_response(msg):
 
32
        return msg.split(" ", 1)[0] == "SIP/2.0"
 
33
 
 
34
def get_code(msg):
 
35
        if msg=="":
 
36
                return 0
 
37
        return int(msg.split(" ", 2)[1])
 
38
 
 
39
def get_tag(msg, hdr="To"):
 
40
        pat = "^" + hdr + ":.*"
 
41
        result = re.search(pat, msg, re.M | re.I)
 
42
        if result==None:
 
43
                return ""
 
44
        line = result.group()
 
45
        #print "line=", line
 
46
        tags = line.split(";tag=")
 
47
        if len(tags)>1:
 
48
                return tags[1]
 
49
        return ""
 
50
        #return re.split("[;& ]", s)
 
51
 
 
52
def get_header(msg, hname):
 
53
        headers = msg.splitlines()
 
54
        for hdr in headers:
 
55
                hfields = hdr.split(": ", 2)
 
56
                if hfields[0]==hname:
 
57
                        return hfields[1]
 
58
        return None
 
59
 
 
60
class Dialog:
 
61
        sock = None
 
62
        dst_addr = ""
 
63
        dst_port = 5060
 
64
        local_ip = ""
 
65
        local_port = 0
 
66
        tcp = False
 
67
        call_id = str(random.random())
 
68
        cseq = 0
 
69
        local_tag = ";tag=" + str(random.random())
 
70
        rem_tag = ""
 
71
        last_resp_code = 0
 
72
        inv_branch = ""
 
73
        trace_enabled = True
 
74
        last_request = ""
 
75
        def __init__(self, dst_addr, dst_port=5060, tcp=False, trace=True, local_port=0):
 
76
                self.dst_addr = dst_addr
 
77
                self.dst_port = dst_port
 
78
                self.tcp = tcp
 
79
                self.trace_enabled = trace
 
80
                if tcp==True:
 
81
                        self.sock = socket(AF_INET, SOCK_STREAM)
 
82
                        self.sock.connect(dst_addr, dst_port)
 
83
                else:
 
84
                        self.sock = socket(AF_INET, SOCK_DGRAM)
 
85
                        self.sock.bind(("127.0.0.1", local_port))
 
86
                
 
87
                self.local_ip, self.local_port = self.sock.getsockname()
 
88
                self.trace("Dialog socket bound to " + self.local_ip + ":" + str(self.local_port))
 
89
 
 
90
        def trace(self, txt):
 
91
                if self.trace_enabled:
 
92
                        print str(time.strftime("%H:%M:%S ")) + txt
 
93
 
 
94
        def update_fields(self, msg):
 
95
                if self.tcp:
 
96
                        transport_param = ";transport=tcp"
 
97
                else:
 
98
                        transport_param = ""
 
99
                msg = msg.replace("$TARGET_URI", "sip:"+self.dst_addr+":"+str(self.dst_port) + transport_param)
 
100
                msg = msg.replace("$LOCAL_IP", self.local_ip)
 
101
                msg = msg.replace("$LOCAL_PORT", str(self.local_port))
 
102
                msg = msg.replace("$FROM_TAG", self.local_tag)
 
103
                msg = msg.replace("$TO_TAG", self.rem_tag)
 
104
                msg = msg.replace("$CALL_ID", self.call_id)
 
105
                msg = msg.replace("$CSEQ", str(self.cseq))
 
106
                branch=str(random.random())
 
107
                msg = msg.replace("$BRANCH", branch)
 
108
                return msg
 
109
 
 
110
        def create_req(self, method, sdp, branch="", extra_headers="", body=""):
 
111
                if branch=="":
 
112
                        self.cseq = self.cseq + 1
 
113
                msg = req_templ
 
114
                msg = msg.replace("$METHOD", method)
 
115
                msg = msg.replace("$SIP_HEADERS", extra_headers)
 
116
                if branch=="":
 
117
                        branch=str(random.random())
 
118
                msg = msg.replace("$BRANCH", branch)
 
119
                if sdp!="":
 
120
                        msg = msg.replace("$CONTENT_LENGTH", str(len(sdp)))
 
121
                        msg = msg + "Content-Type: application/sdp\r\n"
 
122
                        msg = msg + "\r\n"
 
123
                        msg = msg + sdp
 
124
                elif body!="":
 
125
                        msg = msg.replace("$CONTENT_LENGTH", str(len(body)))
 
126
                        msg = msg + "\r\n"
 
127
                        msg = msg + body
 
128
                else:
 
129
                        msg = msg.replace("$CONTENT_LENGTH", "0")
 
130
                return self.update_fields(msg)
 
131
 
 
132
        def create_response(self, request, code, reason, to_tag=""):
 
133
                response = "SIP/2.0 " + str(code) + " " + reason + "\r\n"
 
134
                lines = request.splitlines()
 
135
                for line in lines:
 
136
                        hdr = line.split(":", 1)[0]
 
137
                        if hdr in ["Via", "From", "To", "CSeq", "Call-ID"]:
 
138
                                if hdr=="To" and to_tag!="":
 
139
                                        line = line + ";tag=" + to_tag
 
140
                                elif hdr=="Via":
 
141
                                        line = line + ";received=127.0.0.1"
 
142
                                response = response + line + "\r\n"
 
143
                return response
 
144
 
 
145
        def create_invite(self, sdp, extra_headers="", body=""):
 
146
                self.inv_branch = str(random.random())
 
147
                return self.create_req("INVITE", sdp, branch=self.inv_branch, extra_headers=extra_headers, body=body)
 
148
 
 
149
        def create_ack(self, sdp="", extra_headers=""):
 
150
                return self.create_req("ACK", sdp, extra_headers=extra_headers, branch=self.inv_branch)
 
151
 
 
152
        def create_bye(self, extra_headers=""):
 
153
                return self.create_req("BYE", "", extra_headers)
 
154
 
 
155
        def send_msg(self, msg, dst_addr=None):
 
156
                if (is_request(msg)):
 
157
                        self.last_request = msg.split(" ", 1)[0]
 
158
                if not dst_addr:
 
159
                        dst_addr = (self.dst_addr, self.dst_port)
 
160
                self.trace("============== TX MSG to " + str(dst_addr) + " ============= \n" + msg)
 
161
                self.sock.sendto(msg, 0, dst_addr)
 
162
 
 
163
        def wait_msg_from(self, timeout):
 
164
                endtime = time.time() + timeout
 
165
                msg = ""
 
166
                src_addr = None
 
167
                while time.time() < endtime:
 
168
                        readset = select([self.sock], [], [], 1)
 
169
                        if len(readset[0]) < 1 or not self.sock in readset[0]:
 
170
                                if len(readset[0]) < 1:
 
171
                                        print "select() timeout (will wait for " + str(int(endtime - time.time())) + "more secs)"
 
172
                                elif not self.sock in readset[0]:
 
173
                                        print "select() alien socket"
 
174
                                else:
 
175
                                        print "select other error"
 
176
                                continue
 
177
                        try:
 
178
                                msg, src_addr = self.sock.recvfrom(4096)
 
179
                                break
 
180
                        except:
 
181
                                print "recv() exception: ", sys.exc_info()[0]
 
182
                                continue
 
183
 
 
184
                if msg=="":
 
185
                        return "", None
 
186
                if self.last_request=="INVITE" and self.rem_tag=="":
 
187
                        self.rem_tag = get_tag(msg, "To")
 
188
                        self.rem_tag = self.rem_tag.rstrip("\r\n;")
 
189
                        if self.rem_tag != "":
 
190
                                self.rem_tag = ";tag=" + self.rem_tag
 
191
                        self.trace("=== rem_tag:" + self.rem_tag)
 
192
                self.trace("=========== RX MSG from " + str(src_addr) +  " ===========\n" + msg)
 
193
                return (msg, src_addr)
 
194
        
 
195
        def wait_msg(self, timeout):
 
196
                return self.wait_msg_from(timeout)[0]
 
197
                
 
198
        # Send request and wait for final response
 
199
        def send_request_wait(self, msg, timeout):
 
200
                t1 = 1.0
 
201
                endtime = time.time() + timeout
 
202
                resp = ""
 
203
                code = 0
 
204
                for i in range(0,5):
 
205
                        self.send_msg(msg)
 
206
                        resp = self.wait_msg(t1)
 
207
                        if resp!="" and is_response(resp):
 
208
                                code = get_code(resp)
 
209
                                break
 
210
                last_resp = resp
 
211
                while code < 200 and time.time() < endtime:
 
212
                        resp = self.wait_msg(endtime - time.time())
 
213
                        if resp != "" and is_response(resp):
 
214
                                code = get_code(resp)
 
215
                                last_resp = resp
 
216
                        elif resp=="":
 
217
                                break
 
218
                return last_resp
 
219
        
 
220
        def hangup(self, last_code=0):
 
221
                self.trace("====== hangup =====")
 
222
                if last_code!=0:
 
223
                        self.last_resp_code = last_code
 
224
                if self.last_resp_code>0 and self.last_resp_code<200:
 
225
                        msg = self.create_req("CANCEL", "", branch=self.inv_branch, extra_headers="")
 
226
                        self.send_request_wait(msg, 5)
 
227
                        msg = self.create_ack()
 
228
                        self.send_msg(msg)
 
229
                elif self.last_resp_code>=200 and self.last_resp_code<300:
 
230
                        msg = self.create_ack()
 
231
                        self.send_msg(msg)
 
232
                        msg = self.create_bye()
 
233
                        self.send_request_wait(msg, 5)
 
234
                else:
 
235
                        msg = self.create_ack()
 
236
                        self.send_msg(msg)
 
237
 
 
238
 
 
239
class SendtoCfg:
 
240
        # Test name
 
241
        name = ""
 
242
        # pjsua InstanceParam
 
243
        inst_param = None
 
244
        # Complete INVITE message. If this is not empty, then this
 
245
        # message will be sent instead and the "sdp" and "extra_headers"
 
246
        # settings will be ignored.
 
247
        complete_msg = ""
 
248
        # Initial SDP
 
249
        sdp = ""
 
250
        # Extra headers to add to request
 
251
        extra_headers = ""
 
252
        # Expected code
 
253
        resp_code = 0
 
254
        # Use TCP?
 
255
        use_tcp = False
 
256
        # List of RE patterns that must exist in response
 
257
        resp_include = []
 
258
        # List of RE patterns that must NOT exist in response
 
259
        resp_exclude = []
 
260
        # Full (non-SDP) body
 
261
        body = ""
 
262
        # Constructor
 
263
        def __init__(self, name, pjsua_args, sdp, resp_code, 
 
264
                     resp_inc=[], resp_exc=[], use_tcp=False,
 
265
                     extra_headers="", body="", complete_msg="",
 
266
                     enable_buffer = False):
 
267
                self.complete_msg = complete_msg
 
268
                self.sdp = sdp
 
269
                self.resp_code = resp_code
 
270
                self.resp_include = resp_inc
 
271
                self.resp_exclude = resp_exc
 
272
                self.use_tcp = use_tcp
 
273
                self.extra_headers = extra_headers
 
274
                self.body = body
 
275
                self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
 
276
                self.inst_param.enable_buffer = enable_buffer 
 
277
 
 
278
 
 
279
class RecvfromTransaction:
 
280
        # The test title for this transaction
 
281
        title = ""
 
282
        # Optinal list of pjsua command and optional expect patterns 
 
283
        # to be invoked to make pjsua send a request
 
284
        # Sample:
 
285
        #       (to make call and wait for INVITE to be sent)
 
286
        #       cmds = [ ["m"], ["sip:127.0.0.1", "INVITE sip:"]  ]
 
287
        cmds = []
 
288
        # Check if the CSeq must be greater than last Cseq?
 
289
        check_cseq = True
 
290
        # List of RE patterns that must exists in incoming request
 
291
        include = []
 
292
        # List of RE patterns that MUST NOT exist in incoming request
 
293
        exclude = []
 
294
        # Response code to send
 
295
        resp_code = 0
 
296
        # Additional list of headers to be sent on the response
 
297
        # Note: no need to add CRLF on the header
 
298
        resp_hdr = []
 
299
        # Message body. This should include the Content-Type header too.
 
300
        # Sample:
 
301
        #       body = """Content-Type: application/sdp\r\n
 
302
        #       \r\n
 
303
        #       v=0\r\n
 
304
        #       ...
 
305
        #       """
 
306
        body = None
 
307
        # Pattern to be expected on pjsua when receiving the response
 
308
        expect = ""
 
309
        
 
310
        def __init__(self, title, resp_code, check_cseq=True,
 
311
                        include=[], exclude=[], cmds=[], resp_hdr=[], resp_body=None, expect=""):
 
312
                self.title = title
 
313
                self.cmds = cmds
 
314
                self.include = include
 
315
                self.exclude = exclude
 
316
                self.resp_code = resp_code
 
317
                self.resp_hdr = resp_hdr
 
318
                self.body = resp_body
 
319
                self.expect = expect
 
320
                        
 
321
 
 
322
class RecvfromCfg:
 
323
        # Test name
 
324
        name = ""
 
325
        # pjsua InstanceParam
 
326
        inst_param = None
 
327
        # List of RecvfromTransaction
 
328
        transaction = None
 
329
        # Use TCP?
 
330
        tcp = False
 
331
 
 
332
        # Note:
 
333
        #  Any "$PORT" string in the pjsua_args will be replaced
 
334
        #  by server port
 
335
        def __init__(self, name, pjsua_args, transaction, tcp=False):
 
336
                self.name = name
 
337
                self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
 
338
                self.transaction = transaction
 
339
                self.tcp=tcp
 
340
 
 
341
 
 
342
 
 
343