PydtnApplication.cc

00001 // Copyright 2008 Michael Marsh, University of Maryland.
00002 //
00003 // This file is part of pydtn.
00004 //
00005 // pydtn is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // pydtn is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with pydtn.  If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 // The views and conclusions contained in the software and documentation
00019 // are those of the authors and should not be interpreted as representing
00020 // official policies, either expressed or implied, of the University
00021 // of Maryland.
00022 //
00023 // pydtn extends and embeds the Python interpreter, which is
00024 // Copyright 2001-2006 Python Software Foundation, All Rights Reserved,
00025 // and is released under the PSF License Agreement.
00026 //
00027 // RANLUX random number generation uses the Boost library,
00028 // Copyright 1994-2006 by various authors (details in individual files),
00029 // which is released under the Boost Software License, Version 1.0.
00030 
00031 #include "simlpy/interpreter_hooks.h"
00032 #include "parsers.h"
00033 #include "PydtnApplication.h"
00034 #include "PydtnBundle.h"
00035 #include "WrapNode.h"
00036 
00037 #include <iostream>
00038 
00039 #include "simlpy/SimulationException.h"
00040 
00043 
00044 static PyObject* PydtnAppObject_new( PyTypeObject* type,
00045                                      PyObject* args,
00046                                      PyObject* kwds );
00047 
00050 static void
00051 PydtnAppObject_dealloc( PydtnAppObject* self )
00052 {
00053    if ( 0 == self ) return;
00054    if ( 0 != self->proc ) Py_DECREF(self->proc);
00055    if ( 0 != self->node ) Py_DECREF(self->node);
00056    if ( 0 != self->app ) delete self->app;
00057    self->ob_type->tp_free((PyObject*)self);
00058 }
00059 
00063 static PyObject*
00064 PydtnAppObject_repr( PyObject* self )
00065 {
00066    return construct_string("");
00067 }
00068 
00072 static PyObject*
00073 PydtnAppObject_appID( PydtnAppObject* self )
00074 {
00075    if ( 0 == self ) return 0;
00076    if ( 0 == self->app ) return 0;
00077    PyObject* retval = self->app->pyid();
00078    Py_INCREF(retval);
00079    return retval;
00080 }
00081 
00090 static PyObject*
00091 PydtnAppObject_process( PydtnAppObject* self, PyObject* args )
00092 {
00093    if ( 0 == self ) return 0;
00094    if ( 0 == self->proc ) return 0;
00095    if ( 0 == args ) return 0;
00096    PyObject* newArgs = PyTuple_New(2);
00097    if ( 0 == newArgs )
00098    {
00099       PyErr_SetString( PyExc_MemoryError, "could not allocate tuple" );
00100       return 0;
00101    }
00102    Py_INCREF(self);
00103    PyObject* r = 0;
00104    try
00105    {
00106       PyTuple_SetItem( args, 0, (PyObject*)self );
00107       if ( ! PyTuple_Check(args) )
00108       {
00109          PyErr_SetString( PyExc_TypeError, "expected a tuple" );
00110          throw SimulationException( __FILE__ , __LINE__ );
00111       }
00112       PyObject* b = PyTuple_GetItem(args,0);
00113       if ( 0 == b )
00114       {
00115          throw SimulationException( __FILE__ , __LINE__ );
00116       }
00117       Py_INCREF(b);
00118       PyTuple_SetItem( args, 1, b );
00119       r = PyObject_Call(self->proc,args,0);
00120    }
00121    catch ( ... )
00122    {
00123       Py_DECREF(self);
00124    }
00125    Py_DECREF(newArgs);
00126    return r;
00127 }
00128 
00130 static char PydtnAppObject_doc[] =
00131 "Define an application as a Python object.\n\
00132    \n\
00133    This is a Python class that can be used as a DTN::Application\n\
00134    in a simulation.  The application identifier and process()\n\
00135    method can be specified dynamically when the object is created.\n\
00136    The syntax for creating a pydtn.Application is:\n\
00137    \n\
00138       app = pydtn.Application(node,identifier,proc)\n\
00139    \n\
00140    where:\n\
00141       node       is a sim.Entity of type 'node'\n\
00142       identifier is a string uniquely identifying an application type\n\
00143       proc       is a function or other callable object\n\
00144    \n\
00145    While proc is defined separate from the class, it should look like\n\
00146    a class method:\n\
00147    \n\
00148       def proc(self,b):\n\
00149          # do something with pydtn.Bundle b\n\
00150    \n\
00151    The owner node is available as app.node (or self.node in proc).\n\
00152    \n\
00153    You can call proc directly with a pydtn.Bundle, and it will be\n\
00154    treated as if the bundle was received over the network:\n\
00155    \n\
00156       app.process(b)\n\
00157    \n\
00158    Note that any functionality required by proc must be provided in\n\
00159    some additional way.  In particular, if you want to send bundles,\n\
00160    you need to provide some hook for doing so.\n\
00161    \n\
00162    Attaching a pydtn.Application to all nodes might be accomplished\n\
00163    with code similar to the following:\n\
00164    \n\
00165       pydtn.mobility.applyToNodes( pydtn.Application, identifier, proc )\n\
00166    \n\
00167    Note that this does not give you handles to the pydtn.Applications\n\
00168    created.  You could create a helper function to do this, or inherit\n\
00169    pydtn.Application in a class that maintains its own mapping from\n\
00170    nodes to applications.\n\
00171    \n";
00172 
00174 static PyMethodDef PydtnAppObject_methods[] =
00175 {
00176    { "appID",   (PyCFunction)PydtnAppObject_appID,   METH_NOARGS,
00177      "returns the application identifier" },
00178    { "process", (PyCFunction)PydtnAppObject_process, METH_VARARGS,
00179      "process a pydtn.Bundle as if it were received over the network" },
00180    {0} // sentinel
00181 };
00182 
00185 static PyMemberDef PydtnAppObject_members[] =
00186 {
00187    { "node", T_OBJECT_EX, offsetof(PydtnAppObject, node), READONLY,
00188      "the owner node" },
00189    {0} // sentinel
00190 };
00191 
00195 static PyTypeObject PydtnAppObjectType = {
00196    PyObject_HEAD_INIT(0)
00197    0,                                  // ob_size
00198    "pydtn.Application",                // tp_name
00199    sizeof(PydtnAppObject),             // tp_basicsize
00200    0,                                  // tp_itemsize
00201    (destructor)PydtnAppObject_dealloc, // tp_dealloc
00202    0,                                  // tp_print
00203    0,                                  // tp_getattr
00204    0,                                  // tp_setattr
00205    0,                                  // tp_compare
00206    PydtnAppObject_repr,                // tp_repr
00207    0,                                  // tp_as_number
00208    0,                                  // tp_as_sequence
00209    0,                                  // tp_as_mapping
00210    0,                                  // tp_hash
00211    0,                                  // tp_call
00212    0,                                  // tp_str
00213    0,                                  // tp_getattro
00214    0,                                  // tp_setattro
00215    0,                                  // tp_as_buffer
00216    Py_TPFLAGS_DEFAULT,                 // tp_flags
00217    PydtnAppObject_doc,                 // tp_doc
00218    0,                                  // tp_traverse
00219    0,                                  // tp_clear
00220    0,                                  // tp_richcompare
00221    0,                                  // tp_weaklistoffset
00222    0,                                  // tp_iter
00223    0,                                  // tp_iternext
00224    PydtnAppObject_methods,             // tp_methods
00225    PydtnAppObject_members,             // tp_members
00226    0,                                  // tp_getset
00227    0,                                  // tp_base
00228    0,                                  // tp_dict
00229    0,                                  // tp_descr_get
00230    0,                                  // tp_descr_set
00231    0,                                  // tp_dictoffset
00232    0,                                  // tp_init
00233    0,                                  // tp_alloc
00234    PydtnAppObject_new,                 // tp_new
00235 };
00236 
00242 static PyObject*
00243 PydtnAppObject_new( PyTypeObject* type, PyObject* args, PyObject* kwds )
00244 {
00245    if ( 0 == args )
00246    {
00247       PyErr_SetString( PyExc_TypeError, "expected arguments" );
00248       return 0;
00249    }
00250    Entity::ArgList appArgs;
00251    WrapNode* wn;
00252    PyObject* node;
00253    PyObject* id;
00254    PyObject* proc;
00255    try
00256    {
00257       build_arglist( appArgs, args );
00258       if ( 3 != appArgs.size() )
00259       {
00260          PyErr_SetString(PyExc_TypeError,"three arguments expected");
00261          throw SimulationException( __FILE__ , __LINE__ );
00262       }
00263       node = appArgs[0];
00264       wn = parse_node( node );
00265       id = appArgs[1];
00266       if ( ! PyString_Check( id ) )
00267       {
00268          PyErr_SetString(PyExc_TypeError,"expected a string");
00269          throw SimulationException( __FILE__ , __LINE__ );
00270       }
00271       proc = appArgs[2];
00272       if ( ! PyCallable_Check( proc ) )
00273       {
00274          PyErr_SetString(PyExc_TypeError,"expected a callable object");
00275          throw SimulationException( __FILE__ , __LINE__ );
00276       }
00277    }
00278    catch ( ... )
00279    {
00280       clean_arglist(appArgs);
00281       return 0;
00282    }
00283    clean_arglist(appArgs);
00284 
00285    PydtnAppObject* self =
00286       (PydtnAppObject*)PydtnAppObjectType.tp_alloc(&PydtnAppObjectType,0);
00287    if ( 0 == self )
00288    {
00289       std::cerr << "Could not allocate a new pydtn.Application" << std::endl;
00290       return 0;
00291    }
00292 
00293    self->app = new PydtnApplication( self, id );
00294    wn->addApplication( self->app );
00295    Py_INCREF(proc); self->proc = proc;
00296    Py_INCREF(node); self->node = node;
00297 
00298    Py_INCREF(self);
00299    return (PyObject*)self;
00300 }
00301 
00302 void
00303 addType_PydtnAppObject( PyObject* m )
00304 {
00305    if ( 0 == m ) return;
00306    if ( PyType_Ready(&PydtnAppObjectType) < 0 ) return;
00307    Py_INCREF(&PydtnAppObjectType);
00308    PyModule_AddObject(m,"Application",(PyObject*)&PydtnAppObjectType);
00309 }
00310 
00311 int
00312 PydtnAppObject_Check( PyObject* o )
00313 {
00314    if ( 0 == o ) return 0;
00315    return PyObject_TypeCheck(o,&PydtnAppObjectType);
00316 }
00317 
00318 PydtnApplication::PydtnApplication( PydtnAppObject* pyapp,
00319                                     PyObject* pyappID ) :
00320    DTN::Application()
00321 {
00322    if ( 0 == pyapp )
00323    {
00324       throw SimulationException( __FILE__ , __LINE__ );
00325    }
00326    if ( 0 == pyappID )
00327    {
00328       PyErr_SetString( PyExc_AttributeError,
00329                        "Application requires an identifier" );
00330       throw SimulationException( __FILE__ , __LINE__ );
00331    }
00332    if ( ! PyString_Check(pyappID) )
00333    {
00334       PyErr_SetString( PyExc_TypeError,
00335                        "application identifier must be a string" );
00336       throw SimulationException( __FILE__ , __LINE__ );
00337    }
00338 
00339    Py_INCREF(pyapp); m_pyapp = pyapp;
00340    Py_INCREF(pyappID); m_pyid = pyappID;
00341 
00342    char* buff = NULL;
00343    int bufflen = 0;
00344    if ( -1 != PyString_AsStringAndSize(pyappID,&buff,&bufflen) )
00345    {
00346       for ( int i = 0 ; i < bufflen ; ++i )
00347       {
00348          m_appID += (unsigned char)(buff[i]);
00349       }
00350    }
00351 }
00352 
00353 PydtnApplication::~PydtnApplication()
00354 {
00355    if ( 0 != m_pyid ) Py_DECREF(m_pyid);
00356 }
00357 
00358 PyObject*
00359 PydtnApplication::pyid()
00360 {
00361    return m_pyid; // borrowed reference
00362 }
00363 
00364 void
00365 PydtnApplication::process( const DTN::Bundle& b )
00366 {
00367    if ( 0 == m_pyapp ) return;
00368    if ( 0 == m_pyapp->proc ) return;
00369    if ( ! PyCallable_Check(m_pyapp->proc) ) return;
00370    PyObject* args = PyTuple_New(2);
00371    if ( 0 == args )
00372    {
00373       PyErr_SetString( PyExc_MemoryError, "could not allocate tuple" );
00374       throw SimulationException( __FILE__ , __LINE__ );
00375    }
00376    Py_INCREF(m_pyapp);
00377    PyTuple_SetItem( args, 0, (PyObject*)m_pyapp );
00378    PyTuple_SetItem( args, 1, PydtnBundle_wrapBundle(b) );
00379    PyObject* r = PyObject_Call(m_pyapp->proc,args,0);
00380    if ( 0 != r ) Py_DECREF(r); // we don't use it
00381    Py_DECREF(args);
00382    if ( 0 == r )
00383    {
00384       if ( 0 != PyErr_Occurred() ) PyErr_Print();
00385       throw SimulationException( __FILE__ , __LINE__ );
00386    }
00387 }
00388 

Generated on Mon Mar 24 11:15:46 2008 for Pydtn Simulator by  doxygen 1.5.4