Browse code

Merge branch 'master' into offer_answer

Raphael Coeffic authored on 10/05/2011 08:38:36
Showing 18 changed files
... ...
@@ -42,6 +42,7 @@
42 42
 #define CFG_PARAM_AUTH    "auth_user"
43 43
 #define CFG_PARAM_PASS    "pwd"
44 44
 #define CFG_PARAM_PROXY   "proxy"
45
+#define CFG_PARAM_CONTACT "contact"
45 46
 
46 47
 #define MAX_ACCOUNTS      100
47 48
 
... ...
@@ -72,6 +73,7 @@ int RegistrationAgentFactory::onLoad()
72 73
     ri.auth_user = cfg.getParameter(CFG_PARAM_AUTH+idx_str,"");
73 74
     ri.passwd = cfg.getParameter(CFG_PARAM_PASS+idx_str,"");
74 75
     ri.proxy = cfg.getParameter(CFG_PARAM_PROXY+idx_str,"");
76
+    ri.contact = cfg.getParameter(CFG_PARAM_CONTACT+idx_str,"");
75 77
 
76 78
     if (!ri.domain.length() || !ri.user.length()) {
77 79
       // not including the passwd: might be IP based registration
... ...
@@ -85,9 +87,9 @@ int RegistrationAgentFactory::onLoad()
85 87
       ri.auth_user = ri.user;
86 88
 
87 89
     dialer.add_reg(ri);
88
-    DBG("Adding registration account #%d (%s %s %s %s %s)\n", i, 
90
+    DBG("Adding registration account #%d (%s %s %s %s %s %s)\n", i,
89 91
         ri.domain.c_str(), ri.user.c_str(), ri.display_name.c_str(), 
90
-        ri.auth_user.c_str(), ri.proxy.c_str());
92
+        ri.auth_user.c_str(), ri.proxy.c_str(), ri.contact.c_str());
91 93
 
92 94
     i ++;
93 95
     idx_str = int2str(i);
... ...
@@ -130,10 +132,11 @@ void RegThread::create_registration(RegInfo& ri) {
130 132
       di_args.push(ri.domain.c_str());
131 133
       di_args.push(ri.user.c_str());
132 134
       di_args.push(ri.display_name.c_str()); // display name
133
-      di_args.push(ri.auth_user.c_str());  // auth_user
134
-      di_args.push(ri.passwd.c_str());    // pwd
135
-      di_args.push("reg_agent"); //sess_link
136
-      di_args.push(ri.proxy.c_str()); 
135
+      di_args.push(ri.auth_user.c_str());    // auth_user
136
+      di_args.push(ri.passwd.c_str());       // pwd
137
+      di_args.push("reg_agent");             //sess_link
138
+      di_args.push(ri.proxy.c_str());
139
+      di_args.push(ri.contact.c_str());
137 140
 			
138 141
       uac_auth_i->invoke("createRegistration", di_args, reg_handle);
139 142
       if (reg_handle.size()) 
... ...
@@ -41,6 +41,7 @@ struct RegInfo {
41 41
   string auth_user;
42 42
   string passwd;
43 43
   string proxy;
44
+  string contact;
44 45
 
45 46
   string handle;
46 47
 };
... ...
@@ -15,6 +15,8 @@
15 15
 #auth_user=myuser
16 16
 # optional (defaults to resolved by domain):
17 17
 #proxy=sip.mydomain.net:5060
18
+# optional (default to <user>@<publicip/localip>):
19
+#contact=sip:myuser@10.0.0.2
18 20
 
19 21
 #
20 22
 # For multiple registrations add more entries
... ...
@@ -26,6 +28,7 @@
26 28
 #display_name1=xyz
27 29
 #auth_user1=xyz
28 30
 #proxy1=sip.iptel.org:5060
31
+#contact1=sip:xyz@10.0.0.3
29 32
 
30 33
 #domain2=iptel.org
31 34
 #user2=xyz
... ...
@@ -79,6 +79,10 @@ SIPRegistration::SIPRegistration(const string& handle,
79 79
   // clear dlg.callid? ->reregister?
80 80
   dlg.initFromLocalRequest(req);
81 81
   dlg.cseq = 50;
82
+  if(!info.contact.empty()) {
83
+      dlg.contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) "<sip:";
84
+      dlg.contact_uri += info.contact + ">" + CRLF;
85
+  }
82 86
 }
83 87
 
84 88
 SIPRegistration::~SIPRegistration() {
... ...
@@ -102,12 +106,16 @@ void SIPRegistration::doRegistration()
102 106
     // set outbound proxy as next hop 
103 107
     if (!info.proxy.empty()) {
104 108
 	dlg.outbound_proxy = info.proxy;
105
-    } else if (!AmConfig::OutboundProxy.empty()) 
109
+    } else if (!AmConfig::OutboundProxy.empty()) {
106 110
 	dlg.outbound_proxy = AmConfig::OutboundProxy;
107
-    //else 
108
-    //    dlg.outbound_proxy = "";
111
+    }
112
+
113
+    if(!info.contact.empty()) {
114
+      dlg.contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) "<"
115
+        + info.contact + ">" + CRLF;
116
+    }
109 117
     
