2 * Copyright (C) Amitay Isaacs 2011
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the author nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 Python interface to socket wrapper library.
38 Passes all socket communication over unix domain sockets if the environment
39 variable SOCKET_WRAPPER_DIR is set.
44 #include "replace/replace.h"
45 #include "system/network.h"
46 #include "socket_wrapper.h"
48 #ifndef Py_RETURN_NONE
49 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
52 #ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */
53 #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
57 #define PY_CHECK_TYPE(type, var, fail) \
58 if (!PyObject_TypeCheck(var, type)) {\
59 PyErr_Format(PyExc_TypeError, __location__ ": Expected type '%s' for '%s' of type '%s'", (type)->tp_name, #var, Py_TYPE(var)->tp_name); \
64 staticforward PyTypeObject PySocket;
66 static PyObject *py_socket_error;
68 void initsocket_wrapper(void);
70 static PyObject *py_socket_addr_to_tuple(struct sockaddr *addr, socklen_t len)
77 status = getnameinfo(addr, len, host, 255, service, 7, NI_NUMERICHOST|NI_NUMERICSERV);
79 PyErr_SetString(py_socket_error, gai_strerror(status));
83 pyaddr = PyTuple_New(2);
85 return PyErr_NoMemory();
88 PyTuple_SetItem(pyaddr, 0, PyString_FromString(host));
89 PyTuple_SetItem(pyaddr, 1, PyInt_FromLong(atoi(service)));
94 static bool py_socket_tuple_to_addr(PyObject *pyaddr, struct sockaddr *addr, socklen_t *len)
99 struct addrinfo *ainfo;
102 if (!PyTuple_Check(pyaddr)) {
103 PyErr_SetString(PyExc_TypeError, "Expected a tuple");
107 if (!PyArg_ParseTuple(pyaddr, "sH", &host, &port)) {
111 service = talloc_asprintf(NULL, "%d", port);
112 if (service == NULL) {
117 status = getaddrinfo(host, service, NULL, &ainfo);
119 talloc_free(service);
120 PyErr_SetString(py_socket_error, gai_strerror(status));
124 talloc_free(service);
126 memcpy(addr, ainfo->ai_addr, sizeof(struct sockaddr));
127 *len = ainfo->ai_addrlen;
134 static PyObject *py_socket_accept(pytalloc_Object *self, PyObject *args)
136 int *sock, *new_sock;
137 struct sockaddr addr;
143 sock = pytalloc_get_ptr(self);
145 new_sock = talloc_zero(NULL, int);
146 if (new_sock == NULL) {
147 return PyErr_NoMemory();
150 *new_sock = swrap_accept(*sock, &addr, &addrlen);
152 return PyErr_SetFromErrno(py_socket_error);
155 if ((pysocket = pytalloc_steal(&PySocket, new_sock)) == NULL) {
156 return PyErr_NoMemory();
159 pyret = PyTuple_New(2);
162 return PyErr_NoMemory();
165 pyaddr = py_socket_addr_to_tuple(&addr, addrlen);
166 if (pyaddr == NULL) {
172 PyTuple_SetItem(pyret, 0, pysocket);
173 PyTuple_SetItem(pyret, 1, pyaddr);
177 static PyObject *py_socket_bind(pytalloc_Object *self, PyObject *args)
182 struct sockaddr addr;
185 if (!PyArg_ParseTuple(args, "O:bind", &pyaddr)) {
189 if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
193 sock = pytalloc_get_ptr(self);
195 status = swrap_bind(*sock, &addr, addrlen);
197 PyErr_SetString(py_socket_error, "Unable to bind");
204 static PyObject *py_socket_close(pytalloc_Object *self, PyObject *args)
209 sock = pytalloc_get_ptr(self);
211 status = swrap_close(*sock);
213 return PyErr_SetFromErrno(py_socket_error);
219 static PyObject *py_socket_connect(pytalloc_Object *self, PyObject *args)
223 struct sockaddr addr;
227 if (!PyArg_ParseTuple(args, "O:connect", &pyaddr)) {
231 if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
235 sock = pytalloc_get_ptr(self);
237 status = swrap_connect(*sock, &addr, addrlen);
239 PyErr_SetFromErrno(py_socket_error);
246 static PyObject *py_socket_connect_ex(pytalloc_Object *self, PyObject *args)
250 struct sockaddr addr;
254 if (!PyArg_ParseTuple(args, "O:connect", &pyaddr)) {
258 if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
262 sock = pytalloc_get_ptr(self);
264 status = swrap_connect(*sock, &addr, addrlen);
266 return Py_BuildValue("%d", errno);
269 return Py_BuildValue("%d", 0);
272 static PyObject *py_socket_dup(pytalloc_Object *self, PyObject *args)
274 int *sock, *new_sock;
277 sock = pytalloc_get_ptr(self);
279 new_sock = talloc_zero(NULL, int);
280 if (new_sock == NULL) {
281 return PyErr_NoMemory();
284 *new_sock = swrap_dup(*sock);
286 return PyErr_SetFromErrno(py_socket_error);
289 pysocket = pytalloc_steal(&PySocket, new_sock);
290 if (pysocket == NULL) {
291 return PyErr_NoMemory();
297 static PyObject *py_socket_dup2(pytalloc_Object *self, PyObject *args)
299 int *sock, *new_sock;
303 if (!PyArg_ParseTuple(args, "O", &pysocket)) {
307 PY_CHECK_TYPE(&PySocket, pysocket, return NULL);
309 sock = pytalloc_get_ptr(self);
310 new_sock = pytalloc_get_ptr(pysocket);
312 status = swrap_dup2(*sock, *new_sock);
314 return PyErr_SetFromErrno(py_socket_error);
320 static PyObject *py_socket_fileno(pytalloc_Object *self, PyObject *args)
322 PyErr_SetString(py_socket_error, "Not Supported");
326 static PyObject *py_socket_getpeername(pytalloc_Object *self, PyObject *args)
329 struct sockaddr addr;
334 sock = pytalloc_get_ptr(self);
336 status = swrap_getpeername(*sock, &addr, &addrlen);
338 return PyErr_SetFromErrno(py_socket_error);
341 pyaddr = py_socket_addr_to_tuple(&addr, addrlen);
346 static PyObject *py_socket_getsockname(pytalloc_Object *self, PyObject *args)
349 struct sockaddr addr;
354 sock = pytalloc_get_ptr(self);
356 status = swrap_getsockname(*sock, &addr, &addrlen);
358 return PyErr_SetFromErrno(py_socket_error);
361 pyaddr = py_socket_addr_to_tuple(&addr, addrlen);
366 static PyObject *py_socket_getsockopt(pytalloc_Object *self, PyObject *args)
370 socklen_t optlen = -1, newlen;
372 bool is_integer = false;
377 if (!PyArg_ParseTuple(args, "ii|i:getsockopt", &level, &optname, &optlen)) {
382 optlen = sizeof(int);
386 buffer = talloc_zero_array(NULL, char, optlen);
387 if (buffer == NULL) {
388 return PyErr_NoMemory();
391 sock = pytalloc_get_ptr(self);
393 status = swrap_getsockopt(*sock, level, optname, (void *)buffer, &newlen);
396 return PyErr_SetFromErrno(py_socket_error);
400 optval = *(int *)buffer;
401 pyret = PyInt_FromLong(optval);
403 pyret = PyString_FromStringAndSize(buffer, optlen);
411 static PyObject *py_socket_gettimeout(pytalloc_Object *self, PyObject *args)
413 PyErr_SetString(py_socket_error, "Not Supported");
417 static PyObject *py_socket_listen(pytalloc_Object *self, PyObject *args)
423 if (!PyArg_ParseTuple(args, "i:listen", &backlog)) {
427 sock = pytalloc_get_ptr(self);
429 status = swrap_listen(*sock, backlog);
431 return PyErr_SetFromErrno(py_socket_error);
437 static PyObject *py_socket_makefile(pytalloc_Object *self, PyObject *args)
439 PyErr_SetString(py_socket_error, "Not Supported");
443 static PyObject *py_socket_read(pytalloc_Object *self, PyObject *args)
450 if (!PyArg_ParseTuple(args, "i:read", &bufsize)) {
454 buffer = talloc_zero_array(NULL, char, bufsize);
455 if (buffer == NULL) {
456 return PyErr_NoMemory();
459 sock = pytalloc_get_ptr(self);
461 len = swrap_read(*sock, buffer, bufsize);
463 return PyErr_SetFromErrno(py_socket_error);
466 pyret = PyString_FromStringAndSize(buffer, len);
473 static PyObject *py_socket_recv(pytalloc_Object *self, PyObject *args)
475 int bufsize, flags, len;
480 if (!PyArg_ParseTuple(args, "ii:recv", &bufsize, &flags)) {
484 buffer = talloc_zero_array(NULL, char, bufsize);
485 if (buffer == NULL) {
486 return PyErr_NoMemory();
489 sock = pytalloc_get_ptr(self);
491 len = swrap_recv(*sock, buffer, bufsize, flags);
493 return PyErr_SetFromErrno(py_socket_error);
496 pyret = PyString_FromStringAndSize(buffer, len);
503 static PyObject *py_socket_recvfrom(pytalloc_Object *self, PyObject *args)
505 int bufsize, flags, len;
508 struct sockaddr from;
510 PyObject *pybuf, *pyaddr, *pyret;
512 if (!PyArg_ParseTuple(args, "ii:recvfrom", &bufsize, &flags)) {
516 buffer = talloc_zero_array(NULL, char, bufsize);
517 if (buffer == NULL) {
518 return PyErr_NoMemory();
521 sock = pytalloc_get_ptr(self);
523 fromlen = sizeof(struct sockaddr);
525 len = swrap_recvfrom(*sock, buffer, bufsize, flags, &from, &fromlen);
528 return PyErr_SetFromErrno(py_socket_error);
531 pybuf = PyString_FromStringAndSize(buffer, len);
534 return PyErr_NoMemory();
539 pyaddr = py_socket_addr_to_tuple(&from, fromlen);
540 if (pyaddr == NULL) {
545 pyret = PyTuple_New(2);
549 return PyErr_NoMemory();
552 PyTuple_SetItem(pyret, 0, pybuf);
553 PyTuple_SetItem(pyret, 1, pyaddr);
558 static PyObject *py_socket_send(pytalloc_Object *self, PyObject *args)
565 if (!PyArg_ParseTuple(args, "s#i:sendto", &buffer, &len, &flags)) {
569 sock = pytalloc_get_ptr(self);
571 status = swrap_send(*sock, buffer, len, flags);
573 PyErr_SetFromErrno(py_socket_error);
580 static PyObject *py_socket_sendall(pytalloc_Object *self, PyObject *args)
587 if (!PyArg_ParseTuple(args, "s#i:sendall", &buffer, &len, &flags)) {
591 sock = pytalloc_get_ptr(self);
593 status = swrap_send(*sock, buffer, len, flags);
595 PyErr_SetFromErrno(py_socket_error);
602 static PyObject *py_socket_sendto(pytalloc_Object *self, PyObject *args)
608 struct sockaddr addr;
612 if (!PyArg_ParseTuple(args, "s#iO:sendto", &buffer, &len, &flags, &pyaddr)) {
616 if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
620 sock = pytalloc_get_ptr(self);
622 status = swrap_sendto(*sock, buffer, len, flags, &addr, addrlen);
624 PyErr_SetFromErrno(py_socket_error);
631 static PyObject *py_socket_setblocking(pytalloc_Object *self, PyObject *args)
633 PyErr_SetString(py_socket_error, "Not Supported");
637 static PyObject *py_socket_setsockopt(pytalloc_Object *self, PyObject *args)
647 if (!PyArg_ParseTuple(args, "iiO:getsockopt", &level, &optname, &pyval)) {
651 if (PyInt_Check(pyval)) {
652 optval = PyInt_AsLong(pyval);
653 buffer = (char *)&optval;
654 optlen = sizeof(int);
656 PyString_AsStringAndSize(pyval, &buffer, &optlen);
659 sock = pytalloc_get_ptr(self);
661 status = swrap_setsockopt(*sock, level, optname, (void *)buffer, optlen);
663 return PyErr_SetFromErrno(py_socket_error);
669 static PyObject *py_socket_settimeout(pytalloc_Object *self, PyObject *args)
671 PyErr_SetString(py_socket_error, "Not Supported");
675 static PyObject *py_socket_shutdown(pytalloc_Object *self, PyObject *args)
677 PyErr_SetString(py_socket_error, "Not Supported");
681 static PyObject *py_socket_write(pytalloc_Object *self, PyObject *args)
688 if (!PyArg_ParseTuple(args, "s#:write", &buffer, &len)) {
692 sock = pytalloc_get_ptr(self);
694 status = swrap_send(*sock, buffer, len, 0);
696 PyErr_SetFromErrno(py_socket_error);
704 static PyMethodDef py_socket_methods[] = {
705 { "accept", (PyCFunction)py_socket_accept, METH_NOARGS,
706 "accept() -> (socket object, address info)\n\n \
707 Wait for an incoming connection." },
708 { "bind", (PyCFunction)py_socket_bind, METH_VARARGS,
710 Bind the socket to a local address." },
711 { "close", (PyCFunction)py_socket_close, METH_NOARGS,
713 Close the socket." },
714 { "connect", (PyCFunction)py_socket_connect, METH_VARARGS,
715 "connect(address)\n\n \
716 Connect the socket to a remote address." },
717 { "connect_ex", (PyCFunction)py_socket_connect_ex, METH_VARARGS,
718 "connect_ex(address)\n\n \
719 Connect the socket to a remote address." },
720 { "dup", (PyCFunction)py_socket_dup, METH_VARARGS,
721 "dup() -> socket object\n\n \
722 Return a new socket object connected to the same system resource." },
723 { "dup2", (PyCFunction)py_socket_dup2, METH_VARARGS,
724 "dup2(socket object) -> socket object\n\n \
725 Return a new socket object connected to teh same system resource." },
726 { "fileno", (PyCFunction)py_socket_fileno, METH_NOARGS,
727 "fileno() -> file descriptor\n\n \
728 Return socket's file descriptor." },
729 { "getpeername", (PyCFunction)py_socket_getpeername, METH_NOARGS,
730 "getpeername() -> address info\n\n \
731 Return the address of the remote endpoint." },
732 { "getsockname", (PyCFunction)py_socket_getsockname, METH_NOARGS,
733 "getsockname() -> address info\n\n \
734 Return the address of the local endpoing." },
735 { "getsockopt", (PyCFunction)py_socket_getsockopt, METH_VARARGS,
736 "getsockopt(level, option[, buffersize]) -> value\n\n \
737 Get a socket option." },
738 { "gettimeout", (PyCFunction)py_socket_gettimeout, METH_NOARGS,
739 "gettimeout() -> value\n\n \
740 Return the timeout in seconds associated with socket operations." },
741 { "listen", (PyCFunction)py_socket_listen, METH_VARARGS,
742 "listen(backlog)\n\n \
743 Enable a server to accept connections." },
744 { "makefile", (PyCFunction)py_socket_makefile, METH_NOARGS,
745 "makefile() -> file object\n\n \
746 Return a file object associated with the socket." },
747 { "read", (PyCFunction)py_socket_read, METH_VARARGS,
748 "read(buflen) -> data\n\n \
750 { "recv", (PyCFunction)py_socket_recv, METH_VARARGS,
751 "recv(buflen, flags) -> data\n\n \
753 { "recvfrom", (PyCFunction)py_socket_recvfrom, METH_VARARGS,
754 "recvfrom(buflen, flags) -> (data, sender address)\n\n \
755 Receive data and sender's address." },
756 { "send", (PyCFunction)py_socket_send, METH_VARARGS,
757 "send(data, flags)\n\n \
759 { "sendall", (PyCFunction)py_socket_sendall, METH_VARARGS,
760 "sendall(data, flags)\n\n \
762 { "sendto", (PyCFunction)py_socket_sendto, METH_VARARGS,
763 "sendto(data, flags, addr)\n\n \
764 Send data to a given address." },
765 { "setblocking", (PyCFunction)py_socket_setblocking, METH_VARARGS,
766 "setblocking(flag)\n\n \
767 Set blocking or non-blocking mode of the socket." },
768 { "setsockopt", (PyCFunction)py_socket_setsockopt, METH_VARARGS,
769 "setsockopt(level, option, value)\n\n \
770 Set a socket option." },
771 { "settimeout", (PyCFunction)py_socket_settimeout, METH_VARARGS,
772 "settimeout(value)\n\n \
773 Set a timeout on socket blocking operations." },
774 { "shutdown", (PyCFunction)py_socket_shutdown, METH_VARARGS,
776 Shut down one or both halves of the connection." },
777 { "write", (PyCFunction)py_socket_write, METH_VARARGS,
784 static PyObject *py_socket_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
786 int family, sock_type, protocol;
790 if (!PyArg_ParseTuple(args, "iii:socket", &family, &sock_type, &protocol)) {
794 sock = talloc_zero(NULL, int);
796 return PyErr_NoMemory();
799 *sock = swrap_socket(family, sock_type, protocol);
801 return PyErr_SetFromErrno(py_socket_error);
804 if ((pysocket = pytalloc_steal(type, sock)) == NULL) {
805 return PyErr_NoMemory();
812 static PyTypeObject PySocket = {
813 .tp_name = "socket_wrapper.socket",
814 .tp_basicsize = sizeof(pytalloc_Object),
815 .tp_flags = Py_TPFLAGS_DEFAULT,
816 .tp_methods = py_socket_methods,
817 .tp_new = py_socket_new,
818 .tp_doc = "socket(family, type, proto) -> socket object\n\n Open a socket of the give type.",
821 static PyObject *py_socket_wrapper_dir(PyObject *self)
825 dir = socket_wrapper_dir();
827 return PyString_FromString(dir);
830 static PyObject *py_socket_wrapper_default_interface(PyObject *self)
834 id = socket_wrapper_default_iface();
836 return PyInt_FromLong(id);
840 static PyMethodDef py_socket_wrapper_methods[] = {
841 { "dir", (PyCFunction)py_socket_wrapper_dir, METH_NOARGS,
843 Return socket_wrapper directory." },
844 { "default_iface", (PyCFunction)py_socket_wrapper_default_interface, METH_NOARGS,
845 "default_iface() -> id\n\n \
846 Return default interface id." },
850 void initsocket_wrapper(void)
853 char exception_name[] = "socket_wrapper.error";
855 PyTypeObject *talloc_type = pytalloc_GetObjectType();
856 if (talloc_type == NULL) {
860 PySocket.tp_base = talloc_type;
861 if (PyType_Ready(&PySocket) < 0) {
865 m = Py_InitModule3("socket_wrapper", py_socket_wrapper_methods, "Socket wrapper");
870 py_socket_error = PyErr_NewException(exception_name, NULL, NULL);
871 Py_INCREF(py_socket_error);
872 PyModule_AddObject(m, "error", py_socket_error);
874 Py_INCREF(&PySocket);
875 PyModule_AddObject(m, "socket", (PyObject *)&PySocket);