Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
oai
freediameter
Commits
a6c1c1ed
Commit
a6c1c1ed
authored
Dec 17, 2010
by
Sebastien Decugis
Browse files
Improved usability of dbg_interactive
parent
37f3b35c
Changes
10
Hide whitespace changes
Inline
Side-by-side
doc/dbg_interactive.py.sample
View file @
a6c1c1ed
...
...
@@ -103,7 +103,8 @@ del l1
############# 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 @@ del v
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 @@ a.application_name = "My test appl"
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 @@ t.type_name = "My binary buffer AVP"
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 @@ c.enum_value.os.dump()
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 @@ a.avp_basetype = AVP_TYPE_OCTETSTRING
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 @@ c.cmd_flag_val = CMD_FLAG_PROXIABLE
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 @@ 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.
del r2
del r3
del r4
####### Now play with the "real" dictionary
...
...
@@ -271,10 +309,11 @@ for c in list.enum_as("struct rtd_candidate *"):
## 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 @@ val.os = "my.origin.host"
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 @@ dwr_hdr.msg_hbhid
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.first_child().dump()
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
# 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)
######################### old stuff (need update) ######################
# 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
extensions/dbg_interactive/dbg_interactive.i
View file @
a6c1c1ed
...
...
@@ -128,6 +128,11 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
}
/* 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
*********************************************************/
...
...
extensions/dbg_interactive/dictionary.i
View file @
a6c1c1ed
...
...
@@ -241,4 +241,171 @@ struct dict_object {
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
;
}
}
extensions/dbg_interactive/dispatch.i
View file @
a6c1c1ed
...
...
@@ -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
)
{