110
-    if (dlg.sendRequest(req.method, "", "", "Expires: 1000\n") < 0)
118
+    if (dlg.sendRequest(req.method, "", "", "Expires: 3600\n") < 0)
111 119
       ERROR("failed to send registration.\n");
112 120
     
113 121
     // save TS
... ...
@@ -131,6 +139,10 @@ void SIPRegistration::doUnregister()
131 139
 	dlg.outbound_proxy = AmConfig::OutboundProxy;
132 140
     //else 
133 141
     //    dlg.outbound_proxy = "";
142
+    if(!info.contact.empty()) {
143
+        dlg.contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) "<";
144
+        dlg.contact_uri += info.contact + ">" + CRLF;
145
+    }
134 146
     
135 147
     if (dlg.sendRequest(req.method, "", "", "Expires: 0\n") < 0)
136 148
       ERROR("failed to send deregistration.\n");
... ...
@@ -587,13 +599,14 @@ string SIPRegistrarClient::createRegistration(const string& domain,
587 599
 					      const string& auth_user,
588 600
 					      const string& pwd,
589 601
 					      const string& sess_link,
590
-					      const string& proxy) {
602
+					      const string& proxy,
603
+                                              const string& contact) {
591 604
 	
592 605
   string handle = AmSession::getNewId();
593 606
   instance()->
594 607
     postEvent(new SIPNewRegistrationEvent(SIPRegistrationInfo(domain, user, 
595 608
 							      name, auth_user, pwd, 
596
-							      proxy),
609
+							      proxy, contact),
597 610
 					  handle, sess_link));
598 611
   return handle;
599 612
 }
... ...
@@ -634,6 +647,7 @@ void SIPRegistrarClient::listRegistrations(AmArg& res) {
634 647
     r["auth_user"] = it->second->getInfo().auth_user;
635 648
     r["proxy"] = it->second->getInfo().proxy;
636 649
     r["event_sink"] = it->second->getEventSink();
650
+    r["contact"] = it->second->getInfo().contact;
637 651
     res.push(r);
638 652
   }
639 653
 
... ...
@@ -645,9 +659,11 @@ void SIPRegistrarClient::invoke(const string& method, const AmArg& args,
645 659
 				AmArg& ret)
646 660
 {
647 661
   if(method == "createRegistration"){
648
-    string proxy;
662
+    string proxy, contact;
649 663
     if (args.size() > 6)
650 664
       proxy = args.get(6).asCStr();
665
+    if (args.size() > 7)
666
+      contact = args.get(7).asCStr();
651 667
 
652 668
     ret.push(createRegistration(args.get(0).asCStr(),
653 669
 				args.get(1).asCStr(),
... ...
@@ -655,7 +671,7 @@ void SIPRegistrarClient::invoke(const string& method, const AmArg& args,
655 671
 				args.get(3).asCStr(),
656 672
 				args.get(4).asCStr(),
657 673
 				args.get(5).asCStr(),
658
-				proxy
674
+				proxy, contact
659 675
 				).c_str());
660 676
   }
661 677
   else if(method == "removeRegistration"){
... ...
@@ -49,15 +49,17 @@ struct SIPRegistrationInfo {
49 49
   string auth_user;
50 50
   string pwd;
51 51
   string proxy;
52
+  string contact;
52 53
 
53 54
   SIPRegistrationInfo(const string& domain,
54 55
 		      const string& user,
55 56
 		      const string& name,
56 57
 		      const string& auth_user,
57 58
 		      const string& pwd,
58
-		      const string& proxy)
59
+		      const string& proxy,
60
+		      const string& contact)
59 61
     : domain(domain),user(user),name(name),
60
-    auth_user(auth_user),pwd(pwd),proxy(proxy)
62
+    auth_user(auth_user),pwd(pwd),proxy(proxy),contact(contact)
61 63
   { }
62 64
 };
63 65
 
... ...
@@ -205,7 +207,8 @@ class SIPRegistrarClient  : public AmThread,
205 207
 			    const string& auth_user,
206 208
 			    const string& pwd,
207 209
 			    const string& sess_link,
208
-			    const string& proxy);
210
+			    const string& proxy,
211
+			    const string& contact);
209 212
   void removeRegistration(const string& handle);
