Blame _dbus_bindings/unixfd.c

Packit 130fc8
/* Simple D-Bus types: Unix FD type.
Packit 130fc8
 *
Packit 130fc8
 * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
Packit 130fc8
 * Copyright (C) 2010 Signove  <http://www.signove.com>
Packit 130fc8
 *
Packit 130fc8
 * Permission is hereby granted, free of charge, to any person
Packit 130fc8
 * obtaining a copy of this software and associated documentation
Packit 130fc8
 * files (the "Software"), to deal in the Software without
Packit 130fc8
 * restriction, including without limitation the rights to use, copy,
Packit 130fc8
 * modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 130fc8
 * of the Software, and to permit persons to whom the Software is
Packit 130fc8
 * furnished to do so, subject to the following conditions:
Packit 130fc8
 *
Packit 130fc8
 * The above copyright notice and this permission notice shall be
Packit 130fc8
 * included in all copies or substantial portions of the Software.
Packit 130fc8
 *
Packit 130fc8
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 130fc8
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 130fc8
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 130fc8
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Packit 130fc8
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
Packit 130fc8
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit 130fc8
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Packit 130fc8
 * DEALINGS IN THE SOFTWARE.
Packit 130fc8
 */
Packit 130fc8
Packit 130fc8
#include "dbus_bindings-internal.h"
Packit 130fc8
Packit 130fc8
#include "types-internal.h"
Packit 130fc8
Packit 130fc8
PyDoc_STRVAR(UnixFd_tp_doc,
Packit 130fc8
"An Unix Fd.\n"
Packit 130fc8
"\n"
Packit 130fc8
"Constructor::\n"
Packit 130fc8
"\n"
Packit 130fc8
"    dbus.UnixFd(value: int or file object[, variant_level: int]) -> UnixFd\n"
Packit 130fc8
"\n"
Packit 130fc8
"``value`` must be the integer value of a file descriptor, or an object that\n"
Packit 130fc8
"implements the fileno() method. Otherwise, `ValueError` will be\n"
Packit 130fc8
"raised.\n"
Packit 130fc8
"\n"
Packit 130fc8
"UnixFd keeps a dup() (duplicate) of the supplied file descriptor. The\n"
Packit 130fc8
"caller remains responsible for closing the original fd.\n"
Packit 130fc8
"\n"
Packit 130fc8
"``variant_level`` must be non-negative; the default is 0.\n"
Packit 130fc8
"\n"
Packit 130fc8
":IVariables:\n"
Packit 130fc8
"  `variant_level` : int\n"
Packit 130fc8
"    Indicates how many nested Variant containers this object\n"
Packit 130fc8
"    is contained in: if a message's wire format has a variant containing a\n"
Packit 130fc8
"    variant containing an Unix Fd, this is represented in Python by an\n"
Packit 130fc8
"    Unix Fd with variant_level==2.\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
typedef struct {
Packit 130fc8
    PyObject_HEAD
Packit 130fc8
    int fd;
Packit 130fc8
} UnixFdObject;
Packit 130fc8
Packit 130fc8
/* Return values:
Packit 130fc8
 * -2 - the long value overflows an int
Packit 130fc8
 * -1 - Python failed producing a long (or in Python 2 an int)
Packit 130fc8
 *  0 - success
Packit 130fc8
 *  1 - arg is not a long (or in Python 2 an int)
Packit 130fc8
 *
Packit 130fc8
 * Or to summarize:
Packit 130fc8
 * status  < 0 - an error occurred, and a Python exception is set.
Packit 130fc8
 * status == 0 - all is okay, output argument *fd is set.
Packit 130fc8
 * status  > 0 - try something else
Packit 130fc8
 */
Packit 130fc8
static int
Packit 130fc8
make_fd(PyObject *arg, int *fd)
Packit 130fc8
{
Packit 130fc8
    long fd_arg;
Packit 130fc8
Packit 130fc8
    if (INTORLONG_CHECK(arg))
Packit 130fc8
    {
Packit 130fc8
        /* on Python 2 this accepts either int or long */
Packit 130fc8
        fd_arg = PyLong_AsLong(arg);
Packit 130fc8
        if (fd_arg == -1 && PyErr_Occurred()) {
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        return 1;
Packit 130fc8
    }
Packit 130fc8
    /* Check for int overflow. */
Packit 130fc8
    if (fd_arg < INT_MIN || fd_arg > INT_MAX) {
Packit 130fc8
        PyErr_Format(PyExc_ValueError, "int is outside fd range");
Packit 130fc8
        return -2;
Packit 130fc8
    }
Packit 130fc8
    *fd = (int)fd_arg;
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
UnixFd_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs UNUSED)
Packit 130fc8
{
Packit 130fc8
    UnixFdObject *self = NULL;
Packit 130fc8
    PyObject *arg;
Packit 130fc8
    int status, fd, fd_original = -1;
Packit 130fc8
Packit 130fc8
    if (!PyArg_ParseTuple(args, "O", &arg, NULL)) {
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    status = make_fd(arg, &fd_original);
Packit 130fc8
    if (status < 0)
Packit 130fc8
        return NULL;
Packit 130fc8
Packit 130fc8
    if (status > 0) {
Packit 130fc8
        if (PyObject_HasAttrString(arg, "fileno")) {
Packit 130fc8
            PyObject *fd_number = PyObject_CallMethod(arg, "fileno", NULL);
Packit 130fc8
            if (!fd_number)
Packit 130fc8
                return NULL;
Packit 130fc8
            status = make_fd(fd_number, &fd_original);
Packit 130fc8
            Py_CLEAR(fd_number);
Packit 130fc8
            if (status < 0)
Packit 130fc8
                return NULL;
Packit 130fc8
            if (status > 0) {
Packit 130fc8
                PyErr_Format(PyExc_ValueError, "Argument's fileno() method "
Packit 130fc8
                             "returned a non-int value");
Packit 130fc8
                return NULL;
Packit 130fc8
            }
Packit 130fc8
            /* fd_original is all good. */
Packit 130fc8
        }
Packit 130fc8
        else {
Packit 130fc8
            PyErr_Format(PyExc_ValueError, "Argument is not int and does not "
Packit 130fc8
                         "implement fileno() method");
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
    assert(fd_original >= 0);
Packit 130fc8
    fd = dup(fd_original);
Packit 130fc8
    if (fd < 0) {
Packit 130fc8
        PyErr_Format(PyExc_ValueError, "Invalid file descriptor");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    self = (UnixFdObject *) cls->tp_alloc(cls, 0);
Packit 130fc8
    if (!self)
Packit 130fc8
        return NULL;
Packit 130fc8
Packit 130fc8
    self->fd = fd;
Packit 130fc8
    return (PyObject *)self;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static void
Packit 130fc8
UnixFd_dealloc(UnixFdObject *self)
Packit 130fc8
{
Packit 130fc8
    if (self->fd >= 0) {
Packit 130fc8
        close(self->fd);
Packit 130fc8
        self->fd = -1;
Packit 130fc8
    }
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
PyDoc_STRVAR(UnixFd_take__doc__,
Packit 130fc8
"take() -> int\n"
Packit 130fc8
"\n"
Packit 130fc8
"This method returns the file descriptor owned by UnixFd object.\n"
Packit 130fc8
"Note that, once this method is called, closing the file descriptor is\n"
Packit 130fc8
"the caller's responsibility.\n"
Packit 130fc8
"\n"
Packit 130fc8
"This method may be called at most once; UnixFd 'forgets' the file\n"
Packit 130fc8
"descriptor after it is taken.\n"
Packit 130fc8
"\n"
Packit 130fc8
":Raises ValueError: if this method has already been called\n"
Packit 130fc8
);
Packit 130fc8
static PyObject *
Packit 130fc8
UnixFd_take(UnixFdObject *self)
Packit 130fc8
{
Packit 130fc8
    PyObject *fdnumber;
Packit 130fc8
Packit 130fc8
    if (self->fd < 0) {
Packit 130fc8
        PyErr_SetString(PyExc_ValueError, "File descriptor already taken");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    fdnumber = Py_BuildValue("i", self->fd);
Packit 130fc8
    self->fd = -1;
Packit 130fc8
Packit 130fc8
    return fdnumber;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
int
Packit 130fc8
dbus_py_unix_fd_get_fd(PyObject *self)
Packit 130fc8
{
Packit 130fc8
    return ((UnixFdObject *) self)->fd;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyMethodDef UnixFd_methods[] = {
Packit 130fc8
    {"take", (PyCFunction) UnixFd_take, METH_NOARGS, UnixFd_take__doc__ },
Packit 130fc8
    {NULL}
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
PyTypeObject DBusPyUnixFd_Type = {
Packit 130fc8
    PyVarObject_HEAD_INIT(NULL, 0)
Packit 130fc8
    "dbus.UnixFd",
Packit 130fc8
    sizeof(UnixFdObject),
Packit 130fc8
    0,
Packit 130fc8
    (destructor) UnixFd_dealloc,            /* tp_dealloc */
Packit 130fc8
    0,                                      /* tp_print */
Packit 130fc8
    0,                                      /* tp_getattr */
Packit 130fc8
    0,                                      /* tp_setattr */
Packit 130fc8
    0,                                      /* tp_compare */
Packit 130fc8
    0,                                      /* tp_repr */
Packit 130fc8
    0,                                      /* tp_as_number */
Packit 130fc8
    0,                                      /* tp_as_sequence */
Packit 130fc8
    0,                                      /* tp_as_mapping */
Packit 130fc8
    0,                                      /* tp_hash */
Packit 130fc8
    0,                                      /* tp_call */
Packit 130fc8
    0,                                      /* tp_str */
Packit 130fc8
    0,                                      /* tp_getattro */
Packit 130fc8
    0,                                      /* tp_setattro */
Packit 130fc8
    0,                                      /* tp_as_buffer */
Packit 130fc8
    Py_TPFLAGS_DEFAULT,                     /* tp_flags */
Packit 130fc8
    UnixFd_tp_doc,                          /* tp_doc */
Packit 130fc8
    0,                                      /* tp_traverse */
Packit 130fc8
    0,                                      /* tp_clear */
Packit 130fc8
    0,                                      /* tp_richcompare */
Packit 130fc8
    0,                                      /* tp_weaklistoffset */
Packit 130fc8
    0,                                      /* tp_iter */
Packit 130fc8
    0,                                      /* tp_iternext */
Packit 130fc8
    UnixFd_methods,                         /* tp_methods */
Packit 130fc8
    0,                                      /* tp_members */
Packit 130fc8
    0,                                      /* tp_getset */
Packit 130fc8
    0,                                      /* tp_base */
Packit 130fc8
    0,                                      /* tp_dict */
Packit 130fc8
    0,                                      /* tp_descr_get */
Packit 130fc8
    0,                                      /* tp_descr_set */
Packit 130fc8
    0,                                      /* tp_dictoffset */
Packit 130fc8
    0,                                      /* tp_init */
Packit 130fc8
    0,                                      /* tp_alloc */
Packit 130fc8
    UnixFd_tp_new,                          /* tp_new */
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
dbus_bool_t
Packit 130fc8
dbus_py_init_unixfd_type(void)
Packit 130fc8
{
Packit 130fc8
    if (PyType_Ready(&DBusPyUnixFd_Type) < 0) return 0;
Packit 130fc8
Packit 130fc8
    return 1;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
dbus_bool_t
Packit 130fc8
dbus_py_insert_unixfd_type(PyObject *this_module)
Packit 130fc8
{
Packit 130fc8
    Py_INCREF(&DBusPyUnixFd_Type);
Packit 130fc8
    if (PyModule_AddObject(this_module, "UnixFd",
Packit 130fc8
                           (PyObject *)&DBusPyUnixFd_Type) < 0) return 0;
Packit 130fc8
    return 1;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* vim:set ft=c cino< sw=4 sts=4 et: */