pyzmq.cpp 16.2 KB
Newer Older
tamara's avatar
tamara committed
1
/*
2
    Copyright (c) 2007-2010 iMatix Corporation
tamara's avatar
tamara committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
    the terms of the Lesser GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    Lesser GNU General Public License for more details.

    You should have received a copy of the Lesser GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

20
#include <Python.h>
21 22 23 24
#include <stddef.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
tamara's avatar
tamara committed
25

malosek's avatar
malosek committed
26
#include "../c/zmq.h"
tamara's avatar
tamara committed
27

Martin Sustrik's avatar
Martin Sustrik committed
28 29 30 31 32
#if defined _MSC_VER
#pragma warning (push)
#pragma warning (disable:4996)
#endif

33 34
extern PyTypeObject context_type;

35
struct context_t
tamara's avatar
tamara committed
36 37
{
    PyObject_HEAD
38
    void *handle;
tamara's avatar
tamara committed
39 40
};

41
PyObject *context_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
tamara's avatar
tamara committed
42
{
43
    context_t *self = (context_t*) type->tp_alloc (type, 0);
tamara's avatar
tamara committed
44

45 46
    if (self)
        self->handle = NULL;
tamara's avatar
tamara committed
47 48 49 50 51

    return (PyObject*) self;
}


52
int context_init (context_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
53 54 55
{
    int app_threads;
    int io_threads;
56 57 58 59
    int flags = 0;
    static const char *kwlist [] = {"app_threads", "io_threads", "flags", NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "ii|i", (char**) kwlist,
          &app_threads, &io_threads, &flags)) {
60
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
61
        return -1;
tamara's avatar
tamara committed
62 63
    }

64
    assert (!self->handle);
65
    self->handle = zmq_init (app_threads, io_threads, flags);
66
    if (!self->handle) {
67
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
68
        return -1;
69
    }
tamara's avatar
tamara committed
70

71
    return 0;
tamara's avatar
tamara committed
72 73
}

74
void context_dealloc (context_t *self)
tamara's avatar
tamara committed
75
{
76 77 78
    if (self->handle) {
        int rc = zmq_term (self->handle);
        if (rc != 0)
79
            PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
80
    }
tamara's avatar
tamara committed
81

82
    self->ob_type->tp_free ((PyObject*) self);
tamara's avatar
tamara committed
83 84
}

85 86
extern PyTypeObject socket_type;

87
struct socket_t
tamara's avatar
tamara committed
88
{
89 90 91
    PyObject_HEAD
    void *handle;
};
tamara's avatar
tamara committed
92

93
PyObject *socket_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
tamara's avatar
tamara committed
94
{
95
    socket_t *self = (socket_t*) type->tp_alloc (type, 0);
tamara's avatar
tamara committed
96

97 98
    if (self)
        self->handle = NULL;
tamara's avatar
tamara committed
99

100
    return (PyObject*) self;
tamara's avatar
tamara committed
101 102
}

103
int socket_init (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
104
{
105 106
    context_t *context;
    int socket_type;
tamara's avatar
tamara committed
107
    static const char *kwlist [] = {"context", "type", NULL};
108 109
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "O!i", (char**) kwlist,
          &context_type, &context, &socket_type)) {
110
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
111
        return -1;
112
    }
tamara's avatar
tamara committed
113
	
114 115 116
    assert (!self->handle);
    self->handle = zmq_socket (context->handle, socket_type);
    if (!self->handle) {
117
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
118
        return -1;
tamara's avatar
tamara committed
119 120
    }

121
    return 0;
tamara's avatar
tamara committed
122 123
}

124
void socket_dealloc (socket_t *self)
tamara's avatar
tamara committed
125
{
126 127 128
    if (self->handle) {
        int rc = zmq_close (self->handle);
        if (rc != 0)
129
            PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
130
    }
tamara's avatar
tamara committed
131

132
    self->ob_type->tp_free ((PyObject*) self);
tamara's avatar
tamara committed
133 134
}

135
PyObject *socket_setsockopt (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
136 137 138
{
    int option;
    PyObject* optval;
139 140 141 142 143 144 145
    static const char *kwlist [] = {"option", "optval", NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "iO", (char**) kwlist,
          &option, &optval)) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
    }

146
    int rc = 0;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

    switch (option) {
    case ZMQ_HWM:
    case ZMQ_LWM:
    case ZMQ_SWAP:
    case ZMQ_AFFINITY:
    case ZMQ_RATE:
    case ZMQ_RECOVERY_IVL:
    case ZMQ_MCAST_LOOP:
        {
            int val = PyInt_AsLong (optval);
            rc = zmq_setsockopt (self->handle, option, &val, sizeof (int));
            break;
        }
    case ZMQ_IDENTITY:
    case ZMQ_SUBSCRIBE:
    case ZMQ_UNSUBSCRIBE:
        rc = zmq_setsockopt (self->handle, option, PyString_AsString (optval), 
            PyString_Size (optval));
        break;

    default:
169 170 171
        rc = -1;
        errno = EINVAL;
    }
tamara's avatar
tamara committed
172

173
    if (rc != 0) {
174
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
175 176
        return NULL;
    }
tamara's avatar
tamara committed
177

178 179
    Py_INCREF (Py_None);
    return Py_None;
tamara's avatar
tamara committed
180 181
}

182
PyObject *socket_bind (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
183
{
184 185 186 187 188 189
    char const *addr;
    static const char *kwlist [] = {"addr", NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "s", (char**) kwlist,
          &addr)) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
tamara's avatar
tamara committed
190 191
    }

192 193
    int rc = zmq_bind (self->handle, addr);
    if (rc != 0) {
194
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
195 196 197 198 199
        return NULL;
    }

    Py_INCREF (Py_None);
    return Py_None;
tamara's avatar
tamara committed
200
}
201 202

PyObject *socket_connect (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
203
{
204 205 206 207 208 209 210 211 212 213
    char const *addr;
    static const char *kwlist [] = {"addr", NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "s", (char**) kwlist,
          &addr)) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
    }

    int rc = zmq_connect (self->handle, addr);
    if (rc != 0) {
214
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
215
        return NULL;
tamara's avatar
tamara committed
216 217
    }

218 219
    Py_INCREF (Py_None);
    return Py_None;
tamara's avatar
tamara committed
220 221
}

222
PyObject *socket_send (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
223
{
224 225 226 227 228 229 230 231
    PyObject *msg; /* = PyString_FromStringAndSize (NULL, 0); */
    int flags = 0;
    static const char *kwlist [] = {"msg", "flags", NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "S|i", (char**) kwlist,
          &msg, &flags)) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
    }
