Browse code

DIAMETER client implementation to be used by SEMS apps and modules

git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@565 8eb893ce-cfd4-0310-b710-fb5ebe64c474

Stefan Sayer authored on 16/12/2007 22:59:28
Showing 17 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,150 @@
1
+/*
2
+ * $Id: ServerConnection.cpp 463 2007-09-28 11:54:19Z sayer $
3
+ *
4
+ * Copyright (C) 2007 iptego GmbH
5
+ *
6
+ * This file is part of SEMS, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * sems is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+#include "DiameterClient.h"
29
+
30
+#include "log.h"
31
+//#include <stdlib.h>
32
+
33
+#define MOD_NAME "diameter_client"
34
+
35
+#include <vector>
36
+using std::vector;
37
+
38
+EXPORT_PLUGIN_CLASS_FACTORY(DiameterClient, MOD_NAME);
39
+
40
+DiameterClient* DiameterClient::_instance=0;
41
+
42
+DiameterClient* DiameterClient::instance()
43
+{
44
+  if(_instance == NULL){
45
+    _instance = new DiameterClient(MOD_NAME);
46
+  }
47
+  return _instance;
48
+}
49
+
50
+DiameterClient::DiameterClient(const string& name) 
51
+  : AmDynInvokeFactory(name)
52
+{
53
+}
54
+
55
+DiameterClient::~DiameterClient() {
56
+}
57
+
58
+int DiameterClient::onLoad() {
59
+  DBG("DiameterClient loaded.\n");
60
+  return 0;
61
+}
62
+
63
+void DiameterClient::newConnection(const AmArg& args, 
64
+				   AmArg& ret) {
65
+  string app_name     = args.get(0).asCStr();
66
+  string server_ip    = args.get(1).asCStr();
67
+  int    server_port  = args.get(2).asInt();
68
+  string origin_host  = args.get(3).asCStr();
69
+  string origin_realm = args.get(4).asCStr();
70
+  string origin_ip    = args.get(5).asCStr();
71
+  int    app_id       = args.get(6).asInt();
72
+  int    vendor_id    = args.get(7).asInt();
73
+  string product_name = args.get(8).asCStr();
74
+
75
+  ServerConnection* sc = new ServerConnection();
76
+  DBG("initializing new connection for application %s...\n",
77
+      app_name.c_str());
78
+  sc->init(server_ip, server_port, 
79
+	   origin_host, origin_realm, origin_ip, 
80
+	   app_id, vendor_id, product_name);
81
+  DBG("starting new connection...\n");
82
+  sc->start();
83
+  DBG("registering connection...\n");
84
+  conn_mut.lock();
85
+  connections.insert(make_pair(app_name, sc));
86
+  conn_mut.unlock();
87
+
88
+  ret.push(0);
89
+  ret.push("new connection registered");
90
+  return;
91
+}
92
+
93
+void DiameterClient::sendRequest(const AmArg& args, 
94
+				 AmArg& ret) {
95
+  string app_name     = args.get(0).asCStr();
96
+  int    command_code = args.get(1).asInt();
97
+  int    app_id       = args.get(2).asInt();
98
+  AmArg& val          = args.get(3);
99
+  string sess_link    = args.get(4).asCStr();
100
+
101
+  vector<ServerConnection*> scs;    
102
+  conn_mut.lock();
103
+  for (multimap<string, ServerConnection*>::iterator it=
104
+	 connections.lower_bound(app_name);
105
+       it != connections.upper_bound(app_name); it++) {
106
+    if (it->second->is_open())
107
+      scs.push_back(it->second);
108
+  }
109
+  conn_mut.unlock();
110
+
111
+  DBG("found %d active connections for application %s\n", 
112
+      scs.size(), app_name.c_str());
113
+
114
+  if (scs.empty()) {
115
+    // no connections found
116
+    ret.push(-1);
117
+    ret.push("no active connections");
118
+    return;
119
+  }
120
+  // select one connection randomly 
121
+  size_t pos = random() % scs.size();
122
+  scs[pos]->postEvent(new DiameterRequestEvent(command_code, app_id, 
123
+					       val, sess_link));
124
+  ret.push(0);
125
+  ret.push("request sent");
126
+  return;
127
+}
128
+
129
+void DiameterClient::invoke(const string& method, const AmArg& args, 
130
+			    AmArg& ret)
131
+{
132
+  if(method == "newConnection"){
133
+    args.assertArrayFmt("ssisssiis");
134
+    newConnection(args, ret);
135
+  } else if(method == "sendRequest"){
136
+    args.assertArrayFmt("siias");
137
+    // check values
138
+    AmArg& vals = args.get(3);
139
+    for (size_t i=0;i<vals.size(); i++) {
140
+      AmArg& row = vals.get(i);
141
+      //    [int avp_id, int flags, int vendor, blob data]
142
+      row.assertArrayFmt("iiib");
143
+    }
144
+    sendRequest(args, ret);
145
+  } else if(method == "_list"){ 
146
+    ret.push(AmArg("newConnection"));
147
+    ret.push(AmArg("sendRequest"));
148
+  }  else
149
+    throw AmDynInvoke::NotImplemented(method);
150
+}
0 151
new file mode 100644
... ...
@@ -0,0 +1,69 @@
1
+/*
2
+ * $Id: ServerConnection.cpp 463 2007-09-28 11:54:19Z sayer $
3
+ *
4
+ * Copyright (C) 2007 iptego GmbH
5
+ *
6
+ * This file is part of SEMS, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * sems is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+#ifndef _DIAMETER_CLIENT_H
29
+#define _DIAMETER_CLIENT_H
30
+
31
+#include "AmApi.h"
32
+
33
+#include "ServerConnection.h"
34
+
35
+#include <string>
36
+#include <map>
37
+using std::string;
38
+using std::multimap;
39
+
40
+class DiameterClient  
41
+: public AmDynInvokeFactory,
42
+  public AmDynInvoke
43
+{
44
+
45
+  static DiameterClient* _instance;
46
+
47
+  multimap<string, ServerConnection*> connections;
48
+  AmMutex conn_mut;
49
+
50
+  void newConnection(const AmArg& args, AmArg& ret);
51
+  void sendRequest(const AmArg& args, AmArg& ret);
52
+
53
+ public:
54
+  DiameterClient(const string& name);
55
+  ~DiameterClient();
56
+
57
+  // DI factory
58
+  AmDynInvoke* getInstance() { return instance(); }
59
+
60
+  // DI API
61
+  static DiameterClient* instance();
62
+  void invoke(const string& method, 
63
+	      const AmArg& args, AmArg& ret);
64
+
65
+  // DI-factory
66
+  int onLoad();	
67
+};
68
+
69
+#endif
0 70
new file mode 100644
... ...
@@ -0,0 +1,19 @@
1
+plug_in_name = diameter_client
2
+
3
+DIAMETER_BASE_LIBDIR = lib_dbase/
4
+DIAMETER_BASE_LIBNAME = lib_dbase.a
5
+
6
+module_ldflags =
7
+module_cflags  = -I $(DIAMETER_BASE_LIBDIR)
8
+
9
+module_extra_objs = $(DIAMETER_BASE_LIBDIR)$(DIAMETER_BASE_LIBNAME)
10
+extra_clean = baseclean
11
+
12
+COREPATH ?=../../core
13
+include $(COREPATH)/plug-in/Makefile.app_module
14
+
15
+$(DIAMETER_BASE_LIBDIR)$(DIAMETER_BASE_LIBNAME):
16
+	make -C $(DIAMETER_BASE_LIBDIR) $(DIAMETER_BASE_LIBNAME)
17
+
18
+baseclean:
19
+	make -C $(DIAMETER_BASE_LIBDIR) clean
0 20
new file mode 100644
... ...
@@ -0,0 +1,139 @@
1
+
2
+diameter client                   (C) 2007 iptego GmbH
3
+---------------
4
+
5
+this is a very simple DIAMETER client implementation. it does 
6
+implement only parts of the base protocol, and is not a complete 
7
+DIAMETER implementation.
8
+
9
+it is used from other modules with the DI API - i.e. other modules 
10
+can execute DI functions to add a server connection, or send a 
11
+DIAMETER request.
12
+
13
+the DIAMETER base implementation is based on ser-0.9.6 diameter_auth 
14
+module by Elena-Ramona Modroiu,  Copyright � 2003, 2004 FhG FOKUS.
15
+connection pool and asynchronous message handling has been added, 
16
+together with the CER/CEA handshake and other things.
17
+
18
+be prepared that you will need to look into the source to see how this 
19
+works, and you will need to build up your request AVPs by hand by 
20
+assembling an AmArg with the AVPs as ArgBlobs, and also unpack the 
21
+results/a received event from an AmArg array yourself.
22
+
23
+WHY?
24
+----
25
+It seems that there is no simple to use free DIAMETER client implementation
26
+available. 
27
+ - OpenDIAMETER is probably a complete solution, but seems to 
28
+be very complex to use. 
29
+ - DISC  (http://developer.berlios.de/projects/disc/) is of 2003, seems to 
30
+   be quite complete but assumes to be a complete server
31
+ - openimscore cdp module would probably have been a better basis 
32
+   than ser 0.9.6's auth diameter. well...
33
+
34
+BUGS/TODO
35
+---------
36
+ o CEA needs probably be fixed to specific AVP set
37
+ o mandatory AVP checking in compund AVP not implemented
38
+ 
39
+
40
+API
41
+---
42
+o connections are added with new_connection; connections are pooled for 
43
+  an application, and are retried periodically if broken. only active 
44
+  connections are used when sending a request (obviously)
45
+
46
+o replies to requests are posted as event to the session/module 
47
+  (identified by sess_link)
48
+
49
+new_connection
50
+  string app_name
51
+  string server_ip
52
+  unsigned int server_port
53
+  string origin_host
54
+  string origin_realm
55
+  string origin_ip
56
+  unsigned int app_id
57
+  unsigned int vendor_id
58
+  string product_name
59
+
60
+send_request
61
+  string app_name
62
+  unsigned int command_code
63
+  unsigned int app_id
64
+  arg val
65
+  string sess_link
66
+
67
+  args:  array
68
+    [int avp_id, int flags, int vendor, blob data]
69
+
70
+ returns :
71
+   DIA_OK
72
+   DIA_ERR_NOAPP
73
+   DIA_ERR_NOCONN
74
+
75
+reply events : 
76
+  ... 
77
+
78
+
79
+some testing code
80
+----------------
81
+
82
+else if(method == "test1"){
83
+    AmArg a; 
84
+    a.push(AmArg("vtm"));
85
+    a.push(AmArg("10.1.0.196"));
86
+    a.push(AmArg(8080));
87
+    a.push(AmArg("vtm01"));
88
+    a.push(AmArg("vtm.t-online.de"));
89
+    a.push(AmArg("10.42.32.13"));
90
+    a.push(AmArg(16777241));
91
+    a.push(AmArg(29631));
92
+    a.push(AmArg("vtm"));
93
+    a.assertArrayFmt("ssisssiis");
94
+    newConnection(a, ret);
95
+  } else if(method == "test2"){
96
+    AmArg a; 
97
+#define AAA_APP_USPI    16777241
98
+#define AVP_E164_NUMBER     1024
99
+#define AAA_VENDOR_IPTEGO  29631
100
+#define AAA_LAR         16777214
101
+
102
+    a.push(AmArg("vtm"));
103
+    a.push(AmArg(AAA_LAR));
104
+    a.push(AmArg(AAA_APP_USPI));
105
+    DBG("x pushin \n");
106
+    AmArg avps;
107
+
108
+    AmArg e164;
109
+    e164.push((int)AVP_E164_NUMBER);
110
+    e164.push((int)AAA_AVP_FLAG_VENDOR_SPECIFIC | AAA_AVP_FLAG_MANDATORY);
111
+    e164.push((int)AAA_VENDOR_IPTEGO);
112
+    string e164_number = "+49331600001";
113
+    e164.push(ArgBlob(e164_number.c_str(), e164_number.length()));
114
+    avps.push(e164);
115
+
116
+    AmArg drealm;
117
+    drealm.push((int)AVP_Destination_Realm);
118
+    drealm.push((int)AAA_AVP_FLAG_MANDATORY);
119
+    drealm.push((int)0);
120
+    string dest_realm = "iptego.de";
121
+    drealm.push(ArgBlob(dest_realm.c_str(), dest_realm.length()));
122
+    avps.push(drealm);
123
+
124
+    a.push(avps);
125
+    a.push(AmArg("bogus_link"));
126
+
127
+    // check...
128
+    a.assertArrayFmt("siias");
129
+
130
+    // check values
131
+    AmArg& vals = a.get(3);
132
+    for (size_t i=0;i<vals.size(); i++) {
133
+      AmArg& row = vals.get(i);
134
+      //    [int avp_id, int flags, int vendor, blob data]
135
+      row.assertArrayFmt("iiib");
136
+    }
137
+    DBG("x sendrequest\n");
138
+    sendRequest(a, ret);
139
+
0 140
new file mode 100644
... ...
@@ -0,0 +1,526 @@
1
+/*
2
+ * $Id: ServerConnection.cpp 463 2007-09-28 11:54:19Z sayer $
3
+ *
4
+ * Copyright (C) 2007 iptego GmbH
5
+ *
6
+ * This file is part of SEMS, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * sems is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+#include "ServerConnection.h"
29
+#include "AmSessionContainer.h"
30
+#include "ampi/DiameterClientAPI.h"
31
+#include "diameter_client.h"
32
+
33
+#include <stdlib.h>
34
+#include <string.h>
35
+#include "log.h"
36
+
37
+#include <sys/socket.h>
38
+#include <netinet/in.h>
39
+#include <arpa/inet.h>
40
+#include <sys/time.h>
41
+
42
+#define CONN_WAIT_MAX   4      // 10  (*50ms = 0.5s)
43
+#define CONN_WAIT_USECS 50000  // 50 ms
44
+
45
+#define MAX_RETRANSMIT_RCV_RETRY 4
46
+
47
+// #define EXTRA_DEBUG 
48
+
49
+#define CONNECT_CEA_REPLY_TIMEOUT 2 // seconds
50
+#define RETRY_CONNECTION_INTERVAL 2 // seconds
51
+
52
+DiameterServerConnection::DiameterServerConnection()  
53
+  : in_use(false), sockfd(-1) { 
54
+  memset(&rb, 0, sizeof(rd_buf_t));
55
+  h2h = random();
56
+  e2e = (time(NULL) & 0xFFF << 20) | (random() % 0xFFFFF);
57
+}
58
+
59
+
60
+void DiameterServerConnection::terminate() {
61
+  if (sockfd>0)
62
+    close_tcp_connection(sockfd);
63
+
64
+  sockfd = -1;
65
+}
66
+
67
+void DiameterServerConnection::setIDs(AAAMessage* msg) {
68
+  msg->endtoendId = e2e++;
69
+  msg->hopbyhopId = h2h++;
70
+}
71
+
72
+void ServerConnection::process(AmEvent* ev) {
73
+  DiameterRequestEvent* re = dynamic_cast<DiameterRequestEvent*>(ev);
74
+  if (NULL == re) {
75
+    ERROR("received Event with wrong type!\n");
76
+    return;
77
+  }
78
+  DBG(" making new request\n");
79
+
80
+  AAAMessage* req = ReqEvent2AAAMessage(re);
81
+
82
+  // end2end id, used to correlate req/reply
83
+  unsigned int exe;
84
+
85
+  if (sendRequest(req, exe)) {
86
+    ERROR("sending request\n");
87
+    return;
88
+  }
89
+
90
+  DBG("sent request with ID %d\n", exe);
91
+  struct timeval now;
92
+  gettimeofday(&now, NULL);
93
+
94
+  req_map_mut.lock();
95
+  req_map[exe] = make_pair(re->sess_link, now);
96
+  req_map_mut.unlock();
97
+}
98
+
99
+ServerConnection::ServerConnection() 
100
+  : server_port(-1), open(false),
101
+    AmEventQueue(this)
102
+{
103
+}
104
+
105
+ServerConnection::~ServerConnection() {
106
+  DBG("closing diameter server connection.\n");
107
+  conn.terminate();
108
+}
109
+
110
+int ServerConnection::init(const string& _server_name, 
111
+			 int _server_port,
112
+			 const string& _origin_host, 
113
+			 const string& _origin_realm,
114
+			 const string& _origin_ip,
115
+			 AAAApplicationId _app_id,
116
+			 unsigned int _vendorID,
117
+			 const string& _product_name) {
118
+  server_name = _server_name;
119
+  server_port = _server_port;
120
+  origin_host = _origin_host;
121
+  origin_realm = _origin_realm;
122
+  origin_ip = _origin_ip;
123
+  product_name = _product_name;
124
+  app_id = htonl(_app_id);
125
+  // todo: separate vendor for client/app
126
+  vendorID = htonl(_vendorID);
127
+
128
+  memset(origin_ip_address, 0, sizeof(origin_ip_address));
129
+  origin_ip_address[0] = 0;
130
+  origin_ip_address[1] = AF_IP4;
131
+
132
+  struct in_addr inp;
133
+  if (inet_aton(origin_ip.c_str(), &inp) == 0) {
134
+    ERROR("origin_ip %s could not be decoded.\n", 
135
+	  origin_ip.c_str());
136
+  } else {
137
+    origin_ip_address[2] =  inp.s_addr & 0xFF;
138
+    origin_ip_address[3] = (inp.s_addr & 0xFF00)     >> 8;
139
+    origin_ip_address[4] = (inp.s_addr & 0xFF0000)   >> 16;
140
+    origin_ip_address[5] = (inp.s_addr & 0xFF000000) >> 24;
141
+  }
142
+
143
+  // set connect_ts to past so it try to connect
144
+  memset(&connect_ts, 0, sizeof(struct timeval));
145
+
146
+  return 0;
147
+}
148
+
149
+void ServerConnection::openConnection() {
150
+  DBG("init TCP connection\n");
151
+  int res = init_mytcp(server_name.c_str(), server_port);
152
+  if (res < 0) {
153
+    ERROR("establishing connection to %s\n", 
154
+	  server_name.c_str());
155
+    setRetryConnectLater();
156
+    return;
157
+  }
158
+  conn.sockfd = res;
159
+
160
+  // send CER
161
+  AAAMessage* cer;
162
+  if ((cer=AAAInMessage(AAA_CC_CER, AAA_APP_DIAMETER_COMMON_MSG))==NULL) {
163
+    ERROR(M_NAME":openConnection(): can't create new "
164
+	  "CER AAA message!\n");
165
+    conn.terminate();
166
+    setRetryConnectLater();
167
+    return;
168
+  }
169
+  if (addOrigin(cer) 
170
+      || addDataAVP(cer, AVP_Host_IP_Address, origin_ip_address, sizeof(origin_ip_address)) 
171
+      || addDataAVP(cer, AVP_Vendor_Id, (char*)&vendorID, sizeof(vendorID)) 
172
+      || addDataAVP(cer, AVP_Supported_Vendor_Id, (char*)&vendorID, sizeof(vendorID)) 
173
+      || addStringAVP(cer, AVP_Product_Name, product_name)) {
174
+    ERROR("openConnection(): adding AVPs failed\n");
175
+    conn.terminate();
176
+    setRetryConnectLater();
177
+    return;
178
+  }
179
+
180
+  // supported applications
181
+  AAA_AVP* vs_appid;
182
+  if( (vs_appid=AAACreateAVP(AVP_Vendor_Specific_Application_Id, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, 0, 
183
+			     0, AVP_DONT_FREE_DATA)) == 0) {
184
+    ERROR( M_NAME":openConnection(): creating AVP failed."
185
+	   " (no more free memory!)\n");
186
+    conn.terminate();
187
+    setRetryConnectLater();
188
+    return;
189
+  }
190
+
191
+  // feels like c coding...
192
+  if (addGroupedAVP(vs_appid, AVP_Auth_Application_Id, 
193
+		    (char*)&app_id, sizeof(app_id)) ||
194
+      addGroupedAVP(vs_appid, AVP_Vendor_Id, 
195
+		    (char*)&vendorID, sizeof(vendorID)) ||
196
+      (AAAAddAVPToMessage(cer, vs_appid, 0) != AAA_ERR_SUCCESS)
197
+      ) {
198
+    ERROR( M_NAME":makeConnections(): creating AVP failed."
199
+	   " (no more free memory!)\n");
200
+    conn.terminate();
201
+    setRetryConnectLater();
202
+    return;
203
+  }
204
+
205
+#ifdef EXTRA_DEBUG 
206
+  AAAPrintMessage(cer);
207
+#endif
208
+
209
+  conn.setIDs(cer);
210
+  
211
+  if(AAABuildMsgBuffer(cer) != AAA_ERR_SUCCESS) {
212
+    ERROR( " makeConnections(): message buffer not created\n");
213
+    AAAFreeMessage(&cer);
214
+    return;
215
+  }
216
+  
217
+  int ret = tcp_send(conn.sockfd, cer->buf.s, cer->buf.len);
218
+  if (ret) {
219
+    ERROR( "openConnection(): could not send message\n");
220
+    conn.terminate();
221
+    setRetryConnectLater();
222
+    AAAFreeMessage(&cer);
223
+    return;
224
+  }
225
+  
226
+  AAAMessage* cea = NULL;
227
+  res = tcp_recv_reply(conn.sockfd, &conn.rb, &cea, 
228
+		       CONNECT_CEA_REPLY_TIMEOUT, 0);
229
+  if (res) {
230
+    ERROR( " makeConnections(): did not receive CEA reply.\n");
231
+    conn.terminate();
232
+    setRetryConnectLater();
233
+    AAAFreeMessage(&cer);
234
+    return;
235
+  }
236
+  
237
+#ifdef EXTRA_DEBUG 
238
+  if (cea != NULL)
239
+    AAAPrintMessage(cea);
240
+#endif
241
+  
242
+  DBG("Connection opened.\n");
243
+  open = true;
244
+}
245
+
246
+AAAMessage* ServerConnection::ReqEvent2AAAMessage(DiameterRequestEvent* re) {
247
+  AAAMessage* req = AAAInMessage(re->command_code, re->app_id);
248
+  if (req == NULL) {
249
+    ERROR("creating new request message.\n");
250
+    return NULL;
251
+  }
252
+  
253
+  for (int i=re->val.size()-1;i >= 0; i--) {
254
+    //[int avp_id, int flags, int vendor, int len, blob data]
255
+    
256
+    AmArg& row = re->val.get(i);
257
+    int avp_id    = row.get(0).asInt();
258
+    int flags     = row.get(1).asInt();
259
+    int vendor    = row.get(2).asInt();
260
+    ArgBlob* data = row.get(3).asBlob();
261
+
262
+
263
+#ifdef EXTRA_DEBUG
264
+    DBG("adding avp id %d, flags %d, vendor %d\n", avp_id, flags, vendor);
265
+#endif 
266
+
267
+    if (!data->len) {
268
+#ifdef EXTRA_DEBUG
269
+      DBG("skipping empty AVP id %d\n", avp_id);
270
+#endif 
271
+      continue;
272
+    }
273
+
274
+    AAA_AVP *avp;
275
+    if( (avp=AAACreateAVP(avp_id, (AAA_AVPFlag)flags, vendor, data->data,
276
+			  data->len, AVP_DUPLICATE_DATA)) == 0) {
277
+      ERROR( M_NAME ": addDataAVP() no more free memory!\n");
278
+      continue;
279
+    }
280
+    
281
+    if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) {
282
+      ERROR( M_NAME ": addDataAVP(): AVP not added!\n");
283
+      continue;
284
+    }
285
+  }
286
+  return req;
287
+}
288
+
289
+// add origin host and origin realm
290
+int ServerConnection::addOrigin(AAAMessage* msg) {
291
+  return addStringAVP(msg, AVP_Origin_Host, origin_host, true) || 
292
+    addStringAVP(msg, AVP_Origin_Realm, origin_realm, true);
293
+}
294
+
295
+
296
+int ServerConnection::addStringAVP(AAAMessage* msg, AAA_AVPCode avp_code, string& val, 
297
+				   bool attail) {
298
+  AAA_AVP *avp;
299
+  if( (avp=AAACreateAVP(avp_code, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, val.c_str(),
300
+			val.length(), AVP_DUPLICATE_DATA)) == 0) {
301
+    ERROR( M_NAME ": addStringAVP() no more free memory!\n");
302
+    return -1;
303
+  }
304
+
305
+  AAA_AVP *pos = 0;
306
+  if (attail)
307
+    pos = msg->avpList.tail;
308
+
309
+  if( AAAAddAVPToMessage(msg, avp, pos)!= AAA_ERR_SUCCESS) {
310
+    ERROR( M_NAME ": addStringAVP(): AVP not added!\n");
311
+    return -1;
312
+  }
313
+  return 0;
314
+}
315
+
316
+int ServerConnection::addResultCodeAVP(AAAMessage* msg, AAAResultCode code) {
317
+  uint32_t n_code = htonl(code);
318
+  return addDataAVP(msg, AVP_Result_Code, (char*)&n_code, sizeof(n_code));
319
+}
320
+
321
+int ServerConnection::addDataAVP(AAAMessage* msg, AAA_AVPCode avp_code, char* val, unsigned int len) {
322
+   AAA_AVP *avp;
323
+   if( (avp=AAACreateAVP(avp_code, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, val,
324
+			 len, AVP_DUPLICATE_DATA)) == 0) {
325
+     ERROR( M_NAME ": addDataAVP() no more free memory!\n");
326
+     return -1;
327
+   }
328
+
329
+  if( AAAAddAVPToMessage(msg, avp, 0)!= AAA_ERR_SUCCESS) {
330
+    ERROR( M_NAME ": addDataAVP(): AVP not added!\n");
331
+    return -1;
332
+  }
333
+  return 0;
334
+}
335
+
336
+// add a new group member AVP
337
+int ServerConnection::addGroupedAVP(AAA_AVP *avp, AAA_AVPCode avp_code, 
338
+				  char* val, unsigned int len) {
339
+  AAA_AVP *m_avp;
340
+
341
+  if( (m_avp=AAACreateAVP(avp_code, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, val, 
342
+			  len, AVP_DUPLICATE_DATA)) == 0) {
343
+    ERROR( M_NAME":addGroupedAVP(): no more free memory!\n");
344
+    return -1;
345
+  }
346
+  AAAAddGroupedAVP(avp, m_avp);
347
+  return 0;
348
+}
349
+
350
+// send request and get response  
351
+int ServerConnection::sendRequest(AAAMessage* req, unsigned int& exe) {
352
+  if (addOrigin(req)) {
353
+    return AAA_ERROR_MESSAGE;
354
+  }
355
+
356
+  conn.setIDs(req);
357
+
358
+  if(AAABuildMsgBuffer(req) != AAA_ERR_SUCCESS) {
359
+    ERROR( " sendRequest(): message buffer not created\n");
360
+    return AAA_ERROR_MESSAGE;
361
+  }
362
+  
363
+  int ret = tcp_send(conn.sockfd, req->buf.s, req->buf.len);
364
+  if (ret) {
365
+    ERROR( " sendRequest(): could not send message\n");
366
+    AAAFreeMessage(&req);
367
+    return AAA_ERROR_COMM;
368
+  }
369
+
370
+  exe = req->endtoendId;
371
+
372
+  DBG("msg sent...\n");
373
+  return 0;
374
+}
375
+
376
+int ServerConnection::handleRequest(AAAMessage* req) {
377
+  switch (req->commandCode) {
378
+  case AAA_CC_DWR: { // Device-Watchdog-Request
379
+    DBG("Device-Watchdog-Request received\n");
380
+
381
+    AAAMessage* reply;
382
+    if ( (reply=AAAInMessage(AAA_CC_DWA, AAA_APP_DIAMETER_COMMON_MSG))==NULL) {
383
+      ERROR(M_NAME":handleRequest(): can't create new "
384
+	    "DWA message!\n");
385
+      return -1;
386
+    }
387
+
388
+    AAAMessageSetReply(reply);
389
+    
390
+    if (addOrigin(reply) || addResultCodeAVP(reply, AAA_SUCCESS)) {
391
+      return AAA_ERROR_MESSAGE;
392
+    }
393
+
394
+    reply->endtoendId = req->endtoendId;
395
+    reply->hopbyhopId = req->hopbyhopId;
396
+
397
+    if(AAABuildMsgBuffer(reply) != AAA_ERR_SUCCESS) {
398
+      ERROR( " sendRequest(): message buffer not created\n");
399
+      AAAFreeMessage(&reply);
400
+      return AAA_ERROR_MESSAGE;
401
+    }
402
+    
403
+    DBG("sending Device-Watchdog-Answer...\n");
404
+    int ret = tcp_send(conn.sockfd, reply->buf.s, reply->buf.len);
405
+    if (ret) {
406
+      ERROR( " sendRequest(): could not send message\n");
407
+      open = false;
408
+      AAAFreeMessage(&reply);
409
+      return AAA_ERROR_COMM;
410
+    }
411
+    AAAFreeMessage(&reply);
412
+    return 0;
413
+
414
+  }; break;
415
+
416
+  case AAA_CC_DPR: { // Disconnect-Peer-Request
417
+    DBG("Disconnect-Peer-Request not yet implemented\n");
418
+  }; break;
419
+
420
+  default: {
421
+    ERROR("ignoring unknown request with command code %i\n", 
422
+	  req->commandCode);
423
+  }; break;
424
+  }
425
+
426
+  return 0;
427
+}
428
+
429
+int ServerConnection::handleReply(AAAMessage* rep) {
430
+  unsigned int rep_id = rep->endtoendId;
431
+  DBG("received reply - id %d\n", rep_id);
432
+
433
+  string sess_link  = "";
434
+  req_map_mut.lock();
435
+  map<unsigned int, pair<string, struct timeval> >::iterator it =  
436
+    req_map.find(rep_id);
437
+  if (it != req_map.end()) {
438
+    sess_link = it->second.first;
439
+    req_map.erase(it);
440
+  } else {
441
+    DBG("session link for reply not found\n");
442
+  }
443
+  req_map_mut.unlock();
444
+
445
+  if (!sess_link.empty()) {
446
+    DiameterReplyEvent* r_ev = 
447
+      new DiameterReplyEvent((unsigned int)rep->commandCode, (unsigned int)rep->applicationId, 
448
+			     AAAMessageAVPs2AmArg(rep));
449
+    if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
450
+      DBG("unhandled reply\n");
451
+    }    
452
+  }
453
+
454
+  return 0;
455
+}
456
+
457
+AmArg ServerConnection::AAAMessageAVPs2AmArg(AAAMessage* rep) {
458
+  AmArg res;
459
+  for(AAA_AVP* avp=rep->avpList.head;avp;avp=avp->next) {
460
+    AmArg a_avp;
461
+    a_avp.push((int)avp->code);
462
+    a_avp.push((int)avp->flags);
463
+    a_avp.push((int)avp->vendorId);
464
+    a_avp.push((int)avp->type);
465
+    a_avp.push(ArgBlob(avp->data.s, avp->data.len));
466
+    res.push(a_avp);
467
+  }
468
+  return res;
469
+}
470
+
471
+void ServerConnection::setRetryConnectLater() {
472
+  gettimeofday(&connect_ts, NULL);
473
+  connect_ts.tv_sec += RETRY_CONNECTION_INTERVAL;
474
+}
475
+
476
+void ServerConnection::on_stop() {
477
+  DBG("todo: stop connection.\n");
478
+}
479
+
480
+void ServerConnection::receive() {
481
+  AAAMessage *response = NULL;
482
+  int res = tcp_recv_reply(conn.sockfd, &conn.rb, &response, 
483
+			   0, CONN_WAIT_USECS);
484
+  if (res) {
485
+    ERROR( " receive(): tcp_recv_reply() failed.\n");
486
+    open = false;
487
+  }
488
+
489
+  // nothing received
490
+  if (response == NULL) 
491
+    return;
492
+
493
+    
494
+#ifdef EXTRA_DEBUG 
495
+  AAAPrintMessage(response);
496
+#endif
497
+  
498
+  if (is_req(response)) 
499
+    handleRequest(response);
500
+  else 
501
+    handleReply(response);
502
+  
503
+  AAAFreeMessage(&response);  
504
+}
505
+
506
+void ServerConnection::run() {
507
+  DBG("running server connection\n");
508
+  while (true) {
509
+    if (!open) {
510
+      struct timeval now;
511
+      gettimeofday(&now, NULL);
512
+      
513
+      if(timercmp(&now,&connect_ts,>)){
514
+	DBG("(re)trying to open the connection\n");
515
+	openConnection();
516
+      } else {
517
+	usleep(50000);
518
+      }
519
+    } else {
520
+      receive();
521
+    }
522
+
523
+    processEvents();
524
+  }
525
+}
526
+
0 527
new file mode 100644
... ...
@@ -0,0 +1,156 @@
1
+/*
2
+ * $Id: ServerConnection.cpp 463 2007-09-28 11:54:19Z sayer $
3
+ *
4
+ * Copyright (C) 2007 iptego GmbH
5
+ *
6
+ * This file is part of SEMS, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * sems is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+#ifndef _DIAMETER_SERVER_CONNECTION_H
29
+#define _DIAMETER_SERVER_CONNECTION_H
30
+
31
+#include "diameter_client.h"
32
+
33
+#include "AmThread.h"
34
+#include "AmEventQueue.h"
35
+#include "AmArg.h"
36
+
37
+#include <string>
38
+#include <vector>
39
+#include <map>
40
+#include <utility>
41
+using std::string;
42
+using std::vector;
43
+using std::map;
44
+using std::pair;
45
+
46
+#define AF_IP4 1 // http://www.iana.org/assignments/address-family-numbers
47
+
48
+enum {
49
+  AAA_ERROR_NOTINIT    = -1,
50
+  AAA_ERROR_NOCONN     = -2,
51
+  AAA_ERROR_NOFREECONN = -3,
52
+  AAA_ERROR_TIMEOUT    = -4,
53
+  AAA_ERROR_MESSAGE    = -5,
54
+  AAA_ERROR_COMM       = -6
55
+};
56
+
57
+struct DiameterRequestEvent 
58
+  : public AmEvent
59
+{
60
+  int command_code;
61
+  int app_id;
62
+  AmArg val;
63
+  string sess_link;
64
+
65
+  enum { ID_NewRequest = 0 }; 
66
+  DiameterRequestEvent(int command_code,
67
+		       int app_id,
68
+		       AmArg val,
69
+		       string sess_link)
70
+    : AmEvent(ID_NewRequest), command_code(command_code),
71
+    app_id(app_id), val(val), sess_link(sess_link)
72
+  {
73
+  }
74
+};
75
+
76
+struct DiameterServerConnection {
77
+  bool in_use;
78
+  int sockfd;
79
+  rd_buf_t rb;
80
+
81
+  string origin_host;
82
+
83
+  AAAMsgIdentifier h2h;
84
+  AAAMsgIdentifier e2e;
85
+  void terminate();
86
+
87
+  void setIDs(AAAMessage* msg);
88
+
89
+  DiameterServerConnection();
90
+  ~DiameterServerConnection() {}
91
+};
92
+
93
+class ServerConnection 
94
+: public AmThread,
95
+  public AmEventQueue,
96
+  public AmEventHandler
97
+{
98
+  struct timeval connect_ts;
99
+  bool open;
100
+  
101
+  string server_name;
102
+  int server_port;
103
+  string origin_host;
104
+  string origin_realm;
105
+  string origin_ip;
106
+  AAAApplicationId app_id;
107
+
108
+  char origin_ip_address[2+4];// AF and address
109
+
110
+  //  the client
111
+  string product_name;
112
+  uint32_t vendorID;
113
+  
114
+  DiameterServerConnection conn;
115
+
116
+  map<unsigned int, pair<string, struct timeval> > 
117
+    req_map;
118
+  AmMutex req_map_mut;
119
+
120
+  void openConnection();
121
+
122
+  int addOrigin(AAAMessage* msg);
123
+
124
+  int handleReply(AAAMessage* rep);
125
+  int handleRequest(AAAMessage* req);
126
+  AAAMessage* ReqEvent2AAAMessage(DiameterRequestEvent* re);
127
+  AmArg AAAMessageAVPs2AmArg(AAAMessage* rep);
128
+
129
+  static int addStringAVP(AAAMessage* msg, AAA_AVPCode avp_code, string& val, bool attail = false);
130
+  static int addDataAVP(AAAMessage* msg, AAA_AVPCode avp_code, char* val, unsigned int len);
131
+  static int addResultCodeAVP(AAAMessage* msg, AAAResultCode code);
132
+  static int addGroupedAVP(AAA_AVP *avp, AAA_AVPCode avp_code, char* val, unsigned int len);
133
+
134
+  // send request and get response  
135
+  int sendRequest(AAAMessage* req, unsigned int& exe);
136
+  void process(AmEvent*);
137
+  void receive();
138
+  void setRetryConnectLater();
139
+ public:
140
+  ServerConnection();
141
+  ~ServerConnection();
142
+  int init(const string& _server_name, 
143
+	   int _server_port,
144
+	   const string& _origin_host, 
145
+	   const string& _origin_realm,
146
+	   const string& _origin_ip,
147
+	   AAAApplicationId _app_id,
148
+	   unsigned int _vendorID,
149
+	   const string& _product_name);
150
+
151
+  bool is_open() { return open; }
152
+  void run();
153
+  void on_stop();
154
+};
155
+
156
+#endif
0 157
new file mode 100644
... ...
@@ -0,0 +1,42 @@
1
+lib_name = lib_dbase.a
2
+
3
+.PHONY: all
4
+all: $(lib_name) 
5
+
6
+MCOREPATH ?=../../../core
7
+include $(MCOREPATH)/../Makefile.defs
8
+
9
+
10
+srcs     = $(wildcard *.c)
11
+hrds     = $(wildcard *.h)
12
+objs     = $(srcs:.c=.o) 
13
+depends  = $(srcs:.c=.d)
14
+
15
+cflags  ?= $(CFLAGS) -I $(MCOREPATH) -Wall $(module_cflags)
16
+
17
+AR		= ar
18
+RANLIB		= ranlib
19
+
20
+
21
+.PHONY: clean
22
+clean:
23
+	-@rm -f $(objs) $(depends) $(lib_name)
24
+
25
+.PHONY: deps
26
+deps: $(depends)
27
+
28
+%.d: %.c %.h Makefile 
29
+	$(CC) -MM $< $(cflags) > $@
30
+
31
+%.o: %.c %.d
32
+	$(CC) $(cflags) -c $< -o $@ -fPIC
33
+
34
+$(lib_name): deps $(objs)  Makefile
35
+		if [ -f $(lib_name) ]; then rm $(RMFLAGS) $(lib_name) ; fi
36
+		$(AR) $(ARFLAGS) $(lib_name) $(objs)
37
+		$(RANLIB) $(lib_name)
38
+
39
+ifeq ($(lib_name),$(MAKECMDGOALS))
40
+include $(depends)
41
+endif
42
+
0 43
new file mode 100644
... ...
@@ -0,0 +1,491 @@
1
+/*
2
+ * $Id: avp.c,v 1.3 2004/08/24 08:58:25 janakj Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 FhG Fokus
5
+ *
6
+ * This file is part of disc, a free diameter server/client.
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+
24
+#include <stdio.h>
25
+#include <stdlib.h>
26
+#include <string.h>
27
+#include <sys/types.h>
28
+#include <netinet/in.h>
29
+
30
+
31
+#include "log.h"
32
+#include "diameter_msg.h"
33
+#include "avp.h"
34
+
35
+/*
36
+ * each AVP type has some default set/reset flags and a proper data type.
37
+ * All this default values (for flags and data-type) are correct/set by this
38
+ * function.
39
+ */
40
+inline void set_avp_fields( AAA_AVPCode code, AAA_AVP *avp)
41
+{
42
+  switch (code) {
43
+  case   1: /*AVP_User_Name*/
44
+  case  25: /*AVP_Class*/
45
+  case 263: /*AVP_Session_Id*/
46
+  case 283: /*AVP_Destination_Realm*/
47
+  case 293: /*AVP Destination Host*/
48
+  case 264: /*AVP_Origin_Host*/
49
+  case 296: /*AVP Origin_Realm*/
50
+  case 400: /* AVP_Resource */	
51
+  case 401: /* AVP_Response */	
52
+  case 402: /* AVP_Chalenge */	
53
+  case 403: /* AVP_Method */
54
+  case 404: /* Service_Type AVP */
55
+  case 405: /* User_Group AVP*/
56
+    avp->flags = 0x40|(0x20&avp->flags);
57
+    avp->type = AAA_AVP_STRING_TYPE;
58
+    break;
59
+  case  27: /*AVP_Session_Timeout*/
60
+  case 258: /*AVP_Auth_Aplication_Id*/
61
+  case 262: /*AVP_Redirect_Max_Cache_Time*/
62
+  case 265: /*AVP_Supported_Vendor_Id*/
63
+  case 266: /*AVP_Vendor_Id*/
64
+  case 268: /*AVP_Result_Code*/
65
+  case 270: /*AVP_Session_Binding*/
66
+  case 276: /*AVP_Auth_Grace_Period*/
67
+  case 278: /*AVP_Origin_State_Id*/
68
+  case 291: /*AVP_Authorization_Lifetime*/
69
+    avp->flags = 0x40|(0x20&avp->flags);
70
+    avp->type = AAA_AVP_INTEGER32_TYPE;
71
+    break;
72
+  case 33: /*AVP_Proxy_State*/
73
+    avp->flags = 0x40;
74
+    avp->type = AAA_AVP_STRING_TYPE;
75
+    break;
76
+  case 257: /*AVP_Host_IP_Address*/
77
+    avp->flags = 0x40|(0x20&avp->flags);
78
+    avp->type = AAA_AVP_ADDRESS_TYPE;
79
+    break;
80
+  case 269: /*AVP_Product_Name*/
81
+    avp->flags = 0x00;
82
+    avp->type = AAA_AVP_STRING_TYPE;
83
+    break;
84
+  case 281: /*AVP_Error_Message*/
85
+    avp->flags = (0x20&avp->flags);
86
+    avp->type = AAA_AVP_STRING_TYPE;
87
+    break;
88
+  default:
89
+    avp->type = AAA_AVP_DATA_TYPE;
90
+  };
91
+}
92
+
93
+AAA_AVP* AAAAddGroupedAVP(AAA_AVP* grouped, AAA_AVP* avp) {
94
+  AAA_AVP *mem;
95
+
96
+  if (grouped == NULL || avp == NULL) {
97
+    ERROR("trying to group NULL avp\n");
98
+    return grouped;
99
+  }
100
+  // insert at head
101
+  avp->next = grouped->groupedHead;
102
+  grouped->groupedHead = avp;
103
+  
104
+  // recompute total length
105
+  grouped->data.len = 0;
106
+  for(mem=grouped->groupedHead;mem;mem=mem->next) {
107
+    grouped->data.len += AVP_HDR_SIZE(mem->flags) + 
108
+      to_32x_len( mem->data.len );
109
+  }
110
+
111
+  return grouped;
112
+}
113
+
114
+/* This function creates an AVP and returns a pointer to it;
115
+ */
116
+AAA_AVP*  AAACreateAVP(
117
+		       AAA_AVPCode code,
118
+		       AAA_AVPFlag flags,
119
+		       AAAVendorId vendorId,
120
+		       const char   *data,
121
+		       unsigned int length,
122
+		       AVPDataStatus data_status)
123
+{
124
+  AAA_AVP *avp;
125
+
126
+  /* first check the params */
127
+  if(( data==0 || length==0)  && 
128
+     (( data_status==AVP_DUPLICATE_DATA )||
129
+      ( data_status==AVP_FREE_DATA ))){
130
+    ERROR("ERROR:AAACreateAVP: NULL value received for"
131
+	  " param data/length !!\n");
132
+    return 0;
133
+  }
134
+
135
+  /* allocated a new AVP struct */
136
+  avp = 0;
137
+  avp = (AAA_AVP*)ad_malloc(sizeof(AAA_AVP));
138
+  if (!avp)
139
+    goto error;
140
+  memset( avp, 0, sizeof(AAA_AVP) );
141
+
142
+  /* set some fields */
143
+  //avp->free_it = free_it;
144
+  avp->packetType = AAA_DIAMETER;
145
+  avp->code=code;
146
+  avp->flags=flags;
147
+  avp->vendorId=vendorId;
148
+  set_avp_fields( code, avp);
149
+
150
+  if ( data_status==AVP_DUPLICATE_DATA ) {
151
+    /* make a duplicate for data */
152
+    avp->data.len = length;
153
+    avp->data.s = (void*)ad_malloc(length);
154
+    if(!avp->data.s)
155
+      goto error;
156
+    memcpy( avp->data.s, data, length);
157
+    avp->free_it = 1;
158
+  } else {
159
+    avp->data.s = (char*)data;
160
+    avp->data.len = length;
161
+    avp->free_it = (data_status==AVP_FREE_DATA)?1:0;
162
+  }
163
+
164
+  return avp;
165
+ error:
166
+  ERROR("ERROR:AAACreateAVP: no more free memory!\n");
167
+  return 0;
168
+}
169
+
170
+
171
+
172
+/* Insert the AVP avp into this avpList of a message after position */
173
+AAAReturnCode  AAAAddAVPToMessage(
174
+				  AAAMessage *msg,
175
+				  AAA_AVP *avp,
176
+				  AAA_AVP *position)
177
+{
178
+  AAA_AVP *avp_t;
179
+
180
+  if ( !msg || !avp ) {
181
+    ERROR("ERROR:AAAAddAVPToList: param msg or avp passed null"
182
+	  " or *avpList=NULL and position!=NULL !!\n");
183
+    return AAA_ERR_PARAMETER;
184
+  }
185
+
186
+  if (!position) {
187
+    /* insert at the beginning */
188
+    avp->next = msg->avpList.head;
189
+    avp->prev = 0;
190
+    msg->avpList.head = avp;
191
+    if (avp->next)
192
+      avp->next->prev = avp;
193
+    else
194
+      msg->avpList.tail = avp;
195
+  } else {
196
+    /* look after avp from position */
197
+    for(avp_t=msg->avpList.head;avp_t&&avp_t!=position;avp_t=avp_t->next);
198
+    if (!avp_t) {
199
+      ERROR("ERROR: AAACreateAVP: the \"position\" avp is not in"
200
+	    "\"msg\" message!!\n");
201
+      return AAA_ERR_PARAMETER;
202
+    }
203
+    /* insert after position */
204
+    avp->next = position->next;
205
+    position->next = avp;
206
+    if (avp->next)
207
+      avp->next->prev = avp;
208
+    else
209
+      msg->avpList.tail = avp;
210
+    avp->prev = position;
211
+  }
212
+
213
+  /* update the short-cuts */
214
+  switch (avp->code) {
215
+  case AVP_Session_Id: msg->sessionId = avp;break;
216
+  case AVP_Origin_Host: msg->orig_host = avp;break;
217
+  case AVP_Origin_Realm: msg->orig_realm = avp;break;
218
+  case AVP_Destination_Host: msg->dest_host = avp;break;
219
+  case AVP_Destination_Realm: msg->dest_realm = avp;break;
220
+  case AVP_Result_Code: msg->res_code = avp;break;
221
+  case AVP_Auth_Session_State: msg->auth_ses_state = avp;break;
222
+  }
223
+
224
+  return AAA_ERR_SUCCESS;
225
+}
226
+
227
+/* This function finds an AVP with matching code and vendor id */
228
+AAA_AVP  *AAAFindMatchingAVP(
229
+			     AAAMessage *msg,
230
+			     AAA_AVP *startAvp,
231
+			     AAA_AVPCode avpCode,
232
+			     AAAVendorId vendorId,
233
+			     AAASearchType searchType)
234
+{
235
+  AAA_AVP *avp_t;
236
+
237
+  /* param checking */
238
+  if (!msg) {
239
+    ERROR("ERROR:FindMatchingAVP: param msg passed null !!\n");
240
+    goto error;
241
+  }
242
+  /* search the startAVP avp */
243
+  for(avp_t=msg->avpList.head;avp_t&&avp_t!=startAvp;avp_t=avp_t->next);
244
+  if (!avp_t && startAvp) {
245
+    ERROR("ERROR: AAAFindMatchingAVP: the \"position\" avp is not in"
246
+	  "\"avpList\" list!!\n");
247
+    goto error;
248
+  }
249
+
250
+  /* where should I start searching from ? */
251
+  if (!startAvp)
252
+    avp_t=(searchType==AAA_FORWARD_SEARCH)?(msg->avpList.head):
253
+      (msg->avpList.tail);
254
+  else
255
+    avp_t=startAvp;
256
+
257
+  /* start searching */
258
+  while(avp_t) {
259
+    if (avp_t->code==avpCode && avp_t->vendorId==vendorId)
260
+      return avp_t;
261
+    avp_t = (searchType==AAA_FORWARD_SEARCH)?(avp_t->next):(avp_t->prev);
262
+  }
263
+
264
+ error:
265
+  return 0;
266
+}
267
+
268
+
269
+/* This function removes an AVP from a list of a message */
270
+AAAReturnCode  AAARemoveAVPFromMessage(
271
+				       AAAMessage *msg,
272
+				       AAA_AVP *avp)
273
+{
274
+  AAA_AVP *avp_t;
275
+
276
+  /* param check */
277
+  if ( !msg || !avp ) {
278
+    ERROR("ERROR:AAAAddAVPToList: param AVP_LIST \"avpList\" or AVP "
279
+	  "\"avp\" passed null !!\n");
280
+    return AAA_ERR_PARAMETER;
281
+  }
282
+
283
+  /* search the "avp" avp */
284
+  for(avp_t=msg->avpList.head;avp_t&&avp_t!=avp;avp_t=avp_t->next);
285
+  if (!avp_t) {
286
+    ERROR("ERROR: AAACreateAVP: the \"avp\" avp is not in "
287
+	  "\"avpList\" avp list!!\n");
288
+    return AAA_ERR_PARAMETER;
289
+  }
290
+
291
+  /* remove the avp from list */
292
+  if (msg->avpList.head==avp)
293
+    msg->avpList.head = avp->next;
294
+  else
295
+    avp->prev->next = avp->next;
296
+  if (avp->next)
297
+    avp->next->prev = avp->prev;
298
+  else