Author: sayer
Date: 2008-12-19 20:12:57 +0100 (Fri, 19 Dec 2008)
New Revision: 1213

Modified:
   trunk/apps/diameter_client/DiameterClient.cpp
   trunk/apps/diameter_client/DiameterClient.h
   trunk/apps/diameter_client/Makefile
   trunk/apps/diameter_client/ServerConnection.cpp
   trunk/apps/diameter_client/ServerConnection.h
   trunk/apps/diameter_client/lib_dbase/Makefile
   trunk/apps/diameter_client/lib_dbase/diameter_msg.c
   trunk/apps/diameter_client/lib_dbase/diameter_msg.h
   trunk/apps/diameter_client/lib_dbase/tcp_comm.c
   trunk/apps/diameter_client/lib_dbase/tcp_comm.h
   trunk/core/ampi/DiameterClientAPI.h
Log:
DIAMETER client with TLS, handling of request timeout/retries, multiple servers,
and bugfixes (closing failed sockets)



Modified: trunk/apps/diameter_client/DiameterClient.cpp
===================================================================
--- trunk/apps/diameter_client/DiameterClient.cpp       2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/DiameterClient.cpp       2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -1,9 +1,9 @@
 /*
  * $Id$
  *
- * Copyright (C) 2007 iptego GmbH
+ * Copyright (C) 2007-2008 IPTEGO GmbH
  *
- * This file is part of SEMS, a free SIP media server.
+ * This file is part of sems, a free SIP media server.
  *
  * sems is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,6 +56,11 @@
 }
 
 int DiameterClient::onLoad() {
+  if (tcp_init_tcp()) {
+    ERROR("initializing tcp transport layer.\n");
+    return -1;
+  }
+
   DBG("DiameterClient loaded.\n");
   return 0;
 }
@@ -71,18 +76,31 @@
   int    app_id       = args.get(6).asInt();
   int    vendor_id    = args.get(7).asInt();
   string product_name = args.get(8).asCStr();
+  int    req_timeout  = args.get(9).asInt();
 
+  string ca_file;
+  string cert_file;
+
+  if (args.size() > 10) {
+    ca_file = args.get(10).asCStr();
+    cert_file = args.get(11).asCStr();
+  }
+
   ServerConnection* sc = new ServerConnection();
   DBG("initializing new connection for application %s...\n",
       app_name.c_str());
   sc->init(server_ip, server_port, 
+          ca_file, cert_file,
           origin_host, origin_realm, origin_ip, 
-          app_id, vendor_id, product_name);
+          app_id, vendor_id, product_name, 
+          req_timeout);
+
   DBG("starting new connection...\n");
   sc->start();
+
   DBG("registering connection...\n");
   conn_mut.lock();
-  connections.insert(std::make_pair(app_name, sc));
+  connections.insert(make_pair(app_name, sc));
   conn_mut.unlock();
 
   ret.push(0);
@@ -130,7 +148,12 @@
                            AmArg& ret)
 {
   if(method == "newConnection"){
-    args.assertArrayFmt("ssisssiis");
+    if (args.size()==10 /*sizeof("ssisssiisi")*/) {
+      args.assertArrayFmt("ssisssiisi");
+    } else  {
+      // plus optional ssl/tls parameters ss
+      args.assertArrayFmt("ssisssiisiss"); 
+    }
     newConnection(args, ret);
   } else if(method == "sendRequest"){
     args.assertArrayFmt("siias");

Modified: trunk/apps/diameter_client/DiameterClient.h
===================================================================
--- trunk/apps/diameter_client/DiameterClient.h 2008-12-19 18:48:00 UTC (rev 
1212)
+++ trunk/apps/diameter_client/DiameterClient.h 2008-12-19 19:12:57 UTC (rev 
1213)
@@ -1,9 +1,9 @@
 /*
  * $Id$
  *
- * Copyright (C) 2007 iptego GmbH
+ * Copyright (C) 2007-2008 IPTEGO GmbH
  *
- * This file is part of SEMS, a free SIP media server.
+ * This file is part of sems, a free SIP media server.
  *
  * sems is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
 #ifndef _DIAMETER_CLIENT_H
 #define _DIAMETER_CLIENT_H
 

Modified: trunk/apps/diameter_client/Makefile
===================================================================
--- trunk/apps/diameter_client/Makefile 2008-12-19 18:48:00 UTC (rev 1212)
+++ trunk/apps/diameter_client/Makefile 2008-12-19 19:12:57 UTC (rev 1213)
@@ -3,9 +3,19 @@
 DIAMETER_BASE_LIBDIR = lib_dbase/
 DIAMETER_BASE_LIBNAME = lib_dbase.a
 
+# for TLS support: 
+# 
+#WITH_OPENSSL = 1
+
 module_ldflags =
 module_cflags  = -I $(DIAMETER_BASE_LIBDIR)
 
+
+ifdef WITH_OPENSSL
+module_ldflags += -lssl -lcrypto
+module_cflags += -DWITH_OPENSSL
+endif
+
 module_extra_objs = $(DIAMETER_BASE_LIBDIR)$(DIAMETER_BASE_LIBNAME)
 extra_clean = baseclean
 

Modified: trunk/apps/diameter_client/ServerConnection.cpp
===================================================================
--- trunk/apps/diameter_client/ServerConnection.cpp     2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/ServerConnection.cpp     2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -1,9 +1,9 @@
 /*
  * $Id$
  *
- * Copyright (C) 2007 iptego GmbH
+ * Copyright (C) 2007-2008 IPTEGO GmbH
  *
- * This file is part of SEMS, a free SIP media server.
+ * This file is part of sems, a free SIP media server.
  *
  * sems is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -42,15 +42,20 @@
 #define CONN_WAIT_MAX   4      // 10  (*50ms = 0.5s)
 #define CONN_WAIT_USECS 50000  // 50 ms
 
-#define MAX_RETRANSMIT_RCV_RETRY 4
+#define CHECK_TIMEOUT_USECS   500000 // 0.5ms
+#define CHECK_TIMEOUT_INTERVAL (CHECK_TIMEOUT_USECS / CONN_WAIT_USECS)
 
 // #define EXTRA_DEBUG 
 
 #define CONNECT_CEA_REPLY_TIMEOUT 2 // seconds
 #define RETRY_CONNECTION_INTERVAL 2 // seconds
 
+// after syserror, wait 30 secs for retry
+#define RETRY_CONNECTION_SYSERROR 30 // seconds
+
 DiameterServerConnection::DiameterServerConnection()  
-  : in_use(false), sockfd(-1) { 
+  : in_use(false), dia_conn(0) 
+{ 
   memset(&rb, 0, sizeof(rd_buf_t));
   h2h = random();
   e2e = (time(NULL) & 0xFFF << 20) | (random() % 0xFFFFF);
@@ -58,10 +63,11 @@
 
 
 void DiameterServerConnection::terminate() {
-  if (sockfd>0)
-    close_tcp_connection(sockfd);
-
-  sockfd = -1;
+  if (dia_conn) {
+    tcp_close_connection(dia_conn);
+    tcp_destroy_connection(dia_conn);
+    dia_conn = NULL;
+  }
 }
 
 void DiameterServerConnection::setIDs(AAAMessage* msg) {
@@ -92,13 +98,14 @@
   gettimeofday(&now, NULL);
 
   req_map_mut.lock();
-  req_map[exe] = std::make_pair(re->sess_link, now);
+  req_map[exe] = make_pair(re->sess_link, now);
   req_map_mut.unlock();
 }
 
 ServerConnection::ServerConnection() 
   : server_port(-1), open(false),
-    AmEventQueue(this)
+    AmEventQueue(this), request_timeout(3000),
+    timeout_check_cntr(0)
 {
 }
 
@@ -108,15 +115,20 @@
 }
 
 int ServerConnection::init(const string& _server_name, 
-                        int _server_port,
-                        const string& _origin_host, 
-                        const string& _origin_realm,
-                        const string& _origin_ip,
-                        AAAApplicationId _app_id,
-                        unsigned int _vendorID,
-                        const string& _product_name) {
+                          int _server_port,
+                          const string& _ca_file,
+                          const string& _cert_file,
+                          const string& _origin_host, 
+                          const string& _origin_realm,
+                          const string& _origin_ip,
+                          AAAApplicationId _app_id,
+                          unsigned int _vendorID,
+                          const string& _product_name,
+                          int _request_timeout) {
   server_name = _server_name;
   server_port = _server_port;
+  ca_file = _ca_file;
+  cert_file = _cert_file;
   origin_host = _origin_host;
   origin_realm = _origin_realm;
   origin_ip = _origin_ip;
@@ -124,6 +136,7 @@
   app_id = htonl(_app_id);
   // todo: separate vendor for client/app
   vendorID = htonl(_vendorID);
+  request_timeout = _request_timeout;
 
   memset(origin_ip_address, 0, sizeof(origin_ip_address));
   origin_ip_address[0] = 0;
@@ -147,15 +160,21 @@
 }
 
 void ServerConnection::openConnection() {
+
   DBG("init TCP connection\n");
-  int res = init_mytcp(server_name.c_str(), server_port);
-  if (res < 0) {
+  if (conn.dia_conn) {
+    ERROR("CRITICAL: trying to open new connection, while current one still"
+      " opened.\n");
+    abort();
+  }
+  conn.dia_conn = tcp_create_connection(server_name.c_str(), server_port,
+                                       ca_file.c_str(), cert_file.c_str());
+  if (!conn.dia_conn) {
     ERROR("establishing connection to %s\n", 
          server_name.c_str());
     setRetryConnectLater();
     return;
   }
-  conn.sockfd = res;
 
   // send CER
   AAAMessage* cer;
@@ -195,7 +214,7 @@
                    (char*)&vendorID, sizeof(vendorID)) ||
       (AAAAddAVPToMessage(cer, vs_appid, 0) != AAA_ERR_SUCCESS)
       ) {
-    ERROR( M_NAME":makeConnections(): creating AVP failed."
+    ERROR( M_NAME":openConnection(): creating AVP failed."
           " (no more free memory!)\n");
     conn.terminate();
     setRetryConnectLater();
@@ -209,12 +228,12 @@
   conn.setIDs(cer);
   
   if(AAABuildMsgBuffer(cer) != AAA_ERR_SUCCESS) {
-    ERROR( " makeConnections(): message buffer not created\n");
+    ERROR( " openConnection(): message buffer not created\n");
     AAAFreeMessage(&cer);
     return;
   }
   
-  int ret = tcp_send(conn.sockfd, cer->buf.s, cer->buf.len);
+  int ret = tcp_send(conn.dia_conn, cer->buf.s, cer->buf.len);
   if (ret) {
     ERROR( "openConnection(): could not send message\n");
     conn.terminate();
@@ -225,16 +244,30 @@
   
   AAAFreeMessage(&cer);
 
-  AAAMessage* cea = NULL;
-  res = tcp_recv_reply(conn.sockfd, &conn.rb, &cea, 
-                      CONNECT_CEA_REPLY_TIMEOUT, 0);
-  if (res) {
-    ERROR( " makeConnections(): did not receive CEA reply.\n");
+  int res = tcp_recv_msg(conn.dia_conn, &conn.rb,
+                        CONNECT_CEA_REPLY_TIMEOUT, 0);
+  
+  if (res <= 0) {
+    if (!res) {
+      ERROR( " openConnection(): did not receive response (CEA).\n");
+    } else {
+      ERROR( " openConnection(): error receiving response (CEA).\n");
+    }
     conn.terminate();
     setRetryConnectLater();
-    AAAFreeMessage(&cer);
     return;
   }
+
+  /* obtain the structure corresponding to the message */
+  AAAMessage* cea = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);      
+  if(!cea) {
+    ERROR( " openConnection(): could not decipher response (CEA).\n");
+    conn.terminate();
+    setRetryConnectLater();
+    return;
+  }
+
+  // assume its CEA....
   
 #ifdef EXTRA_DEBUG 
   if (cea != NULL)