tamara's avatar
tamara committed
232

233 234 235
    zmq_msg_t data;
    int rc = zmq_msg_init_size (&data, PyString_Size (msg));
    if (rc != 0) {
236
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
237 238 239 240 241
        return NULL;
    }
    memcpy (zmq_msg_data (&data), PyString_AsString (msg),
        zmq_msg_size (&data));

242
    Py_BEGIN_ALLOW_THREADS
243
    rc = zmq_send (self->handle, &data, flags);
244 245
    Py_END_ALLOW_THREADS

246 247 248 249 250 251 252
    int rc2 = zmq_msg_close (&data);
    assert (rc2 == 0);

    if (rc != 0 && errno == EAGAIN)
        return PyBool_FromLong (0);

    if (rc != 0) {
253
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
254 255
        return NULL;
    }
tamara's avatar
tamara committed
256

257
    return PyBool_FromLong (1);
tamara's avatar
tamara committed
258 259
}

260
PyObject *socket_flush (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
261
{
262 263 264 265 266 267 268 269
    static const char *kwlist [] = {NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "", (char**) kwlist)) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
    }

    int rc = zmq_flush (self->handle);
    if (rc != 0) {
270
        PyErr_SetString (PyExc_SystemError, zmq_strerror (errno));
271 272 273 274 275
        return NULL;
    }

    Py_INCREF (Py_None);
    return Py_None;
