diff options
author | Benny Prijono <bennylp@teluu.com> | 2008-12-22 18:54:58 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2008-12-22 18:54:58 +0000 |
commit | 0723dbc601c74330f792db67ad75f6d580c30d8b (patch) | |
tree | a10e1cc45bdeb80210168f2e26421ae0d7e7295d /tests/pjsua/inc_sip.py | |
parent | 341dea971f9d548cc922f5f3446d80130a1d57d9 (diff) |
Created top-level directory tests and moved test-pjsua there. This will be the placeholder for future developed tests
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2392 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'tests/pjsua/inc_sip.py')
-rw-r--r-- | tests/pjsua/inc_sip.py | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/tests/pjsua/inc_sip.py b/tests/pjsua/inc_sip.py new file mode 100644 index 00000000..6d5ef052 --- /dev/null +++ b/tests/pjsua/inc_sip.py @@ -0,0 +1,330 @@ +# $Id$ +# +from socket import * +import re +import random +import time +import sys +import inc_cfg as cfg +from select import * + +# SIP request template +req_templ = \ +"""$METHOD $TARGET_URI SIP/2.0\r +Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;branch=z9hG4bK$BRANCH\r +Max-Forwards: 70\r +From: <sip:caller@pjsip.org>$FROM_TAG\r +To: <$TARGET_URI>$TO_TAG\r +Contact: <sip:$LOCAL_IP:$LOCAL_PORT;transport=udp>\r +Call-ID: $CALL_ID@pjsip.org\r +CSeq: $CSEQ $METHOD\r +Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, REFER\r +Supported: replaces, 100rel, norefersub\r +User-Agent: pjsip.org Python tester\r +Content-Length: $CONTENT_LENGTH\r +$SIP_HEADERS""" + + +def is_request(msg): + return msg.split(" ", 1)[0] != "SIP/2.0" + +def is_response(msg): + return msg.split(" ", 1)[0] == "SIP/2.0" + +def get_code(msg): + if msg=="": + return 0 + return int(msg.split(" ", 2)[1]) + +def get_tag(msg, hdr="To"): + pat = "^" + hdr + ":.*" + result = re.search(pat, msg, re.M | re.I) + if result==None: + return "" + line = result.group() + #print "line=", line + tags = line.split(";tag=") + if len(tags)>1: + return tags[1] + return "" + #return re.split("[;& ]", s) + +def get_header(msg, hname): + headers = msg.splitlines() + for hdr in headers: + hfields = hdr.split(": ", 2) + if hfields[0]==hname: + return hfields[1] + return None + +class Dialog: + sock = None + dst_addr = "" + dst_port = 5060 + local_ip = "" + local_port = 0 + tcp = False + call_id = str(random.random()) + cseq = 0 + local_tag = ";tag=" + str(random.random()) + rem_tag = "" + last_resp_code = 0 + inv_branch = "" + trace_enabled = True + last_request = "" + def __init__(self, dst_addr, dst_port=5060, tcp=False, trace=True, local_port=0): + self.dst_addr = dst_addr + self.dst_port = dst_port + self.tcp = tcp + self.trace_enabled = trace + if tcp==True: + self.sock = socket(AF_INET, SOCK_STREAM) + self.sock.connect(dst_addr, dst_port) + else: + self.sock = socket(AF_INET, SOCK_DGRAM) + self.sock.bind(("127.0.0.1", local_port)) + + self.local_ip, self.local_port = self.sock.getsockname() + self.trace("Dialog socket bound to " + self.local_ip + ":" + str(self.local_port)) + + def trace(self, txt): + if self.trace_enabled: + print str(time.strftime("%H:%M:%S ")) + txt + + def create_req(self, method, sdp, branch="", extra_headers=""): + if branch=="": + self.cseq = self.cseq + 1 + msg = req_templ + msg = msg.replace("$METHOD", method) + if self.tcp: + transport_param = ";transport=tcp" + else: + transport_param = "" + msg = msg.replace("$TARGET_URI", "sip:"+self.dst_addr+":"+str(self.dst_port) + transport_param) + msg = msg.replace("$LOCAL_IP", self.local_ip) + msg = msg.replace("$LOCAL_PORT", str(self.local_port)) + if branch=="": + branch=str(random.random()) + msg = msg.replace("$BRANCH", branch) + msg = msg.replace("$FROM_TAG", self.local_tag) + msg = msg.replace("$TO_TAG", self.rem_tag) + msg = msg.replace("$CALL_ID", self.call_id) + msg = msg.replace("$CSEQ", str(self.cseq)) + msg = msg.replace("$SIP_HEADERS", extra_headers) + if sdp!="": + msg = msg.replace("$CONTENT_LENGTH", str(len(sdp))) + msg = msg + "Content-Type: application/sdp\r\n" + else: + msg = msg.replace("$CONTENT_LENGTH", "0") + msg = msg + "\r\n" + msg = msg + sdp + return msg + + def create_response(self, request, code, reason, to_tag=""): + response = "SIP/2.0 " + str(code) + " " + reason + "\r\n" + lines = request.splitlines() + for line in lines: + hdr = line.split(":", 1)[0] + if hdr in ["Via", "From", "To", "CSeq", "Call-ID"]: + if hdr=="To" and to_tag!="": + line = line + ";tag=" + to_tag + elif hdr=="Via": + line = line + ";received=127.0.0.1" + response = response + line + "\r\n" + return response + + def create_invite(self, sdp, extra_headers=""): + self.inv_branch = str(random.random()) + return self.create_req("INVITE", sdp, branch=self.inv_branch, extra_headers=extra_headers) + + def create_ack(self, sdp="", extra_headers=""): + return self.create_req("ACK", sdp, extra_headers=extra_headers, branch=self.inv_branch) + + def create_bye(self, extra_headers=""): + return self.create_req("BYE", "", extra_headers) + + def send_msg(self, msg, dst_addr=None): + if (is_request(msg)): + self.last_request = msg.split(" ", 1)[0] + if not dst_addr: + dst_addr = (self.dst_addr, self.dst_port) + self.trace("============== TX MSG to " + str(dst_addr) + " ============= \n" + msg) + self.sock.sendto(msg, 0, dst_addr) + + def wait_msg_from(self, timeout): + endtime = time.time() + timeout + msg = "" + src_addr = None + while time.time() < endtime: + readset = select([self.sock], [], [], timeout) + if len(readset) < 1 or not self.sock in readset[0]: + if len(readset) < 1: + print "select() returns " + str(len(readset)) + elif not self.sock in readset[0]: + print "select() alien socket" + else: + print "select other error" + continue + try: + msg, src_addr = self.sock.recvfrom(2048) + except: + print "recv() exception: ", sys.exc_info()[0] + continue + + if msg=="": + return "", None + if self.last_request=="INVITE" and self.rem_tag=="": + self.rem_tag = get_tag(msg, "To") + self.rem_tag = self.rem_tag.rstrip("\r\n;") + if self.rem_tag != "": + self.rem_tag = ";tag=" + self.rem_tag + self.trace("=== rem_tag:" + self.rem_tag) + self.trace("=========== RX MSG from " + str(src_addr) + " ===========\n" + msg) + return (msg, src_addr) + + def wait_msg(self, timeout): + return self.wait_msg_from(timeout)[0] + + # Send request and wait for final response + def send_request_wait(self, msg, timeout): + t1 = 1.0 + endtime = time.time() + timeout + resp = "" + code = 0 + for i in range(0,5): + self.send_msg(msg) + resp = self.wait_msg(t1) + if resp!="" and is_response(resp): + code = get_code(resp) + break + last_resp = resp + while code < 200 and time.time() < endtime: + resp = self.wait_msg(endtime - time.time()) + if resp != "" and is_response(resp): + code = get_code(resp) + last_resp = resp + elif resp=="": + break + return last_resp + + def hangup(self, last_code=0): + self.trace("====== hangup =====") + if last_code!=0: + self.last_resp_code = last_code + if self.last_resp_code>0 and self.last_resp_code<200: + msg = self.create_req("CANCEL", "", branch=self.inv_branch, extra_headers="") + self.send_request_wait(msg, 5) + msg = self.create_ack() + self.send_msg(msg) + elif self.last_resp_code>=200 and self.last_resp_code<300: + msg = self.create_ack() + self.send_msg(msg) + msg = self.create_bye() + self.send_request_wait(msg, 5) + else: + msg = self.create_ack() + self.send_msg(msg) + + +class SendtoCfg: + # Test name + name = "" + # pjsua InstanceParam + inst_param = None + # Complete INVITE message. If this is not empty, then this + # message will be sent instead and the "sdp" and "extra_headers" + # settings will be ignored. + complete_msg = "" + # Initial SDP + sdp = "" + # Extra headers to add to request + extra_headers = "" + # Expected code + resp_code = 0 + # Use TCP? + use_tcp = False + # List of RE patterns that must exist in response + resp_include = [] + # List of RE patterns that must NOT exist in response + resp_exclude = [] + # Constructor + def __init__(self, name, pjsua_args, sdp, resp_code, + resp_inc=[], resp_exc=[], use_tcp=False, + extra_headers="", complete_msg="", + enable_buffer = False): + self.complete_msg = complete_msg + self.sdp = sdp + self.resp_code = resp_code + self.resp_include = resp_inc + self.resp_exclude = resp_exc + self.use_tcp = use_tcp + self.extra_headers = extra_headers + self.inst_param = cfg.InstanceParam("pjsua", pjsua_args) + self.inst_param.enable_buffer = enable_buffer + + +class RecvfromTransaction: + # The test title for this transaction + title = "" + # Optinal list of pjsua command and optional expect patterns + # to be invoked to make pjsua send a request + # Sample: + # (to make call and wait for INVITE to be sent) + # cmds = [ ["m"], ["sip:127.0.0.1", "INVITE sip:"] ] + cmds = [] + # Check if the CSeq must be greater than last Cseq? + check_cseq = True + # List of RE patterns that must exists in incoming request + include = [] + # List of RE patterns that MUST NOT exist in incoming request + exclude = [] + # Response code to send + resp_code = 0 + # Additional list of headers to be sent on the response + # Note: no need to add CRLF on the header + resp_hdr = [] + # Message body. This should include the Content-Type header too. + # Sample: + # body = """Content-Type: application/sdp\r\n + # \r\n + # v=0\r\n + # ... + # """ + body = None + # Pattern to be expected on pjsua when receiving the response + expect = "" + + def __init__(self, title, resp_code, check_cseq=True, + include=[], exclude=[], cmds=[], resp_hdr=[], resp_body=None, expect=""): + self.title = title + self.cmds = cmds + self.include = include + self.exclude = exclude + self.resp_code = resp_code + self.resp_hdr = resp_hdr + self.resp_body = resp_body + self.expect = expect + + +class RecvfromCfg: + # Test name + name = "" + # pjsua InstanceParam + inst_param = None + # List of RecvfromTransaction + transaction = None + # Use TCP? + tcp = False + + # Note: + # Any "$PORT" string in the pjsua_args will be replaced + # by server port + def __init__(self, name, pjsua_args, transaction, tcp=False): + self.name = name + self.inst_param = cfg.InstanceParam("pjsua", pjsua_args) + self.transaction = transaction + self.tcp=tcp + + + + |