blob: 686338ae1f434501e918f3748480cd9277656ac9 [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2015, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36/* Create and send a message, and receive it */
37
38/* Note that we use both sessions and the argument to answer callback to pass the same value.
39 * This is just for the purpose of checking everything went OK.
40 */
41
42#include "test_app.h"
43
44#include <stdio.h>
45
46static struct session_handler * ta_cli_reg = NULL;
47
48struct sess_state {
49 int32_t randval; /* a random value to store in Test-AVP */
50 struct timespec ts; /* Time of sending the message */
51} ;
52
53/* Cb called when an answer is received */
54static void ta_cb_ans(void * data, struct msg ** msg)
55{
56 struct sess_state * mi = NULL;
57 struct timespec ts;
58 struct session * sess;
59 struct avp * avp;
60 struct avp_hdr * hdr;
61 unsigned long dur;
62 int error = 0;
63
64 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return );
65
66 /* Search the session, retrieve its data */
67 {
68 int new;
69 CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &sess, &new), return );
70 ASSERT( new == 0 );
71
72 CHECK_FCT_DO( fd_sess_state_retrieve( ta_cli_reg, sess, &mi ), return );
73 ASSERT( (void *)mi == data );
74 }
75
76 /* Now log content of the answer */
77 fprintf(stderr, "RECV ");
78
79 /* Value of Test-AVP */
80 CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_avp, &avp), return );
81 if (avp) {
82 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
83 if (hdr->avp_value->i32 == mi->randval) {
84 fprintf(stderr, "%x (%s) ", hdr->avp_value->i32, "Ok");
85 } else {
86 fprintf(stderr, "%x (%s) ", hdr->avp_value->i32, "PROBLEM");
87 error++;
88 }
89 } else {
90 fprintf(stderr, "no_Test-AVP ");
91 error++;
92 }
93
94 /* Value of Result Code */
95 CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_res_code, &avp), return );
96 if (avp) {
97 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
98 fprintf(stderr, "Status: %d ", hdr->avp_value->i32);
99 if (hdr->avp_value->i32 != 2001)
100 error++;
101 } else {
102 fprintf(stderr, "no_Result-Code ");
103 error++;
104 }
105
106 /* Value of Origin-Host */
107 CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_origin_host, &avp), return );
108 if (avp) {
109 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
110 fprintf(stderr, "From '%.*s' ", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
111 } else {
112 fprintf(stderr, "no_Origin-Host ");
113 error++;
114 }
115
116 /* Value of Origin-Realm */
117 CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_origin_realm, &avp), return );
118 if (avp) {
119 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
120 fprintf(stderr, "('%.*s') ", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
121 } else {
122 fprintf(stderr, "no_Origin-Realm ");
123 error++;
124 }
125
126 CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
127 dur = ((ts.tv_sec - mi->ts.tv_sec) * 1000000) + ((ts.tv_nsec - mi->ts.tv_nsec) / 1000);
128 if (ta_conf->stats.nb_recv) {
129 /* Ponderate in the avg */
130 ta_conf->stats.avg = (ta_conf->stats.avg * ta_conf->stats.nb_recv + dur) / (ta_conf->stats.nb_recv + 1);
131 /* Min, max */
132 if (dur < ta_conf->stats.shortest)
133 ta_conf->stats.shortest = dur;
134 if (dur > ta_conf->stats.longest)
135 ta_conf->stats.longest = dur;
136 } else {
137 ta_conf->stats.shortest = dur;
138 ta_conf->stats.longest = dur;
139 ta_conf->stats.avg = dur;
140 }
141
142 if (error)
143 ta_conf->stats.nb_errs++;
144 else
145 ta_conf->stats.nb_recv++;
146
147
148 CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
149
150 /* Display how long it took */
151 if (ts.tv_nsec > mi->ts.tv_nsec) {
152 fprintf(stderr, "in %d.%06ld sec",
153 (int)(ts.tv_sec - mi->ts.tv_sec),
154 (long)(ts.tv_nsec - mi->ts.tv_nsec) / 1000);
155 } else {
156 fprintf(stderr, "in %d.%06ld sec",
157 (int)(ts.tv_sec + 1 - mi->ts.tv_sec),
158 (long)(1000000000 + ts.tv_nsec - mi->ts.tv_nsec) / 1000);
159 }
160 fprintf(stderr, "\n");
161 fflush(stderr);
162
163 /* Free the message */
164 CHECK_FCT_DO(fd_msg_free(*msg), return);
165 *msg = NULL;
166
167 free(mi);
168
169 return;
170}
171
172/* Create a test message */
173static void ta_cli_test_message()
174{
175 struct msg * req = NULL;
176 struct avp * avp;
177 union avp_value val;
178 struct sess_state * mi = NULL, *svg;
179 struct session *sess = NULL;
180
181 TRACE_DEBUG(FULL, "Creating a new message for sending.");
182
183 /* Create the request */
184 CHECK_FCT_DO( fd_msg_new( ta_cmd_r, MSGFL_ALLOC_ETEID, &req ), goto out );
185
186 /* Create a new session */
187 #define TEST_APP_SID_OPT "app_test"
188 CHECK_FCT_DO( fd_msg_new_session( req, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
189 CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, req, &sess, NULL), goto out );
190
191 /* Create the random value to store with the session */
192 mi = malloc(sizeof(struct sess_state));
193 if (mi == NULL) {
194 fd_log_debug("malloc failed: %s", strerror(errno));
195 goto out;
196 }
197
198 mi->randval = (int32_t)random();
199
200 /* Now set all AVPs values */
201
202 /* Set the Destination-Realm AVP */
203 {
204 CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out );
205 val.os.data = (unsigned char *)(ta_conf->dest_realm);
206 val.os.len = strlen(ta_conf->dest_realm);
207 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
208 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
209 }
210
211 /* Set the Destination-Host AVP if needed*/
212 if (ta_conf->dest_host) {
213 CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_host, 0, &avp ), goto out );
214 val.os.data = (unsigned char *)(ta_conf->dest_host);
215 val.os.len = strlen(ta_conf->dest_host);
216 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
217 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
218 }
219
220 /* Set Origin-Host & Origin-Realm */
221 CHECK_FCT_DO( fd_msg_add_origin ( req, 0 ), goto out );
222
223 /* Set the User-Name AVP if needed*/
224 if (ta_conf->user_name) {
225 CHECK_FCT_DO( fd_msg_avp_new ( ta_user_name, 0, &avp ), goto out );
226 val.os.data = (unsigned char *)(ta_conf->user_name);
227 val.os.len = strlen(ta_conf->user_name);
228 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
229 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
230 }
231
232 /* Set the Test-AVP AVP */
233 {
234 CHECK_FCT_DO( fd_msg_avp_new ( ta_avp, 0, &avp ), goto out );
235 val.i32 = mi->randval;
236 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
237 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
238 }
239
240 /* Set the Test-Payload-AVP AVP */
241 if (ta_conf->long_avp_id) {
242 int l;
243 CHECK_FCT_DO( fd_msg_avp_new ( ta_avp_long, 0, &avp ), goto out );
244 CHECK_MALLOC_DO( val.os.data = malloc(ta_conf->long_avp_len), goto out);
245 val.os.len = ta_conf->long_avp_len;
246 for (l=0; l < ta_conf->long_avp_len; l++)
247 val.os.data[l]=l;
248 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
249 free(val.os.data);
250 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
251 }
252
253 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &mi->ts), goto out );
254
255 /* Keep a pointer to the session data for debug purpose, in real life we would not need it */
256 svg = mi;
257
258 /* Store this value in the session */
259 CHECK_FCT_DO( fd_sess_state_store ( ta_cli_reg, sess, &mi ), goto out );
260
261 /* Log sending the message */
262 fprintf(stderr, "SEND %x to '%s' (%s)\n", svg->randval, ta_conf->dest_realm, ta_conf->dest_host?:"-" );
263 fflush(stderr);
264
265 /* Send the request */
266 CHECK_FCT_DO( fd_msg_send( &req, ta_cb_ans, svg ), goto out );
267
268 /* Increment the counter */
269 CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
270 ta_conf->stats.nb_sent++;
271 CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
272
273out:
274 return;
275}
276
277int ta_cli_init(void)
278{
279 CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, (void *)free, NULL, NULL) );
280
281 CHECK_FCT( fd_event_trig_regcb(ta_conf->signal, "test_app.cli", ta_cli_test_message ) );
282
283 return 0;
284}
285
286void ta_cli_fini(void)
287{
288 // CHECK_FCT_DO( fd_sig_unregister(ta_conf->signal), /* continue */ );
289
290 CHECK_FCT_DO( fd_sess_handler_destroy(&ta_cli_reg, NULL), /* continue */ );
291
292 return;
293};