tamara's avatar
tamara committed
276 277
}

278
PyObject *socket_recv (socket_t *self, PyObject *args, PyObject *kwdict)
tamara's avatar
tamara committed
279 280
{
    int flags = 0;
281 282 283 284 285 286
    static const char *kwlist [] = {"flags", NULL};
    if (!PyArg_ParseTupleAndKeywords (args, kwdict, "|i", (char**) kwlist,
          &flags)) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
    }
tamara's avatar
tamara committed
287

288 289 290 291
    zmq_msg_t msg;
    int rc = zmq_msg_init (&msg);
    assert (rc == 0);

292
    Py_BEGIN_ALLOW_THREADS
293
    rc = zmq_recv (self->handle, &msg, flags);
294
    Py_END_ALLOW_THREADS
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310

    if (rc != 0 && errno == EAGAIN) {
        Py_INCREF (Py_None);
        return Py_None;
    }

    if (rc != 0) {
        PyErr_SetString (PyExc_SystemError, "invalid arguments");
        return NULL;
    }

    PyObject *result = PyString_FromStringAndSize ((char*) zmq_msg_data (&msg),
        zmq_msg_size (&msg));
    rc = zmq_msg_close (&msg);
    assert (rc == 0);
    return result;
tamara's avatar
tamara committed
311 312
}

313
static PyMethodDef context_methods [] =
tamara's avatar
tamara committed
314 315
{
    {
316 317 318 319
        NULL
    }
};

320
PyTypeObject context_type =
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
{
    PyObject_HEAD_INIT (NULL)
    0,
    "libpyzmq.Context",              /* tp_name */
    sizeof (context_t),              /* tp_basicsize */
    0,                               /* tp_itemsize */
    (destructor) context_dealloc,    /* tp_dealloc */
    0,                               /* tp_print */
    0,                               /* tp_getattr */
    0,                               /* tp_setattr */
    0,                               /* tp_compare */
    0,                               /* tp_repr */
    0,                               /* tp_as_number */
    0,                               /* tp_as_sequence */
    0,                               /* tp_as_mapping */
    0,                               /* tp_hash */
    0,                               /* tp_call */
    0,                               /* tp_str */
    0,                               /* tp_getattro */
    0,                               /* tp_setattro */
    0,                               /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,              /* tp_flags */
    "",                              /* tp_doc */
    0,                               /* tp_traverse */
    0,                               /* tp_clear */
    0,                               /* tp_richcompare */
    0,                               /* tp_weaklistoffset */
    0,                               /* tp_iter */
    0,                               /* tp_iternext */
    context_methods,                 /* tp_methods */
    0,                               /* tp_members */
    0,                               /* tp_getset */
    0,                               /* tp_base */
    0,                               /* tp_dict */
    0,                               /* tp_descr_get */
    0,                               /* tp_descr_set */
    0,                               /* tp_dictoffset */
    (initproc) context_init,         /* tp_init */
    0,                               /* tp_alloc */
360
    context_new                      /* tp_new */
361 362 363 364
};

