[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