@@ -364,7 +397,7 @@
     return AAA_ERROR_MESSAGE;
   }
   
-  int ret = tcp_send(conn.sockfd, req->buf.s, req->buf.len);
+  int ret = tcp_send(conn.dia_conn, req->buf.s, req->buf.len);
   if (ret) {
     ERROR( " sendRequest(): could not send message\n");
     AAAFreeMessage(&req);
@@ -405,10 +438,10 @@
     }
     
     DBG("sending Device-Watchdog-Answer...\n");
-    int ret = tcp_send(conn.sockfd, reply->buf.s, reply->buf.len);
+    int ret = tcp_send(conn.dia_conn, reply->buf.s, reply->buf.len);
     if (ret) {
       ERROR( " sendRequest(): could not send message\n");
-      open = false;
+      closeConnection();
       AAAFreeMessage(&reply);
       return AAA_ERROR_COMM;
     }
@@ -432,12 +465,12 @@
 
 int ServerConnection::handleReply(AAAMessage* rep) {
   unsigned int rep_id = rep->endtoendId;
-  DBG("received reply - id %d\n", rep_id);
-
+  int reply_code = AAAMessageGetReplyCode(rep);
+  DBG("received reply - id %d, reply code %d\n", rep_id, reply_code);
+  
   string sess_link  = "";
   req_map_mut.lock();
-  map<unsigned int, pair<string, struct timeval> >::iterator it =  
-    req_map.find(rep_id);
+  DReqMap::iterator it =  req_map.find(rep_id);
   if (it != req_map.end()) {
     sess_link = it->second.first;
     req_map.erase(it);
@@ -452,12 +485,22 @@
                             AAAMessageAVPs2AmArg(rep));
     if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
       DBG("unhandled reply\n");
-    }    
+    }
+  } else {
+    DBG("no session-link for DIAMETER reply.\n");
   }
 
