Browse code

sip: message logging draft.

Raphael Coeffic authored on 10/01/2013 14:14:12
Showing 16 changed files
... ...
@@ -46,6 +46,9 @@ SBC - feature-wishlist
46 46
 #include "SBCSimpleRelay.h"
47 47
 #include "RegisterDialog.h"
48 48
 #include "SubscriptionDialog.h"
49
+#include "sip/msg_logger.h"
50
+#include "sip/sip_parser.h"
51
+#include "sip/sip_trans.h"
49 52
 
50 53
 #include "HeaderFilter.h"
51 54
 #include "ParamReplacer.h"
... ...
@@ -620,6 +623,7 @@ bool SBCFactory::CCRoute(const AmSipRequest& req,
620 623
 			 SBCCallProfile& call_profile)
621 624
 {
622 625
   vector<AmDynInvoke*>::iterator cc_mod=cc_modules.begin();
626
+  auto_ptr<file_msg_logger> logger;
623 627
 
624 628
   for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
625 629
        cc_it != call_profile.cc_interfaces.end(); cc_it++) {
... ...
@@ -662,6 +666,34 @@ bool SBCFactory::CCRoute(const AmSipRequest& req,
662 666
       return false;
663 667
     }
664 668
 
669
+    if (!logger.get() && !call_profile.msg_logger_path.empty()) {
670
+
671
+      ParamReplacerCtx ctx;
672
+      call_profile.msg_logger_path = 
673
+	ctx.replaceParameters(call_profile.msg_logger_path,
674
+			      "msg_logger_path",req);
675
+
676
+      if(!call_profile.msg_logger_path.empty()) {
677
+	logger.reset(new file_msg_logger());
678
+	if(logger->open(call_profile.msg_logger_path.c_str())) {
679
+	  ERROR("could not open message logger\n");
680
+	  logger.reset();
681
+	  call_profile.msg_logger_path.clear();
682
+	}
683
+      }
684
+    }
685
+
686
+    if(logger.get()) {
687
+      req.tt.lock_bucket();
688
+      const sip_trans* t = req.tt.get_trans();
689
+      if (t) {
690
+	sip_msg* msg = t->msg;
691
+	logger->log(msg->buf,msg->len,&msg->remote_ip,
692
+		    &msg->local_ip,msg->u.request->method_str);
693
+      }
694
+      req.tt.unlock_bucket();
695
+    }
696
+
665 697
     // evaluate ret
666 698
     if (isArgArray(ret)) {
667 699
       for (size_t i=0;i<ret.size();i++) {
... ...
@@ -703,7 +735,7 @@ bool SBCFactory::CCRoute(const AmSipRequest& req,
703 735
 	  AmBasicSipDialog::reply_error(req,
704 736
 	        ret[i][SBC_CC_REFUSE_CODE].asInt(), 
705 737
 		ret[i][SBC_CC_REFUSE_REASON].asCStr(),
706
-		headers);
738
+		headers,logger.get());
707 739
 
708 740
 	  return false;
709 741
 	}
... ...
@@ -14,6 +14,10 @@
14 14
 #include "RegisterDialog.h"
15 15
 #include "SubscriptionDialog.h"
16 16
 
17
+#include "sip/msg_logger.h"
18
+#include "sip/sip_parser.h"
19
+#include "sip/sip_trans.h"
20
+
17 21
 #include "HeaderFilter.h"
18 22
 #include "ParamReplacer.h"
19 23
 #include "SDPFilter.h"
... ...
@@ -953,6 +957,25 @@ bool SBCCallLeg::CCStart(const AmSipRequest& req) {
953 957
       return false;
954 958
     }
955 959
 
960
+    if (!dlg->getMsgLogger() && !call_profile.msg_logger_path.empty()) {
961
+      ParamReplacerCtx ctx;
962
+      string log_path = ctx.replaceParameters(call_profile.msg_logger_path,
963
+					      "msg_logger_path",req);
964
+      file_msg_logger* logger = new file_msg_logger();
965
+      if(!logger->open(log_path.c_str())) {
966
+        req.tt.lock_bucket();
967
+        const sip_trans* t = req.tt.get_trans();
968
+        if (t) {
969
+          sip_msg* msg = t->msg;
970
+          logger->log(msg->buf,msg->len,&msg->remote_ip,
971
+              &msg->local_ip,msg->u.request->method_str);
972
+        }
973
+        req.tt.unlock_bucket();
974
+        dlg->setMsgLogger(logger);
975
+      }
976
+      else delete logger;
977
+    }
978
+
956 979
     // evaluate ret
957 980
     if (isArgArray(ret)) {
958 981
       for (size_t i=0;i<ret.size();i++) {
... ...
@@ -996,8 +1019,9 @@ bool SBCCallLeg::CCStart(const AmSipRequest& req) {
996 1019
 	      cc_if.cc_name.c_str(), headers.c_str());
997 1020
 
998 1021
 	  dlg->reply(req,
999
-		    ret[i][SBC_CC_REFUSE_CODE].asInt(), ret[i][SBC_CC_REFUSE_REASON].asCStr(),
1000
-		    NULL, headers);
1022
+		     ret[i][SBC_CC_REFUSE_CODE].asInt(), 
1023
+		     ret[i][SBC_CC_REFUSE_REASON].asCStr(),
1024
+		     NULL, headers);
1001 1025
 
1002 1026
 	  // call 'end' of call control modules up to here
1003 1027
 	  call_end_ts.tv_sec = call_start_ts.tv_sec;
... ...
@@ -360,6 +360,8 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
360 360
   if (!codec_prefs.readConfig(cfg)) return false;
361 361
   if (!transcoder.readConfig(cfg)) return false;
362 362
 
363
+  msg_logger_path = cfg.getParameter("msg_logger_path");
364
+
363 365
   md5hash = "<unknown>";
364 366
   if (!cfg.getMD5(profile_file_name, md5hash)){
365 367
     ERROR("calculating MD5 of file %s\n", profile_file_name.c_str());
... ...
@@ -232,6 +232,9 @@ struct SBCCallProfile
232 232
 
233 233
   // todo: RTP transcoding mode
234 234
 
235
+  // message logging feature
236
+  string msg_logger_path;
237
+
235 238
   SBCCallProfile()
236 239
   : auth_enabled(false),
237 240
     transparent_dlg_id(false),
... ...
@@ -8,6 +8,8 @@
8 8
 #include "sip/parse_route.h"
9 9
 #include "sip/parse_uri.h"
10 10
 #include "sip/parse_next_hop.h"
11
+#include "sip/msg_logger.h"
12
+#include "sip/sip_parser.h"
11 13
 
12 14
 const char* AmBasicSipDialog::status2str[AmBasicSipDialog::__max_Status] = {
13 15
   "Disconnected",
... ...
@@ -22,6 +24,7 @@ const char* AmBasicSipDialog::status2str[AmBasicSipDialog::__max_Status] = {
22 24
 AmBasicSipDialog::AmBasicSipDialog(AmBasicSipEventHandler* h)
23 25
   : status(Disconnected),
24 26
     cseq(10),r_cseq_i(false),hdl(h),
27
+    logger(0),
25 28
     outbound_proxy(AmConfig::OutboundProxy),
26 29
     force_outbound_proxy(AmConfig::ForceOutboundProxy),
27 30
     next_hop(AmConfig::NextHop),
... ...
@@ -35,6 +38,8 @@ AmBasicSipDialog::AmBasicSipDialog(AmBasicSipEventHandler* h)
35 38
 
36 39
 AmBasicSipDialog::~AmBasicSipDialog()
37 40
 {
41
+  if (logger) dec_ref(logger);
42
+
38 43
   DBG("callid = %s\n",callid.c_str());
39 44
   DBG("local_tag = %s\n",local_tag.c_str());
40 45
   DBG("uac_trans.size() = %u\n",(unsigned int)uac_trans.size());
... ...
@@ -308,6 +313,15 @@ void AmBasicSipDialog::onRxRequest(const AmSipRequest& req)
308 313
 {
309 314
   DBG("AmBasicSipDialog::onRxRequest(req = %s)\n", req.method.c_str());
310 315
 
316
+  if(logger && (req.method != SIP_METH_ACK)) {
317
+    req.tt.lock_bucket();
318
+    const sip_trans* t = req.tt.get_trans();
319
+    sip_msg* msg = t->msg;
320
+    logger->log(msg->buf,msg->len,&msg->remote_ip,
321
+		&msg->local_ip,msg->u.request->method_str);
322
+    req.tt.unlock_bucket();
323
+  }
324
+
311 325
   if(!onRxReqSanity(req))
312 326
     return;
313 327
     
... ...
@@ -537,7 +551,7 @@ int AmBasicSipDialog::reply(const AmSipRequest& req,
537 551
     reply.contact = getContactHdr();
538 552
   }
539 553
 
540
-  int ret = SipCtrlInterface::send(reply);
554
+  int ret = SipCtrlInterface::send(reply,logger);
541 555
   if(ret){
542 556
     ERROR("Could not send reply: code=%i; reason='%s'; method=%s;"
543 557
 	  " call-id=%s; cseq=%i\n",
... ...
@@ -556,7 +570,8 @@ int AmBasicSipDialog::reply(const AmSipRequest& req,
556 570
 
557 571
 /* static */
558 572
 int AmBasicSipDialog::reply_error(const AmSipRequest& req, unsigned int code, 
559
-				  const string& reason, const string& hdrs)
573
+				  const string& reason, const string& hdrs,
574
+				  msg_logger* logger)
560 575
 {
561 576
   AmSipReply reply;
562 577
 
... ...
@@ -572,7 +587,7 @@ int AmBasicSipDialog::reply_error(const AmSipRequest& req, unsigned int code,
572 587
   // add transcoder statistics into reply headers
573 588
   //addTranscoderStats(reply.hdrs);
574 589
 
575
-  int ret = SipCtrlInterface::send(reply);
590
+  int ret = SipCtrlInterface::send(reply,logger);
576 591
   if(ret){
577 592
     ERROR("Could not send reply: code=%i; reason='%s';"
578 593
 	  " method=%s; call-id=%s; cseq=%i\n",
... ...
@@ -633,7 +648,7 @@ int AmBasicSipDialog::sendRequest(const string& method,
633 648
   int res = SipCtrlInterface::send(req, local_tag,
634 649
 				   remote_tag.empty() || !next_hop_1st_req ?
635 650
 				   next_hop : "",
636
-				   outbound_interface);
651
+				   outbound_interface, logger);
637 652
   if(res) {
638 653
     ERROR("Could not send request: method=%s; call-id=%s; cseq=%i\n",
639 654
 	  req.method.c_str(),req.callid.c_str(),req.cseq);
... ...
@@ -643,3 +658,16 @@ int AmBasicSipDialog::sendRequest(const string& method,
643 658
   onRequestTxed(req);
644 659
   return 0;
645 660
 }
661
+
662
+void AmBasicSipDialog::setMsgLogger(msg_logger* logger)
663
+{
664
+  if(this->logger) {
665
+    dec_ref(this->logger);
666
+  }
667
+
668
+  if(logger){
669
+    inc_ref(logger);
670
+  }
671
+
672
+  this->logger = logger;
673
+}
... ...
@@ -62,6 +62,8 @@ typedef std::map<int,AmSipRequest> TransMap;
62 62
 
63 63
 class AmBasicSipEventHandler;
64 64
 
65
+class msg_logger;
66
+
65 67
 class AmBasicSipDialog
66 68
   : public AmObject
67 69
 {
... ...
@@ -91,6 +93,11 @@ protected:
91 93
 
92 94
   AmBasicSipEventHandler* hdl;
93 95
 
96
+  /**
97
+   * Message logger
98
+   */
99
+  msg_logger* logger;
100
+
94 101
   /**
95 102
    * Executed for replies sent by a local UA,
96 103
    * right before the reply is passed to the transaction layer.
... ...
@@ -290,10 +297,21 @@ public:
290 297
   static int reply_error(const AmSipRequest& req,
291 298
 			 unsigned int  code,
292 299
 			 const string& reason,
293
-			 const string& hdrs = "");
300
+			 const string& hdrs = "",
301
+			 msg_logger* logger = NULL);
294 302
 
295 303
   /* dump transaction information (DBG) */
296 304
   void dump();
305
+
306
+  /**
307
+   * Enable or disable message logger
308
+   */
309
+  void setMsgLogger(msg_logger* logger);
310
+
311
+  /**
312
+   * Get message logger
313
+   */
314
+  msg_logger* getMsgLogger() { return logger; }
297 315
 };
298 316
 
299 317
 /**
... ...
@@ -766,7 +766,7 @@ int AmSipDialog::send_200_ack(unsigned int inv_cseq,
766 766
   int res = SipCtrlInterface::send(req, local_tag,
767 767
 				   remote_tag.empty() || !next_hop_1st_req ? 
768 768
 				   next_hop : "",
769
-				   outbound_interface);
769
+				   outbound_interface, logger);
770 770
   if (res)
771 771
     return res;
772 772
 
... ...
@@ -7,9 +7,9 @@ PLUGIN_DIR=plug-in
7 7
 SIP_STACK_DIR=sip
8 8
 RESAMPLE_DIR=resample
9 9
 
10
-SRCS=$(filter-out $(NAME).cpp, $(wildcard *.cpp))
10
+SRCS=$(wildcard *.cpp)
11 11
 HDRS=$(SRCS:.cpp=.h)
12
-OBJS=$(SRCS:.cpp=.o) $(NAME).o sip/sip_stack.a
12
+OBJS=$(SRCS:.cpp=.o)
13 13
 DEPS=$(SRCS:.cpp=.d) $(NAME).d
14 14
 AUDIO_FILES=$(notdir $(wildcard wav/*.wav))
15 15
 TEST_DIR=tests
... ...
@@ -59,6 +59,11 @@ CPPFLAGS += -DUSE_LIBSAMPLERATE
59 59
 LDFLAGS +=-lsamplerate
60 60
 endif
61 61
 
62
+# This allows symbols defined in the SIP stack but not used
63
+# by the core itself to be included in the executable and
64
+# thus be available for modules
65
+EXTRA_LDFLAGS += -Wl,--whole-archive $(SIP_STACK_DIR)/sip_stack.a -Wl,--no-whole-archive
66
+
62 67
 ifdef USE_INTERNAL_RESAMPLER
63 68
 
64 69
 CPPFLAGS += -DUSE_INTERNAL_RESAMPLER
... ...
@@ -128,7 +128,8 @@ int SipCtrlInterface::cancel(trans_ticket* tt)
128 128
 }
129 129
 
130 130
 int SipCtrlInterface::send(AmSipRequest &req, const string& dialog_id,
131
-			   const string& next_hop, int out_interface)
131
+			   const string& next_hop, int out_interface,
132
+			   msg_logger* logger)
132 133
 {
133 134
     if(req.method == "CANCEL")
134 135
 	return cancel(&req.tt);
... ...
@@ -222,7 +223,7 @@ int SipCtrlInterface::send(AmSipRequest &req, const string& dialog_id,
222 223
     int res = trans_layer::instance()->send_request(msg,&req.tt,
223 224
 						    stl2cstr(dialog_id),
224 225
 						    stl2cstr(next_hop),
225
-						    out_interface);
226
+						    out_interface,logger);
226 227
     delete msg;
227 228
 
228 229
     return res;
... ...
@@ -310,7 +311,7 @@ void SipCtrlInterface::cleanup()
310 311
     }
311 312
 }
312 313
 
313
-int SipCtrlInterface::send(const AmSipReply &rep)
314
+int SipCtrlInterface::send(const AmSipReply &rep, msg_logger* logger)
314 315
 {
315 316
     sip_msg msg;
316 317
 
... ...
@@ -367,7 +368,7 @@ int SipCtrlInterface::send(const AmSipReply &rep)
367 368
 					    rep.code,stl2cstr(rep.reason),
368 369
 					    stl2cstr(rep.to_tag),
369 370
 					    cstring(hdrs_buf,hdrs_len), 
370
-					    stl2cstr(body));
371
+					    stl2cstr(body),logger);
371 372
 
372 373
     delete [] hdrs_buf;
373 374
 
... ...
@@ -90,7 +90,8 @@ public:
90 90
      *            its ticket is written into req.tt.
91 91
      */
92 92
     static int send(AmSipRequest &req, const string& dialog_id,
93
-		    const string& next_hop = "", int outbound_interface = -1);
93
+		    const string& next_hop = "", int outbound_interface = -1,
94
+		    msg_logger* logger = NULL);
94 95
 
95 96
     /**
96 97
      * Sends a SIP reply. 
... ...
@@ -98,7 +99,7 @@ public:
98 99
      * @param rep The reply to be sent. 'rep.tt' should be set to transaction 
99 100
      *            ticket included in the SIP request.
100 101
      */
101
-    static int send(const AmSipReply &rep);
102
+    static int send(const AmSipReply &rep, msg_logger* logger = NULL);
102 103
 
103 104
     /**
104 105
      * CANCELs an INVITE transaction.
105 106
new file mode 100644
... ...
@@ -0,0 +1,125 @@
1
+#include "msg_logger.h"
2
+
3
+#include "AmUtils.h"
4
+
5
+#include <fcntl.h>
6
+#include <netinet/in.h>
7
+#include <arpa/inet.h>
8
+
9
+file_msg_logger::~file_msg_logger()
10
+{
11
+  fd_mut.lock();
12
+  if(fd >= 0)
13
+    close(fd);
14
+  fd_mut.unlock();
15
+}
16
+
17
+int file_msg_logger::open(const char* filename)
18
+{
19
+  fd_mut.lock();
20
+  if(fd != -1) {
21
+    ERROR("file already open\n");
22
+    fd_mut.unlock();
23
+    return -1;
24
+  }
25
+  
26
+  fd = ::open(filename,O_WRONLY | O_CREAT | O_APPEND,
27
+	      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
28
+  if(fd < 0) {
29
+    ERROR("could not open file '%s': %s", filename, strerror(errno));
30
+    fd_mut.unlock();
31
+    return -1;
32
+  }
33
+
34
+  fd_mut.unlock();
35
+  return 0;
36
+}
37
+
38
+static string addr2str(sockaddr_storage* addr)
39
+{
40
+  char ntop_buffer[INET6_ADDRSTRLEN];
41
+
42
+  if(addr->ss_family == AF_INET) {
43
+    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
44
+    if(!inet_ntop(AF_INET, &sin->sin_addr,
45
+		  ntop_buffer,INET6_ADDRSTRLEN)) {
46
+      ERROR("Could not convert IPv4 address to string: %s",strerror(errno));
47
+      return "unknown";
48
+    }
49
+    
50
+    return string(ntop_buffer) + ":" + int2str(ntohs(sin->sin_port));
51
+  }
52
+
53
+  struct sockaddr_in6* sin6 = (struct sockaddr_in6 *)addr;
54
+  if(!inet_ntop(AF_INET6, &sin6->sin6_addr,
55
+		ntop_buffer,INET6_ADDRSTRLEN)) {
56
+    ERROR("Could not convert IPv6 address to string: %s",strerror(errno));
57
+    return "unknown";
58
+  }
59
+  
60
+  return string(ntop_buffer) + ":" + int2str(ntohs(sin6->sin6_port));
61
+}
62
+
63
+#define WRITE_CSTSTR(fd,str)						\
64
+  if(write(fd,str,sizeof(str)-1) != sizeof(str)-1) {			\
65
+    ERROR("while writing to message log: %s\n",strerror(errno));	\
66
+    return -1;								\
67
+  }
68
+
69
+#define WRITE_STLSTR(fd,str)						\
70
+  if(write(fd,str.c_str(),str.length()) != (ssize_t)str.length())  {	\
71
+    ERROR("while writing to message log: %s\n",strerror(errno));	\
72
+    return -1;								\
73
+  }
74
+
75
+
76
+int file_msg_logger::write_src_dst(const string& obj)
77
+{
78
+  if (known_destinations.find(obj) == known_destinations.end()) {
79
+    known_destinations.insert(obj);
80
+    WRITE_CSTSTR(fd,"<object name='");
81
+    WRITE_STLSTR(fd,obj);
82
+    WRITE_CSTSTR(fd,"' desc='");
83
+    WRITE_STLSTR(fd,obj);
84
+    WRITE_CSTSTR(fd,"'/>\n");
85
+  }
86
+
87
+  return 0;
88
+}
89
+
90
+int file_msg_logger::log(const char* buf, int len,
91
+			 sockaddr_storage* src_ip,
92
+			 sockaddr_storage* dst_ip,
93
+			 cstring method, int reply_code)
94
+{
95
+  string src = addr2str(src_ip);
96
+  string dst = addr2str(dst_ip);
97
+
98
+  AmLock _l(fd_mut);
99
+
100
+  write_src_dst(src);
101
+  write_src_dst(dst);
102
+  
103
+  string what = c2stlstr(method);
104
+  if(reply_code > 0) {
105
+    what = int2str(reply_code) + " / " + what;
106
+  }
107
+
108
+  WRITE_CSTSTR(fd,"<call src='");
109
+  WRITE_STLSTR(fd,src);
110
+  WRITE_CSTSTR(fd,"' dst='");
111
+  WRITE_STLSTR(fd,dst);
112
+  WRITE_CSTSTR(fd,"' desc='");
113
+  WRITE_STLSTR(fd,what);
114
+  WRITE_CSTSTR(fd,"'>\n");
115
+
116
+  if(write(fd,buf,len) != len) {
117
+    ERROR("while writing to message log: %s\n",strerror(errno));
118
+    return -1;
119
+  }
120
+
121
+  WRITE_CSTSTR(fd,"</call>\n");
122
+ 
123
+  return 0;
124
+}
125
+
0 126
new file mode 100644
... ...
@@ -0,0 +1,50 @@
1
+#ifndef _msg_logger_h_
2
+#define _msg_logger_h_
3
+
4
+#include "atomic_types.h"
5
+#include "AmThread.h"
6
+#include "cstring.h"
7
+
8
+#include <set>
9
+#include <string>
10
+using std::set;
11
+using std::string;
12
+
13
+
14
+struct sockaddr_storage;
15
+
16
+class msg_logger
17
+  : public atomic_ref_cnt
18
+{
19
+public:
20
+  msg_logger() {}
21
+  virtual ~msg_logger() {}
22
+  virtual int log(const char* buf, int len,
23
+		  sockaddr_storage* src_ip,
24
+		  sockaddr_storage* dst_ip,
25
+		  cstring method, int reply_code=0)=0;
26
+};
27
+
28
+class file_msg_logger
29
+  : public msg_logger
30
+{
31
+  int      fd;
32
+  AmMutex  fd_mut;
33
+
34
+  std::set<string> known_destinations;
35
+
36
+  int write_src_dst(const string& obj);
37
+
38
+public:
39
+  file_msg_logger() : fd(-1) {}
40
+  ~file_msg_logger();
41
+
42
+  int  open(const char* filename);
43
+  int log(const char* buf, int len,
44
+	  sockaddr_storage* src_ip,
45
+	  sockaddr_storage* dst_ip,
46
+	  cstring method, int reply_code=0);
47
+};
48
+
49
+
50
+#endif
... ...
@@ -33,6 +33,7 @@
33 33
 #include "trans_table.h"
34 34
 #include "trans_layer.h"
35 35
 #include "transport.h"
36
+#include "msg_logger.h"
36 37
 
37 38
 #include "log.h"
38 39
 
... ...
@@ -68,7 +69,8 @@ sip_trans::sip_trans()
68 69
       retr_buf(NULL),
69 70
       retr_socket(NULL),
70 71
       retr_len(0),
71
-      last_rseq(0)
72
+      last_rseq(0),
73
+      logger(NULL)
72 74
 {
73 75
     memset(timers,0,SIP_TRANS_TIMERS*sizeof(void*));
74 76
 }
... ...
@@ -84,6 +86,9 @@ sip_trans::~sip_trans()
84 86
     if(dialog_id.s) {
85 87
 	delete [] dialog_id.s;
86 88
     }
89
+    if(logger) {
90
+	dec_ref(logger);
91
+    }
87 92
 }
88 93
 
89 94
 /**
... ...
@@ -101,6 +106,16 @@ void sip_trans::retransmit()
101 106
     if(send_err < 0){
102 107
 	ERROR("Error from transport layer\n");
103 108
     }
109
+
110
+    if(logger) {
111
+	sockaddr_storage src_ip;
112
+	retr_socket->copy_addr_to(&src_ip);
113
+	logger->log(retr_buf,retr_len,
114
+		    &src_ip,&retr_addr,
115
+		    msg->u.request->method_str,
116
+		    reply_status);
117
+    }
118
+
104 119
 }
105 120
 
106 121
 /**
... ...
@@ -37,6 +37,7 @@
37 37
 
38 38
 struct sip_msg;
39 39
 class trsp_socket;
40
+class msg_logger;
40 41
 
41 42
 /**
42 43
  * Transaction types
... ...
@@ -141,6 +142,9 @@ class sip_trans
141 142
     sockaddr_storage retr_addr;
142 143
     trsp_socket*     retr_socket;
143 144
 
145
+    /** message logging */
146
+    msg_logger* logger;
147
+
144 148
     /**
145 149
      * Tells if a specific timer is set
146 150
      *
... ...
@@ -43,6 +43,7 @@
43 43
 #include "ip_util.h"
44 44
 #include "resolver.h"
45 45
 #include "sip_ua.h"
46
+#include "msg_logger.h"
46 47
 
47 48
 #include "wheeltimer.h"
48 49
 #include "sip_timers.h"
... ...
@@ -94,7 +95,7 @@ int _trans_layer::send_reply(const trans_ticket* tt,
94 95
 			     int reply_code, const cstring& reason,
95 96
 			     const cstring& to_tag, const cstring& hdrs,
96 97
 			     const cstring& body,
97
-			     int out_interface)
98
+			     msg_logger* logger)
98 99
 {
99 100
     // Ref.: RFC 3261 8.2.6, 12.1.1
100 101
     //
... ...
@@ -393,16 +394,7 @@ int _trans_layer::send_reply(const trans_ticket* tt,
393 394
     // refs: RFC3261 18.2.2; RFC3581
394 395
 
395 396
     sockaddr_storage remote_ip;
396
-    trsp_socket* local_socket = NULL;
397
-
398
-    // rco: should we overwrite the socket from the request in all cases???
399
-    if((out_interface >= 0) && ((unsigned int)out_interface < transports.size())){
400
-	local_socket = transports[out_interface];
401
-    }
402
-    else {
403
-	local_socket = req->local_socket;
404
-    }
405
-
397
+    trsp_socket* local_socket = req->local_socket;
406 398
     memcpy(&remote_ip,&req->remote_ip,sizeof(sockaddr_storage));
407 399
 
408 400
     if(req->via_p1->has_rport){
... ...
@@ -462,6 +454,18 @@ int _trans_layer::send_reply(const trans_ticket* tt,
462 454
     t->retr_socket = local_socket;
463 455
 
464 456
     update_uas_reply(bucket,t,reply_code);
457
+
458
+    if(logger) {
459
+	sockaddr_storage src_ip;
460
+	local_socket->copy_addr_to(&src_ip);
461
+	logger->log(reply_buf,reply_len,&src_ip,&remote_ip,
462
+		    req->u.request->method_str,reply_code);
463
+
464
+	if(!t->logger){
465
+	    t->logger = logger;
466
+	    inc_ref(logger);
467
+	}
468
+    }
465 469
     
466 470
  end:
467 471
     bucket->unlock();
... ...
@@ -835,7 +839,8 @@ void _trans_layer::timeout(trans_bucket* bucket, sip_trans* t)
835 839
 int _trans_layer::send_request(sip_msg* msg, trans_ticket* tt, 
836 840
 			       const cstring& dialog_id,
837 841
 			       const cstring& _next_hop, 
838
-			       int out_interface)
842
+			       int out_interface,
843
+			       msg_logger* logger)
839 844
 {
840 845
     // Request-URI
841 846
     // To
... ...
@@ -1006,13 +1011,46 @@ int _trans_layer::send_request(sip_msg* msg, trans_ticket* tt,
1006 1011
 	delete p_msg;
1007 1012
     }
1008 1013
     else {
1014
+	// save parsed method, as update_uac_request
1015
+	// might delete p_msg, and msg->u.request->method is not set
1016
+	int method = p_msg->u.request->method;
1017
+
1009 1018
 	DBG("update_uac_request tt->_t =%p\n", tt->_t);
1010 1019
 	send_err = update_uac_request(tt->_bucket,tt->_t,p_msg);
1011 1020
 	if(send_err < 0){
1012 1021
 	    DBG("Could not update UAC state for request\n");
1013 1022
 	    delete p_msg;
1023
+	    tt->_bucket->unlock();
1024
+	    return send_err;
1014 1025
 	}
1015
-	else if(dialog_id.len && !(tt->_t->dialog_id.len)) {
1026
+
1027
+	DBG("logger = %p\n",logger);
1028
+
1029
+	if(logger) {
1030
+	    sockaddr_storage src_ip;
1031
+	    msg->local_socket->copy_addr_to(&src_ip);
1032
+
1033
+	    cstring method_str = msg->u.request->method_str;
1034
+	    char* msg_buffer=NULL;
1035
+	    if(method == sip_request::ACK) {
1036
+		// in case of ACK, p_msg gets deleted in update_uac_request
1037
+		msg_buffer = tt->_t->retr_buf;
1038
+	    }
1039
+	    else {
1040
+		msg_buffer = p_msg->buf;
1041
+	    }
1042
+
1043
+	    logger->log(msg_buffer,request_len,
1044
+			&src_ip,&msg->remote_ip,
1045
+			method_str);
1046
+
1047
+	    if(!tt->_t->logger) {
1048
+		tt->_t->logger = logger;
1049
+		inc_ref(logger);
1050
+	    }
1051
+	}
1052
+
1053
+	if(dialog_id.len && !(tt->_t->dialog_id.len)) {
1016 1054
 	    tt->_t->dialog_id.s = new char[dialog_id.len];
1017 1055
 	    tt->_t->dialog_id.len = dialog_id.len;
1018 1056
 	    memcpy((void*)tt->_t->dialog_id.s,dialog_id.s,dialog_id.len);
... ...
@@ -1142,12 +1180,23 @@ int _trans_layer::cancel(trans_ticket* tt)
1142 1180
     }
1143 1181
     else {
1144 1182
 
1145
-	sip_trans* t=NULL;
1146
-	send_err = update_uac_request(bucket,t,p_msg);
1183
+	sip_trans* cancel_t=NULL;
1184
+	send_err = update_uac_request(bucket,cancel_t,p_msg);
1147 1185
 	if(send_err<0){
1148 1186
 	    DBG("Could not update state for UAC transaction\n");
1149 1187
 	    delete p_msg;
1150 1188
 	}
1189
+	else if(t->logger) {
1190
+	    sockaddr_storage src_ip;
1191
+	    p_msg->local_socket->copy_addr_to(&src_ip);
1192
+	    t->logger->log(p_msg->buf,p_msg->len,&src_ip,
1193
+			   &p_msg->remote_ip,cancel_str);
1194
+
1195
+	    if(!cancel_t->logger) {
1196
+		cancel_t->logger = t->logger;
1197
+		inc_ref(t->logger);
1198
+	    }
1199
+	}
1151 1200
     }
1152 1201
 
1153 1202
     bucket->unlock();
... ...
@@ -1212,6 +1261,12 @@ void _trans_layer::received_msg(sip_msg* msg)
1212 1261
     case SIP_REQUEST: 
1213 1262
 	
1214 1263
 	if((t = bucket->match_request(msg,TT_UAS)) != NULL){
1264
+
1265
+	    if(t->logger) {
1266
+		t->logger->log(msg->buf,msg->len,&msg->remote_ip,
1267
+			       &msg->local_ip,msg->u.request->method_str);
1268
+	    }
1269
+
1215 1270
 	    if(msg->u.request->method != t->msg->u.request->method){
1216 1271
 		
1217 1272
 		// ACK matched INVITE transaction
... ...
@@ -1308,6 +1363,13 @@ void _trans_layer::received_msg(sip_msg* msg)
1308 1363
 	    // Reply matched UAC transaction
1309 1364
 	    
1310 1365
 	    DBG("Reply matched an existing transaction\n");
1366
+
1367
+	    if(t->logger) {
1368
+		t->logger->log(msg->buf,msg->len,&msg->remote_ip,
1369
+			       &msg->local_ip,get_cseq(msg)->method_str,
1370
+			       msg->u.reply->code);
1371
+	    }
1372
+
1311 1373
 	    int res = update_uac_reply(bucket,t,msg);
1312 1374
 	    if(res < 0){
1313 1375
 		ERROR("update_uac_trans() failed, so what happens now???\n");
... ...
@@ -1747,6 +1809,13 @@ void _trans_layer::send_non_200_ack(sip_msg* reply, sip_trans* t)
1747 1809
     if(send_err < 0){
1748 1810
 	ERROR("Error from transport layer\n");
1749 1811
     }
1812
+    
1813
+    if(t->logger) {
1814
+	sockaddr_storage src_ip;
1815
+	inv->local_socket->copy_addr_to(&src_ip);
1816
+	t->logger->log(ack_buf,ack_len,&src_ip,&inv->remote_ip,method);
1817
+    }
1818
+
1750 1819
     delete[] ack_buf;
1751 1820
 
1752 1821
 }
... ...
@@ -1763,6 +1832,14 @@ void _trans_layer::timer_expired(trans_timer* t, trans_bucket* bucket,
1763 1832
 
1764 1833
 	n++;
1765 1834
 	tr->msg->send();
1835
+	
1836
+	if(tr->logger) {
1837
+	    sockaddr_storage src_ip;
1838
+	    tr->msg->local_socket->copy_addr_to(&src_ip);
1839
+	    tr->logger->log(tr->msg->buf,tr->msg->len,&src_ip,&tr->msg->remote_ip,
1840
+			    tr->msg->u.request->method_str);
1841
+	}
1842
+
1766 1843
 	tr->reset_timer((n<<16) | type, A_TIMER<<n, bucket->get_id());
1767 1844
 	break;
1768 1845
 	
... ...
@@ -1884,6 +1961,14 @@ void _trans_layer::timer_expired(trans_timer* t, trans_bucket* bucket,
1884 1961
 
1885 1962
 	    // re-transmit request
1886 1963
 	    tr->msg->send();
1964
+
1965
+	    if(tr->logger) {
1966
+		sockaddr_storage src_ip;
1967
+		tr->msg->local_socket->copy_addr_to(&src_ip);
1968
+		tr->logger->log(tr->msg->buf,tr->msg->len,
1969
+				&src_ip,&tr->msg->remote_ip,
1970
+				tr->msg->u.request->method_str);
1971
+	    }
1887 1972
 	}
1888 1973
 
1889 1974
 	unsigned int retr_timer = (type == STIMER_E) ?
... ...
@@ -2010,6 +2095,14 @@ int _trans_layer::try_next_ip(trans_bucket* bucket, sip_trans* tr)
2010 2095
     // and re-send
2011 2096
     tr->msg->send();
2012 2097
     
2098
+    if(tr->logger) {
2099
+	sockaddr_storage src_ip;
2100
+	tr->msg->local_socket->copy_addr_to(&src_ip);
2101
+	tr->logger->log(tr->msg->buf,tr->msg->len,
2102
+			&src_ip,&tr->msg->remote_ip,
2103
+			tr->msg->u.request->method_str);
2104
+    }
2105
+
2013 2106
     // reset counter for timer A & E
2014 2107
     trans_timer* A_E_timer = tr->get_timer(STIMER_A);
2015 2108
     tr->reset_timer(A_E_timer->type & 0xFFFF,A_TIMER,bucket->get_id());
... ...
@@ -2022,6 +2115,24 @@ int _trans_layer::try_next_ip(trans_bucket* bucket, sip_trans* tr)
2022 2115
     return 0;
2023 2116
 }
2024 2117
 
2118
+void trans_ticket::lock_bucket() const
2119
+{
2120
+    _bucket->lock();
2121
+}
2122
+
2123
+void trans_ticket::unlock_bucket() const
2124
+{
2125
+    _bucket->unlock();
2126
+}
2127
+
2128
+const sip_trans* trans_ticket::get_trans() const
2129
+{
2130
+    if(_bucket->exist(_t))
2131
+	return _t; 
2132
+    else 
2133
+	return NULL; 
2134
+}
2135
+
2025 2136
 /** EMACS **
2026 2137
  * Local variables:
2027 2138
  * mode: c++
... ...
@@ -50,6 +50,9 @@ class trans_timer;
50 50
 class trsp_socket;
51 51
 class sip_ua;
52 52
 
53
+//draft msg logging
54
+class msg_logger;
55
+
53 56
 /** 
54 57
  * The transaction layer object.
55 58
  * Uses the singleton pattern.
... ...
@@ -92,7 +95,7 @@ public:
92 95
 		   int reply_code, const cstring& reason,
93 96
 		   const cstring& to_tag, const cstring& hdrs, 
94 97
 		   const cstring& body,
95
-		   int out_interface = -1);
98
+		   msg_logger* logger=NULL);
96 99
 
97 100
     /**
98 101
      * Sends a UAC request.
... ...
@@ -102,7 +105,8 @@ public:
102 105
      * @param [out] tt transaction ticket (needed for replies & CANCEL)
103 106
      */
104 107
     int send_request(sip_msg* msg, trans_ticket* tt, const cstring& dialog_id,
105
-		     const cstring& _next_hop, int out_interface = -1);
108
+		     const cstring& _next_hop, int out_interface = -1,
109
+		     msg_logger* logger=NULL);
106 110
 
107 111
     /**
108 112
      * Cancels a request. 
... ...
@@ -225,6 +229,22 @@ public:
225 229
 
226 230
     trans_ticket(const trans_ticket& ticket)
227 231
 	: _t(ticket._t), _bucket(ticket._bucket) {}
232
+
233
+    /**
234
+     * Locks the transaction bucket before accessing the transaction pointer.
235
+     */
236
+    void lock_bucket() const;
237
+
238
+    /**
239
+     * Unlocks the transaction bucket after accessing the transaction pointer.
240
+     */
241
+    void unlock_bucket() const;
242
+
243
+    /**
244
+     * Get the transaction pointer
245
+     * Note: the transaction bucket must be locked before
246
+     */
247
+    const sip_trans* get_trans() const;
228 248
 };
229 249
 
230 250
 #endif // _trans_layer_h_