| | 1 | [[PageOutline(2-4)]] |
| | 2 | == Embedded Python interpreter == |
| | 3 | |
| | 4 | This {{{dbg_interactive.fdx}}} extension gives access to the freeDiameter framework through a Python interface layer. It can be used both to run pre-existing scripts or through an interactive console directly for quick tests / monitoring of the daemon's state. |
| | 5 | |
| | 6 | A warning anyway: this python layer should not be used for any purpose other than quick prototyping and/or debug. The memory management and the efficiency are bellow the level of the framework itself -- although still pretty usable. |
| | 7 | |
| | 8 | === Configuration === |
| | 9 | |
| | 10 | {{{dbg_interactive_xml.fdx}}} extension does not use a configuration file. It is possible however to specify a file associated with the extension in the main {{freeDiameter.conf}} file. In that case, this file should be a python script, that will be executed by the embedded python interpreter. If no such file is provided, the interpreter is run interactively (as long as the daemon is run with a usable console). |
| | 11 | |
| | 12 | |
| | 13 | === Usage === |
| | 14 | |
| | 15 | The list of all usable functions is given in [source:freeDiameter/doc/dbg_interactive.py.sample dbg_interactive.py.sample]. Here is a brief example of how to re-create the [wiki:test_app.fdx] client and server function from python: |
| | 16 | {{{ |
| | 17 | #!python |
| | 18 | # Load / create the dictionary objects |
| | 19 | gdict = cvar.fd_g_config.cnf_dict |
| | 20 | d_si = gdict.search ( DICT_AVP, AVP_BY_NAME, "Session-Id" ) |
| | 21 | d_oh = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host" ) |
| | 22 | d_or = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Realm" ) |
| | 23 | d_dh = gdict.search ( DICT_AVP, AVP_BY_NAME, "Destination-Host" ) |
| | 24 | d_dr = gdict.search ( DICT_AVP, AVP_BY_NAME, "Destination-Realm" ) |
| | 25 | d_rc = gdict.search ( DICT_AVP, AVP_BY_NAME, "Result-Code" ) |
| | 26 | d_vnd = gdict.new_obj(DICT_VENDOR, dict_vendor_data(999999, "app_test_py vendor") ) |
| | 27 | d_app = gdict.new_obj(DICT_APPLICATION, dict_application_data(0xffffff, "app_test_py appli"), d_vnd) |
| | 28 | d_req = gdict.new_obj(DICT_COMMAND, dict_cmd_data(0xfffffe, "Test_py-Request", 1), d_app) |
| | 29 | d_ans = gdict.new_obj(DICT_COMMAND, dict_cmd_data(0xfffffe, "Test_py-Answer", 0), d_app) |
| | 30 | d_avp = gdict.new_obj(DICT_AVP, dict_avp_data(0xffffff, "app_test_py avp", AVP_TYPE_INTEGER32, 999999 )) |
| | 31 | # (skip rules in the example) |
| | 32 | |
| | 33 | ###### Server part: |
| | 34 | def test_app_cb(inmsg, inavp, insession): |
| | 35 | tval = inmsg.search(d_avp).header().avp_value.u32 |
| | 36 | print "Py ECHO Test message from '%s' with test value %x, replying..." % (inmsg.search(d_oh).header().avp_value.os.as_str(), tval) |
| | 37 | answ = inmsg.create_answer() |
| | 38 | answ.rescode_set() |
| | 39 | answ.add_origin() |
| | 40 | ta = avp(d_avp, AVPFL_SET_BLANK_VALUE) |
| | 41 | ta.header().avp_value.u32 = tval |
| | 42 | answ.add_child(ta) |
| | 43 | return [ 0, answ, DISP_ACT_SEND ] |
| | 44 | |
| | 45 | # Register the callback for dispatch thread: |
| | 46 | hdl = disp_hdl(test_app_cb, DISP_HOW_CC, disp_when(d_app, d_req)) |
| | 47 | |
| | 48 | # Don't forget to register the application in the daemon for CER/CEA capabilities. |
| | 49 | fd_disp_app_support ( d_app, d_vnd, 1, 0 ) |
| | 50 | |
| | 51 | ###### Client part: |
| | 52 | def receive_answer(ans, testval): |
| | 53 | tval = ans.search(d_avp).header().avp_value.u32 |
| | 54 | 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()) |
| | 55 | del ans |
| | 56 | return None |
| | 57 | |
| | 58 | import random |
| | 59 | def send_query(destrealm="localdomain"): |
| | 60 | qry = msg(d_req) |
| | 61 | sess = session() |
| | 62 | tv = random.randint(1, 1<<32) |
| | 63 | # Session-Id |
| | 64 | a = avp(d_si, AVPFL_SET_BLANK_VALUE) |
| | 65 | a.header().avp_value.os = sess.getsid() |
| | 66 | qry.add_child(a) |
| | 67 | # Destination-Realm |
| | 68 | a = avp(d_dr, AVPFL_SET_BLANK_VALUE) |
| | 69 | a.header().avp_value.os = destrealm |
| | 70 | qry.add_child(a) |
| | 71 | # Origin-Host, Origin-Realm |
| | 72 | qry.add_origin() |
| | 73 | # Test-AVP |
| | 74 | a = avp(d_avp, AVPFL_SET_BLANK_VALUE) |
| | 75 | a.header().avp_value.u32 = tv |
| | 76 | qry.add_child(a) |
| | 77 | print "Py SEND %x to '%s'" % (tv, destrealm) |
| | 78 | qry.send(receive_answer, tv) |
| | 79 | |
| | 80 | send_query() |
| | 81 | }}} |
| | 82 | |
| | 83 | This is a simplified version without error checking, but it should give a good idea of the simplicity of use of the python interface. |
| | 84 | |
| | 85 | === Output === |
| | 86 | |
| | 87 | This application does not produce any particular output -- well, all depends on what is done in python. |
| | 88 | |
| | 89 | === Troubleshooting === |
| | 90 | |
| | 91 | |
| | 92 | |
| | 93 | |
| | 94 | |