+  if ((reply_code == AAA_OUT_OF_SPACE)
+      || reply_code >= AAA_PERMANENT_FAILURE_START) {
+    WARN("critical or permanent failure Diameter error reply"
+        " (code %d) received. Shutdown connection.\n", 
+        reply_code);
+    shutdownConnection();
+  }
+
   return 0;
 }
-
+      
 AmArg ServerConnection::AAAMessageAVPs2AmArg(AAAMessage* rep) {
   AmArg res;
   for(AAA_AVP* avp=rep->avpList.head;avp;avp=avp->next) {
@@ -472,6 +515,16 @@
   return res;
 }
 
+int ServerConnection::AAAMessageGetReplyCode(AAAMessage* rep) {
+  for(AAA_AVP* avp=rep->avpList.head;avp;avp=avp->next) {
+    if (avp->code == AVP_Result_Code) {
+      int res = ntohl(*(uint32_t*)avp->data.s);
+      return res;
+    }
+  }
+  return -1;
+}
+
 void ServerConnection::setRetryConnectLater() {
   gettimeofday(&connect_ts, NULL);
   connect_ts.tv_sec += RETRY_CONNECTION_INTERVAL;
@@ -482,29 +535,36 @@
 }
 
 void ServerConnection::receive() {
-  AAAMessage *response = NULL;
-  int res = tcp_recv_reply(conn.sockfd, &conn.rb, &response, 
-                          0, CONN_WAIT_USECS);
-  if (res) {
-    ERROR( " receive(): tcp_recv_reply() failed.\n");
-    open = false;
+  int res = tcp_recv_msg(conn.dia_conn, &conn.rb,
+                        0, CONN_WAIT_USECS);
+
+  if (res < 0) {
+    ERROR( M_NAME "receive(): tcp_recv_reply() failed.\n");
+    closeConnection();
+    return;
   }
 
-  // nothing received
-  if (response == NULL) 
+  if (!res) // nothing received
     return;
 
+  /* obtain the structure corresponding to the message */
+  AAAMessage* msg = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);      
+  if(!msg) {
+    ERROR( M_NAME "receive(): message structure not obtained from 
message.\n");        
+    closeConnection();
+    return;
+  }
     
 #ifdef EXTRA_DEBUG 
-  AAAPrintMessage(response);
+  AAAPrintMessage(msg);
 #endif
   
-  if (is_req(response)) 
-    handleRequest(response);
+  if (is_req(msg)) 
+    handleRequest(msg);
   else 
-    handleReply(response);
+    handleReply(msg);
   
-  AAAFreeMessage(&response);  
+  AAAFreeMessage(&msg);  
 }
 
 void ServerConnection::run() {
@@ -522,9 +582,78 @@
       }
     } else {
       receive();
+      checkTimeouts();
     }
 
     processEvents();
   }
 }
 
+void ServerConnection::checkTimeouts() {
+  if ((++timeout_check_cntr)%CHECK_TIMEOUT_INTERVAL) 
+    return;
+
+  req_map_mut.lock();
+
+#ifdef EXTRA_DEBUG
+  DBG("checking request timeout of %zd pending requests....\n",
+      req_map.size());
+#endif
+  
+  struct timeval now;
+  gettimeofday(&now, NULL);
+
+  for (DReqMap::iterator it = 
+        req_map.begin();it != req_map.end();) {
+
+    struct timeval diff;
+    timersub(&now,&it->second.second,&diff);
+    // millisec
+    if (diff.tv_sec * 1000 + diff.tv_usec / 1000 > request_timeout) {
+      WARN("timeout for DIAMETER request '%u'\n", it->first);      
+      string& sess_link = it->second.first;
+
+      DBG("notify session '%s' of diameter request timeout\n", 
+         sess_link.c_str());
+      DiameterTimeoutEvent* r_ev = 
+       new DiameterTimeoutEvent(it->first);
+      if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
+       DBG("unhandled timout event.\n");
+      }
+      DReqMap::iterator d_it = it;
+      it++;
+      req_map.erase(d_it);
+    } else {
+      it++;
+    }
+  }
+
+  req_map_mut.unlock();
+}
+
+void ServerConnection::shutdownConnection() {
+  gettimeofday(&connect_ts, NULL);
+  connect_ts.tv_sec += RETRY_CONNECTION_SYSERROR;
+  closeConnection();
+
+  req_map_mut.lock();
+  DBG("shutdown: posting timeout to %zd pending requests....\n",
+      req_map.size());
+  for (DReqMap::iterator it = req_map.begin();
+       it != req_map.end();it++) {
+      string& sess_link = it->second.first;
+      DiameterTimeoutEvent* r_ev = 
+       new DiameterTimeoutEvent(it->first);
+      if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
+       DBG("unhandled timout event.\n");
+      }
+  }
+  req_map.clear();
+  req_map_mut.unlock();
+}
+
+void ServerConnection::closeConnection() {
+  if (open)
+    conn.terminate();
+  open = false;
+}

