[PATCH 7/10] rlm_python: 07-rewrite-python-function-wrapper-at-once.patch
Paul P Komkoff Jr
i at stingr.net
Mon Jan 30 23:23:58 CET 2006
Rewrite python_function wrapper at once
---
commit 97c0260f921dabc7d751a99c5ca7f07a1f916e8a
tree e0b6eab89ae865662aa5a09447fd7ffe805d90a1
parent 8b5cb6f9d73fc724c0ad822fc83523e13d84801e
author <stingray at boxster64.stingr.net> Sun, 29 Jan 2006 15:36:23 +0300
committer <stingray at boxster64.stingr.net> Sun, 29 Jan 2006 15:36:23 +0300
src/modules/rlm_python/rlm_python.c | 331 +++++++++++++----------------------
1 files changed, 125 insertions(+), 206 deletions(-)
diff --git a/src/modules/rlm_python/rlm_python.c b/src/modules/rlm_python/rlm_python.c
--- a/src/modules/rlm_python/rlm_python.c
+++ b/src/modules/rlm_python/rlm_python.c
@@ -295,214 +295,133 @@ static void python_vptuple(VALUE_PAIR **
* xxx We're not checking the errors. If we have errors, what do we do?
*/
-static int python_function(REQUEST *request,
- PyObject *pFunc, const char *function_name)
-{
-#define BUF_SIZE 1024
-
- char buf[BUF_SIZE]; /* same size as vp_print buffer */
-
- VALUE_PAIR *vp;
-
- PyObject *pValue, *pValuePairContainer, **pValueHolder, **pValueHolderPtr;
- int i, n_tuple, return_value;
-
- /* Return with "OK, continue" if the function is not defined. */
- if (pFunc == NULL) {
- return RLM_MODULE_OK;
- }
-
- /* Default return value is "OK, continue" */
- return_value = RLM_MODULE_OK;
-
- /* We will pass a tuple containing (name, value) tuples
- * We can safely use the Python function to build up a tuple,
- * since the tuple is not used elsewhere.
- *
- * Determine the size of our tuple by walking through the packet.
- * If request is NULL, pass None.
- */
- n_tuple = 0;
-
- if (request != NULL) {
- for (vp = request->packet->vps; vp; vp = vp->next) {
- n_tuple++;
- }
- }
-
- /* Create the tuple and a holder for the pointers, so that we can
- * decref more efficiently later without the overhead of reading
- * the tuple.
- *
- * We use malloc() instead of the Python memory allocator since we
- * are not embedded.
- */
-
- if (NULL == (pValueHolder = pValueHolderPtr =
- malloc(sizeof(PyObject *) * n_tuple))) {
-
- radlog(L_ERR, "%s: malloc of %d bytes failed\n",
- function_name, sizeof(PyObject *) * n_tuple);
-
- return -1;
- }
-
- if (n_tuple == 0) {
- pValuePairContainer = Py_None;
- }
- else {
- pValuePairContainer = PyTuple_New(n_tuple);
-
- i = 0;
- for (vp = request->packet->vps; vp; vp = vp->next) {
- PyObject *pValuePair, *pString1, *pString2;
-
- /* The inside tuple has two only: */
- pValuePair = PyTuple_New(2);
-
- /* The name. logic from vp_prints, lib/print.c */
- if (vp->flags.has_tag) {
- snprintf(buf, BUF_SIZE, "%s:%d", vp->name, vp->flags.tag);
- }
- else {
- strcpy(buf, vp->name);
- }
-
- pString1 = PyString_FromString(buf);
- PyTuple_SetItem(pValuePair, 0, pString1);
-
-
- /* The value. Use delimiter - don't know what that means */
- vp_prints_value(buf, sizeof(buf), vp, 1);
- pString2 = PyString_FromString(buf);
- PyTuple_SetItem(pValuePair, 1, pString2);
-
- /* Put the tuple inside the container */
- PyTuple_SetItem(pValuePairContainer, i++, pValuePair);
-
- /* Store the pointer in our malloc() storage */
- *pValueHolderPtr++ = pValuePair;
- }
- }
-
-
- /* Call Python function.
- */
-
- if (pFunc && PyCallable_Check(pFunc)) {
- PyObject *pArgs;
-
- /* call the function with a singleton tuple containing the
- * container tuple.
- */
-
- if ((pArgs = PyTuple_New(1)) == NULL) {
- radlog(L_ERR, "%s: could not create tuple", function_name);
- return -1;
- }
- if ((PyTuple_SetItem(pArgs, 0, pValuePairContainer)) != 0) {
- radlog(L_ERR, "%s: could not set tuple item", function_name);
- return -1;
- }
-
- if ((pValue = PyObject_CallObject(pFunc, pArgs)) == NULL) {
- radlog(L_ERR, "%s: function call failed", function_name);
- python_error();
- return -1;
- }
-
- /* The function returns either:
- * 1. tuple containing the integer return value,
- * then the integer reply code (or None to not set),
- * then the string tuples to build the reply with.
- * (returnvalue, (p1, s1), (p2, s2))
- *
- * 2. the function return value alone
- *
- * 3. None - default return value is set
- *
- * xxx This code is messy!
- */
-
- if (PyTuple_Check(pValue)) {
- PyObject *pTupleInt;
-
- if (PyTuple_Size(pValue) != 3) {
- radlog(L_ERR, "%s: tuple must be " \
- "(return, replyTuple, configTuple)",
- function_name);
-
- }
- else {
- pTupleInt = PyTuple_GetItem(pValue, 0);
-
- if ((pTupleInt == NULL) || !PyInt_Check(pTupleInt)) {
- radlog(L_ERR, "%s: first tuple element not an integer",
- function_name);
- }
- else {
- /* Now have the return value */
- return_value = PyInt_AsLong(pTupleInt);
-
- /* Reply item tuple */
- python_vptuple(&request->reply->vps,
- PyTuple_GetItem(pValue, 1), function_name);
-
- /* Config item tuple */
- python_vptuple(&request->config_items,
- PyTuple_GetItem(pValue, 2), function_name);
- }
- }
- }
- else if (PyInt_Check(pValue)) {
- /* Just an integer */
- return_value = PyInt_AsLong(pValue);
- }
- else if (pValue == Py_None) {
- /* returned 'None', return value defaults to "OK, continue." */
- return_value = RLM_MODULE_OK;
- }
- else {
- /* Not tuple or None */
- radlog(L_ERR, "%s function did not return a tuple or None\n",
- function_name);
- }
-
-
- /* Decrease reference counts for the argument and return tuple */
- Py_DECREF(pArgs);
- Py_DECREF(pValue);
- }
-
- /* Decrease reference count for the tuples passed, the
- * container tuple, and the return value.
- */
-
- pValueHolderPtr = pValueHolder;
- i = n_tuple;
- while (i--) {
- /* Can't write as pValueHolderPtr since Py_DECREF is a macro */
- Py_DECREF(*pValueHolderPtr);
- pValueHolderPtr++;
- }
- free(pValueHolder);
- Py_DECREF(pValuePairContainer);
-
- /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
-
- /* Free pairs if we are rejecting.
- * xxx Shouldn't the core do that?
- */
-
- if ((return_value == RLM_MODULE_REJECT) && (request != NULL)) {
- pairfree(&(request->reply->vps));
- }
-
- /* Return the specified by the Python module */
- return return_value;
+static int python_function(REQUEST *request, PyObject *pFunc, const char *funcname) {
+ char buf[1024];
+ VALUE_PAIR *vp;
+ PyObject *pRet = NULL;
+ PyObject *pArgs = NULL;
+ int tuplelen;
+ int ret;
+
+ PyGILState_STATE gstate;
+
+ /* Return with "OK, continue" if the function is not defined. */
+ if (pFunc == NULL)
+ return RLM_MODULE_OK;
+
+ /* Default return value is "OK, continue" */
+ ret = RLM_MODULE_OK;
+
+ /* We will pass a tuple containing (name, value) tuples
+ * We can safely use the Python function to build up a tuple,
+ * since the tuple is not used elsewhere.
+ *
+ * Determine the size of our tuple by walking through the packet.
+ * If request is NULL, pass None.
+ */
+ tuplelen = 0;
+ if (request != NULL) {
+ for (vp = request->packet->vps; vp; vp = vp->next)
+ tuplelen++;
+ }
+ if (tuplelen == 0) {
+ Py_INCREF(Py_None);
+ pArgs = Py_None;
+ } else {
+ int i = 0;
+ if ((pArgs = PyTuple_New(tuplelen)) == NULL)
+ goto failed;
+ for (vp = request->packet->vps; vp != NULL; vp = vp->next, i++) {
+ PyObject *pPair;
+ PyObject *pStr;
+ /* The inside tuple has two only: */
+ if ((pPair = PyTuple_New(2)) == NULL)
+ goto failed;
+ /* Put the tuple inside the container */
+ PyTuple_SET_ITEM(pArgs, i, pPair);
+ /* The name. logic from vp_prints, lib/print.c */
+ if (vp->flags.has_tag)
+ snprintf(buf, sizeof(buf), "%s:%d", vp->name, vp->flags.tag);
+ else
+ strcpy(buf, vp->name);
+ if ((pStr = PyString_FromString(buf)) == NULL)
+ goto failed;
+ PyTuple_SET_ITEM(pPair, 0, pStr);
+ vp_prints_value(buf, sizeof(buf), vp, 1);
+ if ((pStr = PyString_FromString(buf)) == NULL)
+ goto failed;
+ PyTuple_SET_ITEM(pPair, 1, pStr);
+ }
+ }
+
+ /* Call Python function. */
+ gstate = PyGILState_Ensure();
+
+ pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
+
+ PyGILState_Release(gstate);
+
+ if (pRet == NULL)
+ goto failed;
+
+ if (request == NULL)
+ goto okay;
+ /* The function returns either:
+ * 1. tuple containing the integer return value,
+ * then the integer reply code (or None to not set),
+ * then the string tuples to build the reply with.
+ * (returnvalue, (p1, s1), (p2, s2))
+ *
+ * 2. the function return value alone
+ *
+ * 3. None - default return value is set
+ *
+ * xxx This code is messy!
+ */
+ if (PyTuple_CheckExact(pRet)) {
+ PyObject *pTupleInt;
+
+ if (PyTuple_GET_SIZE(pRet) != 3) {
+ radlog(L_ERR, "rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
+ goto failed;
+ }
+ pTupleInt = PyTuple_GET_ITEM(pRet, 0);
+ if (!PyInt_CheckExact(pTupleInt)) {
+ radlog(L_ERR, "rlm_python:%s: first tuple element not an integer", funcname);
+ goto failed;
+ }
+ /* Now have the return value */
+ ret = PyInt_AsLong(pTupleInt);
+ /* Reply item tuple */
+ python_vptuple(&request->reply->vps, PyTuple_GET_ITEM(pRet, 1), funcname);
+ /* Config item tuple */
+ python_vptuple(&request->config_items, PyTuple_GET_ITEM(pRet, 2), funcname);
+ } else
+ if (PyInt_CheckExact(pRet)) {
+ /* Just an integer */
+ ret = PyInt_AsLong(pRet);
+ } else
+ if (pRet == Py_None) {
+ /* returned 'None', return value defaults to "OK, continue." */
+ ret = RLM_MODULE_OK;
+ } else {
+ /* Not tuple or None */
+ radlog(L_ERR, "rlm_python:%s: function did not return a tuple or None", funcname);
+ goto failed;
+ }
+ if (ret == RLM_MODULE_REJECT && request != NULL)
+ pairfree(&request->reply->vps);
+okay:
+ Py_DECREF(pArgs);
+ Py_DECREF(pRet);
+ return ret;
+failed:
+ python_error();
+ Py_XDECREF(pArgs);
+ Py_XDECREF(pRet);
+ return -1;
}
-
/*
* Import a user module and load a function from it
*/
--
Paul P 'Stingray' Komkoff Jr // http://stingr.net/key <- my pgp key
This message represents the official view of the voices in my head
More information about the Freeradius-Devel
mailing list