Commit 0c11a767 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

dbg_interactive almost complete

parent 30d8181e
......@@ -89,7 +89,7 @@ l3.insert_next(l4) # l3 -> l4
l3.insert_next(l5) # l3 -> l5 -> l4
l1.concat(l3) # l1 -> l2 -> l5 -> l4
elements = l1.enum_as() # default: enumerates as fd_list. Warning: this a copy, changing the python list has no effect on the underlying list.
elements = l1.enum_as() # default: enumerates as fd_list. Warning: this a copy, changing the python list has no effect on the underlying fd_list.
for li in elements:
li.dump()
......@@ -223,9 +223,6 @@ d.new_obj(DICT_RULE, r, my_req)
d.new_obj(DICT_RULE, r, my_ans)
del r
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.
......@@ -233,6 +230,9 @@ del r2
del r3
del r4
d.dump()
del d
####### Now play with the "real" dictionary
gdict = cvar.fd_g_config.cnf_dict
......@@ -272,7 +272,7 @@ hdl = session_handler(my_cleanup)
s1 = session()
s1.getsid()
s2 = session("this.is.a.full.session.id")
r,s3,isnew = fd_sess_fromsid("this.is.a.full.session.id")
r,s3,isnew = fd_sess_fromsid("this.is.a.full.session.id") # use this call if "isnew" is really needed...
s4 = session("host.id", "optional.part")
s4.settimeout(30) # the python wrapper takes a number of seconds as parameter for simplicity
s4.dump()
......@@ -303,6 +303,31 @@ list = rd.extract(-1)
for c in list.enum_as("struct rtd_candidate *"):
print "%s (%s): %s" % (c.diamid, c.realm, c.score)
del rd
# A rt_fwd callback has the following prototype:
def my_rtfwd_cb(msg):
print "Forwarding the following message:"
msg.dump()
return [ 0, msg ] # return None instead of msg to stop forwarding.
fwdhdl = fd_rt_fwd_hdl( my_rtfwd_cb, RT_FWD_REQ )
# A rt_out cb has the following prototype:
def my_rtout_cb(msg, list):
print "Sending out the following message:"
msg.dump()
print "The possible candidates are:"
for c in list.enum_as("struct rtd_candidate *"):
print "%s (%s): %s" % (c.diamid, c.realm, c.score)
return 0 # returns an error code (standard errno values)
outhdl = fd_rt_out_hdl( my_rtout_cb ) # a priority can be specified as 2nd parameter, default is 0.
############# Messages, AVPs ############
......@@ -321,7 +346,7 @@ vsai = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Spe
# Set values
val = avp_value()
val.u32 = 123
vi.setval(None) # this cleans a previous value (not needed)
vi.setval(None) # this cleans a previous value (usually not needed)
vi.setval(val)
val.os = "my.origin.host"
oh.setval(val)
......@@ -378,7 +403,7 @@ avp = avp.get_next() # when last AVP, returns None
# Get all 1st level children (slower) -- warning, changes to the python list will not be reflected on the underlying message. read-only use.
dwr.children()
# example use:
for a in dwr.children()
for a in dwr.children():
a.dump(0) # 0 means: dump only this object, do not walk the tree
......@@ -435,6 +460,7 @@ gavp.children()
# Send a message:
mydwr = msg(buf)
mydwr.send()
# Optionaly, a callback can be registered when a message is sent, with an optional object.
......@@ -446,10 +472,12 @@ def send_callback(msg, obj):
obj
return None
mydwr = msg(buf)
mydwr.send(send_callback, some_object)
# Set a result code in an answer message.
mydwr = msg(buf)
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
......@@ -597,6 +625,21 @@ myqueue.timedget(3)
# Show the number of items in the queue
myqueue.length()
## Variants:
# All the previous calls are suitable to queue Python objects.
# In order to interact with objects queued / poped by C counterpart,
# a second parameter must be passed to specify the object type,
# as follow:
ev = fd_event()
ev.code = FDEV_DUMP_EXT
cvar.fd_g_config.cnf_main_ev.post(ev, "struct fd_event *")
# Similarly, for *get, we can specify the structure that was queued:
myqueue.get("struct fd_event *")
myqueue.tryget("struct fd_event *")
myqueue.timedget(3, "struct fd_event *")
del myqueue
......@@ -613,9 +656,7 @@ for p in peers:
# 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
np.config.pic_flags.pro4 = PI_P4_TCP
# Add this peer into the framework.
......@@ -633,7 +674,55 @@ def add_cb(peer):
else:
print "The peer has been destroyed before it completed the connection."
# Then add the peer simply like this:
# Then add the peer like this:
np.add(add_cb)
# Search a peer by its diameter id (returns a peer_hdr object if found) -- similar to fd_peer_getbyid
p = peer_search("nas.domain.aaa")
## Validation callback (see fd_peer_validate_register documentation)
# cb2 prototype:
def my_validate_cb2(pinfo):
print "Cb2 callback trigged for peer %s" % (pinfo.pi_diamid)
# Usually, this would be used only to check some TLS properties,
# which is not really possible yet through the python interpreter...
return 0 # return an error code if the peer is not validated
# cb prototype:
def my_validate_cb(pinfo):
print "Validate callback trigged for peer %s" % (pinfo.pi_diamid)
# If the peer is not allowed to connect:
#return -1
# If the peer is authorized:
#return 1
# In addition, if IPsec is allowed,
#pinfo.config.pic_flags.sec = PI_SEC_NONE
# If no decision has been made:
#return 0
# If the peer is temporarily authorized but a second callback must be called after TLS negociation:
return my_validate_cb2
# Register the callback, it will be called on new incoming connections.
peer_validate_register(my_validate_cb)
############# ENDPOINTS ############
ep = fd_endpoint("129.168.168.192")
# with port:
ep = fd_endpoint("129.168.168.192", 3868)
# With different flags:
ep = fd_endpoint("129.168.168.192", 3868, EP_FL_PRIMARY)
# Add IP information for the peer
np = peer_info()
ep.add_merge(np.pi_endpoints)
fd_ep_dump(0, np.pi_endpoints)
......@@ -25,6 +25,8 @@ SET(SWIG_MODULE_fDpy_EXTRA_DEPS
dispatch.i
queues.i
peers.i
events.i
endpoints.i
)
SET_SOURCE_FILES_PROPERTIES(dbg_interactive.i PROPERTIES SWIG_MODULE_NAME fDpy)
......
......@@ -67,7 +67,7 @@
/* This is not thread-safe etc. but it should work /most of the time/. */
static int wrapper_errno;
static PyObject* wrapper_errno_py;
static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
static const char * wrapper_error_txt; /* if NULL, use strerror(errno) */
#define DI_ERROR(code, pycode, str) { \
fd_log_debug("[dbg_interactive] ERROR: %s: %s\n", __PRETTY_FUNCTION__, str ? str : strerror(code)); \
wrapper_errno = code; \
......@@ -87,7 +87,7 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
$action
/* Now, test for error */
if (wrapper_errno) {
char * str = wrapper_error_txt ? wrapper_error_txt : strerror(wrapper_errno);
const char * str = wrapper_error_txt ? wrapper_error_txt : strerror(wrapper_errno);
PyObject * exc = wrapper_errno_py;
if (!exc) {
switch (wrapper_errno) {
......@@ -108,7 +108,7 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
Some types & typemaps for usability
***********************************/
%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) }; /* fd_hash */
%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) };
/* Generic typemap for functions that create something */
%typemap(in, numinputs=0,noblock=1) SWIGTYPE ** OUTPUT (void *temp = NULL) {
......@@ -118,21 +118,42 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
%append_output(SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
}
/* Typemap to return a boolean value as output parameter */
%typemap(in, numinputs=0,noblock=1) int * BOOL_OUT (int temp) {
$1 = &temp;
}
%typemap(argout,noblock=1) int * BOOL_OUT {
PyObject * r;
if (*$1)
r = Py_True;
else
r = Py_False;
Py_XINCREF(r);
%append_output(r);
}
/* To allow passing callback functions defined in python */
%typemap(in) PyObject *PyCb {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
SWIG_fail;
if (!$input || ($input == Py_None)) {
$1 = NULL;
} else {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
SWIG_fail;
}
$1 = $input;
}
$1 = $input;
}
/* Forward declaration for the peers module */
%{
/* Forward declaration for the peers module */
static void fd_add_cb(struct peer_info *peer, void *data);
%}
/* Overwrite declaration to apply typemaps */
int fd_sess_fromsid ( char * STRING, size_t LENGTH, struct session ** OUTPUT, int * BOOL_OUT);
/*********************************************************
Now, create wrappers for (almost) all objects from fD API
*********************************************************/
......@@ -154,3 +175,5 @@ for more usable python-style versions.
%include "queues.i"
%include "peers.i"
%include "events.i"
%include "endpoints.i"
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@nict.go.jp> *
* *
* Copyright (c) 2010, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *
* *
* * Neither the name of the WIDE Project or NICT nor the *
* names of its contributors may be used to endorse or *
* promote products derived from this software without *
* specific prior written permission of WIDE Project and *
* NICT. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
/* Do not include this directly, use dbg_interactive.i instead */
/****** ENDPOINTS *********/
%{
#include <sys/socket.h>
#include <netdb.h>
%}
%extend fd_endpoint {
fd_endpoint() {
struct fd_endpoint *np = (struct fd_endpoint *)calloc(1, sizeof(struct fd_endpoint));
if (!np) {
DI_ERROR_MALLOC;
return NULL;
}
fd_list_init(&np->chain, np);
return np;
}
fd_endpoint(const char * endpoint, uint16_t port = 0, uint32_t flags = EP_FL_CONF) {
struct addrinfo hints;
struct addrinfo *ai = NULL;
int ret;
memset(&hints, 0, sizeof(hints));
hints.ai_family= AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(endpoint, NULL, &hints, &ai);
if (ret) {
DI_ERROR(ret, PyExc_ValueError, gai_strerror(ret));
return NULL;
}
if (port) {
switch (ai->ai_family) {
case AF_INET:
((sSA4 *)ai->ai_addr)->sin_port = htons(port);
break;
case AF_INET6:
((sSA6 *)ai->ai_addr)->sin6_port = htons(port);
break;
default:
DI_ERROR(EINVAL, PyExc_RuntimeError, "Unknown family returned by getaddrinfo");
return NULL;
}
}
struct fd_endpoint *np = (struct fd_endpoint *)calloc(1, sizeof(struct fd_endpoint));
if (!np) {
DI_ERROR_MALLOC;
return NULL;
}
fd_list_init(&np->chain, np);
memcpy(&np->s.sa, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
np->flags = flags;
return np;
}
~fd_endpoint() {
fd_list_unlink(&$self->chain);
free($self);
}
/* Merge to a list */
%delobject add_merge;
void add_merge(struct fd_list * eplist) {
int ret;
if (!eplist) {
DI_ERROR(EINVAL, NULL, NULL);
return;
}
ret = fd_ep_add_merge( eplist, &$self->s.sa, sSAlen(&$self->s.sa), $self->flags );
if (ret) {
DI_ERROR(ret, NULL, NULL);
return;
}
return;
}
void dump() {
fd_ep_dump_one( "", $self, "\n" );
}
}
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@nict.go.jp> *
* *
* Copyright (c) 2010, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *
* *
* * Neither the name of the WIDE Project or NICT nor the *
* names of its contributors may be used to endorse or *
* promote products derived from this software without *
* specific prior written permission of WIDE Project and *
* NICT. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
/* Do not include this directly, use dbg_interactive.i instead */
/****** EVENTS *********/
%extend fd_event {
fd_event(int code, char *STRING, size_t LENGTH) {
struct fd_event * fd = calloc(1, sizeof(struct fd_event));
if (!fd) {
DI_ERROR_MALLOC;
return NULL;
}
fd->code = code;
fd->data = STRING; /* Should maybe malloc it ? */
fd->size = LENGTH;
return fd;
}
}
......@@ -70,8 +70,14 @@
fd_list_insert_after($self, li);
}
/* Test for emptyness */
int isempty() {
return FD_IS_LIST_EMPTY($self);
PyObject * isempty() {
PyObject * ret;
if (FD_IS_LIST_EMPTY($self))
ret = Py_True;
else
ret = Py_False;
Py_XINCREF(ret);
return ret;
}
/* Concatenate two lists */
void concat(struct fd_list * li) {
......
......@@ -292,8 +292,14 @@ struct msg {
}
/* Is routable? */
int is_routable() {
return fd_msg_is_routable($self);
PyObject * is_routable() {
PyObject * r;
if (fd_msg_is_routable($self))
r = Py_True;
else
r = Py_False;
Py_XINCREF(r);
return r;
}
/* Get the source */
......
......@@ -66,7 +66,20 @@ static void fd_add_cb(struct peer_info *peer, void *data) {
%}
%extend peer_info {
peer_info () {
struct peer_info *np = (struct peer_info *)calloc(1, sizeof(struct peer_info));
if (!np) {
DI_ERROR_MALLOC;
return NULL;
}
fd_list_init(&np->pi_endpoints, NULL);
return np;
}
/* Wrapper around fd_peer_add to allow calling the python callback */
%delobject add;
void add(PyObject * PyCb=NULL) {
int ret;
......@@ -80,10 +93,135 @@ static void fd_add_cb(struct peer_info *peer, void *data) {
DI_ERROR(ret, NULL, NULL);
}
}
}
%inline %{
static struct peer_hdr * peer_search(char *diamid) {
struct peer_hdr *r = NULL;
int ret = fd_peer_getbyid( diamid, &r );
if (ret) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return r;
}
%}
/* Add an endpoint */
void add_endpoint(char * endpoint) {
fd_log_debug("What is the best way in python to pass an endpoint? (ip + port)");
%{
static PyObject * validate_cb_py = NULL;
static PyObject * validate_cb2_py = NULL;
/* C wrapper that calls validate_cb2_py */
int call_the_python_validate_callback2(struct peer_info * info) {
PyObject *PyInfo;
PyObject *result = NULL;
int ret = 0;
if (!validate_cb2_py) {
fd_log_debug("Internal error: missing the callback2!\n");
return ENOTSUP;
}
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
/* Convert the arguments */
PyInfo = SWIG_NewPointerObj((void *)info, SWIGTYPE_p_peer_info, 0 );
/* Call the function */
result = PyEval_CallFunction(validate_cb2_py, "(O)", PyInfo);
/* The result is an integer */
if ((result == NULL) || !SWIG_IsOK(SWIG_AsVal_int(result, &ret))) {
fd_log_debug("Error: The Python callback did not return an integer.\n");
ret = EINVAL;
goto out;
}
out:
Py_XDECREF(result);
SWIG_PYTHON_THREAD_END_BLOCK;
return ret;
}
/* C wrapper that calls validate_cb_py */
int call_the_python_validate_callback(struct peer_info * info, int * auth, int (**cb2)(struct peer_info *)) {
PyObject *PyInfo;
PyObject *result = NULL;
int ret = 0;
if (!validate_cb_py) {
fd_log_debug("Internal error: missing the callback!\n");
return ENOTSUP;
}
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
/* Convert the arguments */
PyInfo = SWIG_NewPointerObj((void *)info, SWIGTYPE_p_peer_info, 0 );
/* Call the function */
result = PyEval_CallFunction(validate_cb_py, "(O)", PyInfo);
/* The result is supposedly -1, 1, or a cb2 */
if (result == NULL) {
fd_log_debug("Error: The Python callback did not return a value.\n");
ret = EINVAL;
goto out;
}
if (PyCallable_Check(result)) {
if (cb2) {
if (validate_cb2_py && (validate_cb2_py != result)) {
fd_log_debug("Only 1 register callback2 is supported currently\n");
ret = ENOTSUP;
goto out;
}
validate_cb2_py = result;
*cb2 = call_the_python_validate_callback2;
*auth = 1;
goto out_nodec;
} else {
*auth = 1;
goto out; /* ignore the callback since it won't be used */
}
} else { /* In this case, the return value must be -1, 0, or 1 */
if (!SWIG_IsOK(SWIG_AsVal_int(result, auth))) {
fd_log_debug("Error: Cannot convert the return value to integer.\n");
ret = EINVAL;
goto out;
}