Modified: trunk/apps/diameter_client/ServerConnection.h
===================================================================
--- trunk/apps/diameter_client/ServerConnection.h       2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/ServerConnection.h       2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -1,9 +1,9 @@
 /*
  * $Id$
  *
- * Copyright (C) 2007 iptego GmbH
+ * Copyright (C) 2007-2008 IPTEGO GmbH
  *
- * This file is part of SEMS, a free SIP media server.
+ * This file is part of sems, a free SIP media server.
  *
  * sems is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
 #ifndef _DIAMETER_SERVER_CONNECTION_H
 #define _DIAMETER_SERVER_CONNECTION_H
 
@@ -75,7 +74,7 @@
 
 struct DiameterServerConnection {
   bool in_use;
-  int sockfd;
+  dia_tcp_conn* dia_conn; // transport connection
   rd_buf_t rb;
 
   string origin_host;
@@ -97,14 +96,22 @@
 {
   struct timeval connect_ts;
   bool open;
+  int timeout_check_cntr;
   
   string server_name;
   int server_port;
+
+  // openssl
+  string ca_file;
+  string cert_file;
+
   string origin_host;
   string origin_realm;
   string origin_ip;
   AAAApplicationId app_id;
 
+  int request_timeout; // millisec
+
   char origin_ip_address[2+4];// AF and address
 
   //  the client
@@ -113,11 +120,12 @@
   
   DiameterServerConnection conn;
 
-  map<unsigned int, pair<string, struct timeval> > 
-    req_map;
+  typedef map<unsigned int, pair<string, struct timeval> > DReqMap;
+  DReqMap req_map;
   AmMutex req_map_mut;
 
   void openConnection();
+  void closeConnection();
 
   int addOrigin(AAAMessage* msg);
 
@@ -125,6 +133,7 @@
   int handleRequest(AAAMessage* req);
   AAAMessage* ReqEvent2AAAMessage(DiameterRequestEvent* re);
   AmArg AAAMessageAVPs2AmArg(AAAMessage* rep);
+  int AAAMessageGetReplyCode(AAAMessage* rep);
 
   static int addStringAVP(AAAMessage* msg, AAA_AVPCode avp_code, string& val, 
bool attail = false);
   static int addDataAVP(AAAMessage* msg, AAA_AVPCode avp_code, char* val, 
unsigned int len);
@@ -136,17 +145,23 @@
   void process(AmEvent*);
   void receive();
   void setRetryConnectLater();
+  void checkTimeouts();
+  void shutdownConnection();
+
  public:
   ServerConnection();
   ~ServerConnection();
   int init(const string& _server_name, 
           int _server_port,
+          const string& _ca_file,
+          const string& _cert_file,
           const string& _origin_host, 
           const string& _origin_realm,
           const string& _origin_ip,
           AAAApplicationId _app_id,
           unsigned int _vendorID,
-          const string& _product_name);
+          const string& _product_name,
+          int _request_timeout); // millisec
 
   bool is_open() { return open; }
   void run();

Modified: trunk/apps/diameter_client/lib_dbase/Makefile
===================================================================
--- trunk/apps/diameter_client/lib_dbase/Makefile       2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/lib_dbase/Makefile       2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -12,8 +12,14 @@
 objs     = $(srcs:.c=.o) 
 depends  = $(srcs:.c=.d)
 
-cflags  ?= $(CFLAGS) -I $(MCOREPATH) -Wall $(module_cflags)
+cflags  ?= $(C_FLAGS) -I $(MCOREPATH) -Wall $(module_cflags) 
 
+WITH_OPENSSL = 1
+
+ifdef WITH_OPENSSL
+cflags+=  -D WITH_OPENSSL
+endif
+
 AR             = ar
 RANLIB         = ranlib
 

Modified: trunk/apps/diameter_client/lib_dbase/diameter_msg.c
===================================================================
--- trunk/apps/diameter_client/lib_dbase/diameter_msg.c 2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/lib_dbase/diameter_msg.c 2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -232,7 +232,8 @@
 
   /* check the params */
   if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) {
-    ERROR("ERROR:AAATranslateMessage: invalid buffered received!\n");
+    ERROR("ERROR:AAATranslateMessage: could not decipher "
+         "received message - wrong size (%d)!\n", sourceLen);
     goto error;
   }
 

Modified: trunk/apps/diameter_client/lib_dbase/diameter_msg.h
===================================================================
--- trunk/apps/diameter_client/lib_dbase/diameter_msg.h 2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/lib_dbase/diameter_msg.h 2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -200,6 +200,7 @@
        AAA_AUTHENTICATION_REJECTED   = 4001,
        AAA_OUT_OF_SPACE              = 4002,
        AAA_ELECTION_LOST             = 4003,
+       AAA_PERMANENT_FAILURE_START   = 5000,
        AAA_AVP_UNSUPPORTED           = 5001,
        AAA_UNKNOWN_SESSION_ID        = 5002,
        AAA_AUTHORIZATION_REJECTED    = 5003,

Modified: trunk/apps/diameter_client/lib_dbase/tcp_comm.c
===================================================================
--- trunk/apps/diameter_client/lib_dbase/tcp_comm.c     2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/lib_dbase/tcp_comm.c     2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -58,27 +58,112 @@
 
 #define MAX_TRIES      10
 
