00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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}
00181 };
00182
00185 static PyMemberDef PydtnAppObject_members[] =
00186 {
00187 { "node", T_OBJECT_EX, offsetof(PydtnAppObject, node), READONLY,
00188 "the owner node" },
00189 {0}
00190 };
00191
00195 static PyTypeObject PydtnAppObjectType = {
00196 PyObject_HEAD_INIT(0)
00197 0,
00198 "pydtn.Application",
00199 sizeof(PydtnAppObject),
00200 0,
00201 (destructor)PydtnAppObject_dealloc,
00202 0,
00203 0,
00204 0,
00205 0,
00206 PydtnAppObject_repr,
00207 0,
00208 0,
00209 0,
00210 0,
00211 0,
00212 0,
00213 0,
00214 0,
00215 0,
00216 Py_TPFLAGS_DEFAULT,
00217 PydtnAppObject_doc,
00218 0,
00219 0,
00220 0,
00221 0,
00222 0,
00223 0,
00224 PydtnAppObject_methods,
00225 PydtnAppObject_members,
00226 0,
00227 0,
00228 0,
00229 0,
00230 0,
00231 0,
00232 0,
00233 0,
00234 PydtnAppObject_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;
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);
00381 Py_DECREF(args);
00382 if ( 0 == r )
00383 {
00384 if ( 0 != PyErr_Occurred() ) PyErr_Print();
00385 throw SimulationException( __FILE__ , __LINE__ );
00386 }
00387 }
00388