static PyMethodDef socket_methods [] =
{
tamara's avatar
tamara committed
365 366
    {
        "setsockopt",
367
        (PyCFunction) socket_setsockopt,
tamara's avatar
tamara committed
368
        METH_VARARGS | METH_KEYWORDS, 
369
        "setsockopt (option, optval) -> None\n\n"
tamara's avatar
tamara committed
370 371 372
    },
    {
        "bind",
373
        (PyCFunction) socket_bind,
tamara's avatar
tamara committed
374 375 376 377 378
        METH_VARARGS | METH_KEYWORDS, 
        "bind (addr) -> None\n\n"
    },
    {
        "connect",
379
        (PyCFunction) socket_connect,
tamara's avatar
tamara committed
380 381 382 383
        METH_VARARGS | METH_KEYWORDS, 
        "connect (addr) -> None\n\n"
    },
    {
384 385
        "send",
        (PyCFunction) socket_send,
tamara's avatar
tamara committed
386
        METH_VARARGS | METH_KEYWORDS, 
387
        "send (msg, [flags]) -> Bool\n\n"
tamara's avatar
tamara committed
388 389
    },
    {
390 391
        "flush",
        (PyCFunction) socket_flush,
tamara's avatar
tamara committed
392
        METH_VARARGS | METH_KEYWORDS, 
393
        "flush () -> None\n\n"
tamara's avatar
tamara committed
394 395
    },
    {
396 397
        "recv",
        (PyCFunction) socket_recv,
tamara's avatar
tamara committed
398
        METH_VARARGS | METH_KEYWORDS, 
399
        "recv ([flags]) -> String\n\n"
tamara's avatar
tamara committed
400 401 402 403 404 405
    },
    {
        NULL
    }
};

406
PyTypeObject socket_type =
tamara's avatar
tamara committed
407 408 409
{
    PyObject_HEAD_INIT (NULL)
    0,
410
    "libpyzmq.Socket",               /* tp_name */
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
    sizeof (socket_t),               /* tp_basicsize */
    0,                               /* tp_itemsize */
    (destructor) socket_dealloc,     /* tp_dealloc */
    0,                               /* tp_print */
    0,                               /* tp_getattr */
    0,                               /* tp_setattr */
    0,                               /* tp_compare */
    0,                               /* tp_repr */
    0,                               /* tp_as_number */
    0,                               /* tp_as_sequence */
    0,                               /* tp_as_mapping */
    0,                               /* tp_hash */
    0,                               /* tp_call */
    0,                               /* tp_str */
    0,                               /* tp_getattro */
    0,                               /* tp_setattro */
    0,                               /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,              /* tp_flags */
    "",                              /* tp_doc */
    0,                               /* tp_traverse */
    0,                               /* tp_clear */
    0,                               /* tp_richcompare */
    0,                               /* tp_weaklistoffset */
    0,                               /* tp_iter */
    0,                               /* tp_iternext */
    socket_methods,                  /* tp_methods */
    0,                               /* tp_members */
    0,                               /* tp_getset */
    0,                               /* tp_base */
    0,                               /* tp_dict */
    0,                               /* tp_descr_get */
    0,                               /* tp_descr_set */
    0,                               /* tp_dictoffset */
    (initproc) socket_init,          /* tp_init */
    0,                               /* tp_alloc */
446
    socket_new                       /* tp_new */
tamara's avatar
tamara committed
447 448
};

449 450 451 452 453 454
static PyMethodDef module_methods [] = {{ NULL, NULL, 0, NULL }};

static const char* libpyzmq_doc =
    "Python API for 0MQ lightweight messaging kernel.\n"
    "For more information see http://www.zeromq.org.\n"
    "0MQ is distributed under GNU Lesser General Public License v3.\n";
tamara's avatar
tamara committed
455 456 457 458 459

#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC void
#endif

460
PyMODINIT_FUNC initlibpyzmq ()
tamara's avatar
tamara committed
461
{
462 463 464 465
    int rc = PyType_Ready (&context_type);
    assert (rc == 0);
    rc = PyType_Ready (&socket_type);
    assert (rc == 0);
tamara's avatar
tamara committed
466

467 468 469
    PyObject *module = Py_InitModule3 ("libpyzmq", module_methods,
        libpyzmq_doc);
    if (!module)
tamara's avatar
tamara committed
470 471
        return;

472 473
    Py_INCREF (&context_type);
    PyModule_AddObject (module, "Context", (PyObject*) &context_type);
474
    Py_INCREF (&socket_type);
475
    PyModule_AddObject (module, "Socket", (PyObject*) &socket_type);
tamara's avatar
tamara committed
476

477 478
    PyObject *dict = PyModule_GetDict (module);
    assert (dict);
479
    PyObject *t;
480 481
    t = PyInt_FromLong (ZMQ_NOBLOCK);
    PyDict_SetItemString (dict, "NOBLOCK", t);
tamara's avatar
tamara committed
482 483
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_NOFLUSH);
484
    PyDict_SetItemString (dict, "NOFLUSH", t);