+#define WANT_RW_TIMEOUT_USEC 100000 // 100 ms
+
+void reset_read_buffer(rd_buf_t *rb);
+int do_read(dia_tcp_conn* conn_st, rd_buf_t *p);
+
+#ifdef WITH_OPENSSL
+/* for printing error msg */
+BIO* bio_err = 0;
+
+long tcp_ssl_dbg_cb(BIO *bio, int oper, const char *argp,
+                   int argi, long argl, long retvalue) {
+
+  if (oper & BIO_CB_RETURN)
+    return retvalue;
+
+  switch (oper) {
+  case BIO_CB_WRITE: {
+    char buf[256];
+    snprintf(buf, 256, "%s: %s", argp, bio->method->name);
+    INFO("%s", buf);
+  } break;
+
+  case BIO_CB_PUTS: {
+    char buf[2];
+    buf[0] = *argp;
+    buf[1] = '\0';
+    INFO("%s", buf);
+  } break;
+  default: break;
+  }
+
+  return retvalue;
+}
+
+static int password_cb(char *buf,int num,
+                      int rwflag,void *userdata) {
+  ERROR("password protected key file.\n"); /* todo? */
+  return 0;
+}
+
+/* Check that the common name matches the
+   host name*/
+int check_cert(SSL * ssl, char* host) {
+  X509 *peer;
+  char peer_CN[256];
+  
+  if(SSL_get_verify_result(ssl)!=X509_V_OK)  {
+    ERROR("Certificate doesn't verify");
+    return -1;
+  }
+  
+  /*Check the cert chain. The chain length
+    is automatically checked by OpenSSL when
+    we set the verify depth in the ctx */
+  
+  /*Check the common name*/
+  peer=SSL_get_peer_certificate(ssl);
+  X509_NAME_get_text_by_NID
+    (X509_get_subject_name(peer),
+     NID_commonName, peer_CN, 256);
+  if(strcasecmp(peer_CN,host)) {
+    ERROR("Common name doesn't match host name");
+    return -1;
+  }
+
+  return 0;
+}
+
+#endif
+
+int tcp_init_tcp() {
+#ifdef WITH_OPENSSL
+  SSL_library_init();
+  SSL_load_error_strings();
+  bio_err = BIO_new(BIO_s_null());
+  BIO_set_callback(bio_err, tcp_ssl_dbg_cb);
+#endif
+  return 0;
+}
+
 /* it initializes the TCP connection */ 
-int init_mytcp(const char* host, int port)
+dia_tcp_conn* tcp_create_connection(const char* host, int port,
+                                   const char* CA_file, const char* 
client_cert_file)
 {
   int sockfd;
   struct sockaddr_in serv_addr;
   struct hostent *server;
+#ifdef WITH_OPENSSL
+  SSL_METHOD* meth;
+#endif
     
   sockfd = socket(PF_INET, SOCK_STREAM, 0);
        
   if (sockfd < 0) 
     {
-      ERROR(M_NAME":init_mytcp(): error creating the socket\n");
-      return -1;
+      ERROR(M_NAME":init_diatcp(): error creating the socket\n");
+      return 0;
     }  
        
   server = gethostbyname(host);
   if (server == NULL) 
     {
       close(sockfd);
-      ERROR( M_NAME":init_mytcp(): error finding the host\n");
-      return -1;
+      ERROR( M_NAME":init_diatcp(): error finding the host '%s'\n",
+            host);
+      return 0;
     }
 
   memset((char *) &serv_addr, 0, sizeof(serv_addr));
@@ -91,16 +176,79 @@
              sizeof(serv_addr)) < 0) 
     {
       close(sockfd);
-      ERROR( M_NAME":init_mytcp(): error connecting to the "
-         "DIAMETER peer\n");
-      return -1;
+      ERROR( M_NAME":init_diatcp(): error connecting to the "
+            "DIAMETER peer '%s'\n", host);
+      return 0;
     }  
 
-  return sockfd;
-}
+  dia_tcp_conn* conn_st = pkg_malloc(sizeof(dia_tcp_conn));
+  memset(conn_st, 0, sizeof(dia_tcp_conn));
 
+  conn_st->sockfd = sockfd;
 
+#ifdef WITH_OPENSSL
+  if (!strlen(CA_file)) {
+    DBG("no CA certificate - not using TLS.\n");
+    return conn_st;
+  }
 
+  meth=TLSv1_client_method();
+  conn_st->ctx = SSL_CTX_new(meth);
+
+  if (!strlen(client_cert_file)) {
+    DBG("no client certificate - not authenticating client.\n");
+  } else {
+    if (!SSL_CTX_use_certificate_chain_file(conn_st->ctx, client_cert_file)) {
+      ERROR("using certificate from file '%s'\n",
+           client_cert_file);
+      SSL_CTX_free(conn_st->ctx);
+      pkg_free(conn_st);
+      return 0;
+    }
+  
+    SSL_CTX_set_default_passwd_cb(conn_st->ctx, password_cb);
+
+    if(!(SSL_CTX_use_PrivateKey_file(conn_st->ctx,
+                                    client_cert_file,SSL_FILETYPE_PEM))) {
+      ERROR("Loading private key file '%s'\n",
+           client_cert_file);
+      SSL_CTX_free(conn_st->ctx);
+      pkg_free(conn_st);
+      return 0;
+    }
+  }
+  
+  /* Load the CAs we trust*/
+  if(!(SSL_CTX_load_verify_locations(conn_st->ctx,
+                                    CA_file,0))) {
+    ERROR("Loading CA file '%s'\n",
+         CA_file);
+    SSL_CTX_free(conn_st->ctx);
+    pkg_free(conn_st);
+    return 0;
+  }
+  
+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
+  SSL_CTX_set_verify_depth(ctx,1);
+#endif
+
+  conn_st->ssl=SSL_new(conn_st->ctx);
+  conn_st->sbio=BIO_new_socket(sockfd,BIO_NOCLOSE);
+  SSL_set_bio(conn_st->ssl,conn_st->sbio,conn_st->sbio);
+  if(SSL_connect(conn_st->ssl)<=0) {
+    ERROR("in SSL connect\n");
+    SSL_free(conn_st->ssl);
+    SSL_CTX_free(conn_st->ctx);
+    pkg_free(conn_st);
+    return 0;
+  }
+
+#endif
+/*   check_cert(ssl,host); */
+
+  return conn_st;
+}
+
 void reset_read_buffer(rd_buf_t *rb)
 {
   rb->ret_code         = 0;
@@ -116,8 +264,59 @@
   rb->buf              = 0;
 }
 
