/* * Copyright (C) Amitay Isaacs 2011 * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* Python interface to socket wrapper library. Passes all socket communication over unix domain sockets if the environment variable SOCKET_WRAPPER_DIR is set. */ #include #include #include "replace/replace.h" #include "system/network.h" #include "socket_wrapper.h" /* There's no Py_ssize_t in 2.4, apparently */ #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5 typedef int Py_ssize_t; typedef inquiry lenfunc; typedef intargfunc ssizeargfunc; #endif #ifndef Py_RETURN_NONE #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif #ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */ #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif #ifndef PY_CHECK_TYPE #define PY_CHECK_TYPE(type, var, fail) \ if (!PyObject_TypeCheck(var, type)) {\ PyErr_Format(PyExc_TypeError, __location__ ": Expected type '%s' for '%s' of type '%s'", (type)->tp_name, #var, Py_TYPE(var)->tp_name); \ fail; \ } #endif staticforward PyTypeObject PySocket; static PyObject *py_socket_error; void initsocket_wrapper(void); static PyObject *py_socket_addr_to_tuple(struct sockaddr *addr, socklen_t len) { char host[256]; char service[8]; int status; PyObject *pyaddr; status = getnameinfo(addr, len, host, 255, service, 7, NI_NUMERICHOST|NI_NUMERICSERV); if (status < 0) { PyErr_SetString(py_socket_error, gai_strerror(status)); return NULL; } pyaddr = PyTuple_New(2); if (pyaddr == NULL) { return PyErr_NoMemory(); } PyTuple_SetItem(pyaddr, 0, PyString_FromString(host)); PyTuple_SetItem(pyaddr, 1, PyInt_FromLong(atoi(service))); return pyaddr; } static bool py_socket_tuple_to_addr(PyObject *pyaddr, struct sockaddr *addr, socklen_t *len) { const char *host; char *service; in_port_t port; struct addrinfo *ainfo; int status; if (!PyTuple_Check(pyaddr)) { PyErr_SetString(PyExc_TypeError, "Expected a tuple"); return false; } if (!PyArg_ParseTuple(pyaddr, "sH", &host, &port)) { return false; } service = talloc_asprintf(NULL, "%d", port); if (service == NULL) { PyErr_NoMemory(); return false; } status = getaddrinfo(host, service, NULL, &ainfo); if (status < 0) { talloc_free(service); PyErr_SetString(py_socket_error, gai_strerror(status)); return false; } talloc_free(service); memcpy(addr, ainfo->ai_addr, sizeof(struct sockaddr)); *len = ainfo->ai_addrlen; freeaddrinfo(ainfo); return true; } static PyObject *py_socket_accept(pytalloc_Object *self, PyObject *args) { int *sock, *new_sock; struct sockaddr addr; socklen_t addrlen; PyObject *pysocket; PyObject *pyaddr; PyObject *pyret; sock = pytalloc_get_ptr(self); new_sock = talloc_zero(NULL, int); if (new_sock == NULL) { return PyErr_NoMemory(); } *new_sock = swrap_accept(*sock, &addr, &addrlen); if (*new_sock < 0) { return PyErr_SetFromErrno(py_socket_error); } if ((pysocket = pytalloc_steal(&PySocket, new_sock)) == NULL) { return PyErr_NoMemory(); } pyret = PyTuple_New(2); if (pyret == NULL) { Py_DECREF(pysocket); return PyErr_NoMemory(); } pyaddr = py_socket_addr_to_tuple(&addr, addrlen); if (pyaddr == NULL) { Py_DECREF(pysocket); Py_DECREF(pysocket); return NULL; } PyTuple_SetItem(pyret, 0, pysocket); PyTuple_SetItem(pyret, 1, pyaddr); return pyret; } static PyObject *py_socket_bind(pytalloc_Object *self, PyObject *args) { PyObject *pyaddr; int *sock; int status; struct sockaddr addr; socklen_t addrlen; if (!PyArg_ParseTuple(args, "O:bind", &pyaddr)) { return NULL; } if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_bind(*sock, &addr, addrlen); if (status < 0) { PyErr_SetString(py_socket_error, "Unable to bind"); return NULL; } Py_RETURN_NONE; } static PyObject *py_socket_close(pytalloc_Object *self, PyObject *args) { int *sock; int status; sock = pytalloc_get_ptr(self); status = swrap_close(*sock); if (status < 0) { return PyErr_SetFromErrno(py_socket_error); } Py_RETURN_NONE; } static PyObject *py_socket_connect(pytalloc_Object *self, PyObject *args) { int *sock; PyObject *pyaddr; struct sockaddr addr; socklen_t addrlen; int status; if (!PyArg_ParseTuple(args, "O:connect", &pyaddr)) { return NULL; } if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_connect(*sock, &addr, addrlen); if (status < 0) { PyErr_SetFromErrno(py_socket_error); return NULL; } Py_RETURN_NONE; } static PyObject *py_socket_connect_ex(pytalloc_Object *self, PyObject *args) { int *sock; PyObject *pyaddr; struct sockaddr addr; socklen_t addrlen; int status; if (!PyArg_ParseTuple(args, "O:connect", &pyaddr)) { return NULL; } if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_connect(*sock, &addr, addrlen); if (status < 0) { return Py_BuildValue("%d", errno); } return Py_BuildValue("%d", 0); } static PyObject *py_socket_dup(pytalloc_Object *self, PyObject *args) { int *sock, *new_sock; PyObject *pysocket; sock = pytalloc_get_ptr(self); new_sock = talloc_zero(NULL, int); if (new_sock == NULL) { return PyErr_NoMemory(); } *new_sock = swrap_dup(*sock); if (*new_sock < 0) { return PyErr_SetFromErrno(py_socket_error); } pysocket = pytalloc_steal(&PySocket, new_sock); if (pysocket == NULL) { return PyErr_NoMemory(); } return pysocket; } static PyObject *py_socket_dup2(pytalloc_Object *self, PyObject *args) { int *sock, *new_sock; PyObject *pysocket; int status; if (!PyArg_ParseTuple(args, "O", &pysocket)) { return NULL; } PY_CHECK_TYPE(&PySocket, pysocket, return NULL); sock = pytalloc_get_ptr(self); new_sock = pytalloc_get_ptr(pysocket); status = swrap_dup2(*sock, *new_sock); if (status < 0) { return PyErr_SetFromErrno(py_socket_error); } Py_RETURN_NONE; } static PyObject *py_socket_fileno(pytalloc_Object *self, PyObject *args) { PyErr_SetString(py_socket_error, "Not Supported"); return NULL; } static PyObject *py_socket_getpeername(pytalloc_Object *self, PyObject *args) { int *sock; struct sockaddr addr; socklen_t addrlen; int status; PyObject *pyaddr; sock = pytalloc_get_ptr(self); status = swrap_getpeername(*sock, &addr, &addrlen); if (status < 0) { return PyErr_SetFromErrno(py_socket_error); } pyaddr = py_socket_addr_to_tuple(&addr, addrlen); return pyaddr; } static PyObject *py_socket_getsockname(pytalloc_Object *self, PyObject *args) { int *sock; struct sockaddr addr; socklen_t addrlen; int status; PyObject *pyaddr; sock = pytalloc_get_ptr(self); status = swrap_getsockname(*sock, &addr, &addrlen); if (status < 0) { return PyErr_SetFromErrno(py_socket_error); } pyaddr = py_socket_addr_to_tuple(&addr, addrlen); return pyaddr; } static PyObject *py_socket_getsockopt(pytalloc_Object *self, PyObject *args) { int level, optname; int *sock; socklen_t optlen = 0, newlen; int optval; bool is_integer = false; char *buffer; PyObject *pyret; int status; if (!PyArg_ParseTuple(args, "ii|i:getsockopt", &level, &optname, &optlen)) { return NULL; } if (optlen == 0) { optlen = sizeof(int); is_integer = true; } buffer = talloc_zero_array(NULL, char, optlen); if (buffer == NULL) { return PyErr_NoMemory(); } sock = pytalloc_get_ptr(self); status = swrap_getsockopt(*sock, level, optname, (void *)buffer, &newlen); if (status < 0) { talloc_free(buffer); return PyErr_SetFromErrno(py_socket_error); } if (is_integer) { optval = *(int *)buffer; pyret = PyInt_FromLong(optval); } else { pyret = PyString_FromStringAndSize(buffer, optlen); } talloc_free(buffer); return pyret; } static PyObject *py_socket_gettimeout(pytalloc_Object *self, PyObject *args) { PyErr_SetString(py_socket_error, "Not Supported"); return NULL; } static PyObject *py_socket_listen(pytalloc_Object *self, PyObject *args) { int backlog; int *sock; int status; if (!PyArg_ParseTuple(args, "i:listen", &backlog)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_listen(*sock, backlog); if (status < 0) { return PyErr_SetFromErrno(py_socket_error); } Py_RETURN_NONE; } static PyObject *py_socket_makefile(pytalloc_Object *self, PyObject *args) { PyErr_SetString(py_socket_error, "Not Supported"); return NULL; } static PyObject *py_socket_read(pytalloc_Object *self, PyObject *args) { int bufsize, len; int *sock; char *buffer; PyObject *pyret; if (!PyArg_ParseTuple(args, "i:read", &bufsize)) { return NULL; } buffer = talloc_zero_array(NULL, char, bufsize); if (buffer == NULL) { return PyErr_NoMemory(); } sock = pytalloc_get_ptr(self); len = swrap_read(*sock, buffer, bufsize); if (len < 0) { return PyErr_SetFromErrno(py_socket_error); } pyret = PyString_FromStringAndSize(buffer, len); talloc_free(buffer); return pyret; } static PyObject *py_socket_recv(pytalloc_Object *self, PyObject *args) { int bufsize, flags, len; int *sock; char *buffer; PyObject *pyret; if (!PyArg_ParseTuple(args, "ii:recv", &bufsize, &flags)) { return NULL; } buffer = talloc_zero_array(NULL, char, bufsize); if (buffer == NULL) { return PyErr_NoMemory(); } sock = pytalloc_get_ptr(self); len = swrap_recv(*sock, buffer, bufsize, flags); if (len < 0) { return PyErr_SetFromErrno(py_socket_error); } pyret = PyString_FromStringAndSize(buffer, len); talloc_free(buffer); return pyret; } static PyObject *py_socket_recvfrom(pytalloc_Object *self, PyObject *args) { int bufsize, flags, len; int *sock; char *buffer; struct sockaddr from; socklen_t fromlen; PyObject *pybuf, *pyaddr, *pyret; if (!PyArg_ParseTuple(args, "ii:recvfrom", &bufsize, &flags)) { return NULL; } buffer = talloc_zero_array(NULL, char, bufsize); if (buffer == NULL) { return PyErr_NoMemory(); } sock = pytalloc_get_ptr(self); fromlen = sizeof(struct sockaddr); len = swrap_recvfrom(*sock, buffer, bufsize, flags, &from, &fromlen); if (len < 0) { talloc_free(buffer); return PyErr_SetFromErrno(py_socket_error); } pybuf = PyString_FromStringAndSize(buffer, len); if (pybuf == NULL) { talloc_free(buffer); return PyErr_NoMemory(); } talloc_free(buffer); pyaddr = py_socket_addr_to_tuple(&from, fromlen); if (pyaddr == NULL) { Py_DECREF(pybuf); return NULL; } pyret = PyTuple_New(2); if (pyret == NULL) { Py_DECREF(pybuf); Py_DECREF(pyaddr); return PyErr_NoMemory(); } PyTuple_SetItem(pyret, 0, pybuf); PyTuple_SetItem(pyret, 1, pyaddr); return pyret; } static PyObject *py_socket_send(pytalloc_Object *self, PyObject *args) { char *buffer; int len, flags; int *sock; int status; if (!PyArg_ParseTuple(args, "s#i:sendto", &buffer, &len, &flags)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_send(*sock, buffer, len, flags); if (status < 0) { PyErr_SetFromErrno(py_socket_error); return NULL; } Py_RETURN_NONE; } static PyObject *py_socket_sendall(pytalloc_Object *self, PyObject *args) { char *buffer; int len, flags; int *sock; int status; if (!PyArg_ParseTuple(args, "s#i:sendall", &buffer, &len, &flags)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_send(*sock, buffer, len, flags); if (status < 0) { PyErr_SetFromErrno(py_socket_error); return NULL; } Py_RETURN_NONE; } static PyObject *py_socket_sendto(pytalloc_Object *self, PyObject *args) { PyObject *pyaddr; char *buffer; int len, flags; int *sock; struct sockaddr addr; socklen_t addrlen; int status; if (!PyArg_ParseTuple(args, "s#iO:sendto", &buffer, &len, &flags, &pyaddr)) { return NULL; } if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_sendto(*sock, buffer, len, flags, &addr, addrlen); if (status < 0) { PyErr_SetFromErrno(py_socket_error); return NULL; } Py_RETURN_NONE; } static PyObject *py_socket_setblocking(pytalloc_Object *self, PyObject *args) { PyErr_SetString(py_socket_error, "Not Supported"); return NULL; } static PyObject *py_socket_setsockopt(pytalloc_Object *self, PyObject *args) { int level, optname; int *sock; PyObject *pyval; int optval; Py_ssize_t optlen; char *buffer; int status; if (!PyArg_ParseTuple(args, "iiO:getsockopt", &level, &optname, &pyval)) { return NULL; } if (PyInt_Check(pyval)) { optval = PyInt_AsLong(pyval); buffer = (char *)&optval; optlen = sizeof(int); } else { PyString_AsStringAndSize(pyval, &buffer, &optlen); } sock = pytalloc_get_ptr(self); status = swrap_setsockopt(*sock, level, optname, (void *)buffer, optlen); if (status < 0) { return PyErr_SetFromErrno(py_socket_error); } Py_RETURN_NONE; } static PyObject *py_socket_settimeout(pytalloc_Object *self, PyObject *args) { PyErr_SetString(py_socket_error, "Not Supported"); return NULL; } static PyObject *py_socket_shutdown(pytalloc_Object *self, PyObject *args) { PyErr_SetString(py_socket_error, "Not Supported"); return NULL; } static PyObject *py_socket_write(pytalloc_Object *self, PyObject *args) { char *buffer; int len; int *sock; int status; if (!PyArg_ParseTuple(args, "s#:write", &buffer, &len)) { return NULL; } sock = pytalloc_get_ptr(self); status = swrap_send(*sock, buffer, len, 0); if (status < 0) { PyErr_SetFromErrno(py_socket_error); return NULL; } Py_RETURN_NONE; } static PyMethodDef py_socket_methods[] = { { "accept", (PyCFunction)py_socket_accept, METH_NOARGS, "accept() -> (socket object, address info)\n\n \ Wait for an incoming connection." }, { "bind", (PyCFunction)py_socket_bind, METH_VARARGS, "bind(address)\n\n \ Bind the socket to a local address." }, { "close", (PyCFunction)py_socket_close, METH_NOARGS, "close()\n\n \ Close the socket." }, { "connect", (PyCFunction)py_socket_connect, METH_VARARGS, "connect(address)\n\n \ Connect the socket to a remote address." }, { "connect_ex", (PyCFunction)py_socket_connect_ex, METH_VARARGS, "connect_ex(address)\n\n \ Connect the socket to a remote address." }, { "dup", (PyCFunction)py_socket_dup, METH_VARARGS, "dup() -> socket object\n\n \ Return a new socket object connected to the same system resource." }, { "dup2", (PyCFunction)py_socket_dup2, METH_VARARGS, "dup2(socket object) -> socket object\n\n \ Return a new socket object connected to teh same system resource." }, { "fileno", (PyCFunction)py_socket_fileno, METH_NOARGS, "fileno() -> file descriptor\n\n \ Return socket's file descriptor." }, { "getpeername", (PyCFunction)py_socket_getpeername, METH_NOARGS, "getpeername() -> address info\n\n \ Return the address of the remote endpoint." }, { "getsockname", (PyCFunction)py_socket_getsockname, METH_NOARGS, "getsockname() -> address info\n\n \ Return the address of the local endpoing." }, { "getsockopt", (PyCFunction)py_socket_getsockopt, METH_VARARGS, "getsockopt(level, option[, buffersize]) -> value\n\n \ Get a socket option." }, { "gettimeout", (PyCFunction)py_socket_gettimeout, METH_NOARGS, "gettimeout() -> value\n\n \ Return the timeout in seconds associated with socket operations." }, { "listen", (PyCFunction)py_socket_listen, METH_VARARGS, "listen(backlog)\n\n \ Enable a server to accept connections." }, { "makefile", (PyCFunction)py_socket_makefile, METH_NOARGS, "makefile() -> file object\n\n \ Return a file object associated with the socket." }, { "read", (PyCFunction)py_socket_read, METH_VARARGS, "read(buflen) -> data\n\n \ Receive data." }, { "recv", (PyCFunction)py_socket_recv, METH_VARARGS, "recv(buflen, flags) -> data\n\n \ Receive data." }, { "recvfrom", (PyCFunction)py_socket_recvfrom, METH_VARARGS, "recvfrom(buflen, flags) -> (data, sender address)\n\n \ Receive data and sender's address." }, { "send", (PyCFunction)py_socket_send, METH_VARARGS, "send(data, flags)\n\n \ Send data." }, { "sendall", (PyCFunction)py_socket_sendall, METH_VARARGS, "sendall(data, flags)\n\n \ Send data." }, { "sendto", (PyCFunction)py_socket_sendto, METH_VARARGS, "sendto(data, flags, addr)\n\n \ Send data to a given address." }, { "setblocking", (PyCFunction)py_socket_setblocking, METH_VARARGS, "setblocking(flag)\n\n \ Set blocking or non-blocking mode of the socket." }, { "setsockopt", (PyCFunction)py_socket_setsockopt, METH_VARARGS, "setsockopt(level, option, value)\n\n \ Set a socket option." }, { "settimeout", (PyCFunction)py_socket_settimeout, METH_VARARGS, "settimeout(value)\n\n \ Set a timeout on socket blocking operations." }, { "shutdown", (PyCFunction)py_socket_shutdown, METH_VARARGS, "shutdown(how)\n\n \ Shut down one or both halves of the connection." }, { "write", (PyCFunction)py_socket_write, METH_VARARGS, "write(data)\n\n \ Send data." }, { NULL }, }; static PyObject *py_socket_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { int family, sock_type, protocol; int *sock; PyObject *pysocket; if (!PyArg_ParseTuple(args, "iii:socket", &family, &sock_type, &protocol)) { return NULL; } sock = talloc_zero(NULL, int); if (sock == NULL) { return PyErr_NoMemory(); } *sock = swrap_socket(family, sock_type, protocol); if (*sock < 0) { return PyErr_SetFromErrno(py_socket_error); } if ((pysocket = pytalloc_steal(type, sock)) == NULL) { return PyErr_NoMemory(); } return pysocket; } static PyTypeObject PySocket = { .tp_name = "socket_wrapper.socket", .tp_basicsize = sizeof(pytalloc_Object), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_methods = py_socket_methods, .tp_new = py_socket_new, .tp_doc = "socket(family, type, proto) -> socket object\n\n Open a socket of the give type.", }; static PyObject *py_socket_wrapper_dir(PyObject *self) { const char *dir; dir = socket_wrapper_dir(); return PyString_FromString(dir); } static PyObject *py_socket_wrapper_default_interface(PyObject *self) { unsigned int id; id = socket_wrapper_default_iface(); return PyInt_FromLong(id); } static PyMethodDef py_socket_wrapper_methods[] = { { "dir", (PyCFunction)py_socket_wrapper_dir, METH_NOARGS, "dir() -> path\n\n \ Return socket_wrapper directory." }, { "default_iface", (PyCFunction)py_socket_wrapper_default_interface, METH_NOARGS, "default_iface() -> id\n\n \ Return default interface id." }, { NULL }, }; void initsocket_wrapper(void) { PyObject *m; char exception_name[] = "socket_wrapper.error"; PyTypeObject *talloc_type = pytalloc_GetObjectType(); if (talloc_type == NULL) { return; } PySocket.tp_base = talloc_type; if (PyType_Ready(&PySocket) < 0) { return; } m = Py_InitModule3("socket_wrapper", py_socket_wrapper_methods, "Socket wrapper"); if (m == NULL) { return; } py_socket_error = PyErr_NewException(exception_name, NULL, NULL); Py_INCREF(py_socket_error); PyModule_AddObject(m, "error", py_socket_error); Py_INCREF(&PySocket); PyModule_AddObject(m, "socket", (PyObject *)&PySocket); }