Mercurial > hg > freeDiameter
changeset 638:9448cba86673
Improved usability of dbg_interactive
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Fri, 17 Dec 2010 18:41:19 +0900 |
parents | 22e8fac3b2d6 |
children | 95a784729cac |
files | doc/dbg_interactive.py.sample extensions/dbg_interactive/dbg_interactive.i extensions/dbg_interactive/dictionary.i extensions/dbg_interactive/dispatch.i extensions/dbg_interactive/messages.i extensions/dbg_interactive/peers.i extensions/dbg_interactive/queues.i extensions/dbg_interactive/sessions.i include/freeDiameter/libfreeDiameter.h libfreeDiameter/messages.c |
diffstat | 10 files changed, 791 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/dbg_interactive.py.sample Thu Dec 16 18:56:41 2010 +0900 +++ b/doc/dbg_interactive.py.sample Fri Dec 17 18:41:19 2010 +0900 @@ -103,7 +103,8 @@ ############# Hash ############ -hex(fd_hash("hello world")) # A typemap is applied to accept binary data + +hex(fd_hash("hello world")) # It accepts binary data ############# Dictionary ############ @@ -121,6 +122,10 @@ d.dump() d.vendors_list() +# Compact invocation also possible: +v2 = dict_vendor_data(124, "My test vendor 2") +del v2 + # New application a = dict_application_data() a.application_id = 99 @@ -128,6 +133,9 @@ my_appl = d.new_obj(DICT_APPLICATION, a, my_vendor) del a +a2 = dict_application_data(99, "My test appl 2") +del a2 + # New type (callbacks are not supported yet...) t = dict_type_data() t.type_base = AVP_TYPE_INTEGER32 @@ -138,6 +146,9 @@ my_type_os = d.new_obj(DICT_TYPE, t, my_appl) del t +t2 = dict_type_data(AVP_TYPE_UNSIGNED32, "u32 type") +del t2 + # Constants c = dict_enumval_data() c.enum_name = "AVP_VALUE_TROIS" @@ -150,6 +161,12 @@ d.new_obj(DICT_ENUMVAL, c, my_type_os) del c +c2 = dict_enumval_data("enum 23", 23) # The constructor only accepts unsigned32, for other values, set them afterwards +c3 = dict_enumval_data("enum other") +c3.os = "other value" +del c2 +del c3 + # AVP a = dict_avp_data() a.avp_code = 234 @@ -166,6 +183,16 @@ my_avp_os = d.new_obj(DICT_AVP, a, my_type_os) del a +a2 = dict_avp_data(235, "no vendor, not mandatory", AVP_TYPE_OCTETSTRING) +a3 = dict_avp_data(236, "vendor 12, not mandatory", AVP_TYPE_OCTETSTRING, 12) +a4 = dict_avp_data(237, "vendor 12, mandatory", AVP_TYPE_OCTETSTRING, 12, 1) +a5 = dict_avp_data(238, "no vendor, mandatory", AVP_TYPE_OCTETSTRING, 0, 1) +del a2 +del a3 +del a4 +del a5 + + # Command c = dict_cmd_data() c.cmd_code = 345 @@ -178,6 +205,11 @@ my_ans = d.new_obj(DICT_COMMAND, c, my_appl) del c +c2 = dict_cmd_data(346, "Second-Request", 1) # Default created with PROXIABLE flag. +c3 = dict_cmd_data(346, "Second-Answer", 0) +del c2 +del c3 + # Rule r = dict_rule_data() r.rule_avp = my_avp_int @@ -194,6 +226,12 @@ d.dump() del d +r2 = dict_rule_data(my_avp_int, RULE_REQUIRED) # min & max are optional parameters, default to -1 +r3 = dict_rule_data(my_avp_int, RULE_REQUIRED, 2, 3) # min is 2, max is 3 +r4 = dict_rule_data(my_avp_int, RULE_FIXED_HEAD) # The r4.rule_order = 1 by default, change afterwards if needed. +del r2 +del r3 +del r4 ####### Now play with the "real" dictionary @@ -271,10 +309,11 @@ ## AVP -# Create empty (as for messages, pass None or a dictionary object as 1st param, and flags as optional 2nd param) +# Create empty blank_avp = avp() del blank_avp +# Create from dictionary definitions oh = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host")) # Octet String vi = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Id")) # U32 vsai = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Specific-Application-Id")) # Grouped @@ -288,10 +327,15 @@ oh.setval(val) vsai.add_child(vi) # call as add_child(vi, 1) to add the new AVP at the beginning, default is at the end +# It is possible to initialize the AVP with a blank value as follow: +blank_with_value = avp(None, AVPFL_SET_BLANK_VALUE) +# it enables this without doing the setval call: +blank_with_value.header().avp_value.u32 = 12 + ## Messages -# Create empty +# Create empt (as for avps, pass None or a dictionary object as 1st param, and flags as optional 2nd param)y a_msg = msg() a_msg.dump() del a_msg @@ -357,7 +401,8 @@ oh_hdr = oh.header() hex(oh_hdr.avp_flags) oh_hdr.avp_vendor -oh_hdr.avp_value.os.dump() # The initial avp value must be set with setval(), but then this accessor is allowed. +oh_hdr.avp_value.os.as_str() + # Get or set the routing data rd = rt_data() @@ -389,21 +434,206 @@ gavp.children() +# Send a message: +mydwr.send() + +# Optionaly, a callback can be registered when a message is sent, with an optional object. +# This callback takes the answer message as parameter and should return None or a message. (cf. fd_msg_send) +def send_callback(msg, obj): + print "Received answer:" + msg.dump() + print "Associated data:" + obj + return None + +mydwr.send(send_callback, some_object) + + +# Set a result code in an answer message. +dwa = mydwr.create_answer() +dwa.rescode_set() # This adds the DIAMETER_SUCCESS result code +dwa.rescode_set("DIAMETER_LIMITED_SUCCESS" ) # This adds a different result code +dwa.rescode_set("DIAMETER_LIMITED_SUCCESS", "Something went not so well" ) # This adds a different result code + specified Error-Message +dwa.rescode_set("DIAMETER_INVALID_AVP", None, faulty_avp ) # This adds a Failed-AVP +dwa.rescode_set("DIAMETER_SUCCESS", None, None, 1 ) # This adds origin information (see fd_msg_rescode_set's type_id for more info) + +# Set the origin to local host +mydwr.add_origin() # adds Origin-Host & Origin-Realm +mydwr.add_origin(1) # adds Origin-State-Id in addition. + + +############# DISPATCH (aka. server application) ############ + +# As for sessions, only one dispatch handler can be registered in this extension at the moment. +# The callback for the handler has the following syntax: +def dispatch_cb_model(inmsg, inavp, insession): + print "Callback trigged on message: " + inmsg.dump() + # inavp is None or the AVP that trigged the callback, depending on how it was registered. + if inavp: + print "From the following AVP:" + inavp.dump() + else: + print "No AVP" + # Session is provided only if a Session-Id is in the message + if insession: + print "The session is: ", insession.getsid() + else: + print "No session" + # Now, for the return value. + # This callback must return 3 elements: + # - an integer which is interpreted as an error code (errno.h) + # - a message or None, depending on the next item + # - an enum disp_action value, with the same meaning as in C (see libfreeDiameter.h) + del inmsg + return [ 0, None, DISP_ACT_CONT ] + + +### Example use: rebuild the server-side of test_app.fdx in python + +# The following block defines the dictionary objects from the test_app.fdx application that we use on the remote peer +gdict = cvar.fd_g_config.cnf_dict +d_si = gdict.search ( DICT_AVP, AVP_BY_NAME, "Session-Id" ) +d_oh = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host" ) +d_or = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Realm" ) +d_dh = gdict.search ( DICT_AVP, AVP_BY_NAME, "Destination-Host" ) +d_dr = gdict.search ( DICT_AVP, AVP_BY_NAME, "Destination-Realm" ) +d_rc = gdict.search ( DICT_AVP, AVP_BY_NAME, "Result-Code" ) +d_vnd = gdict.new_obj(DICT_VENDOR, dict_vendor_data(999999, "app_test_py vendor") ) +d_app = gdict.new_obj(DICT_APPLICATION, dict_application_data(0xffffff, "app_test_py appli"), d_vnd) +d_req = gdict.new_obj(DICT_COMMAND, dict_cmd_data(0xfffffe, "Test_py-Request", 1), d_app) +d_ans = gdict.new_obj(DICT_COMMAND, dict_cmd_data(0xfffffe, "Test_py-Answer", 0), d_app) +d_avp = gdict.new_obj(DICT_AVP, dict_avp_data(0xffffff, "app_test_py avp", AVP_TYPE_INTEGER32, 999999 )) +gdict.new_obj(DICT_RULE, dict_rule_data(d_si, RULE_FIXED_HEAD, 1, 1), d_req) +gdict.new_obj(DICT_RULE, dict_rule_data(d_si, RULE_FIXED_HEAD, 1, 1), d_ans) +gdict.new_obj(DICT_RULE, dict_rule_data(d_avp, RULE_REQUIRED, 1, 1), d_req) +gdict.new_obj(DICT_RULE, dict_rule_data(d_avp, RULE_REQUIRED, 1, 1), d_ans) +gdict.new_obj(DICT_RULE, dict_rule_data(d_oh, RULE_REQUIRED, 1, 1), d_req) +gdict.new_obj(DICT_RULE, dict_rule_data(d_oh, RULE_REQUIRED, 1, 1), d_ans) +gdict.new_obj(DICT_RULE, dict_rule_data(d_or, RULE_REQUIRED, 1, 1), d_req) +gdict.new_obj(DICT_RULE, dict_rule_data(d_or, RULE_REQUIRED, 1, 1), d_ans) +gdict.new_obj(DICT_RULE, dict_rule_data(d_dr, RULE_REQUIRED, 1, 1), d_req) +gdict.new_obj(DICT_RULE, dict_rule_data(d_dh, RULE_OPTIONAL, 0, 1), d_req) +gdict.new_obj(DICT_RULE, dict_rule_data(d_rc, RULE_REQUIRED, 1, 1), d_ans) + +# Now, create the Test_app server callback: +def test_app_cb(inmsg, inavp, insession): + tval = inmsg.search(d_avp).header().avp_value.u32 + print "Py ECHO Test message from '%s' with test value %x, replying..." % (inmsg.search(d_oh).header().avp_value.os.as_str(), tval) + answ = inmsg.create_answer() + answ.rescode_set() + answ.add_origin() + ta = avp(d_avp, AVPFL_SET_BLANK_VALUE) + ta.header().avp_value.u32 = tval + answ.add_child(ta) + return [ 0, answ, DISP_ACT_SEND ] + +# Register the callback for dispatch thread: +hdl = disp_hdl(test_app_cb, DISP_HOW_CC, disp_when(d_app, d_req)) # disp_when() takes 0 to 4 arguments as follow: (app=NULL, cmd=NULL, avp=NULL, val=NULL) + +# Don't forget to register the application in the daemon for CER/CEA capabilities. +fd_disp_app_support ( d_app, d_vnd, 1, 0 ) + + +### For the fun, the client part of the test_app: + +def receive_answer(ans, testval): + try: + tval = ans.search(d_avp).header().avp_value.u32 + except: + print "Error in receive_answer: no Test-AVP included" + tval = 0 + try: + print "Py RECV %x (expected: %x) Status: %d From: '%s'" % (tval, testval, ans.search(d_rc).header().avp_value.u32, ans.search(d_oh).header().avp_value.os.as_str()) + except: + print "Error in receive_answer: Result-Code or Origin-Host are missing" + del ans + return None + +import random + +def send_query(destrealm="localdomain"): + qry = msg(d_req) + sess = session() + tv = random.randint(1, 1<<32) + # Session-Id + a = avp(d_si, AVPFL_SET_BLANK_VALUE) + a.header().avp_value.os = sess.getsid() + qry.add_child(a) + # Destination-Realm + a = avp(d_dr, AVPFL_SET_BLANK_VALUE) + a.header().avp_value.os = destrealm + qry.add_child(a) + # Origin-Host, Origin-Realm + qry.add_origin() + # Test-AVP + a = avp(d_avp, AVPFL_SET_BLANK_VALUE) + a.header().avp_value.u32 = tv + qry.add_child(a) + print "Py SEND %x to '%s'" % (tv, destrealm) + qry.send(receive_answer, tv) + +send_query() + + +############# FIFO queues ############ + +myqueue = fifo() + +# enqueue any object +myqueue.post(3) +myqueue.post("blah") +myqueue.post( [ 3, 2 ] ) + +# Simple get (blocks when the queue is empty) +myqueue.get() + +# Try get: returns the next object, or None if the queue is empty +myqueue.tryget() + +# timed get: like get, but returns None after x seconds +myqueue.timedget(3) + +# Show the number of items in the queue +myqueue.length() + +del myqueue +############# PEERS ############ +# Get the list of peers defined in the system +# (well, we are supposed actually to readlock fd_g_peers_rw before doing this, but it should be fine most of the time) +peers = cvar.fd_g_peers.enum_as("struct peer_hdr *") +for p in peers: + print "Peer:", p.info.pi_diamid + + +# Create a new peer +np = peer_info() +np.pi_diamid = "nas.localdomain" +np.config.pic_flags.pro4 = 1 # 1 for TCP, for some reason PI_P4_TCP is not defined -######################### old stuff (need update) ###################### +# Add this peer into the framework. +np.add() + +# It is possible to specify a callback for when the connection completes or fails to this peer. +# The prototype is as follow: +def add_cb(peer): + if peer: + if peer.runtime.pir_state == STATE_OPEN: + print "Connection to peer '%s' completed" % (peer.pi_diamid) + # can find more information in peer.runtime.* + else: + print "Connection to peer '%s' failed (state:%d)" % (peer.pi_diamid, peer.runtime.pir_state) + else: + print "The peer has been destroyed before it completed the connection." + +# Then add the peer simply like this: +np.add(add_cb) -# Create a new peer_info structure and add the peer to the framework. -mypeer = peer_info() -mypeer.pi_diamid = "nas.testbed.aaa" -mypeer.config.pic_flags.pro4 = 1 # 1 for TCP, for some reason PI_P4_TCP is not defined -fd_peer_add(mypeer, "python", None, None) -del mypeer -
--- a/extensions/dbg_interactive/dbg_interactive.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/dbg_interactive.i Fri Dec 17 18:41:19 2010 +0900 @@ -128,6 +128,11 @@ } +/* Forward declaration for the peers module */ +%{ +static void fd_add_cb(struct peer_info *peer, void *data); +%} + /********************************************************* Now, create wrappers for (almost) all objects from fD API *********************************************************/
--- a/extensions/dbg_interactive/dictionary.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/dictionary.i Fri Dec 17 18:41:19 2010 +0900 @@ -241,4 +241,171 @@ fd_log_debug("%02.2X", $self->data[i]); fd_log_debug("] '%.*s%s'\n", n, $self->data, n == LEN_MAX ? "..." : ""); } + %cstring_output_allocate_size(char ** outbuffer, size_t * outlen, free(*$1)); + void as_str ( char ** outbuffer, size_t * outlen ) { + char * b; + if (!$self->len) { + *outlen = 0; + *outbuffer = NULL; + return; + } + b = malloc($self->len); + if (!b) { + DI_ERROR_MALLOC; + return; + } + memcpy(b, $self->data, $self->len); + *outlen = $self->len; + *outbuffer = b; + } } + + +/* Allow constructors with parameters for the dict_*_data */ +%extend dict_vendor_data { + dict_vendor_data(uint32_t id = 0, char * name = NULL) { + struct dict_vendor_data * d = (struct dict_vendor_data *)calloc(1, sizeof(struct dict_vendor_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + d->vendor_id = id; + if (name) { + d->vendor_name = strdup(name); + if (!d->vendor_name) { + DI_ERROR_MALLOC; + free(d); + return NULL; + } + } + return d; + } +} + +%extend dict_application_data { + dict_application_data(uint32_t id = 0, char * name = NULL) { + struct dict_application_data * d = (struct dict_application_data *)calloc(1, sizeof(struct dict_application_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + d->application_id = id; + if (name) { + d->application_name = strdup(name); + if (!d->application_name) { + DI_ERROR_MALLOC; + free(d); + return NULL; + } + } + return d; + } +} + +%extend dict_type_data { + dict_type_data(enum dict_avp_basetype base = 0, char * name = NULL) { + struct dict_type_data * d = (struct dict_type_data *)calloc(1, sizeof(struct dict_type_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + d->type_base = base; + if (name) { + d->type_name = strdup(name); + if (!d->type_name) { + DI_ERROR_MALLOC; + free(d); + return NULL; + } + } + return d; + } +} + +%extend dict_enumval_data { + dict_enumval_data(char * name = NULL, uint32_t v = 0) { + struct dict_enumval_data * d = (struct dict_enumval_data *)calloc(1, sizeof(struct dict_enumval_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + if (name) { + d->enum_name = strdup(name); + if (!d->enum_name) { + DI_ERROR_MALLOC; + free(d); + return NULL; + } + } + d->enum_value.u32 = v; + return d; + } +} + +%extend dict_avp_data { + dict_avp_data(uint32_t code = 0, char * name = NULL, enum dict_avp_basetype basetype = 0, uint32_t vendor = 0, int mandatory=0) { + struct dict_avp_data * d = (struct dict_avp_data *)calloc(1, sizeof(struct dict_avp_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + if (name) { + d->avp_name = strdup(name); + if (!d->avp_name) { + DI_ERROR_MALLOC; + free(d); + return NULL; + } + } + d->avp_code = code; + d->avp_basetype = basetype; + d->avp_vendor = vendor; + if (vendor) { + d->avp_flag_val |= AVP_FLAG_VENDOR; + d->avp_flag_mask |= AVP_FLAG_VENDOR; + } + d->avp_flag_mask |= AVP_FLAG_MANDATORY; + if (mandatory) + d->avp_flag_val |= AVP_FLAG_MANDATORY; + return d; + } +} + +%extend dict_cmd_data { + dict_cmd_data(uint32_t code = 0, char * name = NULL, int request = 1) { + struct dict_cmd_data * d = (struct dict_cmd_data *)calloc(1, sizeof(struct dict_cmd_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + if (name) { + d->cmd_name = strdup(name); + if (!d->cmd_name) { + DI_ERROR_MALLOC; + free(d); + return NULL; + } + } + d->cmd_code = code; + d->cmd_flag_mask = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE; + d->cmd_flag_val = CMD_FLAG_PROXIABLE | ( request ? CMD_FLAG_REQUEST : 0 ); + return d; + } +} + +%extend dict_rule_data { + dict_rule_data(struct dict_object *avp = NULL, enum rule_position pos = 0, int min = -1, int max = -1 ) { + struct dict_rule_data * d = (struct dict_rule_data *)calloc(1, sizeof(struct dict_rule_data)); + if (!d) { + DI_ERROR_MALLOC; + return NULL; + } + d->rule_avp = avp; + d->rule_position = pos; + d->rule_order = 1; + d->rule_min = min; + d->rule_max = max; + return d; + } +} +
--- a/extensions/dbg_interactive/dispatch.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/dispatch.i Fri Dec 17 18:41:19 2010 +0900 @@ -35,3 +35,120 @@ /* Do not include this directly, use dbg_interactive.i instead */ +/****** DISPATCH *********/ + + +%{ +/* store the python callback function here */ +static PyObject * py_dispatch_cb = NULL; +static int py_dispatch_cb_n = 0; +/* call it (will be called from a different thread than the interpreter, when message arrives) */ +static int call_the_python_dispatch_callback(struct msg **msg, struct avp *avp, struct session *session, enum disp_action *action) { + PyObject *PyMsg, *PyAvp, *PySess; + PyObject *result = NULL; + int ret = 0; + + if (!py_dispatch_cb) + return ENOTSUP; + + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + /* Convert the arguments */ + PyMsg = SWIG_NewPointerObj((void *)*msg, SWIGTYPE_p_msg, 0 ); + PyAvp = SWIG_NewPointerObj((void *) avp, SWIGTYPE_p_avp, 0 ); + PySess = SWIG_NewPointerObj((void *) session, SWIGTYPE_p_session, 0 ); + + /* Call the function */ + result = PyEval_CallFunction(py_dispatch_cb, "(OOO)", PyMsg, PyAvp, PySess); + + /* The result is supposedly composed of: [ ret, *msg, *action ] */ + if ((result == NULL) || (!PyList_Check(result)) || (PyList_Size(result) != 3)) { + fd_log_debug("Error: The Python callback did not return [ ret, msg, action ].\n"); + ret = EINVAL; + goto out; + } + + /* Convert the return values */ + if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 0), &ret))) { + fd_log_debug("Error: Cannot convert the first return value to integer.\n"); + ret = EINVAL; + goto out; + } + if (ret) { + TRACE_DEBUG(INFO, "The Python callback returned the error code %d (%s)\n", ret, strerror(ret)); + goto out; + } + + if (!SWIG_IsOK(SWIG_ConvertPtr(PyList_GetItem(result, 1), (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) { + fd_log_debug("Error: Cannot convert the second return value to message.\n"); + ret = EINVAL; + goto out; + } + + if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 2), (int *)action))) { + fd_log_debug("Error: Cannot convert the third return value to integer.\n"); + ret = EINVAL; + goto out; + } + + TRACE_DEBUG(FULL, "Python callback return: *action = %d\n", *action); +out: + Py_XDECREF(result); + + SWIG_PYTHON_THREAD_END_BLOCK; + return ret; +} +%} + +struct disp_hdl { +}; + +%nodefaultctor disp_hdl; +%extend disp_hdl { + disp_hdl(PyObject * PyCb, enum disp_how how, struct disp_when * when) { + struct disp_hdl * hdl = NULL; + int ret; + if (py_dispatch_cb && (py_dispatch_cb != PyCb)) { + DI_ERROR(EINVAL, PyExc_SyntaxError, "Only one dispatch callback is supported at the moment in this extension\n."); + return NULL; + } + py_dispatch_cb = PyCb; + py_dispatch_cb_n += 1; + Py_XINCREF(py_dispatch_cb); + + ret = fd_disp_register ( call_the_python_dispatch_callback, how, when, &hdl ); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + return NULL; + } + return hdl; + } + ~disp_hdl() { + struct disp_hdl * hdl = self; + int ret = fd_disp_unregister(&hdl); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + /* Now free the callback */ + Py_XDECREF(py_dispatch_cb); + py_dispatch_cb_n -= 1; + if (!py_dispatch_cb_n) + py_dispatch_cb = NULL; + return; + } +} + + +%extend disp_when { + disp_when(struct dict_object * app = NULL, struct dict_object * command = NULL, struct dict_object * avp = NULL, struct dict_object * value = NULL) { + struct disp_when * w = (struct disp_when *)calloc(1, sizeof(struct disp_when)); + if (!w) { + DI_ERROR_MALLOC; + return NULL; + } + w->app = app; + w->command = command; + w->avp = avp; + w->value = value; + return w; + } +}
--- a/extensions/dbg_interactive/messages.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/messages.i Fri Dec 17 18:41:19 2010 +0900 @@ -37,6 +37,49 @@ /****** MESSAGES *********/ +%{ +struct anscb_py_layer { + PyObject * cb; + PyObject * data; +}; + +/* If a python callback was provided, it is received in cbdata */ +static void anscb_python(void *cbdata, struct msg ** msg) { + /* The python callback is received in cbdata */ + PyObject * result, *PyMsg; + struct anscb_py_layer * l = cbdata; + + if (!l) { + fd_log_debug("Internal error! Python callback disappeared...\n"); + return; + } + + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + + if (!msg || !*msg) { + PyMsg = Py_None; + } else { + PyMsg = SWIG_NewPointerObj((void *)*msg, SWIGTYPE_p_msg, 0 ); + } + + result = PyEval_CallFunction(l->cb, "(OO)", PyMsg, l->data); + Py_XDECREF(l->cb); + Py_XDECREF(l->data); + free(l); + + /* The callback is supposed to return a message or NULL */ + if (!SWIG_IsOK(SWIG_ConvertPtr(result, (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) { + fd_log_debug("Error: Cannot convert the return value to message.\n"); + *msg = NULL; + } + + Py_XDECREF(result); + + SWIG_PYTHON_THREAD_END_BLOCK; + +} +%} + struct msg { }; @@ -74,6 +117,34 @@ DI_ERROR(ret, NULL, NULL); } } + + /* SEND THE MESSAGE */ + %delobject send; /* when this has been called, the msg must not be freed anymore */ + void send(PyObject * PyCb = NULL, PyObject * data = NULL) { + int ret; + struct msg * m = $self; + struct anscb_py_layer * l = NULL; + + if (PyCb) { + l = malloc(sizeof(struct anscb_py_layer)); + if (!l) { + DI_ERROR_MALLOC; + return; + } + + Py_XINCREF(PyCb); + Py_XINCREF(data); + l->cb = PyCb; + l->data = data; + } + + ret = fd_msg_send(&m, PyCb ? anscb_python : NULL, l); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + } + + /* Create an answer */ %delobject create_answer; /* when this has been called, the original msg should not be freed anymore */ struct msg * create_answer(struct dictionary * dict = NULL, int flags = 0) { /* if dict is not provided, attempt to get it from the request model */ @@ -312,6 +383,23 @@ DI_ERROR(ret, NULL, NULL); } } + + /* Set the result code */ + void rescode_set(char * rescode = "DIAMETER_SUCCESS", char * errormsg = NULL, struct avp * optavp = NULL, int type_id = 0) { + int ret = fd_msg_rescode_set( $self, rescode, errormsg, optavp, type_id ); + if (ret) { + DI_ERROR(ret, NULL, NULL); + } + } + + /* Add the origin */ + void add_origin(int osi = 0) { + int ret = fd_msg_add_origin( $self, osi ); + if (ret) { + DI_ERROR(ret, NULL, NULL); + } + } + } struct avp {
--- a/extensions/dbg_interactive/peers.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/peers.i Fri Dec 17 18:41:19 2010 +0900 @@ -35,3 +35,55 @@ /* Do not include this directly, use dbg_interactive.i instead */ +/****** PEERS *********/ + +%{ +static void fd_add_cb(struct peer_info *peer, void *data) { + /* Callback called when the peer connection completes (or fails) */ + PyObject *PyPeer, *PyFunc; + PyObject *result = NULL; + + if (!data) { + TRACE_DEBUG(INFO, "Internal error: missing callback\n"); + return; + } + PyFunc = data; + + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + + /* Convert the argument */ + PyPeer = SWIG_NewPointerObj((void *)peer, SWIGTYPE_p_peer_info, 0 ); + + /* Call the function */ + result = PyEval_CallFunction(PyFunc, "(O)", PyPeer); + + Py_XDECREF(result); + Py_XDECREF(PyFunc); + + SWIG_PYTHON_THREAD_END_BLOCK; + return; +} +%} + +%extend peer_info { + /* Wrapper around fd_peer_add to allow calling the python callback */ + void add(PyObject * PyCb=NULL) { + int ret; + + if (PyCb) { + Py_XINCREF(PyCb); + ret = fd_peer_add ( $self, "dbg_interactive", fd_add_cb, PyCb ); + } else { + ret = fd_peer_add ( $self, "dbg_interactive", NULL, NULL ); + } + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + } + + /* Add an endpoint */ + void add_endpoint(char * endpoint) { + fd_log_debug("What is the best way in python to pass an endpoint? (ip + port)"); + } + +}
--- a/extensions/dbg_interactive/queues.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/queues.i Fri Dec 17 18:41:19 2010 +0900 @@ -35,3 +35,111 @@ /* Do not include this directly, use dbg_interactive.i instead */ +/****** FIFO QUEUES *********/ + +struct fifo { +}; + +%extend fifo { + fifo() { + struct fifo * q = NULL; + int ret = fd_fifo_new(&q); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + return NULL; + } + return q; + } + ~fifo() { + struct fifo *q = self; + fd_fifo_del(&q); + } + + /* Move all elements to another queue */ + void move(struct fifo * to) { + int ret = fd_fifo_move($self, to, NULL); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + } + + /* Get the length of the queue (nb elements) */ + int length() { + int l; + int ret = fd_fifo_length ( $self, &l ); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + return l; + } + + /* Is the threashold function useful here? TODO... */ + + /* Post an item */ + void post(PyObject * item) { + int ret; + PyObject * i = item; + + Py_XINCREF(i); + ret = fd_fifo_post($self, &i); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + } + + /* Get (blocking) */ + PyObject * get() { + int ret; + PyObject * i = NULL; + + ret = fd_fifo_get($self, &i); + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + + return i; + } + + /* TryGet (non-blocking, returns None on empty queue) */ + PyObject * tryget() { + int ret; + PyObject * i = NULL; + + ret = fd_fifo_tryget($self, &i); + if (ret == EWOULDBLOCK) { + Py_XINCREF(Py_None); + return Py_None; + } + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + + return i; + } + + /* TimedGet (blocking for a while) */ + PyObject * timedget(long seconds) { + int ret; + PyObject * i = NULL; + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += seconds; + + ret = fd_fifo_timedget($self, &i, &ts); + if (ret == ETIMEDOUT) { + Py_XINCREF(Py_None); + return Py_None; + } + if (ret != 0) { + DI_ERROR(ret, NULL, NULL); + } + + return i; + } + +} + + + +
--- a/extensions/dbg_interactive/sessions.i Thu Dec 16 18:56:41 2010 +0900 +++ b/extensions/dbg_interactive/sessions.i Fri Dec 17 18:41:19 2010 +0900 @@ -58,11 +58,8 @@ struct session_handler { }; +%nodefaultctor session_handler; %extend session_handler { - session_handler() { - DI_ERROR(EINVAL, PyExc_SyntaxError, "a cleanup callback parameter is required."); - return NULL; - } session_handler(PyObject * PyCb) { struct session_handler * hdl = NULL; int ret; @@ -96,6 +93,7 @@ } } + struct session { };
--- a/include/freeDiameter/libfreeDiameter.h Thu Dec 16 18:56:41 2010 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Fri Dec 17 18:41:19 2010 +0900 @@ -1876,6 +1876,9 @@ }; /* Some flags used in the functions bellow */ +#define AVPFL_SET_BLANK_VALUE 0x01 /* When creating an AVP, initialize its value to a blank area */ +#define AVPFL_MAX AVPFL_SET_BLANK_VALUE /* The biggest valid flag value */ + #define MSGFL_ALLOC_ETEID 0x01 /* When creating a message, a new end-to-end ID is allocated and set in the message */ #define MSGFL_ANSW_ERROR 0x02 /* When creating an answer message, set the 'E' bit and use the generic error ABNF instead of command-specific ABNF */ #define MSGFL_ANSW_NOSID 0x04 /* When creating an answer message, do not add the Session-Id even if present in request */ @@ -1889,7 +1892,7 @@ * * PARAMETERS: * model : Pointer to a DICT_AVP dictionary object describing the avp to create, or NULL. - * flags : Flags to use in creation (not used yet, should be 0). + * flags : Flags to use in creation (AVPFL_*). * avp : Upon success, pointer to the new avp is stored here. * * DESCRIPTION:
--- a/libfreeDiameter/messages.c Thu Dec 16 18:56:41 2010 +0900 +++ b/libfreeDiameter/messages.c Fri Dec 17 18:41:19 2010 +0900 @@ -139,6 +139,7 @@ /* Macro to validate a MSGFL_ value */ +#define CHECK_AVPFL(_fl) ( ((_fl) & (- (AVPFL_MAX << 1) )) == 0 ) #define CHECK_MSGFL(_fl) ( ((_fl) & (- (MSGFL_MAX << 1) )) == 0 ) @@ -199,7 +200,7 @@ TRACE_ENTRY("%p %x %p", model, flags, avp); /* Check the parameters */ - CHECK_PARAMS( avp && CHECK_MSGFL(flags) ); + CHECK_PARAMS( avp && CHECK_AVPFL(flags) ); if (model) { enum dict_object_type dicttype; @@ -224,6 +225,10 @@ new->avp_public.avp_vendor = dictdata.avp_vendor; } + if (flags & AVPFL_SET_BLANK_VALUE) { + new->avp_public.avp_value = &new->avp_storage; + } + /* The new object is ready, return */ *avp = new; return 0;