dimmodule.cpp

Go to the documentation of this file.
00001 #define DIMC_MODULE
00002 #include <cctype>
00003 #include <cstdlib>
00004 #include <cstdio>
00005 #include <map>
00006 #include <string>
00007 
00008 #ifndef _WIN32
00009 #include <unistd.h>
00010 #include <pthread.h>
00011 #else
00012 #define HOST_NAME_MAX 256
00013 #include <winsock.h>
00014 #endif
00015 
00016 extern "C" {
00017 #include <Python.h>
00018 #include "dic.h"
00019 #include "dis.h"
00020 #include "dim_common.h"
00021 }
00022 #include "pydim_utils.cpp"
00023 
00024 using namespace std;
00025 static char server_name[HOST_NAME_MAX + 1];
00026 typedef void* func(int*);
00027 
00028 /******************************************************************************/
00029 /* DIS containers for callbacks*/
00030 /******************************************************************************/
00031 
00032 typedef struct {
00033   char *name;
00034   char *format;
00035   PyObject *pyTag;
00036   PyObject *pyFunc;
00037 } CmndCallback;
00038 typedef CmndCallback* CmndCallbackPtr;
00039 
00040 map<string, CmndCallbackPtr> cmndName2PythonFunc;
00041 map<long, CmndCallbackPtr> cmndUniqueTag2PythonFunc;
00042 
00043 typedef struct {
00044   char *name;
00045   char *format;
00046   char *buffer;
00047   unsigned int bufferSize;
00048   bool isUpdated;
00049   bool firstCall;
00050   long pyTag;
00051   PyObject *pyFunc;
00052 } ServiceCallback;
00053 
00054 typedef ServiceCallback *ServiceCallbackPtr;
00055 map<unsigned int, ServiceCallbackPtr> serviceID2Callback;
00056 
00057 static void dim_callbackCommandFunc(void*, void*, int*);
00058 
00059 /******************************************************************************/
00060 /* DIC containers for callbacks and function prototypes                       */
00061 /******************************************************************************/
00062 struct _dic_info_service_callback{
00063   PyObject* pyFunc;
00064   char* name;
00065   char* format;
00066   PyObject* pyDefaultArg;
00067   long pyTag;
00068   int service_id;
00069 };
00070 
00071 struct _dic_cmnd_callback {
00072   PyObject* pyFunc;
00073   long pyTag;
00074 };
00075 
00076 unsigned long _dic_cmnd_callback_ID;
00077 
00078 
00079 static map<string,_dic_info_service_callback*>_dic_info_service_name2Callback;
00080 static map<unsigned int, _dic_info_service_callback*>_dic_info_service_id2Callback;
00081 static map<long, _dic_cmnd_callback*> _dic_cmnd_callback_tag2Callback;
00082 
00083 void _dic_error_user_routine_dummy(int, int, char*);
00084 void _dic_info_service_dummy (void*, void*, int*);
00085 void _dic_cmnd_callback_dummy(void*, int*);
00086 void _dic_error_user_routine_dummy(int, int, char*);
00087 
00088 /******************************************************************************/
00089 
00090 
00091 /** \defgroup dim DIM interface functions
00092  * @{
00093  */
00094 
00095 static PyObject*
00096 dim_dis_start_serving (PyObject* /* self */, PyObject *args)  {
00097   /** Calls dis_start_serving.
00098    * @param server_name The name under which the server is going to be
00099    * registered in the DIM DNS. If not specified the hostname is used.
00100    */
00101   char *name = NULL;
00102   int ret;
00103 
00104   if (!PyArg_ParseTuple(args, "|s", &name)) {
00105     PyErr_SetString(PyExc_RuntimeError, "Invalid server name.");
00106     return NULL;
00107   }
00108   if (name)
00109     strncpy(server_name, name, HOST_NAME_MAX + 1);
00110   else {
00111     gethostname(server_name, HOST_NAME_MAX);
00112     debug("No server name specified. Using machine hostname...\n");
00113   }
00114   Py_BEGIN_ALLOW_THREADS  
00115   ret = dis_start_serving(server_name);
00116   Py_END_ALLOW_THREADS
00117 
00118   return Py_BuildValue("i", ret);
00119 }
00120 
00121 static PyObject*
00122 dim_dis_stop_serving(PyObject* /* self */, PyObject* /* args */) {
00123   /** Calls void dis_stop_serving(void)
00124   */
00125   Py_BEGIN_ALLOW_THREADS  
00126   dis_stop_serving();
00127   Py_END_ALLOW_THREADS
00128   Py_RETURN_NONE;
00129 }
00130 
00131 
00132 static PyObject*
00133 dim_dis_set_dns_node(PyObject* /* self */, PyObject* args) {
00134   /**
00135    * Calls dis_set_dns_node(char* node)
00136    *
00137    * @param dns_node_name The name of the DNS server
00138    * @return DIM return code (1 for success)
00139    */
00140   char* name = NULL;
00141   int ret;
00142 
00143   if ( !PyArg_ParseTuple(args, "s", &name) ) {
00144     PyErr_SetString(PyExc_RuntimeError, "Invalid DNS name");
00145     return NULL;
00146   }
00147   ret = dis_set_dns_node(name);
00148 
00149   return Py_BuildValue("i", ret);
00150 }
00151 
00152 
00153 static PyObject*
00154 dim_dis_get_dns_node(PyObject* /* self */, PyObject* /* args */) {
00155   /* calls dis_get_dns_node(char* node)
00156      the function should return the DNS node
00157      */
00158   char names[256];
00159   if ( !dis_get_dns_node(names) ) {
00160     PyErr_SetString(PyExc_RuntimeError, "Failed to get DNS node name");
00161     return NULL;
00162   }
00163   return Py_BuildValue("s", names);
00164 }
00165 
00166 
00167 static PyObject*
00168 dim_dis_set_dns_port(PyObject* /* self */, PyObject* args) {
00169   /**
00170    * Calls dis_set_dns_port(int port).
00171    *
00172    * @param dim_dns_port (unsigned integer)
00173    * @return DIM return code (1 for success)
00174    */
00175   unsigned int port;
00176   int ret;
00177 
00178   if (!PyArg_ParseTuple(args, "I", &port)) {
00179     PyErr_SetString(PyExc_TypeError,
00180         "Argument 'port' must be a pozitive integer");
00181     return NULL;
00182   }
00183   ret = dis_set_dns_port(port);
00184 
00185   return Py_BuildValue("i", ret);
00186 }
00187 
00188 static PyObject*
00189 dim_dis_get_dns_port(PyObject* /* self */, PyObject* /* args */) {
00190   /**
00191    * Calls dis_get_dns_port().
00192    * @return port The DIM DNS port.
00193    */
00194   int port;
00195   port = dis_get_dns_port();
00196   return Py_BuildValue("i", port);
00197 }
00198 
00199 
00200 typedef struct {
00201   PyObject* self;
00202   PyObject* func;
00203 } PyCallback; //for Python callbacks
00204 
00205 static PyCallback dis_callbackExitHandler_func,
00206                   dis_callbackErrorHandler_func,
00207                   dis_callbackClientExitHandler_func;
00208 
00209 static PyCallback _dic_callback_errorHandler_func;
00210 
00211 static void
00212 dim_dis_callbackExitHandler(int* code) {
00213   /**
00214    * NOTE: this function does not have the interpretor lock when called.
00215    * @param code The exit code passed by the DIM library.
00216    */
00217   PyObject *arg, *res;
00218   PyGILState_STATE gstate;
00219 
00220   if ( dis_callbackExitHandler_func.func ) {
00221     gstate = PyGILState_Ensure();
00222     arg = Py_BuildValue("i", *code);
00223     res = PyEval_CallObject(dis_callbackExitHandler_func.func, arg);
00224     Py_DECREF(arg);
00225     Py_XDECREF(res);
00226     PyGILState_Release(gstate);
00227   } else {
00228     debug("Could not find any registered Python function. "\
00229         "Dropping DIM exit callback.");
00230   }
00231 }
00232 
00233 
00234 static void
00235 dim_dis_callbackErrorHandler(int severity, int error_code, char* message) {
00236   /**
00237    * NOTE: this function does not have the interpretor lock when called.
00238    * @param code The error code passed by the DIM library.
00239    */
00240   PyObject *arg, *res;
00241   PyGILState_STATE gstate;
00242 
00243   if (dis_callbackErrorHandler_func.func) {
00244     gstate = PyGILState_Ensure();
00245     arg = Py_BuildValue("iis", severity, error_code, message);
00246     res = PyEval_CallObject(dis_callbackErrorHandler_func.func, arg);
00247     Py_DECREF(arg);
00248     Py_XDECREF(res);
00249     PyGILState_Release(gstate);
00250   } else {
00251     debug("Could not find any registered Python function. "\
00252         "Dropping DIM error callback.");
00253   }
00254 }
00255 
00256 
00257 static void
00258 dim_dis_callbackClientExitHandler(int* tag) {
00259   /*Interface function with signature: void client_exit_user_routine (int* tag)
00260     Calls the associated Python function.
00261     */
00262   PyObject *arg, *res;
00263   PyGILState_STATE gstate;
00264 
00265   if (dis_callbackClientExitHandler_func.func) {
00266     gstate = PyGILState_Ensure();
00267     arg = Py_BuildValue("i", *tag);
00268     res = PyEval_CallObject(dis_callbackClientExitHandler_func.func, arg);
00269     Py_DECREF(arg);
00270     Py_XDECREF(res);
00271     PyGILState_Release(gstate);
00272   } else {
00273     debug("Could not find any registered Python function. "\
00274         "Dropping DIM client exit callback.");
00275   }
00276 }
00277 
00278 
00279 static PyObject*
00280 dim_dis_add_exit_handler(PyObject* self, PyObject* args) {
00281   /**
00282    * Calls dis_add_exit_handler
00283    * @param callback A callable Python object.
00284    */
00285   PyObject *temp;
00286 
00287   if (!PyArg_ParseTuple(args, "O:set_callback", &temp) ||
00288       !PyCallable_Check(temp))
00289   {
00290     PyErr_SetString(PyExc_TypeError, "Expected a callable Python object");
00291     return NULL;
00292   }
00293 
00294   Py_XINCREF(temp);
00295   Py_XINCREF(self);
00296   /* Dispose of previous callback */
00297   Py_XDECREF(dis_callbackExitHandler_func.self);
00298   Py_XDECREF(dis_callbackExitHandler_func.func);
00299   dis_callbackExitHandler_func.self = self;
00300   dis_callbackExitHandler_func.func = temp;
00301   dis_add_exit_handler(dim_dis_callbackExitHandler);
00302 
00303   Py_RETURN_NONE;
00304 }
00305 
00306 
00307 static PyObject*
00308 dim_dis_add_error_handler(PyObject* self, PyObject* args) {
00309   /**
00310    * Calls dis_add_error_handler
00311    * @param callback A callable Python object.
00312    */
00313   PyObject *temp;
00314 
00315   if (!PyArg_ParseTuple(args, "O:set_callback", &temp) ||
00316       !PyCallable_Check(temp))
00317   {
00318     PyErr_SetString(PyExc_TypeError, "Expected a callable Python object");
00319     return NULL;
00320   }
00321   /* Add a reference to new callback */
00322   Py_XINCREF(temp);
00323   Py_XINCREF(self);
00324   /* Dispose of previous callback */
00325   Py_XDECREF(dis_callbackErrorHandler_func.self);
00326   Py_XDECREF(dis_callbackErrorHandler_func.func);
00327   dis_callbackErrorHandler_func.self = self;
00328   dis_callbackErrorHandler_func.func = temp;
00329   dis_add_error_handler(dim_dis_callbackErrorHandler);
00330 
00331   Py_RETURN_NONE;
00332 }
00333 
00334 static PyObject*
00335 dim_dis_add_client_exit_handler(PyObject* self, PyObject* args) {
00336   /**
00337    * Calls dis_add_client_exit_handler
00338    * @param callback A callable Python object.
00339    */
00340   PyObject *temp;
00341 
00342   if (!PyArg_ParseTuple(args, "O:set_callback", &temp) ||
00343       !PyCallable_Check(temp))
00344   {
00345     PyErr_SetString(PyExc_TypeError, "Expected a callable Python object");
00346     return NULL;
00347   }
00348   /* Add a reference to new callback */
00349   Py_XINCREF(temp);
00350   Py_XINCREF(self);
00351   /* Dispose of previous callback */
00352   Py_XDECREF(dis_callbackClientExitHandler_func.self);
00353   Py_XDECREF(dis_callbackClientExitHandler_func.func);
00354   dis_callbackClientExitHandler_func.self = self;
00355   dis_callbackClientExitHandler_func.func = temp;
00356   dis_add_client_exit_handler(dim_dis_callbackClientExitHandler);
00357 
00358   Py_RETURN_NONE;
00359 }
00360 
00361 
00362 static PyObject*
00363 dim_dis_selective_update_service(PyObject* /* self */, PyObject* args) {
00364   /**
00365    *  Calls int dis_selective_update_service (int service_id, int** client_ids)
00366    */
00367   int* client_ids=NULL, res;
00368   PyObject* listOrTuple;
00369   int service_id;
00370 
00371   if (!PyArg_ParseTuple(args, "iO;list or tuple", &service_id, &listOrTuple)) {
00372     PyErr_SetString(PyExc_TypeError,
00373         "Invalid arguments: expected and integer and a list/tuple of integers");
00374     return NULL;
00375   }
00376   if (!listOrTuple2Int(listOrTuple, &client_ids)) {
00377     PyErr_SetString(PyExc_TypeError,
00378         "Second argument must a list/tuple of integers"
00379         );
00380     return NULL;
00381   }
00382   res = dis_selective_update_service(service_id, client_ids);
00383 
00384   return Py_BuildValue("i", res);
00385 }
00386 
00387 
00388 static PyObject*
00389 dim_dis_set_quality(PyObject* /* self */, PyObject* args) {
00390   /**
00391    * Calls void dis_set_quality (service_id, quality)
00392    * @param service_id The service ID returned by dis_add_service().
00393    * @param quality A flag for the quality of a service.
00394    */
00395   unsigned int service_id;
00396   int quality;
00397 
00398   if (!PyArg_ParseTuple(args, "Ii", &service_id, &quality)) {
00399     PyErr_SetString(PyExc_TypeError,
00400         "Invalid arguments: expected an unsigned integer and an integer");
00401     return NULL;
00402   }
00403   dis_set_quality(service_id, quality);
00404 
00405   Py_RETURN_NONE;
00406 }
00407 
00408 
00409 static PyObject*
00410 dim_dis_set_timestamp(PyObject* /* self */, PyObject* args) {
00411   /**
00412    * Calls void dis_set_timestamp(unsigned int service_id,
00413    *                              int secs,
00414    *                              int milisecs)
00415    * @param service_id
00416    * @param secs
00417    * @param milisecs
00418    */
00419   unsigned int service_id;
00420   int secs, milisecs;
00421 
00422   if (!PyArg_ParseTuple(args, "Iii", &service_id, &secs, &milisecs)) {
00423     PyErr_SetString(PyExc_TypeError,
00424         "Invalid arguments: expected an unsigned integer and two integers");
00425     return NULL;
00426   }
00427   dis_set_timestamp(service_id, secs, milisecs);
00428 
00429   Py_RETURN_NONE;
00430 }
00431 
00432 
00433 static PyObject*
00434 dim_dis_remove_service(PyObject* /* self */, PyObject* args) {
00435   /**
00436    * Call int dis_remove_service (unsigned int service_id)
00437    * @param service_id
00438    */
00439   unsigned int service_id;
00440   int res;
00441 
00442   if ( !PyArg_ParseTuple(args, "I", &service_id) ) {
00443     PyErr_SetString(PyExc_TypeError,
00444         "Invalid argument: expected an unsigned integer");
00445     return NULL;
00446   }
00447   res = dis_remove_service(service_id);
00448 
00449   return Py_BuildValue("i", res);
00450 }
00451 
00452 
00453 static PyObject*
00454 dim_dis_get_next_cmnd(PyObject* /* self */, PyObject* args) {
00455   /**
00456    * Calls int dis_get_next_cmnd (long* tag, int* buffer, int* size)
00457    *
00458    * TODO: Make sure this actually works
00459    * Problem: the way the results are received is not done in a "pythonic" way.
00460    * Better to return a tuple with all the results.
00461    *
00462    * INFO: the DIM function implementation does not define a value for buffer,
00463    * size or tag in case a command is not found.
00464    *
00465    * @param size The maximum size of the data received by the command
00466    */
00467   int res=0, *buffer, size;
00468   long tag=0;
00469   PyObject* tmp;
00470 
00471   if ( !PyArg_ParseTuple(args, "I", &size) ) {
00472     PyErr_SetString(PyExc_TypeError,
00473         "Invalid argument: expected an unsigned integer");
00474     return NULL;
00475   }
00476   buffer = (int*)malloc(size*sizeof(int));
00477   res = dis_get_next_cmnd(&tag, buffer, &size);
00478   tmp = Py_BuildValue("(iis#)", res, tag, buffer, size);
00479   free(buffer);
00480 
00481   return tmp;
00482 }
00483 
00484 
00485 static PyObject*
00486 dim_dis_get_client(PyObject* /* self */, PyObject* args) {
00487   /**
00488    * Calls: int dis_get_client (char* name)
00489    */
00490   char* name; int res;
00491 
00492   if ( !PyArg_ParseTuple(args, "s", &name) ) {
00493     PyErr_SetString(PyExc_TypeError, "Invalid argument: expected an string");
00494     return NULL;
00495   }
00496   res = dis_get_client(name);
00497 
00498   return Py_BuildValue("i", res);
00499 }
00500 
00501 
00502 static PyObject*
00503 dim_dis_get_conn_id(PyObject* /* self */, PyObject* /* args */) {
00504   /**
00505    * Calls: int dis_get_conn_id()
00506    */
00507   int res;
00508   res = dis_get_conn_id();
00509   return Py_BuildValue("i", res);
00510 }
00511 
00512 
00513 static PyObject*
00514 dim_dis_get_timeout(PyObject* /* self */, PyObject* args) {
00515   /**
00516    * Calls: int dis_get_timeout (unsigned int service_id, int client_id)
00517    * @param service_id The service_id returned by dis_add_service or by
00518    * dis_add_cmnd.
00519    * @param client_id The connection ID of a DIM client as obtained by
00520    * the routine dis_get_conn_id.
00521    */
00522   unsigned int service_id;
00523   int client_id, res;
00524 
00525   if ( !PyArg_ParseTuple(args, "Ii", &service_id, &client_id) ) {
00526     PyErr_SetString(PyExc_TypeError,
00527         "Invalid argument: expected an unsigned int and an int");
00528     return NULL;
00529   }
00530   res = dis_get_timeout(service_id, client_id);
00531 
00532   return Py_BuildValue("i", res);
00533 }
00534 
00535 
00536 static PyObject*
00537 dim_dis_get_client_services(PyObject* /* self */, PyObject* args) {
00538   /**
00539    * Calls: char* dis_get_client_services (int conn_id)
00540    *
00541    * @param conn_id The connection ID to a client.
00542    */
00543   char* res=NULL;
00544   int conn_id;
00545 
00546   if ( !PyArg_ParseTuple(args, "i", &conn_id) ) {
00547     PyErr_SetString(PyExc_TypeError, "Invalid argument: expected an int");
00548     return NULL;
00549   }
00550   res = dis_get_client_services(conn_id);
00551 
00552   return Py_BuildValue("s", res);
00553 }
00554 
00555 
00556 static PyObject*
00557 dim_dis_set_client_exit_handler(PyObject* /* self */, PyObject* args) {
00558   /**
00559    * Calls: void dis_set_client_exit_handler (int conn_id, int tag)
00560    */
00561   int conn_id, tag;
00562 
00563   if ( !PyArg_ParseTuple(args, "ii", &conn_id, &tag) ) {
00564     PyErr_SetString(PyExc_TypeError, "Invalid argument: expected two ints");
00565     return NULL;
00566   }
00567   dis_set_client_exit_handler(conn_id, tag);
00568 
00569   Py_RETURN_NONE;
00570 }
00571 
00572 
00573 static PyObject*
00574 dim_dis_get_error_services(PyObject* /* self */, PyObject* /* args */) {
00575   /**
00576    * Calls: char* dis_get_error_services (int conn_id)
00577    */
00578   char* res=NULL;
00579   res = dis_get_error_services();
00580   return Py_BuildValue("s", res);
00581 }
00582 
00583 
00584 static PyObject*
00585 dim_dis_add_cmnd(PyObject* /* self */, PyObject* args) {
00586   /* @param name
00587    * @param description
00588    * @param py_function
00589    * @param tag
00590    * @return DIM integer status code (1 for success)
00591    *
00592    * Implementation details: in order to preserve the C interface, unique
00593    * tags are generated for each call. The original tags are preserved with
00594    * the python function pointer and passed back when doing a callback.
00595    *
00596    * Proxy function for:
00597    *         unsigned int dis_add_cmnd(name,description,cmnd_user_routine,tag)
00598    * Where:
00599    *         char* name - the name of the command. Will be used for identifing the
00600    *                 python callback
00601    *         char* description - the command format
00602    *         void cmnd_user_routine (long* tag, int* address, int* size) - The
00603    *                 long pointer will be transformed in A long Python object
00604    *                 for the callback. The address will become a string long
00605    *                 tag - will be passed back to the Python callback
00606    */
00607   unsigned int res=0;
00608   char *name = NULL, *format = NULL;
00609   PyObject *tag = NULL;
00610   int sizeFormat, sizeName;
00611   PyObject *pyFunc;
00612   CmndCallback *callback, *oldCallback;
00613   string s;
00614 
00615   if (!PyArg_ParseTuple(args, "s#s#O|O",
00616         &name, &sizeName, &format, &sizeFormat, &pyFunc, &tag)
00617       || !PyCallable_Check(pyFunc) )
00618   {
00619     PyErr_SetString(PyExc_TypeError,
00620                      "Invalid arguments: expected two strings, "
00621                  "a callable object and an integer");
00622     return NULL;
00623   }
00624   debug("Adding command name %s, format %s and tag %p", name, format, tag);
00625   callback = (CmndCallback*)malloc(sizeof(CmndCallback));
00626   callback->format = (char*)malloc(sizeof(char)*(sizeFormat+1));
00627   callback->name = (char*)malloc(sizeof(char)*(sizeName+1));
00628   callback->pyFunc = pyFunc;  
00629   if (tag) { 
00630   Py_INCREF(tag);
00631   callback->pyTag = tag;
00632   } 
00633   strcpy(callback->format, format);
00634   strcpy(callback->name, name);
00635   /* TODO: The following portion is inherently unsafe. If a command comes
00636    * between the adding the command to the lookup tables and the actual
00637    * DIM registration of the new command, then results are undefined. The
00638    * portion of code bellow relies at least that the type of the commands will
00639    * be the same. The alternative is to become 'smart' and remove the command
00640    * first using dis_remove_service and then add it again.
00641    * TODO: check that res below is actually <= 0 if a command is registered
00642    * twice.
00643    */
00644   oldCallback = cmndName2PythonFunc[name];
00645   cmndUniqueTag2PythonFunc[(long)callback] = callback;
00646   cmndName2PythonFunc[name] = callback;
00647   res = dis_add_cmnd(name, format, dim_callbackCommandFunc, (long)callback);
00648   if (oldCallback && res<1) {
00649     Py_XDECREF(oldCallback->pyFunc);
00650   Py_XDECREF(oldCallback->pyTag);
00651     free(oldCallback->name);
00652     free(oldCallback->format);
00653     free(oldCallback);
00654   }
00655 
00656   return Py_BuildValue("i", res);
00657 }
00658 
00659 
00660 void
00661 serviceProxy(void *tagp, void **buf, int *size, int * /*first_time*/) {
00662   /** Internal function for returning the data buffer for a service.
00663    * A DIM service functions in two ways:
00664    *   - by specifying a pointer to a fixed size structure at creation time
00665    *   - by specifying a callback that is done when a service is updated
00666    * In order to pass variable length parameters (the only really useful
00667    * situation), the second approach is needed. On the other hand, the user code
00668    * will become harder to understant if the parameters can only be supplied
00669    * by the means of a callback function. For this a DIM 'extension' was made
00670    * to allow variable lenght parameters in both cases:
00671    *   1. When a service is created on the C world, the pointer to the service
00672    * structure is registered as a tag. The actual tag given in python is saved
00673    * to the service data structure.
00674    *   2. In case the arguments are specified when the python function
00675    * dis_update_service is called, they are converted to a buffer and stored
00676    * in the service structure. The 'serviceProxy' method is going to be called
00677    * by the DIM 'dis_update_service' (or more exactly the internal funtion
00678    * 'execute_service') and 'serviceProxy' is going to take the necesarry steps
00679    * to return the python objects converted to a buffer
00680    *
00681    * @param tagp A pointer to the ServiceCallback structure.
00682    * @param buffer The buffer that should be sent by DIM
00683    * @param size The total size of the buffer
00684    * @param first_time Whether the service is called for the first time or not.
00685    */
00686 
00687   // the implicit assumption is that tagp is a pointer to a ServiceCallback
00688   ServiceCallback* svc =(ServiceCallback*)(*(long *)tagp);
00689 
00690   if (!svc->isUpdated || !svc->buffer) {
00691     /* what happens here? we have no data and we can't signal this to
00692      * DIM.Two options:
00693      *    - returning NULL + size 0
00694      *    - return some default data => unpredictable results client side
00695      */
00696     print("ERROR: You should not see this message! The service update has failed");
00697     debug("Could not get data to update service %s, pointer %x. Output buffer is %x with size %d, updated %d",
00698            svc->name, svc, (long)svc->buffer, svc->bufferSize, svc->isUpdated);
00699     svc->bufferSize = 0;
00700     if (svc->buffer) {
00701       free(svc->buffer);
00702       svc->buffer = NULL;
00703     }
00704   } else if (svc->isUpdated && svc->buffer) {
00705     /* nothing much to do there, we have everything already */
00706   }
00707   *buf = svc->buffer;
00708   *size = svc->bufferSize;
00709 }
00710 
00711 
00712 static PyObject*
00713 dim_dis_add_service(PyObject* /* self */, PyObject* args) {
00714   /**
00715    * Proxy function to:
00716    *        unsigned int dis_add_service (char* name,
00717    *                                      char* description,
00718    *                                      int*  address,
00719    *                                      int   size,
00720    *                                      func  user_routine,
00721    *                                      long tag)
00722    *        func = void user_routine(long* tag, int** address, int* size)
00723    *
00724    * Observation: the size of the command is calculated using the
00725    * description parameter so if size is omitted it is considered 1.
00726    *
00727    * @param name
00728    * @param description
00729    * @param python_function
00730    * @param tag
00731    */
00732 
00733   int name_size, format_size, service_id=0;
00734   char *name, *format;
00735   long pyTag;
00736   PyObject *pyFunc;
00737   ServiceCallback *svc;
00738 
00739   if (!PyArg_ParseTuple(args, "s#s#Ol", &name,
00740         &name_size,
00741         &format,
00742         &format_size,
00743         &pyFunc,
00744         &pyTag)
00745       || !PyCallable_Check(pyFunc))
00746   {
00747     PyErr_SetString(PyExc_TypeError,
00748         "Invalid arguments: expected two strings, a callable object and a long.");
00749     return NULL;
00750   }
00751 
00752   Py_INCREF(pyFunc);
00753   svc = (ServiceCallback*)malloc(sizeof(ServiceCallback));
00754   svc->name = (char*)malloc(sizeof(char)*(name_size+1));
00755   svc->format = (char*)malloc(sizeof(char)*(format_size+1));
00756   if (!svc || !svc->name || !svc->format) goto noMem;
00757   strcpy(svc->name, name);
00758   strcpy(svc->format, format);
00759   svc->pyTag = pyTag;
00760   svc->pyFunc = pyFunc;
00761   svc->buffer = NULL;
00762   svc->bufferSize = 0;
00763 
00764   service_id = dis_add_service(name,
00765                                format,
00766                                NULL,
00767                                0,
00768                                serviceProxy,
00769                                (long)svc);
00770   if (!service_id) {
00771     PyErr_SetString(PyExc_RuntimeError, "Could not create service");
00772     return NULL;
00773   }
00774 
00775   if (serviceID2Callback[service_id]) {
00776     /* a service with the same name added again? */
00777     debug("Replacing service %s",svc->name);
00778     Py_XDECREF(serviceID2Callback[service_id]->pyFunc);
00779     free(serviceID2Callback[service_id]->name);
00780     free(serviceID2Callback[service_id]->format);
00781     free(serviceID2Callback[service_id]->buffer);
00782     free(serviceID2Callback[service_id]);
00783   }
00784   serviceID2Callback[service_id] = svc;
00785   debug("Service %s added successfully with pointer %x", svc->name, svc);
00786 
00787   return Py_BuildValue("i", service_id);
00788 
00789  noMem:
00790   PyErr_SetString(PyExc_MemoryError, "Could not allocate memory");
00791   return NULL;
00792 }
00793 
00794 
00795 static PyObject*
00796 dim_dis_update_service(PyObject* /* self */, PyObject* args) {
00797   /**
00798    *  Calls: int dis_update_service (int service_id)
00799    */
00800   int service_id, res;
00801   PyObject *svc_args=NULL, *arg;
00802   ServiceCallbackPtr svc;
00803   PyGILState_STATE gstate;
00804 
00805   if ( !PyArg_ParseTuple(args, "i|O", &service_id, &svc_args) ){
00806       //if ( !PyArg_ParseTuple(args, "i", &service_id) ){
00807     PyErr_SetString(PyExc_TypeError,
00808         "Argument error: incorect service ID");
00809     return NULL;
00810   }
00811   svc = serviceID2Callback[service_id];
00812   if (!svc){
00813     // Service was not found, already deleted?
00814     PyErr_SetString(PyExc_RuntimeError,
00815         "Service ID doesn't match any service");
00816     return NULL;
00817   }
00818   if (!svc_args) {
00819     if (!svc->pyFunc) {
00820       PyErr_SetString(PyExc_TypeError,
00821           "No arguments and no callback function was given");
00822       return NULL;
00823     }
00824     gstate = PyGILState_Ensure();
00825     arg = Py_BuildValue("(i)", svc->pyTag);
00826     free(svc_args);
00827     svc_args = PyEval_CallObject(svc->pyFunc, arg);
00828     Py_DECREF(arg);
00829     //Py_DECREF(svc_args); // !!!!!
00830     PyGILState_Release(gstate);
00831     if (!svc_args) {
00832       /* there was an exception raised when calling the python function
00833        * returning NULL implies the exception will be propageted
00834        * back to the interpretor
00835        */
00836       print("Error in calling python function %p", svc->pyFunc);
00837       PyErr_Print();
00838       return NULL;
00839     }
00840   }
00841   /* NOTE: it might not be optimal to allocate a buffer each time */
00842   if (svc->buffer)
00843     free(svc->buffer);
00844   if (!iterator_to_allocated_buffer(svc_args,
00845                                     svc->format,
00846                                     &svc->buffer,
00847                                     &svc->bufferSize) )
00848   {
00849     PyErr_SetString(PyExc_TypeError,
00850         "Arguments do not match initial service format");
00851     return NULL;
00852   }
00853   Py_DECREF(svc_args);
00854   svc->isUpdated = 1;
00855   Py_BEGIN_ALLOW_THREADS
00856   res = dis_update_service(service_id);
00857   Py_END_ALLOW_THREADS
00858 
00859   return Py_BuildValue("i", res);
00860 }
00861 
00862 
00863 static void
00864 dim_callbackCommandFunc(void* uTag, void* address, int* size) {
00865   /** \brief Proxy function for passing the call to Python.
00866    * It is registered by default when a command service is
00867    * created.
00868    */
00869   CmndCallbackPtr pycall = (CmndCallbackPtr)(*(long *)uTag);
00870   PyObject *args, *res, *funargs;
00871   PyGILState_STATE gstate;
00872   
00873   gstate = PyGILState_Ensure();
00874   args = dim_buf_to_tuple(pycall->format, (char*)address, *size);
00875   if (args) {
00876     /* performing the Python callback */
00877   if (pycall->pyTag) {
00878     funargs = PyTuple_New(2);
00879     PyTuple_SET_ITEM(funargs, 0, args);
00880     PyTuple_SET_ITEM(funargs, 1, pycall->pyTag);
00881   } else {
00882     funargs = PyTuple_New(1);
00883     PyTuple_SET_ITEM(funargs, 0, args);
00884   }   
00885     res = PyEval_CallObject(pycall->pyFunc, funargs);
00886     Py_DECREF(args);
00887   Py_DECREF(funargs);
00888     if (!res) {
00889       /* The Python function called throwed an exception.
00890        * We can't do much with it so we might as well print it */
00891       PyErr_Print();
00892     } else {
00893       Py_DECREF(res);
00894     }
00895   } else {
00896     print ("Could not convert received DIM buffer to Python objects");
00897   }
00898   PyGILState_Release(gstate);
00899 }
00900 
00901 
00902 /******************************************************************************/
00903 /* DIC interface functions */
00904 /******************************************************************************/
00905 static PyObject*
00906 dim_dic_set_dns_node(PyObject* /* self */, PyObject* args) {
00907   /**
00908    * Proxy function to:
00909    *         dic_set_dns_node(char* node)
00910    * @param dns_name The name of the new DNS.
00911    * @return ret_code The DIM return code (1 for success).
00912    */
00913   char* name = NULL;
00914   int i;
00915 
00916   if ( !PyArg_ParseTuple(args, "s", &name) ) {
00917     PyErr_SetString(PyExc_TypeError, "Invalid DIM DNS name");
00918     return NULL;
00919   }
00920   i = dic_set_dns_node(name);
00921 
00922   return Py_BuildValue("i", i);
00923 }
00924 
00925 
00926 static PyObject*
00927 dim_dic_get_dns_node(PyObject* /* self */, PyObject* /* args */) {
00928   /* calls dic_get_dns_node(char* node)
00929      the function should return the DNS node
00930      */
00931   char names[256];
00932 
00933   if ( !dic_get_dns_node(names) ) {
00934     PyErr_SetString(PyExc_TypeError,
00935         "Could not get DIM DNS node name.");
00936     return NULL;
00937   }
00938 
00939   return Py_BuildValue("s", names);
00940 }
00941 
00942 
00943 static PyObject*
00944 dim_dic_set_dns_port(PyObject* /* self */, PyObject* args) {
00945   /**
00946    * Proxy function to:
00947    *        dic_set_dns_port(int port)
00948    * @return return_code The DIM return code (1 for success).
00949    */
00950   unsigned int port;
00951   int i;
00952 
00953   if ( !PyArg_ParseTuple(args, "I", &port) ) {
00954     PyErr_SetString(PyExc_TypeError,
00955         "Invalid argument: expected a pozitive integer"
00956         );
00957     return NULL;
00958   }
00959   i = dic_set_dns_port(port);
00960 
00961   return Py_BuildValue("i", i);
00962 }
00963 
00964 
00965 static PyObject*
00966 dim_dic_get_dns_port(PyObject* /* self */, PyObject* /* args */) {
00967   /**
00968    * Proxy function to:
00969    *         dis_get_dns_port().
00970    * @return dns_port The DIM DNS port.
00971    */
00972   int port;
00973   port = dim_get_dns_port();
00974   return Py_BuildValue("i", port);
00975 }
00976 
00977 
00978 static PyObject*
00979 dim_dic_get_id(PyObject* /* self */, PyObject* /* args */) {
00980   /** Proxy function to:
00981    *         int dic_get_id (char* name)
00982    * @return client_name The client name or an empty string if the
00983    *  command was not successful.
00984    */
00985   char name[256];
00986   int res;
00987 
00988   res = dic_get_id(name);
00989   if (!res)
00990     name[0] = 0;
00991 
00992   return Py_BuildValue("s", name);
00993 }
00994 
00995 
00996 static PyObject*
00997 dim_dic_disable_padding(PyObject* /* self */, PyObject* /* args */) {
00998   /**
00999    * Proxy function to:
01000    *         int dic_disable_padding(void)
01001    */
01002   dic_disable_padding();
01003   Py_RETURN_NONE;
01004 }
01005 
01006 
01007 static PyObject*
01008 dim_dic_get_quality(PyObject* /* self */, PyObject* args) {
01009   /**
01010    * Proxy function to:
01011    *         int dic_get_quality (unsigned int service_id);
01012    * @return service_quality The service quality (int)
01013    */
01014   unsigned int service_id;
01015   int res;
01016 
01017   if (!PyArg_ParseTuple(args, "I", &service_id) ) {
01018     PyErr_SetString(PyExc_TypeError,
01019         "Invalid argument: expected an unsigned integer");
01020     return NULL;
01021   }
01022   res = dic_get_quality(service_id);
01023 
01024   return Py_BuildValue("i", res);
01025 }
01026 
01027 
01028 static PyObject*
01029 dim_dic_get_timestamp(PyObject* /* self */, PyObject* args) {
01030   /**
01031    * Proxy function to:
01032    *        int dic_get_timestamp (service_id, secs, milisecs).
01033    *
01034    * @param service_id (unsigned int)
01035    * @return timestamp Python tuple with seconds and miliseconds
01036    */
01037   unsigned int service_id;
01038   int secs, milisecs=0, res=0;
01039 
01040   if (!PyArg_ParseTuple(args, "Iii", &service_id)) {
01041     PyErr_SetString(PyExc_TypeError,
01042         "service id should be an unsigned integer");
01043     return NULL;
01044   }
01045   res = dic_get_timestamp(service_id, &secs, &milisecs);
01046 
01047   return Py_BuildValue("ii", secs, milisecs);
01048 }
01049 
01050 
01051 static PyObject*
01052 dim_dic_get_format(PyObject* /* self */, PyObject* args) {
01053   /**
01054    * Proxy function to:
01055    *        char *dic_get_format (unsigned int service_id)
01056    * @return format A string containing the format description.
01057    */
01058   unsigned int service_id;
01059   char* format=NULL;
01060 
01061   if (! PyArg_ParseTuple(args, "I", &service_id) ) {
01062     PyErr_SetString(PyExc_TypeError,
01063         "Service id should be an unsigned integer");
01064     return NULL;
01065   }
01066   format = dic_get_format(service_id);
01067 
01068   return Py_BuildValue("s", format);
01069 }
01070 
01071 
01072 static PyObject*
01073 dim_dic_release_service(PyObject* /* self */, PyObject* args) {
01074   /**
01075    * Proxy function to:
01076    *        void dic_release_service (unsigned int service_id)
01077    */
01078   unsigned int service_id;
01079   string cppName;
01080   _dic_info_service_callback *tmp;
01081 
01082   if (!PyArg_ParseTuple(args, "I", &service_id)) {
01083     debug("Invalid service id specified");
01084     PyErr_SetString(PyExc_TypeError,
01085         "Service id should be an unsigned integer");
01086     return NULL;
01087   }
01088   Py_BEGIN_ALLOW_THREADS
01089   dic_release_service(service_id);
01090   Py_END_ALLOW_THREADS
01091   tmp = _dic_info_service_id2Callback[service_id];
01092   cppName = tmp->name;
01093   if (!tmp) {
01094     print("Service with id %d is not known", service_id);
01095     Py_RETURN_NONE;
01096   }
01097   _dic_info_service_name2Callback.erase(cppName);
01098   _dic_info_service_id2Callback.erase(service_id);
01099   free(tmp->format);
01100   free(tmp->name);
01101   Py_XDECREF(tmp->pyFunc);
01102   Py_XDECREF(tmp->pyDefaultArg);
01103   free(tmp);
01104 
01105   Py_RETURN_NONE;
01106 }
01107 
01108 
01109 static PyObject*
01110 dim_dic_info_service(PyObject* /* self */, PyObject* args) {
01111   /**
01112    * @param string_name
01113    * @param string_format
01114    * @param callbackFunction A callable Python object
01115    * @param service_type Optional, default=MONITORED (int)
01116    * @param timeout Optional, default=0 (int)
01117    * @param tag Optional, default=0 (int)
01118    * @param default_value  Optional, default=NULL, (Python object)
01119    * Proxy function to:
01120    *         unsigned int dic_info_service (char* name         ,
01121    *                                        int   type         ,
01122    *                                        int   timeout      ,
01123    *                                        int*  address      ,
01124    *                                        int*  size         ,
01125    *                                        void* user_routine ,
01126    *                                        long  tag          ,
01127    *                                        int*  fill_address ,
01128    *                                        int   fill_size)
01129    * @return service_id The id of the newly created service.
01130    */
01131   char* name, *format;
01132   int service_type=MONITORED;
01133   int timeout=0;
01134   int tag=0;
01135   int format_size;
01136   int name_size;
01137   unsigned int service_id;
01138   string cppName;
01139   PyObject* pyFunc=NULL, *default_value=NULL ;
01140   _dic_info_service_callback *tmp=NULL, *svc;
01141 
01142   if (!PyArg_ParseTuple(args, "s#s#O|iiiO",
01143         &name, &name_size,
01144         &format, &format_size,
01145         &pyFunc,
01146         &service_type,
01147         &timeout,
01148         &tag,
01149         &default_value)
01150       || !PyCallable_Check(pyFunc))
01151   {
01152     goto invalid_args;
01153   }
01154   /* I am using a map and keys of type char * will not work */
01155   cppName = name;
01156   /* increasing the ref count of the python objects */
01157   Py_INCREF(pyFunc);
01158   if (default_value) Py_INCREF(default_value);
01159   /* creating a new service structure and storing all the service
01160    * details inside
01161    */
01162   svc = (_dic_info_service_callback*)malloc(sizeof(_dic_info_service_callback));
01163   if (!svc) goto no_memory;
01164   svc->format = (char*)malloc(sizeof(char)*format_size+1);
01165   svc->name = (char*)malloc(sizeof(char)*name_size+1);
01166   if (!svc->format || !svc->name) goto no_memory;
01167   svc->pyDefaultArg = default_value;
01168   svc->pyTag = tag;
01169   svc->pyFunc = pyFunc;
01170   strcpy(svc->name, name);
01171   strcpy(svc->format, format);
01172 
01173   /* registering the stub function. The C tag is the actual pointer to the
01174    * service structure
01175    */
01176   Py_BEGIN_ALLOW_THREADS  
01177   service_id = dic_info_service(name,
01178                                 service_type,
01179                                 timeout,
01180                                 0, 0, /* service buffer and size */
01181                                 _dic_info_service_dummy,
01182                                 (long)svc,
01183                                 0, 0); /* default buffer and size */
01184   Py_END_ALLOW_THREADS
01185   if (!service_id) {
01186     print("Service %s creation failed. Received result %d", name, service_id);
01187     goto dealocate;
01188   }
01189   svc->service_id = service_id;
01190   tmp = _dic_info_service_name2Callback[cppName];
01191   if (tmp) {
01192     free(tmp->format);
01193     free(tmp->name);
01194     Py_XDECREF(tmp->pyFunc);
01195     Py_XDECREF(tmp->pyDefaultArg);
01196     _dic_info_service_name2Callback.erase(cppName);
01197     _dic_info_service_id2Callback.erase(tmp->service_id);
01198     free(_dic_info_service_name2Callback[cppName]);
01199   }
01200   _dic_info_service_name2Callback[cppName] = svc;
01201   _dic_info_service_id2Callback[service_id] = svc;
01202 
01203   return Py_BuildValue("i", service_id);
01204 
01205   /* invalid arguments */
01206 invalid_args:
01207   PyErr_SetString(PyExc_TypeError,
01208       "Invalid parameters. Expected:string name               ,"\
01209       "                             string format             ,"\
01210       "                             int service_type          ,"\
01211       "                             int timeout               ,"\
01212       "                             PyObject* callbackFunction,"\
01213       "                             int tag                   ,"\
01214       "                             PyObject* default_value"
01215       );
01216   return NULL;
01217 
01218   /* memory problems */
01219 no_memory:
01220   PyErr_SetString(PyExc_MemoryError, "Could not allocate memory");
01221   Py_DECREF(pyFunc);
01222   return NULL;
01223 
01224   /* invalid service registration */
01225 dealocate:
01226   Py_XDECREF(tmp->pyFunc);
01227   _dic_info_service_name2Callback.erase(cppName);
01228   //_dic_info_service_id2Callback.erase(tmp->buffer);
01229   free(tmp->format);
01230   free(tmp->name);
01231   free(tmp);
01232   return 0;
01233 }
01234 
01235 
01236 static PyObject*
01237 dim_dic_info_service_stamped(PyObject* self, PyObject* args){
01238   /* Proxy function to:
01239    *         to dim_dic_info_service (PyObject* self,
01240    *                                  PyObject* args,
01241    *                                  PyObject* keywds
01242    *                                 )
01243    * Accepts same arguments and returns the new ID of the created service.
01244    */
01245   return dim_dic_info_service(self, args);
01246 }
01247 
01248 
01249 static PyObject*
01250 dim_dic_get_server(PyObject* /* self */, PyObject* args) {
01251   /**
01252    * Proxy function for:
01253    *         dic_get_server(char* name)
01254    * @param server_name string
01255    * @return server_id
01256    */
01257   int service_id;
01258   char* server_name;
01259 
01260   if ( !PyArg_ParseTuple(args, "s", &server_name) ) {
01261     PyErr_SetString(PyExc_TypeError,
01262         "Invalid parameters. Expected argument:string service_name");
01263     return NULL;
01264   }
01265   service_id = dic_get_server(server_name);
01266 
01267   return Py_BuildValue("i", service_id);
01268 }
01269 
01270 
01271 static PyObject*
01272 dim_dic_get_conn_id(PyObject* /* self */, PyObject* /* args */) {
01273   /**
01274    * Proxy function for:
01275    *         dic_get_conn_id(char* name)
01276    * @return connection id
01277    */
01278   int service_id;
01279 
01280   service_id = dic_get_conn_id();
01281   return Py_BuildValue("i", service_id);
01282 }
01283 
01284 
01285 static PyObject*
01286 dim_dic_get_server_services(PyObject* /* self */, PyObject* args) {
01287   /**
01288    * Proxy function for:
01289    *         dic_get_server_services(int conn_id)
01290    * @param connection id
01291    * @return services_list A Python list of services.
01292    */
01293   int conn_id;
01294   char* server_names=NULL;
01295   PyObject* ret;
01296 
01297   if (!PyArg_ParseTuple(args, "i", &conn_id)) {
01298     PyErr_SetString(PyExc_TypeError,
01299         "Invalid parameters. Expected argument:int conn_id");
01300     return NULL;
01301   }
01302   server_names = dic_get_server_services(conn_id);
01303   ret = stringList_to_tuple(server_names);
01304 
01305   return ret;
01306 }
01307 
01308 
01309 static PyObject*
01310 dim_dic_get_error_services(PyObject* /* self */, PyObject* args) {
01311   /** It is meant to be called inside the error handler to determine
01312    *  what service originated the error.
01313    *
01314    * Proxy function for:
01315    *         dic_get_error_services(int conn_id)
01316    *
01317    * @return service_list a python list of services in error.
01318    */
01319   char* server_names=NULL;
01320   PyObject* ret;
01321   server_names = dic_get_error_services();
01322   ret = stringList_to_tuple(server_names);
01323   return args;
01324 }
01325 
01326 
01327 static PyObject*
01328 dim_dic_add_error_handler(PyObject* self, PyObject* args) {
01329   /**
01330    * @param python callback (callable object)
01331    * It is a stub function for calling:
01332    *         dic_add_error_handler ( void* error_routine(int, int, char*) )
01333    * @returns the python None object
01334    */
01335   PyObject* pyFunc;
01336 
01337   if (!PyArg_ParseTuple(args, "O:set_callback", &pyFunc)
01338       || !PyCallable_Check(pyFunc))
01339   {
01340     PyErr_SetString(PyExc_TypeError,
01341         "Invalid parameters. Expected argument: callable object ");
01342     return NULL;
01343   }
01344   Py_XINCREF(pyFunc);
01345   Py_XINCREF(self);
01346   /* Dispose of previous callback */
01347   Py_XDECREF(_dic_callback_errorHandler_func.self);
01348   Py_XDECREF(_dic_callback_errorHandler_func.func);
01349   _dic_callback_errorHandler_func.self = self;
01350   _dic_callback_errorHandler_func.func = pyFunc;
01351 
01352   dic_add_error_handler(_dic_error_user_routine_dummy);
01353 
01354   Py_RETURN_NONE;
01355 }
01356 
01357 static PyObject*
01358 dim_dic_cmnd_service(PyObject* /* self */, PyObject* args) {
01359   /**
01360    * @param service_name (string),
01361    * @param command_data (tuple or list),
01362    * @param format (string)
01363    * Proxy function for calling:
01364    *        dic_cmnd_service(char* name, int* address, int size)
01365    * @return the DIM return code (1 for a successful request)
01366    */
01367   char *service_name, *format, *buffer;
01368   unsigned int buffer_size;
01369   int res;
01370   PyObject *pySeq;
01371 
01372   res = PyArg_ParseTuple(args, "sOs", &service_name, &pySeq, &format);
01373   if (!res)
01374     goto invalid_arguments;
01375   /* creating dummy command request */
01376   if (!iterator_to_allocated_buffer(pySeq, format, &buffer, &buffer_size))
01377     goto error;
01378   Py_BEGIN_ALLOW_THREADS
01379   res = dic_cmnd_service(service_name, buffer, buffer_size);
01380   Py_END_ALLOW_THREADS
01381   /* freeing allocated buffer */
01382   free(buffer);
01383 
01384   return Py_BuildValue("i", res);
01385 
01386 invalid_arguments:
01387   PyErr_SetString(PyExc_TypeError,
01388       "Invalid parameters. Expected: string service_name (string), "\
01389       "update_data (tuple or list), format (DIM format string)");
01390   return NULL;
01391 
01392 error:
01393   PyErr_SetString(PyExc_RuntimeError,
01394             "Could not serialise provided arguments to a DIM buffer.\n"\
01395             "Please check that the order/number "\
01396             "of the argument maches the provided command format.");
01397   free(buffer);
01398   return NULL;
01399 
01400 }
01401 
01402 
01403 static PyObject*
01404 dim_dic_cmnd_callback(PyObject* /* self */, PyObject* args) {
01405   /**
01406    * @param service_name (string),
01407    * @param command_data (tuple or list),
01408    * @param format (string)
01409    * @param cmnd_callback (callable object)
01410    * @param tag (int)
01411    * Stub function for calling:
01412    *        dic_cmnd_service(char* name,
01413    *                         int* address,
01414    *                         int size,
01415    *                         void* cmd_callback,
01416    *                         long tag)
01417    * @return the DIM return code (int) (1 for successful request)
01418    */
01419   char *service_name, *format, *buffer;
01420   unsigned int buffer_size;
01421   int res;
01422   long pyTag;
01423   PyObject *pySeq, *pyFunc;
01424   _dic_cmnd_callback *callback;
01425 
01426   if (!PyArg_ParseTuple(args, "sOsOl",
01427         &service_name, &pySeq, &format, &pyFunc, &pyTag)
01428       || !PyCallable_Check(pyFunc))
01429   {
01430     goto invalid_arguments;
01431   }
01432   /* saving callback */
01433   Py_INCREF(pyFunc);
01434   callback = (_dic_cmnd_callback*)malloc(sizeof(_dic_cmnd_callback));
01435   if (!callback)
01436     goto memory_error;
01437   callback->pyFunc = pyFunc;
01438   callback->pyTag = pyTag;
01439   /* creating dummy cmnd_callback request */
01440   if (!iterator_to_allocated_buffer(pySeq, format, &buffer, &buffer_size)) {
01441     goto error;
01442   }
01443   /* If we don't release the Python lock and if the client is on the
01444    * same machine we are going to have a deadlock!
01445    */
01446   Py_BEGIN_ALLOW_THREADS
01447   res = dic_cmnd_callback(service_name,
01448                           buffer,
01449                           buffer_size,
01450                           _dic_cmnd_callback_dummy,
01451                           (long)callback);
01452   Py_END_ALLOW_THREADS
01453   /* freeing temporary buffer and returning */
01454   free(buffer);
01455 
01456   return Py_BuildValue("i", res);
01457 
01458  invalid_arguments:
01459   PyErr_SetString(PyExc_TypeError,
01460       "Invalid parameters. "
01461       "   Expected: service_name (string), \n"\
01462       "             command_data (a tuple or list of values), \n"\
01463       "             format (a DIM format string), \n"\
01464       "             function_callback (a Python callable object) \n"\
01465       "             int tag"
01466       );
01467   return NULL;
01468 
01469  error:
01470   PyErr_SetString(PyExc_RuntimeError,
01471             "Could not serialise provided arguments to a DIM buffer.\n"\
01472             "Please check that the order/number "\
01473             "of the argument maches the provided command format.");
01474   return NULL;
01475 
01476  memory_error:
01477   PyErr_SetString(PyExc_MemoryError, "Could not allocate memory");
01478   return NULL;
01479 }
01480 
01481 
01482 /******************************************************************************/
01483 /* DIC interface internal functions */
01484 /******************************************************************************/
01485 void _dic_cmnd_callback_dummy(void *uTag, int* ret_code) {
01486   /**
01487    * @param uniqueTagPtr is used to identify the actual Python functions that
01488    * needs to be called. The tag that might have been speciffied in python is
01489    * substituted before passing the call.
01490    *
01491    * Stub function for passing the callback to the error handler to the Python
01492    * layer. This functions is registered to DIM instead of the Python function
01493    * and will forward the call to the interpreter.
01494    *
01495    * @return no value is returned
01496    */
01497   PyObject* res;
01498   PyGILState_STATE gstate;
01499   _dic_cmnd_callback* callback = (_dic_cmnd_callback *)(*(long *)uTag) ;
01500 
01501   /* The python calls to the API are encapsulated by the usual
01502    * Ensure(), Release()
01503    */
01504   gstate = PyGILState_Ensure();
01505   res = pyCallFunction(callback->pyFunc,
01506                        Py_BuildValue("li", callback->pyTag, *ret_code));
01507   Py_DECREF(res);
01508   Py_DECREF(callback->pyFunc);
01509   PyGILState_Release(gstate);
01510   /* delete callback information */
01511   free(callback);
01512 }
01513 
01514 
01515 void _dic_error_user_routine_dummy(int severity, int error_code, char* message) {
01516   /* Stub function for passing the callback to the error handler to the Python
01517    * layer.
01518    * To the callback to the python layer the DIM severity, error_code and
01519    * message are passed.
01520    * NOTE: When this function is called it does not have the interpretor lock.
01521    */
01522 
01523   PyObject *arg, *res;
01524   PyGILState_STATE gstate;
01525   if ( _dic_callback_errorHandler_func.func ) {
01526   gstate = PyGILState_Ensure();
01527   arg = Py_BuildValue("iis", severity, error_code, message);
01528   res = PyEval_CallObject(_dic_callback_errorHandler_func.func, arg);
01529   Py_DECREF(arg);
01530   Py_XDECREF(res);
01531   PyGILState_Release(gstate);
01532   } else {
01533     debug("Could not find any registered Python function. "\
01534         "Dropping DIM client error callback.");
01535     PyErr_SetString(PyExc_RuntimeError, "Could not find any registered Python function. "\
01536         "Dropping DIM client error callback.");
01537     return;
01538   }
01539 }
01540 
01541 
01542 void _dic_info_service_dummy (void* tag, void* buffer, int* size) {
01543   /** Stub function for passing the received data from a service to a python
01544    *  callback.
01545    *
01546    * @param tag A tag that identifies the service. This parameter is used in
01547    * the wrapper to identify the update service, convert the buffer to Python
01548    * objects and pass the call to the interpretor.
01549    * @param buffer The buffer containing the service update data.
01550    * @param size The size of the buffer.
01551    *
01552    * When this function is called we don't have the interpretor lock. We must
01553    * ensure that before calling any Python API function we have it! Note also
01554    * that dim_buf_to_tuple creates Python object so the lock must be held.
01555    */
01556 
01557   PyObject* args, *res;
01558   _dic_info_service_callback* svc;
01559   PyGILState_STATE gstate;
01560 
01561   //debug("Received update for a service with size %d, buffer pointer %x, tag %x",
01562   //   *size, (long)buffer, (long *)tag);
01563   svc = (_dic_info_service_callback*)(*(long *)tag);
01564 
01565   gstate = PyGILState_Ensure();
01566   if (!(*size)) {
01567     /* The service update request failed. Passing default argument */
01568     args = svc->pyDefaultArg;
01569   } else {
01570     args = dim_buf_to_tuple(svc->format, (char*)buffer, *size);
01571   }
01572   if (args) {
01573 //    Py_INCREF(args);
01574     res = PyEval_CallObject(svc->pyFunc, args);
01575     if (!res){
01576       if (PyErr_Occurred() != NULL) {
01577         PyErr_Print();
01578       } else {
01579         print("ERROR: Bad call to Python layer");
01580       }
01581     } else {
01582       /* call succedded */
01583       Py_DECREF(res);
01584     }
01585     Py_XDECREF(args);
01586   } else {
01587     /* service failed and a default value was not specified */
01588     print("ERROR: Could not get new data to update service");
01589   }
01590   PyGILState_Release(gstate);
01591 }
01592 
01593 /** @}
01594 */
01595 
01596 static PyMethodDef DimMethods[] = {
01597   {    "dis_start_serving"          ,
01598     dim_dis_start_serving        ,
01599     METH_VARARGS                 ,
01600     "Start providing DIM service"
01601   },
01602   {    "dis_stop_serving"           ,
01603     dim_dis_stop_serving         ,
01604     METH_VARARGS                 ,
01605     "Stop DIM service"
01606   },
01607   {    "dis_set_dns_node"           ,
01608     dim_dis_set_dns_node         ,
01609     METH_VARARGS                 ,
01610     "Function for setting the DNS node"
01611   },
01612   {    "dis_get_dns_node"           ,
01613     dim_dis_get_dns_node         ,
01614     METH_VARARGS                 ,
01615     "Function for getting the DNS node"
01616   },
01617   {    "dis_set_dns_port"           ,
01618     dim_dis_set_dns_port         ,
01619     METH_VARARGS                 ,
01620     "Function for setting the DNS port"
01621   },
01622   {    "dis_get_dns_port"           ,
01623     dim_dis_get_dns_port         ,
01624     METH_VARARGS                 ,
01625     "Function for getting the DNS port"
01626   },
01627   {    "dis_add_exit_handler"       ,
01628     dim_dis_add_exit_handler     ,
01629     METH_VARARGS                 ,
01630     "Function for setting the DIM exit handler"
01631   },
01632   {    "dis_add_error_handler"      ,
01633     dim_dis_add_error_handler    ,
01634     METH_VARARGS                 ,
01635     "Function for setting the DIM error handler"
01636   },
01637   {    "dis_add_client_exit_handler"  ,
01638     dim_dis_add_client_exit_handler,
01639     METH_VARARGS                   ,
01640     "Function for setting the DIM Client exit handler"
01641   },
01642   {    "dis_update_service"           ,
01643     dim_dis_update_service         ,
01644     METH_VARARGS                   ,
01645     "Function for updating the specified service"
01646   },
01647   {    "dis_selective_update_service"  ,
01648     dim_dis_selective_update_service,
01649     METH_VARARGS                    ,
01650     "Function for updating the specified service and clients"
01651   },
01652   {    "dis_set_quality"               ,
01653     dim_dis_set_quality             ,
01654     METH_VARARGS                    ,
01655     "Function for setting the quality of a service"
01656   },
01657   {    "dis_set_timestamp"             ,
01658     dim_dis_set_timestamp           ,
01659     METH_VARARGS                    ,
01660     "Function for setting the the timestamp of a service"
01661   },
01662   {    "dis_remove_service"            ,
01663     dim_dis_remove_service          ,
01664     METH_VARARGS                    ,
01665     "Function for removing a service"
01666   },
01667   {    "dis_get_next_cmnd"             ,
01668     dim_dis_get_next_cmnd           ,
01669     METH_VARARGS                    ,
01670     "Get a command from the list of waiting command requests"
01671   },
01672   {    "dis_remove_service"            ,
01673     dim_dis_remove_service          ,
01674     METH_VARARGS                    ,
01675     "Remove a Service from the list of provided services"
01676   },
01677   {    "dis_get_client"                ,
01678     dim_dis_get_client              ,
01679     METH_VARARGS                    ,
01680     "Gets the process identification of the current DIM client"
01681   },
01682   {    "dis_get_conn_id"               ,
01683     dim_dis_get_conn_id             ,
01684     METH_VARARGS                    ,
01685     "Gets the connection ID of the current DIM client"
01686   },
01687   {    "dis_get_timeout"               ,
01688     dim_dis_get_timeout             ,
01689     METH_VARARGS                    ,
01690     "Gets the update rate that was specified by a client for a specific service"
01691   },
01692   {    "dis_get_client_services"       ,
01693     dim_dis_get_client_services     ,
01694     METH_VARARGS                    ,
01695     "Gets the services of a DIM client, which has subscribed to this DIM server"
01696   },
01697   {    "dis_set_client_exit_handler"   ,
01698     dim_dis_set_client_exit_handler ,
01699     METH_VARARGS                    ,
01700     "Activates the client exit handler for a specific client and a specific service"
01701   },
01702   {    "dis_get_error_services"        ,
01703     dim_dis_get_error_services      ,
01704     METH_VARARGS                    ,
01705     "Gets the names of DIM services that have an error"
01706   },
01707   {    "dis_add_cmnd"                  ,
01708     dim_dis_add_cmnd                ,
01709     METH_VARARGS                    ,
01710     "Adds a new command"
01711   },
01712   {    "dis_add_service"               ,
01713     dim_dis_add_service             ,
01714     METH_VARARGS                    ,
01715     "Adds a new service"
01716   },
01717   {    "dic_set_dns_node"              ,
01718     dim_dic_set_dns_node            ,
01719     METH_VARARGS                    ,
01720     "Function for setting the DNS node"
01721   },
01722   {    "dic_get_dns_node"              ,
01723     dim_dic_get_dns_node            ,
01724     METH_VARARGS                    ,
01725     "Function for getting the DNS node"
01726   },
01727   {    "dic_set_dns_port"              ,
01728     dim_dic_set_dns_port            ,
01729     METH_VARARGS                    ,
01730     "Function for setting the DNS port"
01731   },
01732   {    "dic_get_dns_port"              ,
01733     dim_dic_get_dns_port            ,
01734     METH_VARARGS                    ,
01735     "Function for getting the DNS port"
01736   },
01737   {    "dic_get_id"                    ,
01738     dim_dic_get_id                  ,
01739     METH_VARARGS                    ,
01740     "Gets the process identification of this DIM client."
01741   },
01742   {    "dic_disable_padding"           ,
01743     dim_dic_disable_padding         ,
01744     METH_VARARGS                    ,
01745     "Disable padding of received services."
01746   },
01747   {    "dic_get_quality"               ,
01748     dim_dic_get_quality             ,
01749     METH_VARARGS                    ,
01750     "Gets the quality of  a received service."
01751   },
01752   {    "dic_get_timestamp"             ,
01753     dim_dic_get_timestamp           ,
01754     METH_VARARGS                    ,
01755     "Gets the time stamp of a received service."
01756   },
01757   {    "dic_get_format"                ,
01758     dim_dic_get_format              ,
01759     METH_VARARGS                    ,
01760     "Gets the format description of a received service."
01761   },
01762   {    "dic_release_service"           ,
01763     dim_dic_release_service         ,
01764     METH_VARARGS                    ,
01765     "Called by a client when a service is not needed anymore."
01766   },
01767   {    "dic_info_service"               ,
01768     dim_dic_info_service,
01769     METH_VARARGS | METH_KEYWORDS     ,
01770     "Called by a client for subscribing to a service."
01771   },
01772   {    "dic_cmnd_service"        ,
01773     dim_dic_cmnd_service      ,
01774     METH_VARARGS              ,
01775     "Request the execution of a command by a server."
01776   },
01777   {    "dic_cmnd_callback"       ,
01778     dim_dic_cmnd_callback     ,
01779     METH_VARARGS              ,
01780     "Request the execution of a command and registers a completion callback."
01781   },
01782   {    "dic_info_service_stamped"       ,
01783     dim_dic_info_service_stamped  ,
01784     METH_VARARGS              ,
01785     "Request a time stamped (and quality flagged) information service from a server"
01786   },
01787   {    "dic_get_server"          ,
01788     dim_dic_get_server        ,
01789     METH_VARARGS              ,
01790     "Gets the process identification of the current DIM server"
01791   },
01792   {    "dic_get_conn_id"          ,
01793     dim_dic_get_conn_id        ,
01794     METH_VARARGS               ,
01795     "Gets the connection ID of the current DIM server"
01796   },
01797   {    "dic_get_server_services"          ,
01798     dim_dic_get_server_services     ,
01799     METH_VARARGS              ,
01800     "Gets the services of a DIM server to which the client has subscribed."
01801   },
01802   {    "dic_get_error_services"          ,
01803     dim_dic_get_error_services       ,
01804     METH_VARARGS              ,
01805     "Gets the names of DIM services that have an error."
01806   },
01807   {    "dic_add_error_handler"          ,
01808     dim_dic_add_error_handler   ,
01809     METH_VARARGS              ,
01810     "Adds an error handler to this client."
01811   },
01812   {NULL, NULL, 0, NULL}        /* Sentinel */
01813 };
01814 
01815 #ifndef _WIN32
01816 static pthread_t maintid;
01817 static pthread_mutex_t pydimlock = PTHREAD_MUTEX_INITIALIZER; 
01818 #endif
01819   PyMODINIT_FUNC
01820 initdimc(void)
01821 {
01822   PyObject *m;
01823   PyEval_InitThreads();
01824   debug("Initializing the C DIM interface... \n");
01825   m = Py_InitModule3("dimc", DimMethods, "DIM methods");
01826 
01827   if (m == NULL)
01828     return;
01829 #ifndef _WIN32
01830   maintid = pthread_self();
01831 #endif
01832   //Add constants for service type definitions
01833   PyModule_AddIntConstant (m, "ONCE_ONLY", ONCE_ONLY);
01834   PyModule_AddIntConstant (m, "TIMED", TIMED);
01835   PyModule_AddIntConstant (m, "MONITORED", MONITORED);
01836   PyModule_AddIntConstant (m, "COMMAND", COMMAND);
01837   PyModule_AddIntConstant (m, "DIM_DELETE", DIM_DELETE);
01838   PyModule_AddIntConstant (m, "MONIT_ONLY", MONIT_ONLY);
01839   PyModule_AddIntConstant (m, "UPDATE", UPDATE);
01840   PyModule_AddIntConstant (m, "TIMED_ONLY", TIMED_ONLY);
01841   PyModule_AddIntConstant (m, "MONIT_FIRST", MONIT_FIRST);
01842   PyModule_AddIntConstant (m, "MAX_TYPE_DEF", MAX_TYPE_DEF);
01843   PyModule_AddIntConstant (m, "STAMPED", STAMPED);
01844 
01845   dic_disable_padding();
01846   dis_disable_padding();
01847 }
01848 
01849 #ifdef RINUNX
01850 #include <stdio.h>
01851 #include <dlfcn.h>
01852 #include <errno.h>
01853 #include <string.h>
01854 #include <semaphore.h>
01855 
01856 extern sem_t DIM_INIT_Sema;
01857 
01858 PyGILState_STATE gilstack[GILSTACKSIZE];
01859 int gilstackp = 0;
01860 
01861 void dim_lock()
01862 {
01863   static void  (*func)(void);
01864   int v;
01865 
01866     if(!func) {
01867         func = (void (*)()) dlsym(RTLD_NEXT, "dim_lock");
01868     if (!func) {
01869       printf("Couldn't find dim_lock");
01870       exit(1);
01871     }
01872   }
01873   if (gilstackp == GILSTACKSIZE) {
01874     printf("ERROR: GILstack overflow");
01875     exit(1);
01876   }
01877   pthread_mutex_lock(&pydimlock);
01878   if ((pthread_self() != maintid)) {
01879     gilstack[gilstackp++] = PyGILState_Ensure();
01880   }
01881   sem_getvalue(&DIM_INIT_Sema, &v);
01882   printf("%d\n", v);
01883   (*func)();
01884     printf("dim_lock() is called: %d\n", gilstackp);
01885   pthread_mutex_unlock(&pydimlock); 
01886     return;
01887 }
01888 
01889 void dim_unlock()
01890 {
01891         
01892   static void  (*func)(void);
01893 
01894   if(!func) {
01895         func = (void (*)()) dlsym(RTLD_NEXT, "dim_unlock");
01896     if (!func) {
01897       printf("Couldn't find dim_unlock");
01898       exit(1);
01899     }
01900   }        
01901    // gilstackp--;  
01902   pthread_mutex_lock(&pydimlock);
01903     (*func)();
01904   if ((pthread_self() != maintid)) {
01905     PyGILState_Release(gilstack[gilstackp--]);
01906   }           
01907   pthread_mutex_unlock(&pydimlock);
01908     printf("dim_unlock() is called: %d\n", gilstackp); 
01909     return;
01910 }
01911 
01912 #endif
01913 
01914 

Generated on 5 Feb 2014 for PyDIM by  doxygen 1.4.7