210 213
 
211 214
   bool hasRegistration(const string& handle);
... ...
@@ -575,14 +575,20 @@ void AmB2BSession::saveSessionDescription(const string& content_type,
575 575
 
576 576
   const char* cmp_body_begin = body.c_str();
577 577
   size_t cmp_body_length = body.length();
578
-  if (content_type == SIP_APPLICATION_SDP) {
579
-    // for SDP, skip v and o line
580
-    // (o might change even if SDP unchanged)
578
+
581 579
 #define skip_line						\
582
-    while (cmp_body_length-- && *cmp_body_begin != '\n')	\
580
+    while (cmp_body_length && *cmp_body_begin != '\n') {	\
581
+      cmp_body_begin++;						\
582
+      cmp_body_length--;					\
583
+    }								\
584
+    if (cmp_body_length) {					\
583 585
       cmp_body_begin++;						\
584
-    cmp_body_begin++;						\
586
+      cmp_body_length--;					\
587
+    }
585 588
 
589
+  if (body.length() && content_type == SIP_APPLICATION_SDP) {
590
+    // for SDP, skip v and o line
591
+    // (o might change even if SDP unchanged)
586 592
     skip_line;
587 593
     skip_line;
588 594
   }
... ...
@@ -594,7 +600,7 @@ bool AmB2BSession::updateSessionDescription(const string& content_type,
594 600
 					    const string& body) {
595 601
   const char* cmp_body_begin = body.c_str();
596 602
   size_t cmp_body_length = body.length();
597
-  if (content_type == SIP_APPLICATION_SDP) {
603
+  if (body.length() && content_type == SIP_APPLICATION_SDP) {
598 604
     // for SDP, skip v and o line
599 605
     // (o might change even if SDP unchanged)
600 606
     skip_line;
... ...
@@ -249,9 +249,11 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
249 249
 	{
250 250
 	  s = is_eql_next(s);
251 251
 	  next = get_next_line(s);
252
-	  string version(s, int(next-s)-2);
253
-	  str2i(version, sdp_msg->version);
254
-	  //DBG("parse_sdp_line_ex: found version\n");
252
+	  if (int(next-s)-2 >= 0) {
253
+	    string version(s, int(next-s)-2);
254
+	    str2i(version, sdp_msg->version);
255
+	    //DBG("parse_sdp_line_ex: found version\n");
256
+	  }
255 257
 	  s = next;
256 258
 	  state = SDP_DESCR;
257 259
 	  break;
... ...
@@ -269,8 +271,10 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
269 271
 	  //DBG("parse_sdp_line_ex: found session\n");
270 272
 	  s = is_eql_next(s);
271 273
 	  next = get_next_line(s);
272
-	  string sessionName(s, int(next-s)-2);
273
-	  sdp_msg->sessionName = sessionName;
274
+	  if (int(next-s)-2 >= 0) {
275
+	    string sessionName(s, int(next-s)-2);
276
+	    sdp_msg->sessionName = sessionName;
277
+	  }
274 278
 	  s = next;
275 279
 	  break;
276 280
 	}
... ...
@@ -279,7 +283,9 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
279 283
 	//DBG("parse_sdp_line_ex: found uri\n");
280 284
 	  s = is_eql_next(s);
281 285
 	  next = get_next_line(s);
282
-	  sdp_msg->uri = string(s, int(next-s)-2);
286
+	  if (int(next-s)-2 >= 0) {
287
+	    sdp_msg->uri = string(s, int(next-s)-2);
288
+	  }
283 289
 	  s = next;
284 290
       } break;
285 291
 
... ...
@@ -319,8 +325,11 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
319 325
       default:
320 326
 	{
321 327
 	  next = get_next_line(s);
322
-	  string line(s, int(next-s)-2);
323
-	  DBG("parse_sdp_line: skipping unknown Session description %s=\n", (char*)line.c_str());
328
+	  if (int(next-s)-2 >= 0) {
329
+	    string line(s, int(next-s)-2);
330
+	    DBG("parse_sdp_line: skipping unknown Session description %s=\n",
331
+		(char*)line.c_str());
332
+	  }
324 333
 	  s = next;
325 334
 	  break;
326 335
 	}
... ...
@@ -367,9 +376,11 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
367 376
       default :
368 377
 	{
369 378
 	  next = get_next_line(s);
370
-	  string line(s, int(next-s)-2);
371
-	  DBG("parse_sdp_line: skipping unknown Media description '%s'\n", 
372
-	      (char*)line.c_str());
379
+	  if (int(next-s)-2 >= 0) {
380
+	    string line(s, int(next-s)-2);
381
+	    DBG("parse_sdp_line: skipping unknown Media description '%s'\n",
382
+		(char*)line.c_str());
383
+	  }
373 384
 	  s = next;
374 385
 	  break;
375 386
 	}
... ...
@@ -517,12 +528,15 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
517 528
       {
518 529
 	next = parse_until(media_line, ' ');
519 530
 	string proto(media_line, int(next-media_line)-1);
520
-	if(transport_type(proto) < 0){
521
-	  ERROR("parse_sdp_media: Unknown transport protocol\n");
522
-	  state = FMT;
523
-	  break;
524
-	}
531
+	// if(transport_type(proto) < 0){
532
+	//   ERROR("parse_sdp_media: Unknown transport protocol\n");
533
+	//   state = FMT;
534
+	//   break;
535
+	// }
525 536
 	m.transport = transport_type(proto);
537
+	if(m.transport < 0){
538
+	  DBG("Unknown transport protocol: %s\n",proto.c_str());
539
+	}
526 540
 	media_line = next;
527 541
 	state = FMT;
528 542
 	break;
... ...
@@ -76,9 +76,9 @@ void AmSipDispatcher::handleSipMsg(AmSipRequest &req)
76 76
 				     "Call leg/Transaction does not exist");
77 77
 	  }
78 78
 	  else {
79
-	    WARN("received ACK for non-existing dialog "
80
-		  "(callid=%s;remote_tag=%s;local_tag=%s)\n",
81
-		  callid.c_str(),remote_tag.c_str(),local_tag.c_str());
79
+	    DBG("received ACK for non-existing dialog "
80
+		"(callid=%s;remote_tag=%s;local_tag=%s)\n",
81
+		callid.c_str(),remote_tag.c_str(),local_tag.c_str());
82 82
 	  }
83 83
       }
84 84
 
... ...
@@ -457,7 +457,7 @@ use_default_signature=yes
457 457
 #
458 458
 # Accept final replies without To-tag? [yes|no]
459 459
 #
460
-#accept_fr_without_totag=yes
460
+accept_fr_without_totag=yes
461 461
 
462 462
 #
463 463
 # Log raw messages?  [no|debug|info|warn|error]
... ...
@@ -39,9 +39,6 @@
39 39
 using std::list;
40 40
 using std::map;
41 41
 
42
-class sip_trans;
43
-struct sip_msg;
44
-
45 42
 
46 43
 template<class Value>
47 44
 class ht_bucket: public AmMutex
... ...
@@ -155,7 +155,7 @@ bool UACAuth::onSipReply(const AmSipReply& reply, AmSipDialog::Status old_dlg_st
155 155
 				
156 156
 	  if (do_auth(reply.code, auth_hdr,  
157 157
 		      ri->second.method,
158
-		      auth_uri, result)) {
158
+		      auth_uri, ri->second.body, result)) {
159 159
 	    string hdrs = ri->second.hdrs;
160 160
 	    // TODO(?): strip headers 
161 161
 	    // ((code==401) ? stripHeader(ri->second.hdrs, "Authorization")  :
... ...
@@ -187,7 +187,7 @@ bool UACAuth::onSipReply(const AmSipReply& reply, AmSipDialog::Status old_dlg_st
187 187
 	    if (dlg->sendRequest(ri->second.method,
188 188
 				 ri->second.content_type,
189 189
 				 ri->second.body, 
190
-				 hdrs) == 0) {
190
+				 hdrs, SIP_FLAGS_VERBATIM) == 0) {
191 191
 	      processed = true;
192 192
               DBG("authenticated request successfully sent.\n");
193 193
 	      // undo SIP dialog status change
... ...
@@ -270,11 +270,14 @@ bool UACAuth::parse_header(const string& auth_hdr, UACAuthDigestChallenge& chall
270 270
   challenge.opaque = find_attribute("opaque", auth_hdr);
271 271
   challenge.algorithm = find_attribute("algorithm", auth_hdr);
272 272
   challenge.qop = find_attribute("qop", auth_hdr);
273
+  
273 274
   return (challenge.realm.length() && challenge.nonce.length());
274 275
 }
275 276
 
276 277
 bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,  
277
-		      const string& method, const string& uri, string& result) {
278
+		      const string& method, const string& uri, 
279
+		      const string& body, string& result) 
280
+{
278 281
   if (!auth_hdr.length()) {
279 282
     ERROR("empty auth header.\n");
280 283
     return false;
... ...
@@ -291,8 +294,10 @@ bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,
291 294
     return false;
292 295
   }
293 296
 
294
-  DBG("realm='%s', nonce='%s'\n", challenge.realm.c_str(), 
295
-      challenge.nonce.c_str());
297
+  DBG("realm='%s', nonce='%s', qop='%s'\n", 
298
+      challenge.realm.c_str(), 
299
+      challenge.nonce.c_str(),
300
+      challenge.qop.c_str());
296 301
 
297 302
   if (credential->realm.length() 
298 303
       && (credential->realm != challenge.realm)) {
... ...
@@ -302,23 +307,60 @@ bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,
302 307
  
303 308
   HASHHEX ha1;
304 309
   HASHHEX ha2;
310
+  HASHHEX hentity;
305 311
   HASHHEX response;
312
+  bool    qop_auth=false;
313
+  bool    qop_auth_int=false;
314
+  string  cnonce;
315
+  string  qop_value;
316
+
317
+  if(!challenge.qop.empty()){
318
+
319
+    qop_auth = key_in_list(challenge.qop,"auth");
320
+    qop_auth_int = key_in_list(challenge.qop,"auth-int");
321
+
322
+    if(qop_auth || qop_auth_int) {
323
+
324
+      cnonce = int2hex(get_random(),true);
325
+
326
+      if(challenge.nonce == nonce)
327
+	nonce_count++;
328
+      else
329
+	nonce_count = 1;
330
+
331
+      if(qop_auth_int){
332
+	uac_calc_hentity(body,hentity);
333
+	qop_value = "auth-int";
334
+      }
335
+      else
336
+	qop_value = "auth";
337
+    }
338
+  }
306 339
 
307 340
   /* do authentication */
308
-  uac_calc_HA1( challenge, ""/*cnonce*/, ha1);
309
-  uac_calc_HA2( method, uri, challenge, 0/*hentity*/, ha2);
310
-  uac_calc_response( ha1, ha2, challenge, ""/*nc*/, "" /*cnonce*/, response);
341
+  uac_calc_HA1( challenge, cnonce, ha1);
342
+  uac_calc_HA2( method, uri, challenge, qop_auth_int ? hentity : NULL, ha2);
343
+  uac_calc_response( ha1, ha2, challenge, cnonce, qop_value, response);
311 344
   DBG("calculated response = %s\n", response);
312 345
 
313 346
   // compile auth response
314
-  result = ((code==401) ? SIP_HDR_COLSP(SIP_HDR_AUTHORIZATION) "Digest username=\"" : 
315
-	    SIP_HDR_COLSP(SIP_HDR_PROXY_AUTHORIZATION) "Digest username=\"")
316
-    + credential->user + "\", realm=\"" + challenge.realm + "\", nonce=\""+challenge.nonce + 
317
-    "\", uri=\""+uri+"\", ";
347
+  result = ((code==401) ? SIP_HDR_COLSP(SIP_HDR_AUTHORIZATION) : 
348
+	    SIP_HDR_COLSP(SIP_HDR_PROXY_AUTHORIZATION));
349
+
350
+  result += "Digest username=\"" + credential->user + "\", "
351
+    "realm=\"" + challenge.realm + "\", "
352
+    "nonce=\"" + challenge.nonce + "\", "
353
+    "uri=\"" + uri + "\", ";
354
+
318 355
   if (challenge.opaque.length())
319
-    result+="opaque=\""+challenge.opaque+"\", ";
356
+    result += "opaque=\"" + challenge.opaque + "\", ";
320 357
   
321
-  result+="response=\""+string((char*)response)+"\", algorithm=MD5\n";
358
+  if (!qop_value.empty())
359
+    result += "qop=\"" + qop_value + "\", "
360
+      "cnonce=\"" + cnonce + "\", "
361
+      "nc=\"" + int2hex(nonce_count,true) + "\", ";
362
+
363
+  result += "response=\"" + string((char*)response) + "\", algorithm=MD5\n";
322 364
 
323 365
   DBG("Auth req hdr: '%s'\n", result.c_str());
324 366
   
... ...
@@ -406,7 +448,7 @@ void UACAuth::uac_calc_HA2( const string& method, const string& uri,
406 448
   MD5Update(&Md5Ctx, hc, 1);
407 449
   w_MD5Update(&Md5Ctx, uri);
408 450
 
409
-  if ( challenge.qop == "auth-int" ) 
451
+  if ( hentity != 0 ) 
410 452
     {
411 453
       MD5Update(&Md5Ctx, hc, 1);
412 454
       MD5Update(&Md5Ctx, hentity, HASHHEXLEN);
... ...
@@ -416,15 +458,27 @@ void UACAuth::uac_calc_HA2( const string& method, const string& uri,
416 458
   cvt_hex(HA2, HA2Hex);
417 459
 }
418 460
 
461
+/*
462
+ * calculate H(body)
463
+ */
419 464
 
465
+void UACAuth::uac_calc_hentity( const string& body, HASHHEX hentity )
466
+{
467
+  MD5_CTX Md5Ctx;
468
+  HASH    h;
469
+
470
+  MD5Init(&Md5Ctx);
471
+  w_MD5Update(&Md5Ctx, body);
472
+  MD5Final(h, &Md5Ctx);
473
+  cvt_hex(h,hentity);
474
+}
420 475
 
421 476
 /* 
422 477
  * calculate request-digest/response-digest as per HTTP Digest spec 
423 478
  */
424 479
 void UACAuth::uac_calc_response( HASHHEX ha1, HASHHEX ha2,
425
-				 UACAuthDigestChallenge& challenge,
426
-				 const string& nc, const string& cnonce,
427
-				 HASHHEX response)
480
+				 UACAuthDigestChallenge& challenge, const string& cnonce,
481
+				 const string& qop_value, HASHHEX response)
428 482
 {
429 483
   unsigned char hc[1]; hc[0]=':';
430 484
   MD5_CTX Md5Ctx;
... ...
@@ -436,17 +490,15 @@ void UACAuth::uac_calc_response( HASHHEX ha1, HASHHEX ha2,
436 490
   w_MD5Update(&Md5Ctx, challenge.nonce);
437 491
   MD5Update(&Md5Ctx, hc, 1);
438 492
 
439
-  if (challenge.qop.length()
440
-      && challenge.qop == "auth_int")
441
-    {
493
+  if (!qop_value.empty()) {
442 494
       
443
-      w_MD5Update(&Md5Ctx, nc);
444
-      MD5Update(&Md5Ctx, hc, 1);
445
-      w_MD5Update(&Md5Ctx, cnonce);
446
-      MD5Update(&Md5Ctx, hc, 1);
447
-      w_MD5Update(&Md5Ctx, "" /*challenge.qop*/);
448
-      MD5Update(&Md5Ctx, hc, 1);
449
-    };
495
+    w_MD5Update(&Md5Ctx, int2hex(nonce_count,true));
496
+    MD5Update(&Md5Ctx, hc, 1);
497
+    w_MD5Update(&Md5Ctx, cnonce);
498
+    MD5Update(&Md5Ctx, hc, 1);
499
+    w_MD5Update(&Md5Ctx, qop_value);
500
+    MD5Update(&Md5Ctx, hc, 1);
501
+  };
450 502
 
451 503
   MD5Update(&Md5Ctx, ha2, HASHHEXLEN);
452 504
   MD5Final(RespHash, &Md5Ctx);
... ...
@@ -105,6 +105,9 @@ class UACAuth : public AmSessionEventHandler
105 105
   UACAuthCred* credential;
106 106
   AmSipDialog* dlg;
107 107
 
108
+  string nonce; // last nonce received from server
109
+  unsigned int nonce_count;
110
+
108 111
   std::string find_attribute(const std::string& name, const std::string& header);
109 112
   bool parse_header(const std::string& auth_hdr, UACAuthDigestChallenge& challenge);
110 113
 
... ...
@@ -116,10 +119,12 @@ class UACAuth : public AmSessionEventHandler
116 119
 		     UACAuthDigestChallenge& challenge,
117 120
 		     HASHHEX hentity,
118 121
 		     HASHHEX HA2Hex );
122
+
123
+  void uac_calc_hentity( const std::string& body, HASHHEX hentity );
119 124
 	
120 125
   void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
121 126
 			  UACAuthDigestChallenge& challenge,
122
-			  const std::string& nc, const std::string& cnonce,
127
+			  const std::string& cnonce, const string& qop_value, 
123 128
 			  HASHHEX response);
124 129
 	
125 130
   /** 
... ...
@@ -127,7 +132,8 @@ class UACAuth : public AmSessionEventHandler
127 132
    *  @return true if successful 
128 133
    */
129 134
   bool do_auth(const unsigned int code, const string& auth_hdr,  
130
-	       const string& method, const string& uri, string& result);
135
+	       const string& method, const string& uri, 
136
+	       const string& body, string& result);
131 137
 	
132 138
  public:
133 139
 	
... ...
@@ -1127,13 +1127,18 @@ void _trans_layer::received_msg(sip_msg* msg)
1127 1127
 		    // should we forward the ACK to SEMS-App upstream? Yes
1128 1128
 		    bucket->unlock();
1129 1129
 		    
1130
-		    //  let's pass the request to
1131
-		    //  the UA. 
1132
-		    assert(ua);
1133
-		    DBG("Passing ACK to the UA.\n");
1134
-		    ua->handle_sip_request(trans_ticket(), // dummy
1135
-					   msg);
1136
-		    
1130
+		    if(err == TS_REMOVED) {
1131
+			//  let's pass the request to
1132
+			//  the UA, iff it was a 200-ACK
1133
+			assert(ua);
1134
+			DBG("Passing ACK to the UA.\n");
1135
+			ua->handle_sip_request(trans_ticket(), // dummy
1136
+					       msg);
1137
+		    }
1138
+		    else {
1139
+			DBG("Absorbing non-200-ACK\n");
1140
+		    }
1141
+
1137 1142
 		    DROP_MSG;
1138 1143
 		}
1139 1144
 	    }
... ...
@@ -1271,9 +1276,12 @@ int _trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg*
1271 1276
     }
1272 1277
     
1273 1278
     to_tag = ((sip_from_to*)msg->to->p)->tag;
1274
-    if((t->msg->u.request->method != sip_request::CANCEL) && !to_tag.len){
1279
+    if((t->msg->u.request->method != sip_request::CANCEL) && 
1280
+       (reply_code < 300) &&
1281
+       !to_tag.len){
1275 1282
 	if (!trans_layer::accept_fr_without_totag) {
1276
-	    DBG("To-tag missing in final reply (see sems.conf?)\n");
1283
+	    DBG("To-tag missing in final reply (see "
1284
+		"sems.conf: accept_fr_without_totag?)\n");
1277 1285
 	    return -1;
1278 1286
 	}
1279 1287
     }
... ...
@@ -1802,7 +1810,7 @@ trsp_socket* _trans_layer::find_transport(sockaddr_storage* remote_ip)
1802 1810
     
1803 1811
   int temp_sock = socket(remote_ip->ss_family, SOCK_DGRAM, 0 );
1804 1812
   if (temp_sock == -1) {
1805
-    printf( "ERROR: socket() failed: %s\n",
1813
+    ERROR( "ERROR: socket() failed: %s\n",
1806 1814
 	strerror(errno));
1807 1815
     return NULL;
1808 1816
   }
... ...
@@ -3,6 +3,7 @@
3 3
 
4 4
 #include "hash_table.h"
5 5
 #include "cstring.h"
6
+#include "sip_trans.h"
6 7
 
7 8
 #define H_TABLE_POWER   10
8 9
 #define H_TABLE_ENTRIES (1<<H_TABLE_POWER)
... ...
@@ -66,18 +66,19 @@ void trsp_socket::copy_addr_to(sockaddr_storage* sa)
66 66
 bool trsp_socket::match_addr(sockaddr_storage* other_addr)
67 67
 {
68 68
     
69
-    if(addr.ss_family != other_addr->ss_family) return false;
69
+    if(addr.ss_family != other_addr->ss_family)
70
+	return false;
70 71
 
71 72
     if(addr.ss_family == AF_INET){
72 73
 	if( !memcmp(&((sockaddr_in*)&addr)->sin_addr, 
73 74
 		    &((sockaddr_in*)other_addr)->sin_addr, 
74
-		    sizeof(sockaddr_in)) )
75
+		    sizeof(in_addr)) )
75 76
 	    return true;
76 77
     }
77 78
     else if(addr.ss_family == AF_INET6) {
78 79
 	if( !memcmp(&((sockaddr_in6*)&addr)->sin6_addr, 
79 80
 		    &((sockaddr_in6*)other_addr)->sin6_addr, 
80
-		    sizeof(sockaddr_in6)) )
81
+		    sizeof(in6_addr)) )
81 82
 	    return true;
82 83
     }
83 84
     
... ...
@@ -1,8 +1,9 @@
1 1
 Readme for reg_agent module
2 2
 
3
-This module uses the registrar_client to register the contact
4
-sems@<local_ip>:<sip_port> at a SIP registrar. The accounts 
5
-(identities) are set in the config file.
3
+This module uses the registrar_client to register SEMS
4
+at a SIP registrar. The accounts  (identities) are set in
5
+the config file.
6
+
6 7
 If the registration is not successful, it tries to 
7 8
 re-register.
8 9
 
... ...
@@ -22,6 +22,9 @@ args:
22 22
 	   CStr pwd       : password
23 23
 	   CStr sess_link : local tag of session or name of factory that receives
24 24
                         events about the status of the registration
25
+   optional:
26
+           CStr proxy     : proxy to be used for registration
27
+           CStr contact   : contact to register
25 28
 
26 29
 returns: CStr handle  : used to remove the registration or correlate events
27 30
 
... ...
@@ -248,8 +248,11 @@ Outbound proxy and next hop
248 248
 
249 249
 An outbound proxy may be set with the outbound_proxy option. If this is
250 250
 not set, the outbound_proxy option of sems.conf is used, if that one is set.
251
-Setting an outbound proxy will add a route header. force_outbound_proxy forces
252
-the outbound proxy route also for in-dialog requests.
251
+Setting an outbound proxy will add a route header.
252
+
253
+force_outbound_proxy forces the outbound proxy as first route and request URI
254
+also for in-dialog requests. Note that this is NOT RFC3261 compliant (section
255
+2.2 Requests within a Dialog, 12.2.1 UAC Behavior).
253 256
 
254 257
 The next hop (destination IP[:port] of outgoing requests) can be set with
255 258
 the next_hop_ip and next_hop_port options. next_hop_port defaults to 5060
... ...
@@ -257,6 +260,9 @@ if not set or empty. Usually, replies are sent back to where the request came
257 260
 from (honoring rport), but if next_hop should be used nevertheless,
258 261
 next_hop_for_replies profile option can be set to "yes".
259 262
 
263
+These two settings apply only for the UAC side, i.e. the outgoing side of
264
+the initial INVITE.
265
+
260 266
 Filters
261 267
 -------
262 268
 Headers and messages may be filtered. A filter can be set to