blob: 3d13e5d1bbef99ba22554e445482fdf3c7ba551a [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) 2013, 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/* Do not include this directly, use dbg_interactive.i instead */
37
38/****** MESSAGES *********/
39
40%{
41struct anscb_py_layer {
42 PyObject * cb;
43 PyObject * expcb;
44 PyObject * data;
45};
46
47/* If a python callback was provided, it is received in cbdata */
48static void anscb_python(void *cbdata, struct msg ** msg) {
49 /* The python callback is received in cbdata */
50 PyObject * result, *PyMsg;
51 struct anscb_py_layer * l = cbdata;
52
53 if (!l) {
54 fd_log_debug("Internal error! Python callback disappeared...");
55 return;
56 }
57
58 if (l->cb) {
59
60 SWIG_PYTHON_THREAD_BEGIN_BLOCK;
61
62 if (!msg || !*msg) {
63 PyMsg = Py_None;
64 } else {
65 PyMsg = SWIG_NewPointerObj((void *)*msg, SWIGTYPE_p_msg, 0 );
66 }
67
68 result = PyObject_CallFunction(l->cb, "(OO)", PyMsg, l->data);
69 Py_XDECREF(l->cb);
70 Py_XDECREF(l->expcb);
71 Py_XDECREF(l->data);
72 free(l);
73
74 /* The callback is supposed to return a message or NULL */
75 if (!SWIG_IsOK(SWIG_ConvertPtr(result, (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
76 fd_log_debug("Error: Cannot convert the return value to message.");
77 *msg = NULL;
78 }
79
80 Py_XDECREF(result);
81
82 SWIG_PYTHON_THREAD_END_BLOCK;
83
84 }
85 /* else */
86 /* Only the timeout was specified, without a callback */
87 /* in this case, just delete the message */
88 /* it actually happens automatically when we do nothing. */
89}
90
91static void expcb_python(void *cbdata, DiamId_t sentto, size_t senttolen, struct msg ** msg) {
92 /* The python callback is received in cbdata */
93 PyObject * result, *PyMsg;
94 struct anscb_py_layer * l = cbdata;
95
96 if (!l) {
97 fd_log_debug("Internal error! Python callback disappeared...");
98 return;
99 }
100
101 SWIG_PYTHON_THREAD_BEGIN_BLOCK;
102
103 if (!msg || !*msg) {
104 PyMsg = Py_None;
105 } else {
106 PyMsg = SWIG_NewPointerObj((void *)*msg, SWIGTYPE_p_msg, 0 );
107 }
108
109 result = PyObject_CallFunction(l->expcb, "(Os#O)", PyMsg, sentto, senttolen, l->data);
110 Py_XDECREF(l->cb);
111 Py_XDECREF(l->expcb);
112 Py_XDECREF(l->data);
113 free(l);
114
115 /* The callback is supposed to return a message or NULL */
116 if (!SWIG_IsOK(SWIG_ConvertPtr(result, (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
117 fd_log_debug("Error: Cannot convert the return value to message.");
118 *msg = NULL;
119 }
120
121 Py_XDECREF(result);
122
123 SWIG_PYTHON_THREAD_END_BLOCK;
124
125}
126
127
128
129%}
130
131struct msg {
132};
133
134%extend msg {
135 msg(struct dict_object * model=NULL, int flags = MSGFL_ALLOC_ETEID) {
136 struct msg * m = NULL;
137 int ret = fd_msg_new( model, flags, &m);
138 if (ret != 0) {
139 DI_ERROR(ret, NULL, NULL);
140 }
141 return m;
142 }
143 /* construct also from a binary buffer */
144 msg(char * STRING, size_t LENGTH) {
145 int ret;
146 struct msg * m = NULL;
147 /* First, copy the string */
148 unsigned char * buf = malloc(LENGTH);
149 if (buf == NULL) {
150 DI_ERROR_MALLOC;
151 return NULL;
152 }
153 memcpy(buf, STRING, LENGTH);
154 ret = fd_msg_parse_buffer(&buf, LENGTH, &m);
155 if (ret != 0) {
156 DI_ERROR(ret, NULL, NULL);
157 free(buf);
158 return NULL;
159 }
160 return m;
161 }
162 ~msg() {
163 int ret = fd_msg_free($self);
164 if (ret != 0) {
165 DI_ERROR(ret, NULL, NULL);
166 }
167 }
168
169 /* SEND THE MESSAGE */
170 %delobject send; /* when this has been called, the msg must not be freed anymore */
171 void send(PyObject * PyCb = NULL, PyObject * data = NULL, PyObject * PyExpCb = NULL, unsigned int timeout = 0) {
172 int ret;
173 struct msg * m = $self;
174 struct anscb_py_layer * l = NULL;
175
176 if (PyCb || timeout) {
177 l = malloc(sizeof(struct anscb_py_layer));
178 if (!l) {
179 DI_ERROR_MALLOC;
180 return;
181 }
182
183 Py_XINCREF(PyCb);
184 Py_XINCREF(data);
185 Py_XINCREF(PyExpCb);
186 l->expcb = PyExpCb;
187 l->cb = PyCb;
188 l->data = data;
189 }
190
191 if (timeout) {
192 struct timespec ts;
193 (void) clock_gettime(CLOCK_REALTIME, &ts);
194 ts.tv_sec += timeout;
195 ret = fd_msg_send_timeout(&m, anscb_python, l, expcb_python, &ts);
196 } else {
197 ret = fd_msg_send(&m, PyCb ? anscb_python : NULL, l);
198 }
199 if (ret != 0) {
200 DI_ERROR(ret, NULL, NULL);
201 }
202 }
203
204 /* Create an answer */
205 %delobject create_answer; /* when this has been called, the original msg should not be freed anymore */
206 struct msg * create_answer(struct dictionary * dict = NULL, int flags = 0) {
207 /* if dict is not provided, attempt to get it from the request model */
208 struct dictionary * d = dict;
209 struct msg * m = $self;
210 int ret;
211 if (!d) {
212 struct dict_object * mo = NULL;
213 ret = fd_msg_model($self, &mo);
214 if (ret != 0) {
215 DI_ERROR(ret, NULL, "Error retrieving query model.");
216 return NULL;
217 }
218 if (mo == NULL) {
219 /* use the fD dictionary by default */
220 d = fd_g_config->cnf_dict;
221 } else {
222 ret = fd_dict_getdict ( mo, &d );
223 if (ret != 0) {
224 DI_ERROR(ret, NULL, "Error retrieving query's dictionary.");
225 return NULL;
226 }
227 }
228 }
229 ret = fd_msg_new_answer_from_req(d, &m, flags);
230 if (ret != 0) {
231 DI_ERROR(ret, NULL, "Cannot guess the dictionary to use, please provide it as parameter.");
232 return NULL;
233 }
234
235 return m;
236 }
237 /* Return the first child AVP if any */
238 struct avp * first_child() {
239 struct avp * a = NULL;
240 int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
241 if (ret != 0) {
242 DI_ERROR(ret, NULL, NULL);
243 }
244 return a;
245 }
246
247 /* Enumerable list of children AVP */
248 %newobject children;
249 PyObject * children() {
250 struct avp * a = NULL;
251 PyObject * rl;
252 int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
253 if (ret != 0) {
254 DI_ERROR(ret, NULL, NULL);
255 return NULL;
256 }
257 SWIG_PYTHON_THREAD_BEGIN_BLOCK;
258 rl = PyList_New(0);
259 while (a) {
260 PyList_Append(rl, SWIG_NewPointerObj((void *)a, SWIGTYPE_p_avp, 0 /* do not own the AVPs */ ));
261 ret = fd_msg_browse(a, MSG_BRW_NEXT, &a, NULL);
262 if (ret != 0) {
263 DI_ERROR(ret, NULL, NULL);
264 return NULL;
265 }
266 }
267 Py_XINCREF(rl);
268 SWIG_PYTHON_THREAD_END_BLOCK;
269 return rl;
270 }
271
272 /* Add a new AVP */
273 void add_child(struct avp *DISOWN, int begin = 0) {
274 int ret = fd_msg_avp_add ( $self, begin ? MSG_BRW_FIRST_CHILD : MSG_BRW_LAST_CHILD, DISOWN);
275 if (ret != 0) {
276 DI_ERROR(ret, NULL, NULL);
277 }
278 }
279
280 /* Search an AVP */
281 struct avp * search(struct dict_object * what) {
282 struct avp * a = NULL;
283 int ret = fd_msg_search_avp($self, what, &a);
284 if (ret != 0) {
285 DI_ERROR(ret, NULL, NULL);
286 return NULL;
287 }
288 return a;
289 }
290
291 /* Dump */
292 void dump (int tree = 1) {
293 char * buf = NULL;
294 size_t len;
295 printf("%s", fd_msg_dump_treeview(&buf, &len, NULL, $self, NULL, 0, tree));
296 free(buf);
297 }
298
299 /* Model */
300 struct dict_object * model() {
301 struct dict_object * m = NULL;
302 int ret = fd_msg_model($self, &m);
303 if (ret != 0) {
304 DI_ERROR(ret, NULL, NULL);
305 return NULL;
306 }
307 return m;
308 }
309
310 /* Header */
311 struct msg_hdr * header() {
312 struct msg_hdr * h = NULL;
313 int ret = fd_msg_hdr($self, &h);
314 if (ret != 0) {
315 DI_ERROR(ret, NULL, NULL);
316 return NULL;
317 }
318 return h;
319 }
320
321 /* Get query if message is an answer */
322 struct msg * get_query() {
323 struct msg * q = NULL;
324 int ret = fd_msg_answ_getq($self, &q);
325 if (ret != 0) {
326 DI_ERROR(ret, NULL, NULL);
327 return NULL;
328 }
329 return q;
330 }
331
332 /* Get / Set routing data */
333 struct rt_data * get_rtd() {
334 struct rt_data * r = NULL;
335 int ret = fd_msg_rt_get($self, &r);
336 if (ret != 0) {
337 DI_ERROR(ret, NULL, NULL);
338 return NULL;
339 }
340 return r;
341 }
342 void set_rtd(struct rt_data *DISOWN) {
343 struct rt_data * r = DISOWN;
344 int ret = fd_msg_rt_associate($self, r);
345 if (ret != 0) {
346 DI_ERROR(ret, NULL, NULL);
347 }
348 return;
349 }
350
351 /* Is routable? */
352 PyObject * is_routable() {
353 PyObject * r;
354 if (fd_msg_is_routable($self))
355 r = Py_True;
356 else
357 r = Py_False;
358 Py_XINCREF(r);
359 return r;
360 }
361
362 /* Is request? (shortcut) */
363 PyObject * is_request() {
364 PyObject * r;
365 int ret;
366 struct msg_hdr * h;
367
368 ret = fd_msg_hdr($self, &h);
369 if (ret != 0) {
370 DI_ERROR(ret, NULL, NULL);
371 }
372 if (h->msg_flags & CMD_FLAG_REQUEST)
373 r = Py_True;
374 else
375 r = Py_False;
376 Py_XINCREF(r);
377 return r;
378 }
379
380 /* Get the source */
381 %cstring_output_allocate_size(char ** outid, size_t * outlen, /* do not free */);
382 void source(char ** outid, size_t * outlen) {
383 int ret = fd_msg_source_get($self, outid, outlen);
384 if (ret != 0) {
385 DI_ERROR(ret, NULL, NULL);
386 return;
387 }
388 return;
389 }
390
391 /* Get the session */
392 %newobject get_session; /* it may be created or not, it is harmless because we only reclaim in ~session */
393 struct session *get_session(struct dictionary * dict = NULL) {
394 struct session *s = NULL;
395 struct dictionary * d = dict;
396 int ret = 0;
397 if (d == NULL)
398 d = fd_g_config->cnf_dict; /* default: use daemon's */
399 ret = fd_msg_sess_get(d, $self, &s, NULL);
400 if (ret != 0) {
401 DI_ERROR(ret, NULL, NULL);
402 return NULL;
403 }
404 return s;
405 }
406
407 /* Bufferize */
408 %cstring_output_allocate_size(char ** outbuffer, size_t * outlen, free(*$1));
409 void bufferize ( char ** outbuffer, size_t * outlen ) {
410 int ret = fd_msg_bufferize ( $self, (void *)outbuffer, outlen );
411 if (ret != 0) {
412 DI_ERROR(ret, NULL, NULL);
413 }
414 }
415
416 /* Dictionary parsing */
417 %newobject parse_dict;
418 struct fd_pei * parse_dict(struct dictionary * dict=NULL) {
419 int ret;
420 struct fd_pei pei, *e = NULL;
421 struct dictionary * d = dict;
422 memset(&pei, 0, sizeof(struct fd_pei));
423 if (d == NULL)
424 d = fd_g_config->cnf_dict; /* default: use daemon's */
425
426 ret = fd_msg_parse_dict ( $self, d, &pei );
427 if (ret != 0) {
428 e = malloc(sizeof(struct fd_pei));
429 if (!e) {
430 DI_ERROR_MALLOC;
431 return NULL;
432 }
433 memcpy(e, &pei, sizeof(struct fd_pei));
434 }
435 return e; /* returns NULL when everything went OK */
436 }
437
438 /* Rules parsing */
439 %newobject parse_rules;
440 struct fd_pei * parse_rules(struct dictionary * dict=NULL) {
441 int ret;
442 struct fd_pei pei, *e = NULL;
443 struct dictionary * d = dict;
444 memset(&pei, 0, sizeof(struct fd_pei));
445 if (d == NULL)
446 d = fd_g_config->cnf_dict; /* default: use daemon's */
447
448 ret = fd_msg_parse_rules ( $self, d, &pei );
449 if (ret != 0) {
450 e = malloc(sizeof(struct fd_pei));
451 if (!e) {
452 DI_ERROR_MALLOC;
453 return NULL;
454 }
455 memcpy(e, &pei, sizeof(struct fd_pei));
456 }
457 return e; /* returns NULL when everything went OK */
458 }
459
460 /* Update the length info in header */
461 void update_length() {
462 int ret = fd_msg_update_length ( $self );
463 if (ret) {
464 DI_ERROR(ret, NULL, NULL);
465 }
466 }
467
468 /* Set the result code */
469 void rescode_set(char * rescode = "DIAMETER_SUCCESS", char * errormsg = NULL, struct avp * optavp = NULL, int type_id = 0) {
470 int ret = fd_msg_rescode_set( $self, rescode, errormsg, optavp, type_id );
471 if (ret) {
472 DI_ERROR(ret, NULL, NULL);
473 }
474 }
475
476 /* Add the origin */
477 void add_origin(int osi = 0) {
478 int ret = fd_msg_add_origin( $self, osi );
479 if (ret) {
480 DI_ERROR(ret, NULL, NULL);
481 }
482 }
483
484}
485
486struct avp {
487};
488
489%extend avp {
490 avp(struct dict_object * model = NULL, int flags = 0) {
491 struct avp * a = NULL;
492 int ret = fd_msg_avp_new( model, flags, &a);
493 if (ret != 0) {
494 DI_ERROR(ret, NULL, NULL);
495 }
496 return a;
497 }
498 ~avp() {
499 int ret = fd_msg_free($self);
500 if (ret != 0) {
501 DI_ERROR(ret, NULL, NULL);
502 }
503 }
504
505 /* Return the first child AVP if any */
506 struct avp * first_child() {
507 struct avp * a = NULL;
508 int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
509 if (ret != 0) {
510 DI_ERROR(ret, NULL, NULL);
511 }
512 return a;
513 }
514
515 /* Enumerable list of children AVP */
516 %newobject children;
517 PyObject * children() {
518 struct avp * a = NULL;
519 PyObject * rl;
520 int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
521 if (ret != 0) {
522 DI_ERROR(ret, NULL, NULL);
523 return NULL;
524 }
525 SWIG_PYTHON_THREAD_BEGIN_BLOCK;
526 rl = PyList_New(0);
527 while (a) {
528 PyList_Append(rl, SWIG_NewPointerObj((void *)a, SWIGTYPE_p_avp, 0 /* the AVPs are not owned */ ));
529 ret = fd_msg_browse(a, MSG_BRW_NEXT, &a, NULL);
530 if (ret != 0) {
531 DI_ERROR(ret, NULL, NULL);
532 return NULL;
533 }
534 }
535 Py_XINCREF(rl);
536 SWIG_PYTHON_THREAD_END_BLOCK;
537 return rl;
538 }
539
540 /* Add a new AVP */
541 void add_next(struct avp *avp) {
542 int ret = fd_msg_avp_add ( $self, MSG_BRW_NEXT, avp);
543 if (ret != 0) {
544 DI_ERROR(ret, NULL, NULL);
545 }
546 }
547 void add_prev(struct avp *avp) {
548 int ret = fd_msg_avp_add ( $self, MSG_BRW_PREV, avp);
549 if (ret != 0) {
550 DI_ERROR(ret, NULL, NULL);
551 }
552 }
553 void add_child(struct avp *DISOWN, int begin = 0) {
554 int ret = fd_msg_avp_add ( $self, begin ? MSG_BRW_FIRST_CHILD : MSG_BRW_LAST_CHILD, DISOWN);
555 if (ret != 0) {
556 DI_ERROR(ret, NULL, NULL);
557 }
558 }
559
560 /* Get the next AVP at the same level */
561 struct avp * get_next() {
562 struct avp * a = NULL;
563 int ret = fd_msg_browse($self, MSG_BRW_NEXT, &a, NULL);
564 if (ret != 0) {
565 DI_ERROR(ret, NULL, NULL);
566 }
567 return a;
568 }
569
570 /* Dump */
571 void dump (int tree = 1) {
572 char * buf = NULL;
573 size_t len;
574 printf("%s", fd_msg_dump_treeview(&buf, &len, NULL, $self, NULL, 0, tree));
575 free(buf);
576 }
577
578 /* Model */
579 struct dict_object * model() {
580 struct dict_object * m = NULL;
581 int ret = fd_msg_model($self, &m);
582 if (ret != 0) {
583 DI_ERROR(ret, NULL, NULL);
584 return NULL;
585 }
586 return m;
587 }
588
589 /* Header */
590 struct avp_hdr * header() {
591 struct avp_hdr * h = NULL;
592 int ret = fd_msg_avp_hdr($self, &h);
593 if (ret != 0) {
594 DI_ERROR(ret, NULL, NULL);
595 return NULL;
596 }
597 return h;
598 }
599
600 /* set value */
601 void setval(union avp_value * val) {
602 int ret = fd_msg_avp_setvalue ( $self, val );
603 if (ret != 0) {
604 DI_ERROR(ret, NULL, NULL);
605 }
606 }
607
608 /* Update the length info in header */
609 void update_length() {
610 int ret = fd_msg_update_length ( $self );
611 if (ret) {
612 DI_ERROR(ret, NULL, NULL);
613 }
614 }
615}