+int tryreceive(dia_tcp_conn* conn_st, unsigned char* ptr, int nwanted) {
+#ifdef WITH_OPENSSL
+  int res;
+  fd_set rw_fd_set;
+  struct timeval tv;
+
+  tv.tv_sec = 0;
+  tv.tv_usec = WANT_RW_TIMEOUT_USEC;
+      
+  if (conn_st->ssl) {
+    while (1) {
+      res = SSL_read(conn_st->ssl, ptr, nwanted);
+      switch(SSL_get_error(conn_st->ssl,res)){
+      case SSL_ERROR_NONE: {
+       return res;
+      }
+       
+      case SSL_ERROR_ZERO_RETURN: /* shutdown */
+       DBG("SSL shutdown connection (in SSL_read)\n");
+       return 0;
+       
+      case SSL_ERROR_WANT_READ: {
+       FD_ZERO(&rw_fd_set);
+       FD_SET(conn_st->sockfd, &rw_fd_set);
+       res = select (conn_st->sockfd+1, &rw_fd_set, NULL, NULL, &tv);
+       if ( res < 0) {
+         ERROR( M_NAME":SSL_WANT_READ select failed\n");
+         return -1;
+       }
+      } break;
+       
+      case SSL_ERROR_WANT_WRITE:  {
+       FD_ZERO(&rw_fd_set);
+       FD_SET(conn_st->sockfd, &rw_fd_set);
+       res = select (conn_st->sockfd+1, NULL, &rw_fd_set, NULL, &tv);
+       if ( res < 0) {
+         ERROR( M_NAME":SSL_WANT_WRITE select failed\n");
+         return -1;
+       }
+      } break;
+      default: return 0;
+      }
+    }    
+  } else {
+#endif
+    return recv(conn_st->sockfd, ptr, nwanted, MSG_DONTWAIT);
+#ifdef WITH_OPENSSL
+  }
+#endif
+}
+
 /* read from a socket, an AAA message buffer */
-int do_read( int socket, rd_buf_t *p)
+int do_read(dia_tcp_conn* conn_st, rd_buf_t *p)
 {
   unsigned char  *ptr;
   unsigned int   wanted_len, len;
@@ -134,7 +333,7 @@
       ptr = p->buf + p->buf_len;
     }
 
-  while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) 
+  while( (n=tryreceive(conn_st, ptr, wanted_len))>0 ) 
     {
       //               DBG("DEBUG:do_read (sock=%d)  -> n=%d (expected=%d)\n",
       //                       p->sock,n,wanted_len);
@@ -154,7 +353,7 @@
              if (len<AAA_MSG_HDR_SIZE || len>MAX_AAA_MSG_SIZE)
                {
                  ERROR("ERROR:do_read (sock=%d): invalid message "
-                     "length read %u (%x)\n", socket, len, p->first_4bytes);
+                     "length read %u (%x)\n", conn_st->sockfd, len, 
p->first_4bytes);
                  goto error;
                }
              //DBG("message length = %d(%x)\n",len,len);
@@ -185,22 +384,39 @@
 
   if (n==0)
     {
-      INFO("INFO:do_read (sock=%d): FIN received\n", socket);
+      INFO("INFO:do_read (sock=%d): FIN received\n", conn_st->sockfd);
       return CONN_CLOSED;
     }
   if ( n==-1 && errno!=EINTR && errno!=EAGAIN )
     {
       ERROR("ERROR:do_read (sock=%d): n=%d , errno=%d (%s)\n",
-         socket, n, errno, strerror(errno));
+         conn_st->sockfd, n, errno, strerror(errno));
       goto error;
     }
  error:
   return CONN_ERROR;
 }
 
