Index: pjproject/trunk/pjsip-apps/src/test-pjsua/inc_sip.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/inc_sip.py	(revision 2109)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/inc_sip.py	(revision 2110)
@@ -50,4 +50,11 @@
 	#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:
@@ -66,5 +73,5 @@
 	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
@@ -76,5 +83,5 @@
 		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()
@@ -114,4 +121,17 @@
 		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())
@@ -124,13 +144,16 @@
 		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))
-
-	def wait_msg(self, timeout):
+		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)
@@ -144,5 +167,5 @@
 				continue
 			try:
-				msg = self.sock.recv(2048)
+				msg, src_addr = self.sock.recvfrom(2048)
 			except:
 				print "recv() exception: ", sys.exc_info()[0]
@@ -150,5 +173,5 @@
 
 		if msg=="":
-			return ""
+			return "", None
 		if self.last_request=="INVITE" and self.rem_tag=="":
 			self.rem_tag = get_tag(msg, "To")
@@ -157,7 +180,10 @@
 				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):
@@ -237,2 +263,68 @@
 		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
+
+
+
+
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/mod_recvfrom.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/mod_recvfrom.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/mod_recvfrom.py	(revision 2110)
@@ -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)
+
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/201_reg_good_ok.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/201_reg_good_ok.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/201_reg_good_ok.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/205_reg_good_no_realm.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/205_reg_good_no_realm.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/205_reg_good_no_realm.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/215_reg_good_multi_ok.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/215_reg_good_multi_ok.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/220_reg_good_ims_ok.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/220_reg_good_ims_ok.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/220_reg_good_ims_ok.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py	(revision 2110)
@@ -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])
Index: pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py	(revision 2110)
+++ pjproject/trunk/pjsip-apps/src/test-pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py	(revision 2110)
@@ -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])