tamara's avatar
tamara committed
485 486
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_P2P);
487
    PyDict_SetItemString (dict, "P2P", t);
tamara's avatar
tamara committed
488 489
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_PUB);
490
    PyDict_SetItemString (dict, "PUB", t);
tamara's avatar
tamara committed
491 492
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_SUB);
493
    PyDict_SetItemString (dict, "SUB", t);
tamara's avatar
tamara committed
494 495
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_REQ);
496
    PyDict_SetItemString (dict, "REQ", t);
tamara's avatar
tamara committed
497 498
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_REP);
499
    PyDict_SetItemString (dict, "REP", t);
tamara's avatar
tamara committed
500
    Py_DECREF (t);
501 502 503 504 505 506
    t = PyInt_FromLong (ZMQ_XREQ);
    PyDict_SetItemString (dict, "XREQ", t);
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_XREP);
    PyDict_SetItemString (dict, "XREP", t);
    Py_DECREF (t);
507 508 509 510 511 512
    t = PyInt_FromLong (ZMQ_UPSTREAM);
    PyDict_SetItemString (dict, "UPSTREAM", t);
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_DOWNSTREAM);
    PyDict_SetItemString (dict, "DOWNSTREAM", t);
    Py_DECREF (t);
tamara's avatar
tamara committed
513
    t = PyInt_FromLong (ZMQ_HWM);
514
    PyDict_SetItemString (dict, "HWM", t);
tamara's avatar
tamara committed
515 516
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_LWM);
517 518
    PyDict_SetItemString (dict, "LWM", t);
    Py_DECREF (t);
tamara's avatar
tamara committed
519
    t = PyInt_FromLong (ZMQ_SWAP);
520
    PyDict_SetItemString (dict, "SWAP", t);
tamara's avatar
tamara committed
521 522
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_AFFINITY);
523
    PyDict_SetItemString (dict, "AFFINITY", t);
tamara's avatar
tamara committed
524 525
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_IDENTITY);
526
    PyDict_SetItemString (dict, "IDENTITY", t);
527 528 529 530 531 532 533 534 535
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_SUBSCRIBE);
    PyDict_SetItemString (dict, "SUBSCRIBE", t);
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_UNSUBSCRIBE);
    PyDict_SetItemString (dict, "UNSUBSCRIBE", t);
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_RATE);
    PyDict_SetItemString (dict, "RATE", t);
536
    Py_DECREF (t);    
537 538 539 540 541 542
    t = PyInt_FromLong (ZMQ_RECOVERY_IVL);
    PyDict_SetItemString (dict, "RECOVERY_IVL", t);
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_MCAST_LOOP);
    PyDict_SetItemString (dict, "MCAST_LOOP", t);
    Py_DECREF (t);
543 544 545 546 547 548
    t = PyInt_FromLong (ZMQ_SNDBUF);
    PyDict_SetItemString (dict, "SNDBUF", t);
    Py_DECREF (t);
    t = PyInt_FromLong (ZMQ_RCVBUF);
    PyDict_SetItemString (dict, "RCVBUF", t);
    Py_DECREF (t);
549 550 551
    t = PyInt_FromLong (ZMQ_POLL);
    PyDict_SetItemString (dict, "POLL", t);
    Py_DECREF (t);
tamara's avatar
tamara committed
552
}
Martin Sustrik's avatar
Martin Sustrik committed
553 554 555 556

#if defined _MSC_VER
#pragma warning (pop)
#endif