+int tcp_send(dia_tcp_conn* conn_st, char* buf, int len) {
+  int n;
+  int sockfd;
+  fd_set rw_fd_set;
+  struct timeval tv;
 
-int tcp_send(int sockfd, char* buf, int len) {
-  int n;
+  tv.tv_sec = 0;
+  tv.tv_usec = WANT_RW_TIMEOUT_USEC;
+
+
+  if (!conn_st) {
+    ERROR("called without conn_st\n");
+    return CONN_ERROR;
+  }
+  
+  sockfd = conn_st->sockfd;
+
+#ifdef WITH_OPENSSL
+  if (!conn_st->ssl) { 
+#endif
   /* try to write the message to the Diameter client */
   while( (n=write(sockfd, buf, len))==-1 ) {
     if (errno==EINTR)
@@ -213,29 +429,77 @@
     ERROR( M_NAME": write gave no error but wrote less than asked\n");
     return AAA_ERROR;
   }
+#ifdef WITH_OPENSSL
+  } else {
+    while (1) {
+      n = SSL_write(conn_st->ssl, buf, len);
+      switch(SSL_get_error(conn_st->ssl, n)) {
+      case SSL_ERROR_NONE: {
+       if (len != n) {
+         ERROR( M_NAME": write gave no error but wrote less than asked\n");
+         return AAA_ERROR;
+       }
+       return 0;
+      };
+      case SSL_ERROR_ZERO_RETURN: /* shutdown */
+       DBG("SSL shutdown connection (in SSL_write)\n");
+       return 0;
+       
+      case SSL_ERROR_WANT_READ: {
+       FD_ZERO(&rw_fd_set);
+       FD_SET(conn_st->sockfd, &rw_fd_set);
+       n=select(conn_st->sockfd+1, &rw_fd_set, NULL, NULL, &tv);
+       if (n < 0) {
+         ERROR( M_NAME":SSL_WANT_READ select failed\n");
+         return -1;
+       }
+      } break; /* try again */
+       
+      case SSL_ERROR_WANT_WRITE:  {
+       FD_ZERO(&rw_fd_set);
+       FD_SET(conn_st->sockfd, &rw_fd_set);
+       n=select(conn_st->sockfd+1, NULL, &rw_fd_set, NULL, &tv);
+       if (n < 0) {
+         ERROR( M_NAME":SSL_WANT_WRITE select failed\n");
+         return -1;
+       }
+      } break; /* try again */
 
+      default: {
+       ERROR("SSL write error.\n");
+       return AAA_ERROR;
+      }
+      }
+    }
+  }
+#endif
+
   return 0;
 }
 
-int tcp_recv_reply(int sockfd, rd_buf_t* rb, AAAMessage** msg, 
-                  time_t wait_sec, suseconds_t wait_usec) {
+int tcp_recv_msg(dia_tcp_conn* conn_st, rd_buf_t* rb, 
+                time_t wait_sec, suseconds_t wait_usec) {
   int res;
-  fd_set active_fd_set, read_fd_set;
+  fd_set rd_fd_set;
   struct timeval tv;
+  int sockfd;
 
-  if (msg == NULL)
-    return AAA_ERROR;
+  if (!conn_st) {
+    ERROR("called without conn_st\n");
+    return CONN_ERROR;
+  }
+  
+  sockfd = conn_st->sockfd;
 
   /* wait for the answer a limited amount of time */
   tv.tv_sec = wait_sec;
   tv.tv_usec = wait_usec;
 
   /* Initialize the set of active sockets. */
-  FD_ZERO (&active_fd_set);
-  FD_SET (sockfd, &active_fd_set);
+  FD_ZERO (&rd_fd_set);
+  FD_SET (sockfd, &rd_fd_set);
 
-  read_fd_set = active_fd_set;
-  res = select (sockfd+1, &read_fd_set, NULL, NULL, &tv);
+  res = select (sockfd+1, &rd_fd_set, NULL, NULL, &tv);
   if ( res < 0) {
     ERROR( M_NAME":tcp_reply_recv(): select function failed\n");
     return AAA_ERROR;
@@ -246,7 +510,7 @@
 
   /* Data arriving on a already-connected socket. */
   reset_read_buffer(rb);
-  switch( do_read(sockfd, rb) )
+  switch( do_read(conn_st, rb) )
     {
     case CONN_ERROR:
       ERROR( M_NAME":tcp_reply_recv(): error when trying to read from 
socket\n");
@@ -255,163 +519,31 @@
       ERROR( M_NAME":tcp_reply_recv(): connection closed by diameter peer\n");
       return AAA_CONN_CLOSED;
     }
-  
-  /* obtain the structure corresponding to the message */
-  *msg = AAATranslateMessage(rb->buf, rb->buf_len, 0); 
-  if(! (*msg)) {
-    ERROR( M_NAME":tcp_reply_recv(): message structure not obtained\n");       
-    return AAA_ERROR;
+  return 1; //received something
+}
+
+void tcp_close_connection(dia_tcp_conn* conn_st)
+{
+  if (!conn_st) {
+    ERROR("called without conn_st\n");
+    return;
   }
   
-  return 0;
+  shutdown(conn_st->sockfd, SHUT_RDWR);
+  DBG("closing DIAMETER socket %d\n", conn_st->sockfd);
+  close(conn_st->sockfd);
 }
 
-/* send a message over an already opened TCP connection */
-int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, 
-                 unsigned int waited_id)
-{
-  int n, number_of_tries;
-  fd_set active_fd_set, read_fd_set;
-  struct timeval tv;
-  unsigned long int result_code;
-  AAAMessage *msg;
-  AAA_AVP      *avp;
-  char serviceType;
-  unsigned int m_id;
+void tcp_destroy_connection(dia_tcp_conn* conn_st) {
+  if (!conn_st) {
+    ERROR("called without conn_st\n");
+    return;
+  }    
 
-  /* try to write the message to the Diameter client */
-  while( (n=write(sockfd, buf, len))==-1 ) 
-    {
-      if (errno==EINTR)
-       continue;
-      ERROR( M_NAME": write returned error: %s\n", strerror(errno));
-      return AAA_ERROR;
-    }
+  if (conn_st->ssl)
+    SSL_free(conn_st->ssl);
+  if (conn_st->ctx)
+    SSL_CTX_free(conn_st->ctx);
 
-  if (n!=len) 
-    {
-      ERROR( M_NAME": write gave no error but wrote less than asked\n");
-      return AAA_ERROR;
-    }
-
-  /* wait for the answer a limited amount of time */
-  tv.tv_sec = MAX_WAIT_SEC;
-  tv.tv_usec = MAX_WAIT_USEC;
-
-  /* Initialize the set of active sockets. */
-  FD_ZERO (&active_fd_set);
-  FD_SET (sockfd, &active_fd_set);
-  number_of_tries = 0;
-
-  while(number_of_tries<MAX_TRIES)
-    {
-      read_fd_set = active_fd_set;
-      if (select (sockfd+1, &read_fd_set, NULL, NULL, &tv) < 0)
-       {
-         ERROR( M_NAME":tcp_send_msg(): select function failed\n");
-         return AAA_ERROR;
-       }
-      /*
-       if (!FD_ISSET (sockfd, &read_fd_set))
-       {
-       ERROR( M_NAME":tcp_send_rcv(): no response message received\n");
-       //                      return AAA_ERROR;
-       }
-      */
-      /* Data arriving on a already-connected socket. */
-      reset_read_buffer(rb);
-      switch( do_read(sockfd, rb) )
-       {
-       case CONN_ERROR:
-         ERROR( M_NAME": error when trying to read from socket\n");
-         return AAA_CONN_CLOSED;
-       case CONN_CLOSED:
-         ERROR( M_NAME": connection closed by diameter client!\n");
-         return AAA_CONN_CLOSED;
-       }
-               
-      /* obtain the structure corresponding to the message */
-      msg = AAATranslateMessage(rb->buf, rb->buf_len, 0);      
-      if(!msg)
-       {
-         ERROR( M_NAME": message structure not obtained\n");   
-         return AAA_ERROR;
-       }
-      avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID,
-                              0 /* vendorID */, AAA_FORWARD_SEARCH);
-      if(!avp)
-       {
-         ERROR( M_NAME": AVP_SIP_MSGID not found\n");
-         return AAA_ERROR;
-       }
-      m_id = *((unsigned int*)(avp->data.s));
-      DBG("######## m_id=%d\n", m_id);
-      if(m_id!=waited_id)
-       {
-         number_of_tries ++;
-         DBG(M_NAME": old message received\n");
-         continue;
-       }
-      goto next;
-    }
-
-  ERROR( M_NAME": too many old messages received\n");
-  return AAA_TIMEOUT;
- next:
-  /* Finally die correct answer */
-  avp = AAAFindMatchingAVP(msg, NULL, AVP_Service_Type,
-                          0 /* vendorID */, AAA_FORWARD_SEARCH);
-  if(!avp)
-    {
-      ERROR( M_NAME": AVP_Service_Type not found\n");
-      return AAA_ERROR;
-    }
-  serviceType = avp->data.s[0];
-
-  result_code = ntohl(*((unsigned long int*)(msg->res_code->data.s)));
-  switch(result_code)
-    {
-    case AAA_SUCCESS:                                  /* 2001 */
-      rb->ret_code = AAA_AUTHORIZED;
-      break;
-    case AAA_AUTHENTICATION_REJECTED:  /* 4001 */
-      if(serviceType!=SIP_AUTH_SERVICE)
-       {
-         rb->ret_code = AAA_NOT_AUTHORIZED;
-         break;
-       }
-      avp = AAAFindMatchingAVP(msg, NULL, AVP_Challenge,
-                              0 /* vendorID */, AAA_FORWARD_SEARCH);
-      if(!avp)
-       {
-         ERROR( M_NAME": AVP_Response not found\n");
-         rb->ret_code = AAA_SRVERR;
-         break;
-       }
-      rb->chall_len=avp->data.len;
-      rb->chall = (unsigned char*)pkg_malloc(avp->data.len*sizeof(char));
-      if(rb->chall == NULL)
-       {
-         ERROR( M_NAME": no more free memory\n");
-         rb->ret_code = AAA_SRVERR;
-         break;
-       }
-      memcpy(rb->chall, avp->data.s, avp->data.len);
-      rb->ret_code = AAA_CHALENGE;
-      break;
-    case AAA_AUTHORIZATION_REJECTED:   /* 5003 */
-      rb->ret_code = AAA_NOT_AUTHORIZED;
-      break;
-    default:                                                   /* error */
-      rb->ret_code = AAA_SRVERR;
-    }
-       
-  return rb->ret_code; 
+  pkg_free(conn_st);
 }
-
-void close_tcp_connection(int sfd)
-{
-  shutdown(sfd, 2);
-}
-
-

Modified: trunk/apps/diameter_client/lib_dbase/tcp_comm.h
===================================================================
--- trunk/apps/diameter_client/lib_dbase/tcp_comm.h     2008-12-19 18:48:00 UTC 
(rev 1212)
+++ trunk/apps/diameter_client/lib_dbase/tcp_comm.h     2008-12-19 19:12:57 UTC 
(rev 1213)
@@ -4,6 +4,7 @@
  * Digest Authentication - Diameter support
  *
  * Copyright (C) 2001-2003 FhG Fokus
+ * Copyright (C) 2008 iptego GmbH
  *
  * This file is part of ser, a free SIP server.
  *
@@ -40,6 +41,10 @@
 
 #include "sys/time.h"
 
+#ifdef WITH_OPENSSL
+#include <openssl/ssl.h>
+#endif
+
 #define MAX_WAIT_SEC   2
 #define MAX_WAIT_USEC  0
 
@@ -49,25 +54,46 @@
 #define CONN_ERROR     -1
 #define CONN_CLOSED    -2
 
+#ifdef  __cplusplus
+extern "C" {
+#endif
 
-void reset_read_buffer(rd_buf_t *rb);
-int do_read( int socket, rd_buf_t *p);
+#ifdef WITH_OPENSSL
+  extern BIO* bio_err;
+#endif
 
+  struct dia_tcp_conn_t {
+    int sockfd;
+#ifdef WITH_OPENSSL
+    SSL_CTX* ctx;
+    SSL* ssl;
+    BIO* sbio;
+#endif
+  };
 
-/* it initializes the TCP connection */ 
-int init_mytcp(const char* host, int port);
+  typedef  struct dia_tcp_conn_t dia_tcp_conn;
 
-/* send a message over an already opened TCP connection */
-int tcp_send(int sockfd, char* buf, int len);
-/* receive reply
- */
-int tcp_recv_reply(int sockfd, rd_buf_t* rb, AAAMessage** msg, 
-                  time_t wait_sec, suseconds_t wait_usec);
+  /* initializes the lib/module */ 
+  int tcp_init_tcp();
 
-/* send a message over an already opened TCP connection */
-int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* resp,
-                                        unsigned int id);
+  /* initializes the TCP connection */ 
+  dia_tcp_conn* tcp_create_connection(const char* host, int port,
+                                     const char* CA_file, const char* 
client_cert_file);
 
-void close_tcp_connection(int sfd);
+  /* send a message over an already opened TCP connection */
+  int tcp_send(dia_tcp_conn* conn_st, char* buf, int len);
 
+  /* receive reply
+   */
+  int tcp_recv_msg(dia_tcp_conn* conn_st, rd_buf_t* rb,  
+                    time_t wait_sec, suseconds_t wait_usec);
+
+  void tcp_close_connection(dia_tcp_conn* conn_st);
+
+  void tcp_destroy_connection(dia_tcp_conn* conn_st);
+
+#ifdef  __cplusplus
+}
 #endif
+
+#endif

Modified: trunk/core/ampi/DiameterClientAPI.h
===================================================================
--- trunk/core/ampi/DiameterClientAPI.h 2008-12-19 18:48:00 UTC (rev 1212)
+++ trunk/core/ampi/DiameterClientAPI.h 2008-12-19 19:12:57 UTC (rev 1213)
@@ -20,6 +20,7 @@
 //   unsigned int app_id
 //   unsigned int vendor_id
 //   string product_name
+//   unsigned int timeout // millisec
 
 
 // sendRequest
@@ -55,4 +56,15 @@
   { }
 };
 
+struct DiameterTimeoutEvent 
+  : public AmEvent
+{
+  unsigned int req_id;
+
+  DiameterTimeoutEvent(unsigned int req_id)
+    : AmEvent(1), req_id(req_id) 
+  { }
+};
+
+
 #endif

_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev

Reply via email to