diff options
author | Benny Prijono <bennylp@teluu.com> | 2008-07-07 20:14:41 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2008-07-07 20:14:41 +0000 |
commit | 28ec1de558e5b6fa5d6695ee797dc2774fb8739f (patch) | |
tree | 6a1603be3a43e159dd0829623e719c0aed7b9be0 /pjsip-apps | |
parent | a7c65d1eaeec40ce135ba5b1c1d14a0255bb99f2 (diff) |
Added mod_recvfrom.py testing module and some registrar test scenarios
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2110 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip-apps')
13 files changed, 503 insertions, 10 deletions
diff --git a/pjsip-apps/src/test-pjsua/inc_sip.py b/pjsip-apps/src/test-pjsua/inc_sip.py index c8dadc69..6d5ef052 100644 --- a/pjsip-apps/src/test-pjsua/inc_sip.py +++ b/pjsip-apps/src/test-pjsua/inc_sip.py @@ -49,6 +49,13 @@ def get_tag(msg, hdr="To"): 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 @@ -65,7 +72,7 @@ class Dialog: inv_branch = "" trace_enabled = True last_request = "" - def __init__(self, dst_addr, dst_port=5060, tcp=False, trace=True): + 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 @@ -75,7 +82,7 @@ class Dialog: self.sock.connect(dst_addr, dst_port) else: self.sock = socket(AF_INET, SOCK_DGRAM) - self.sock.bind(("127.0.0.1", 0)) + 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)) @@ -113,6 +120,19 @@ class Dialog: 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) @@ -123,15 +143,18 @@ class Dialog: def create_bye(self, extra_headers=""): return self.create_req("BYE", "", extra_headers) - def send_msg(self, msg): + def send_msg(self, msg, dst_addr=None): if (is_request(msg)): self.last_request = msg.split(" ", 1)[0] - self.trace("============== TX MSG ============= \n" + msg) - self.sock.sendto(msg, 0, (self.dst_addr, self.dst_port)) + 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(self, timeout): + 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]: @@ -143,22 +166,25 @@ class Dialog: print "select other error" continue try: - msg = self.sock.recv(2048) + msg, src_addr = self.sock.recvfrom(2048) except: print "recv() exception: ", sys.exc_info()[0] continue if msg=="": - return "" + 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 ===========\n" + msg) - return msg + 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 @@ -236,3 +262,69 @@ class SendtoCfg: 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 + + + + diff --git a/pjsip-apps/src/test-pjsua/mod_recvfrom.py b/pjsip-apps/src/test-pjsua/mod_recvfrom.py new file mode 100644 index 00000000..259083f5 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/mod_recvfrom.py @@ -0,0 +1,92 @@ +# $Id:$ +import imp +import sys +import inc_sip as sip +import inc_const as const +import re +from inc_cfg import * + +# Read configuration +cfg_file = imp.load_source("cfg_file", ARGS[1]) + +# Default server port (should we randomize?) +srv_port = 50070 + +def test_func(test): + pjsua = test.process[0] + dlg = sip.Dialog("127.0.0.1", pjsua.inst_param.sip_port, + local_port=srv_port, + tcp=cfg_file.recvfrom_cfg.tcp) + + last_cseq = 0 + last_method = "" + for t in cfg_file.recvfrom_cfg.transaction: + # Print transaction title + if t.title != "": + dlg.trace(t.title) + # Run command and expect patterns + for c in t.cmds: + if c[0] and c[0] != "": + pjsua.send(c[0]) + if len(c)>1 and c[1] and c[1] != "": + pjsua.expect(c[1]) + # Wait for request + if t.check_cseq: + # Absorbs retransmissions + cseq = 0 + method = last_method + while cseq <= last_cseq and method == last_method: + request, src_addr = dlg.wait_msg_from(10) + if request==None or request=="": + raise TestError("Timeout waiting for request") + method = request.split(" ", 1)[0] + cseq_hval = sip.get_header(request, "CSeq") + cseq_hval = cseq_hval.split(" ")[0] + cseq = int(cseq_hval) + last_cseq = cseq + last_method = method + else: + request, src_addr = dlg.wait_msg_from(10) + if request==None or request=="": + raise TestError("Timeout waiting for request") + + # Check for include patterns + for pat in t.include: + if re.search(pat, request, re.M | re.I)==None: + if t.title: + tname = " in " + t.title + " transaction" + else: + tname = "" + raise TestError("Pattern " + pat + " not found" + tname) + # Check for exclude patterns + for pat in t.exclude: + if re.search(pat, request, re.M | re.I)!=None: + if t.title: + tname = " in " + t.title + " transaction" + else: + tname = "" + raise TestError("Excluded pattern " + pat + " found" + tname) + # Create response + response = dlg.create_response(request, t.resp_code, "Status reason") + # Add headers to response + for h in t.resp_hdr: + response = response + h + "\r\n" + # Add message body if required + if t.body: + response = response + t.body + # Send response + dlg.send_msg(response, src_addr) + # Expect something to happen in pjsua + if t.expect != "": + pjsua.expect(t.expect) + # Sync + pjsua.sync_stdout() + +# Replace "$PORT" with server port in pjsua args +cfg_file.recvfrom_cfg.inst_param.arg = cfg_file.recvfrom_cfg.inst_param.arg.replace("$PORT", str(srv_port)) + +# Here where it all comes together +test = TestParam(cfg_file.recvfrom_cfg.name, + [cfg_file.recvfrom_cfg.inst_param], + test_func) + diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py new file mode 100644 index 00000000..9a0cd41a --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py @@ -0,0 +1,15 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT" + +req1 = sip.RecvfromTransaction("", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""], + expect="PJSIP_ENOCREDENTIAL" + ) + +recvfrom_cfg = sip.RecvfromCfg("Failed registration test", + pjsua, [req1]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/201_reg_good_ok.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/201_reg_good_ok.py new file mode 100644 index 00000000..5532d73f --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/201_reg_good_ok.py @@ -0,0 +1,23 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--username user --realm python --password passwd --auto-update-nat=0" + +req1 = sip.RecvfromTransaction("Initial registration", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""], + expect="SIP/2.0 401" + ) + +req2 = sip.RecvfromTransaction("Registration retry with auth", 200, + include=["REGISTER sip", "Authorization:", + "realm=\"python\"", "username=\"user\"", + "nonce=\"1234\"", "response="], + expect="registration success" + ) + +recvfrom_cfg = sip.RecvfromCfg("Successful registration test", + pjsua, [req1, req2]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py new file mode 100644 index 00000000..4fd9cdb7 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py @@ -0,0 +1,23 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--username user --realm \"*\" --password passwd --auto-update-nat=0" + +req1 = sip.RecvfromTransaction("Initial registration", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""], + expect="SIP/2.0 401" + ) + +req2 = sip.RecvfromTransaction("Registration retry with auth", 200, + include=["REGISTER sip", "Authorization:", + "realm=\"python\"", "username=\"user\"", + "nonce=\"1234\"", "response="], + expect="registration success" + ) + +recvfrom_cfg = sip.RecvfromCfg("Successful registration with wildcard realm test", + pjsua, [req1, req2]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/205_reg_good_no_realm.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/205_reg_good_no_realm.py new file mode 100644 index 00000000..69c0ecfd --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/205_reg_good_no_realm.py @@ -0,0 +1,16 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--realm=provider --user=username --password=password" + +req1 = sip.RecvfromTransaction("", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""], + expect="PJSIP_ENOCREDENTIAL" + ) + +recvfrom_cfg = sip.RecvfromCfg("Failed registration because of realm test", + pjsua, [req1]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py new file mode 100644 index 00000000..11f11bfc --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py @@ -0,0 +1,26 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +# Authentication failure test with same nonce + + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--realm=python --user=username --password=password" + +req1 = sip.RecvfromTransaction("Initial request", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""] + ) + +req2 = sip.RecvfromTransaction("REGISTER retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"1\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""], + expect="PJSIP_EFAILEDCREDENTIAL" + ) + + +recvfrom_cfg = sip.RecvfromCfg("Authentication failure with same nonce", + pjsua, [req1, req2]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py new file mode 100644 index 00000000..5f47a7bd --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py @@ -0,0 +1,29 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--realm=python --user=username --password=password " + \ + "--auto-update-nat=0" + +req1 = sip.RecvfromTransaction("Initial request", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""] + ) + +req2 = sip.RecvfromTransaction("REGISTER first retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"1\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"] + ) + + +req3 = sip.RecvfromTransaction("REGISTER retry with new nonce", 200, + include=["REGISTER sip", "Authorization", "nonce=\"2\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + expect="registration success" + ) + +recvfrom_cfg = sip.RecvfromCfg("Authentication okay after retry with new nonce", + pjsua, [req1, req2, req3]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/215_reg_good_multi_ok.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/215_reg_good_multi_ok.py new file mode 100644 index 00000000..32970f41 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/215_reg_good_multi_ok.py @@ -0,0 +1,28 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--username theuser1 --realm python1 --password passwd --next-cred " + \ + "--username theuser2 --realm python2 --password passwd " + \ + "--auto-update-nat=0" + +req1 = sip.RecvfromTransaction("Initial registration", 401, + include=["REGISTER sip"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python1\", nonce=\"1234\"", + "WWW-Authenticate: Digest realm=\"python2\", nonce=\"6789\""], + expect="SIP/2.0 401" + ) + +req2 = sip.RecvfromTransaction("Registration retry with auth", 200, + include=["REGISTER sip", + "Authorization:[\\s\\S]+Authorization:", # Must have 2 Auth hdrs + "realm=\"python1\"", "realm=\"python2\"", + "username=\"theuser1\"", "username=\"theuser2\"", + "nonce=\"1234\"", "nonce=\"6789\"", + "response="], + expect="registration success" + ) + +recvfrom_cfg = sip.RecvfromCfg("Multiple authentication challenges", + pjsua, [req1, req2]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/220_reg_good_ims_ok.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/220_reg_good_ims_ok.py new file mode 100644 index 00000000..3d02a1d6 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/220_reg_good_ims_ok.py @@ -0,0 +1,26 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--username user@ims-domain --realm python --password passwd --use-ims --auto-update-nat=0" + +req1 = sip.RecvfromTransaction("Initial registration", 401, + include=["REGISTER sip", "Authorization", + "username=\"user@ims-domain\"", + "realm=\"python\""], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""], + expect="SIP/2.0 401" + ) + +req2 = sip.RecvfromTransaction("Registration retry with auth", 200, + include=["REGISTER sip", "Authorization:", + "realm=\"python\"", "username=\"user@ims-domain\"", + "nonce=\"1234\"", "response="], + # Must not have double Authorization header: + exclude=["Authorization:[\\s\\S]+Authorization:"], + expect="registration success" + ) + +recvfrom_cfg = sip.RecvfromCfg("Successful IMS registration test", + pjsua, [req1, req2]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py new file mode 100644 index 00000000..396a7bc8 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py @@ -0,0 +1,41 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +# In this test we simulate broken server, where it always sends +# stale=true with all 401 responses. We should expect pjsip to +# retry the authentication until PJSIP_MAX_STALE_COUNT is +# exceeded. When pjsip retries the authentication, it should +# use the new nonce from server + + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--realm=python --user=username --password=password" + +req1 = sip.RecvfromTransaction("Initial request", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""] + ) + +req2 = sip.RecvfromTransaction("First retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"1\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"] + ) + +req3 = sip.RecvfromTransaction("Second retry retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"2\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"3\", stale=true"] + ) + +req4 = sip.RecvfromTransaction("Third retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"3\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"4\", stale=true"], + expect="PJSIP_EAUTHSTALECOUNT" + ) + +recvfrom_cfg = sip.RecvfromCfg("Failed registration retry (server rejects with stale=true) ", + pjsua, [req1, req2, req3, req4]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py new file mode 100644 index 00000000..ab0798d8 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py @@ -0,0 +1,41 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +# In this test we simulate broken server, where: +# - it wants to signal that NONCE has change +# - but it sets stale=false +# For this case pjsip will retry authentication until +# PJSIP_MAX_STALE_COUNT is exceeded. +# + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--realm=python --user=username --password=password" + +req1 = sip.RecvfromTransaction("Initial request", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""] + ) + +req2 = sip.RecvfromTransaction("First retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"1\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"] + ) + +req3 = sip.RecvfromTransaction("Second retry retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"2\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"3\", stale=true"] + ) + +req4 = sip.RecvfromTransaction("Third retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"3\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"4\", stale=true"], + expect="PJSIP_EAUTHSTALECOUNT" + ) + +recvfrom_cfg = sip.RecvfromCfg("Failed registration retry (server rejects with stale=true) ", + pjsua, [req1, req2, req3, req4]) diff --git a/pjsip-apps/src/test-pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py b/pjsip-apps/src/test-pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py new file mode 100644 index 00000000..1be92c5f --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py @@ -0,0 +1,41 @@ +# $Id:$ +import inc_sip as sip +import inc_sdp as sdp + +# In this test we simulate broken server, where it wants to +# change the nonce, but it fails to set stale to true. In this +# case, we should expect pjsip to retry the authentication until +# PJSIP_MAX_STALE_COUNT is exceeded as it should have detected +# that that nonce has changed + + +pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \ + "--realm=python --user=username --password=password " + \ + "--auto-update-nat=0" + +req1 = sip.RecvfromTransaction("Initial request", 401, + include=["REGISTER sip"], + exclude=["Authorization"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""] + ) + +req2 = sip.RecvfromTransaction("First retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"1\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\""] + ) + +req3 = sip.RecvfromTransaction("Second retry retry", 401, + include=["REGISTER sip", "Authorization", "nonce=\"2\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"3\""] + ) + +req4 = sip.RecvfromTransaction("Third retry", 200, + include=["REGISTER sip", "Authorization", "nonce=\"3\""], + exclude=["Authorization:[\\s\\S]+Authorization:"], + expect="registration success" + ) + +recvfrom_cfg = sip.RecvfromCfg("Successful auth server changes nonce but with stale=false", + pjsua, [req1, req2, req3, req4]) |