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
00032
00033
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <unistd.h>
00047 #include <time.h>
00048 #include <sys/time.h>
00049
00050 #include "Python.h"
00051 #include "tuple.h"
00052
00053
00054 staticforward PyTypeObject CtxType;
00055
00059 typedef struct {
00060 PyObject_HEAD;
00061 struct context ctx;
00062 } CtxObject;
00063
00064
00065 static char ctx_put_doc_string[];
00066 static char ctx_get_doc_string[];
00067 static char ctx_read_doc_string[];
00068 static char ctx_get_nb_doc_string[];
00069 static char ctx_read_nb_doc_string[];
00070 static char ctx_dump_doc_string[];
00071 static char ctx_log_doc_string[];
00072 static PyMethodDef linuxtuples_methods[];
00073 static PyMethodDef ctx_methods[];
00074
00075 static PyObject *ctx_getattr(CtxObject *obj, char *name);
00076 static PyObject *new_ctx(PyObject *self, PyObject *args);
00077 static void ctx_dealloc(PyObject *self);
00078 static struct tuple *PyTuple_to_LinuxTuple(PyObject *pytup, int puttable);
00079 static PyObject *LinuxTuple_to_PyTuple(struct tuple *t);
00080 static PyObject *ctx_put_tuple(PyObject *self, PyObject *args);
00081 static PyObject * ctx_get_read(CtxObject *pyctx,
00082 PyObject *args,
00083 struct tuple * (*func)(struct tuple *,
00084 struct context *),
00085 int blocking);
00086 static PyObject *ctx_get_tuple(PyObject *self, PyObject *args);
00087 static PyObject *ctx_read_tuple(PyObject *self, PyObject *args);
00088 static PyObject *ctx_get_nb_tuple(PyObject *self, PyObject *args);
00089 static PyObject *ctx_read_nb_tuple(PyObject *self, PyObject *args);
00090 static PyObject *ctx_dump_tuple_space(PyObject *self, PyObject *args);
00091 static PyObject *ctx_tuple_server_log(PyObject *self, PyObject *args);
00092
00093 static char py_random_int_doc_string[];
00094 static PyObject *py_random_int(PyObject *self, PyObject *args);
00095
00096 void initlinuxtuples(void);
00097
00098
00099 static char
00100 linuxtuples_doc_string[] =
00101 "This is the Python client API for the linuxtuples tuple server. The\n"
00102 "connect() method returns a connection to the tuple server. The\n"
00103 "random() method returns a 32-bit integer taken from /dev/urandom.";
00104
00105
00106 static char
00107 ctx_doc_string[] =
00108 "This is a connection to a tuple server. Its methods give access to\n"
00109 "tuple space.\n"
00110 "\n"
00111 "The put(tuple) method lets you put a tuple into the tuple space.\n"
00112 "get(template) removes a tuple that matches the template (where None is\n"
00113 "used as a wildcard), blocking until a matching tuple becomes\n"
00114 "available. read(template) is like get(), but it returns a copy of the\n"
00115 "tuple, leaving the original in tuple space.\n"
00116 "\n"
00117 "get_nonblocking() and read_nonblocking() are non-blocking versions of\n"
00118 "get() and read(), which return None if a matching tuple is not\n"
00119 "available.\n"
00120 "\n"
00121 "The dump() method returns a list of the tuples in tuple space. If\n"
00122 "supplied with a list of templates as an argument, it will return a\n"
00123 "list of only those tuples that match at least one template.\n"
00124 "\n"
00125 "The log() method prints a running log of tuple server activity to\n"
00126 "stdout. It should be called in a \"while 1:\" loop.";
00127
00128
00132 static PyMethodDef ctx_methods[] = {
00133 {"put", ctx_put_tuple, METH_VARARGS,
00134 ctx_put_doc_string},
00135 {"get", ctx_get_tuple, METH_VARARGS,
00136 ctx_get_doc_string},
00137 {"read", ctx_read_tuple, METH_VARARGS,
00138 ctx_read_doc_string},
00139 {"get_nonblocking", ctx_get_nb_tuple, METH_VARARGS,
00140 ctx_get_nb_doc_string},
00141 {"read_nonblocking", ctx_read_nb_tuple, METH_VARARGS,
00142 ctx_read_nb_doc_string},
00143 {"dump", ctx_dump_tuple_space, METH_VARARGS,
00144 ctx_dump_doc_string},
00145 {"log", ctx_tuple_server_log, METH_VARARGS,
00146 ctx_log_doc_string},
00147 {NULL, NULL, 0, NULL}
00148 };
00149
00153 static PyObject *
00154 ctx_getattr(CtxObject *obj, char *name)
00155 {
00156 if (strcmp(name, "__doc__") == 0) {
00157 return PyString_FromString(ctx_doc_string);
00158 }
00159 return Py_FindMethod(ctx_methods, (PyObject *)obj, name);
00160 }
00161
00162
00163 #define SETENV_STRING \
00164 "\nUnable to find the environment variables (LINUXTUPLES_HOST,\n" \
00165 "LINUXTUPLES_PORT). Please set them."
00166
00167
00168 static char
00169 new_ctx_doc_string[] =
00170 "conn = connect()\n"
00171 "conn = connect(int)\n"
00172 "Return a connection to the tuple server.";
00173
00177 static PyObject*
00178 new_ctx(PyObject* self, PyObject* args)
00179 {
00180 CtxObject* pyctx;
00181
00182 if (!PyArg_ParseTuple(args,""))
00183 return NULL;
00184
00185 pyctx = PyObject_New(CtxObject, &CtxType);
00186
00187 if (get_server_portnumber(&pyctx->ctx)) {
00188 PyErr_SetString(PyExc_ImportError, SETENV_STRING);
00189 return NULL;
00190 };
00191
00192 return (PyObject*)pyctx;
00193 }
00194
00198 static void
00199 ctx_dealloc(PyObject* self)
00200 {
00201 CtxObject *pyctx = (CtxObject*) self;
00202 close(pyctx->ctx.sock);
00203 PyObject_Del(self);
00204 }
00205
00209 static PyTypeObject CtxType = {
00210 PyObject_HEAD_INIT(NULL)
00211 0,
00212 "Ctx",
00213 sizeof(CtxObject),
00214 0,
00215 ctx_dealloc,
00216 0,
00217 (getattrfunc) ctx_getattr,
00218 0,
00219 0,
00220 0,
00221 0,
00222 0,
00223 0,
00224 0,
00225 };
00226
00227
00228
00235 static struct tuple *
00236 PyTuple_to_LinuxTuple(PyObject *pytup, int puttable)
00237 {
00238 int i, len;
00239 struct tuple *t;
00240 len = PyTuple_Size(pytup);
00241 t = malloc(sizeof(struct tuple));
00242 if (t == NULL) {
00243 return (struct tuple*) PyErr_NoMemory();
00244 }
00245 t->tag = I_AM_A_TUPLE;
00246 t->num_elts = len;
00247 t->elements = malloc(t->num_elts * sizeof(struct element));
00248 if (t->elements == NULL) {
00249 return (struct tuple *) PyErr_NoMemory();
00250 }
00251 t->string_space = NULL;
00252 t->string_length = 0;
00253
00254 for (i = 0; i < len; i++) {
00255 PyObject *elem;
00256 elem = PyTuple_GetItem(pytup, i);
00257 if (elem == Py_None) {
00258 if (puttable)
00259 goto bad_element;
00260 t->elements[i].tag = '?';
00261 }
00262 else if (PyInt_Check(elem)) {
00263 t->elements[i].tag = 'i';
00264 t->elements[i].data.i = PyInt_AsLong(elem);
00265 }
00266 else if (PyFloat_Check(elem)) {
00267 t->elements[i].tag = 'd';
00268 t->elements[i].data.d = PyFloat_AsDouble(elem);
00269 }
00270 else if (PyString_Check(elem)) {
00271 int n = PyString_Size(elem);
00272 t->elements[i].tag = 's';
00273 t->elements[i].data.s.ptr = PyString_AsString(elem);
00274 t->elements[i].data.s.len = n;
00275 t->string_length += n;
00276 }
00277 else {
00278 bad_element:
00279 PyErr_SetString(PyExc_RuntimeError,
00280 "Bad element in LinuxTuples tuple");
00281 return NULL;
00282 }
00283 }
00284 return t;
00285 }
00286
00287
00291 static PyObject *
00292 LinuxTuple_to_PyTuple(struct tuple * t)
00293 {
00294 PyObject *pytup;
00295 int i;
00296
00297
00298
00299 pytup = PyTuple_New(t->num_elts);
00300 if (pytup == NULL)
00301 return PyErr_NoMemory();
00302 for (i = 0; i < t->num_elts; i++) {
00303 PyObject *ob;
00304 switch (t->elements[i].tag) {
00305 case '?':
00306 Py_INCREF(Py_None);
00307 PyTuple_SetItem(pytup, i, Py_None);
00308 break;
00309 case 'i':
00310 ob = PyInt_FromLong(t->elements[i].data.i);
00311 if (ob == NULL)
00312 return PyErr_NoMemory();
00313 PyTuple_SetItem(pytup, i, ob);
00314 break;
00315 case 'd':
00316 ob = PyFloat_FromDouble(t->elements[i].data.d);
00317 if (ob == NULL)
00318 return PyErr_NoMemory();
00319 PyTuple_SetItem(pytup, i, ob);
00320 break;
00321 case 's':
00322 ob = PyString_FromStringAndSize(
00323 t->elements[i].data.s.ptr,
00324 t->elements[i].data.s.len);
00325 if (ob == NULL)
00326 return PyErr_NoMemory();
00327 PyTuple_SetItem(pytup, i, ob);
00328 break;
00329 }
00330 }
00331 return pytup;
00332 }
00333
00334
00335 static char
00336 ctx_put_doc_string[] =
00337 "conn.put(tuple)\n"
00338 "Put a tuple into tuple space.";
00339
00343 static PyObject *
00344 ctx_put_tuple(PyObject *self, PyObject *args)
00345 {
00346 CtxObject *pyctx = (CtxObject*) self;
00347 PyObject *pytup;
00348 struct tuple *t;
00349
00350 if (!PyArg_ParseTuple(args, "O", &pytup))
00351 return NULL;
00352 if (!PyTuple_Check(pytup)) {
00353 PyErr_SetString(PyExc_TypeError,
00354 "argument must be a tuple");
00355 return NULL;
00356 }
00357
00358 t = PyTuple_to_LinuxTuple(pytup, 1);
00359 if (t == NULL) {
00360 return NULL;
00361 }
00362
00363
00364
00365
00366
00367 if (put_tuple(t, &pyctx->ctx)) {
00368 PyErr_SetString(PyExc_RuntimeError, "put() failed");
00369 return NULL;
00370 }
00371 destroy_tuple(t);
00372
00373 Py_INCREF(Py_None);
00374 return Py_None;
00375 }
00376
00377
00378
00382 static PyObject *
00383 ctx_get_read(CtxObject *pyctx,
00384 PyObject *args,
00385 struct tuple * (*func)(struct tuple *,
00386 struct context *),
00387 int blocking)
00388 {
00389 PyObject *pytup;
00390 struct tuple *s, *t;
00391
00392 if (!PyArg_ParseTuple(args, "O", &pytup))
00393 return NULL;
00394 if (!PyTuple_Check(pytup)) {
00395 PyErr_SetString(PyExc_TypeError,
00396 "argument must be a tuple");
00397 return NULL;
00398 }
00399
00400
00401
00402
00403 s = PyTuple_to_LinuxTuple(pytup, 0);
00404 if (s == NULL) {
00405 return NULL;
00406 }
00407
00408
00409
00410
00411 t = (*func)(s, &pyctx->ctx);
00412 destroy_tuple(s);
00413 if (t == (struct tuple *) -1) {
00414 goto abject_failure;
00415 }
00416 if (!blocking && t == NULL) {
00417 Py_INCREF(Py_None);
00418 return Py_None;
00419 }
00420 if (t == NULL) {
00421 abject_failure:
00422 PyErr_SetString(PyExc_RuntimeError, "get() or read() failed");
00423 return NULL;
00424 }
00425
00426
00427
00428
00429 pytup = LinuxTuple_to_PyTuple(t);
00430 destroy_tuple(t);
00431 return pytup;
00432 }
00433
00434
00435 static char
00436 ctx_get_doc_string[] =
00437 "tuple = conn.get(template)\n"
00438 "Get a tuple from tuple space. Items in the returned tuple\n"
00439 "must match any non-None items in the template. Nones are\n"
00440 "wildcards. This call blocks until a matching tuple is found.";
00441
00446 static PyObject *
00447 ctx_get_tuple(PyObject *self, PyObject *args)
00448 {
00449 return ctx_get_read((CtxObject*)self, args, get_tuple, 1);
00450 }
00451
00452 static char
00453 ctx_read_doc_string[] =
00454 "tuple = conn.read(template)\n"
00455 "Read a copy of a tuple from tuple space. Items in the\n"
00456 "returned tuple must match any non-None items in the template.\n"
00457 "Nones are wildcards. This call blocks until a matching\n"
00458 "tuple is found.";
00459
00464 static PyObject *
00465 ctx_read_tuple(PyObject *self, PyObject *args)
00466 {
00467 return ctx_get_read((CtxObject*)self, args, read_tuple, 1);
00468 }
00469
00470 static char
00471 ctx_get_nb_doc_string[] =
00472 "tuple = conn.get_nonblocking(template)\n"
00473 "Get a tuple from tuple space. Items in the returned tuple\n"
00474 "must match any non-None items in the template. Nones are\n"
00475 "wildcards. If no matching tuple is found, returns None.";
00476
00481 static PyObject *
00482 ctx_get_nb_tuple(PyObject *self, PyObject *args)
00483 {
00484 return ctx_get_read((CtxObject*)self, args, get_nb_tuple, 0);
00485 }
00486
00487 static char
00488 ctx_read_nb_doc_string[] =
00489 "tuple = conn.read_nonblocking(template)\n"
00490 "Read a copy of a tuple from tuple space. Items in the\n"
00491 "returned tuple must match any non-None items in the template.\n"
00492 "Nones are wildcards. If no matching tuple is found, returns\n"
00493 "None.";
00494
00499 static PyObject *
00500 ctx_read_nb_tuple(PyObject *self, PyObject *args)
00501 {
00502 return ctx_get_read((CtxObject*)self, args, read_nb_tuple, 0);
00503 }
00504
00505 static char
00506 ctx_dump_doc_string[] =
00507 "tuple_list = conn.dump( [template_list] )\n"
00508 "Return a list of the tuples in the tuple space. If no template\n"
00509 "list is given, return all the tuples. If there is a template\n"
00510 "list, return only the tuples that match at least one template.";
00511
00516 static PyObject *
00517 ctx_dump_tuple_space(PyObject *self, PyObject *args)
00518 {
00519 PyObject *pylst = NULL, *pytup;
00520 CtxObject *pyctx;
00521 struct tuple_list *slist, *tlist, *x;
00522 int i, count, listsize;
00523
00524 pyctx = (CtxObject*)self;
00525 if (!PyArg_ParseTuple(args, "|O", &pylst))
00526 return NULL;
00527 if (pylst != NULL) {
00528 if (!PyList_Check(pylst)) {
00529 PyErr_SetString(PyExc_TypeError,
00530 "argument must be a list");
00531 return NULL;
00532 }
00533 listsize = PyList_Size(pylst);
00534 } else {
00535 listsize = 0;
00536 }
00537
00538
00539
00540
00541 slist = NULL;
00542 for (i = 0; i < listsize; i++) {
00543 pytup = PyList_GetItem(pylst, i);
00544 if (!PyTuple_Check(pytup)) {
00545 PyErr_SetString(PyExc_TypeError,
00546 "list members must be tuples");
00547 return NULL;
00548 }
00549 x = malloc(sizeof(struct tuple_list));
00550 if (x == NULL)
00551 return PyErr_NoMemory();
00552 x->tup = PyTuple_to_LinuxTuple(pytup, 0);
00553 x->next = slist;
00554 slist = x;
00555 }
00556
00557 x = slist;
00558 while (x != NULL) {
00559 x = x->next;
00560 }
00561
00562
00563
00564 tlist = dump_tuple_space(slist, &pyctx->ctx);
00565 while (slist) {
00566 x = slist;
00567 slist = slist->next;
00568 free(x);
00569 }
00570
00571 count = 0;
00572 x = tlist;
00573 while (x != NULL) {
00574 count++;
00575 x = x->next;
00576 }
00577 pylst = PyList_New(count);
00578 if (pylst == NULL)
00579 return PyErr_NoMemory();
00580 for (i = 0, x = tlist; x != NULL; x = x->next, i++)
00581 PyList_SetItem(pylst, i,
00582 LinuxTuple_to_PyTuple(x->tup));
00583
00584 while (tlist) {
00585 x = tlist;
00586 tlist = tlist->next;
00587 free(x);
00588 }
00589
00590 return pylst;
00591 }
00592
00593 static char
00594 ctx_log_doc_string[] =
00595 "Dump a continuous log of tuple space activity to stdout. Call this\n"
00596 "method in a \"while 1:\" loop. Looping in Python rather than C\n"
00597 "means that you can break out of the loop easily with control-C,\n"
00598 "and you can put other code in the loop.";
00599
00604 static PyObject *
00605 ctx_tuple_server_log(PyObject *self, PyObject *args)
00606 {
00607 CtxObject *pyctx = (CtxObject*)self;
00608 if (!PyArg_ParseTuple(args, ""))
00609 return NULL;
00610 tuple_server_log(stdout, &pyctx->ctx);
00611 Py_INCREF(Py_None);
00612 return Py_None;
00613 }
00614
00615 static char
00616 py_random_int_doc_string[] =
00617 "Return a 32-bit random integer, taken from /dev/urandom.";
00618
00623 static PyObject *
00624 py_random_int(PyObject *self, PyObject *args)
00625 {
00626 if (!PyArg_ParseTuple(args, ""))
00627 return NULL;
00628 return PyInt_FromLong(random_int());
00629 }
00630
00631
00632
00636 static PyMethodDef
00637 linuxtuples_methods[] = {
00638 {"connect", new_ctx, METH_VARARGS, new_ctx_doc_string},
00639 {"random", py_random_int, METH_VARARGS, py_random_int_doc_string},
00640 {NULL, NULL}
00641 };
00642
00643
00648 DL_EXPORT(void)
00649 initlinuxtuples()
00650 {
00651 PyObject *m, *d;
00652
00653 CtxType.ob_type = &PyType_Type;
00654 m = Py_InitModule("linuxtuples", linuxtuples_methods);
00655 d = PyModule_GetDict(m);
00656 PyDict_SetItemString(d, "__doc__",
00657 PyString_FromString(linuxtuples_doc_string));
00658 }