Commit a441f5e3 authored by Tom Niget's avatar Tom Niget

remove c passfd

parent ba619ec3
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
from distutils.core import setup, Extension, Command from distutils.core import setup, Extension, Command
passfd = Extension('_passfd', sources = ['src/passfd/passfd.c'])
setup( setup(
name = 'nemu', name = 'nemu',
version = '0.3.1', version = '0.3.1',
...@@ -18,6 +16,5 @@ setup( ...@@ -18,6 +16,5 @@ setup(
platforms = 'Linux', platforms = 'Linux',
packages = ['nemu'], packages = ['nemu'],
install_requires = ['unshare', 'six'], install_requires = ['unshare', 'six'],
package_dir = {'': 'src'}, package_dir = {'': 'src'}
ext_modules = [passfd]
) )
...@@ -26,7 +26,7 @@ def __check_socket(sock: socket.socket | IOBase): ...@@ -26,7 +26,7 @@ def __check_socket(sock: socket.socket | IOBase):
raise ValueError("Only AF_UNIX sockets are allowed") raise ValueError("Only AF_UNIX sockets are allowed")
if hasattr(sock, 'fileno'): if hasattr(sock, 'fileno'):
sock = socket.socket(fileno=sock.fileno()) sock = socket.fromfd(sock.fileno(), family=socket.AF_UNIX, type=socket.SOCK_STREAM)
if not isinstance(sock, socket.socket): if not isinstance(sock, socket.socket):
raise TypeError("An socket object or file descriptor was expected") raise TypeError("An socket object or file descriptor was expected")
...@@ -45,34 +45,8 @@ def __check_fd(fd): ...@@ -45,34 +45,8 @@ def __check_fd(fd):
def recvfd(sock: socket.socket | IOBase, msg_buf: int = 4096): def recvfd(sock: socket.socket | IOBase, msg_buf: int = 4096):
"""
import _passfd
(ret, msg) = _passfd.recvfd(__check_socket(sock), msg_buf)
# -1 should raise OSError
if ret == -2:
raise RuntimeError("The message received did not contain exactly one" +
" file descriptor")
if ret == -3:
raise RuntimeError("The received file descriptor is not valid")
assert ret >= 0
return (ret, msg)
"""
"""
size = struct.calcsize("@i")
+ with socket.fromfd(conn.fileno(), socket.AF_UNIX, socket.SOCK_STREAM) as s:
+ msg, ancdata, flags, addr = s.recvmsg(1, socket.CMSG_LEN(size))
+ try:
+ cmsg_level, cmsg_type, cmsg_data = ancdata[0]
+ if (cmsg_level == socket.SOL_SOCKET and
+ cmsg_type == socket.SCM_RIGHTS):
+ return struct.unpack("@i", cmsg_data[:size])[0]
+ except (ValueError, IndexError, struct.error):
+ pass
+ raise RuntimeError('Invalid data received')"""
size = struct.calcsize("@i") size = struct.calcsize("@i")
msg, ancdata, flags, addr = __check_socket(sock).recvmsg(4096, socket.CMSG_LEN(size)) msg, ancdata, flags, addr = __check_socket(sock).recvmsg(msg_buf, socket.CMSG_SPACE(size))
cmsg_level, cmsg_type, cmsg_data = ancdata[0] cmsg_level, cmsg_type, cmsg_data = ancdata[0]
if not (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): if not (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS):
raise RuntimeError("The message received did not contain exactly one" + raise RuntimeError("The message received did not contain exactly one" +
...@@ -86,10 +60,6 @@ def recvfd(sock: socket.socket | IOBase, msg_buf: int = 4096): ...@@ -86,10 +60,6 @@ def recvfd(sock: socket.socket | IOBase, msg_buf: int = 4096):
def sendfd(sock: socket.socket | IOBase, fd: int, message: bytes = b"NONE"): def sendfd(sock: socket.socket | IOBase, fd: int, message: bytes = b"NONE"):
"""
import _passfd
return _passfd.sendfd(__check_socket(sock), __check_fd(fd), message)
"""
return __check_socket(sock).sendmsg( return __check_socket(sock).sendmsg(
[message], [message],
[(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack("@i", fd))]) [(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack("@i", fd))])
\ No newline at end of file
#!/usr/bin/env python
# vim: set fileencoding=utf-8
# vim: ts=4:sw=4:et:ai:sts=4
# passfd.py: Python library to pass file descriptors across UNIX domain sockets.
'''This simple extension provides two functions to pass and receive file
descriptors across UNIX domain sockets, using the BSD-4.3+ sendmsg() and
recvmsg() interfaces.
Direct bindings to sendmsg and recvmsg are not provided, as the API does
not map nicely into Python.
Please note that this only supports BSD-4.3+ style file descriptor
passing, and was only tested on Linux. Patches are welcomed!
For more information, see one of the R. Stevens' books:
- Richard Stevens: Unix Network Programming, Prentice Hall, 1990;
chapter 6.10
- Richard Stevens: Advanced Programming in the UNIX Environment,
Addison-Wesley, 1993; chapter 15.3
'''
#
# Please note that this only supports BSD-4.3+ style file descriptor passing,
# and was only tested on Linux. Patches are welcomed!
#
# Copyright © 2010 Martina Ferrari <tina@tina.pm>
#
# Inspired by Socket::PassAccessRights, which is:
# Copyright (c) 2000 Sampo Kellomaki <sampo@iki.fi>
#
# For more information, see one of the R. Stevens' books:
# - Richard Stevens: Unix Network Programming, Prentice Hall, 1990;
# chapter 6.10
#
# - Richard Stevens: Advanced Programming in the UNIX Environment,
# Addison-Wesley, 1993; chapter 15.3
#
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program 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 GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
import socket
def __check_socket(sock):
if hasattr(sock, 'family') and sock.family != socket.AF_UNIX:
raise ValueError("Only AF_UNIX sockets are allowed")
if hasattr(sock, 'fileno'):
sock = sock.fileno()
if not isinstance(sock, int):
raise TypeError("An socket object or file descriptor was expected")
return sock
def __check_fd(fd):
try:
fd = fd.fileno()
except AttributeError:
pass
if not isinstance(fd, int):
raise TypeError("An file object or file descriptor was expected")
return fd
def sendfd(sock, fd, message = "NONE"):
"""Sends a message and piggybacks a file descriptor through a Unix
domain socket.
Note that the file descriptor cannot be sent by itself, at least
one byte of payload needs to be sent also.
Parameters:
sock: socket object or file descriptor for an AF_UNIX socket
fd: file object or file descriptor to pass
message: message to send
Return value:
On success, sendfd returns the number of bytes sent, not including
the file descriptor nor the control data. If there was no message
to send, 0 is returned."""
import _passfd
return _passfd.sendfd(__check_socket(sock), __check_fd(fd), message)
def recvfd(sock, msg_buf = 4096):
"""Receive a message and a file descriptor from a Unix domain socket.
Parameters:
sock: file descriptor or socket object for an AF_UNIX socket
buffersize: maximum message size to receive
Return value:
On success, recvfd returns a tuple containing the received
file descriptor and message. If recvmsg fails, an OSError exception
is raised. If the received data does not carry exactly one file
descriptor, or if the received file descriptor is not valid,
RuntimeError is raised."""
import _passfd
(ret, msg) = _passfd.recvfd(__check_socket(sock), msg_buf)
# -1 should raise OSError
if ret == -2:
raise RuntimeError("The message received did not contain exactly one" +
" file descriptor")
if ret == -3:
raise RuntimeError("The received file descriptor is not valid")
assert ret >= 0
return (ret, msg)
\ No newline at end of file
/* vim:ts=4:sw=4:et:ai:sts=4
*
* passfd.c: Functions to pass file descriptors across UNIX domain sockets.
*
* Please note that this only supports BSD-4.3+ style file descriptor passing,
* and was only tested on Linux. Patches are welcomed!
*
* Copyright © 2010 Martina Ferrari <tina@tina.pm>
*
* Inspired by Socket::PassAccessRights, which is:
* Copyright (c) 2000 Sampo Kellomaki <sampo@iki.fi>
*
* For more information, see one of the R. Stevens' books:
* - Richard Stevens: Unix Network Programming, Prentice Hall, 1990;
* chapter 6.10
*
* - Richard Stevens: Advanced Programming in the UNIX Environment,
* Addison-Wesley, 1993; chapter 15.3
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
int _sendfd(int sock, int fd, size_t len, const void *msg);
int _recvfd(int sock, size_t *len, void *buf);
/* Python wrapper for _sendfd */
static PyObject *
sendfd(PyObject *self, PyObject *args) {
const char *message;
char *buf;
int ret, sock, fd;
Py_ssize_t message_len;
if(!PyArg_ParseTuple(args, "iis#", &sock, &fd, &message, &message_len))
return NULL;
/* I don't know if I need to make a copy of the message buffer for thread
* safety, but let's do it just in case... */
buf = strndup(message, (size_t)message_len);
if(buf == NULL)
return PyErr_SetFromErrno(PyExc_OSError);
Py_BEGIN_ALLOW_THREADS;
ret = _sendfd(sock, fd, message_len, message);
Py_END_ALLOW_THREADS;
free(buf);
if(ret == -1)
return PyErr_SetFromErrno(PyExc_OSError);
return Py_BuildValue("i", ret);
}
/* Python wrapper for _recvfd */
static PyObject *
recvfd(PyObject *self, PyObject *args) {
char *buffer;
int ret, sock;
Py_ssize_t buffersize = 4096;
size_t _buffersize;
PyObject *retval;
if(!PyArg_ParseTuple(args, "i|i", &sock, &buffersize))
return NULL;
if((buffer = malloc(buffersize)) == NULL)
return PyErr_SetFromErrno(PyExc_OSError);
_buffersize = buffersize;
Py_BEGIN_ALLOW_THREADS;
ret = _recvfd(sock, &_buffersize, buffer);
Py_END_ALLOW_THREADS;
buffersize = _buffersize;
if(ret == -1) {
free(buffer);
return PyErr_SetFromErrno(PyExc_OSError);
}
retval = Py_BuildValue("is#", ret, buffer, buffersize);
free(buffer);
return retval;
}
static PyMethodDef methods[] = {
{"sendfd", sendfd, METH_VARARGS, "rv = sendfd(sock, fd, message)"},
{"recvfd", recvfd, METH_VARARGS, "(fd, message) = recvfd(sock, "
"buffersize = 4096)"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef passfdmodule = {
PyModuleDef_HEAD_INIT,
"_passfd", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
methods
};
PyMODINIT_FUNC PyInit__passfd(void) {
return PyModule_Create(&passfdmodule);
}
/* Size of the cmsg including one file descriptor */
#define CMSG_SIZE CMSG_SPACE(sizeof(int))
/*
* _sendfd(): send a message and piggyback a file descriptor.
*
* Note that the file descriptor cannot be sent by itself, at least one byte of
* payload needs to be sent.
*
* Parameters:
* sock: AF_UNIX socket
* fd: file descriptor to pass
* len: length of the message
* msg: the message itself
*
* Return value:
* On success, sendfd returns the number of characters from the message sent,
* the file descriptor information is not taken into account. If there was no
* message to send, 0 is returned. On error, -1 is returned, and errno is set
* appropriately.
*
*/
int _sendfd(int sock, int fd, size_t len, const void *msg) {
struct iovec iov[1];
struct msghdr msgh;
char buf[CMSG_SIZE];
struct cmsghdr *h;
int ret;
/* At least one byte needs to be sent, for some reason (?) */
if(len < 1)
return 0;
memset(&iov[0], 0, sizeof(struct iovec));
memset(&msgh, 0, sizeof(struct msghdr));
memset(buf, 0, CMSG_SIZE);
msgh.msg_name = NULL;
msgh.msg_namelen = 0;
msgh.msg_iov = iov;
msgh.msg_iovlen = 1;
msgh.msg_control = buf;
msgh.msg_controllen = CMSG_SIZE;
msgh.msg_flags = 0;
/* Message to be sent */
iov[0].iov_base = (void *)msg;
iov[0].iov_len = len;
/* Control data */
h = CMSG_FIRSTHDR(&msgh);
h->cmsg_len = CMSG_LEN(sizeof(int));
h->cmsg_level = SOL_SOCKET;
h->cmsg_type = SCM_RIGHTS;
((int *)CMSG_DATA(h))[0] = fd;
ret = sendmsg(sock, &msgh, 0);
return ret;
}
/*
* _recvfd(): receive a message and a file descriptor.
*
* Parameters:
* sock: AF_UNIX socket
* len: pointer to the length of the message buffer, modified on return
* buf: buffer to contain the received buffer
*
* If len is 0 or buf is NULL, the received message is stored in a temporary
* buffer and discarded later.
*
* Return value:
* On success, recvfd returns the received file descriptor, and len points to
* the size of the received message.
* If recvmsg fails, -1 is returned, and errno is set appropriately.
* If the received data does not carry exactly one file descriptor, -2 is
* returned. If the received file descriptor is not valid, -3 is returned.
*
*/
int _recvfd(int sock, size_t *len, void *buf) {
struct iovec iov[1];
struct msghdr msgh;
char cmsgbuf[CMSG_SIZE];
char extrabuf[4096];
struct cmsghdr *h;
int st, fd;
if(*len < 1 || buf == NULL) {
/* For some reason, again, one byte needs to be received. (it would not
* block?) */
iov[0].iov_base = extrabuf;
iov[0].iov_len = sizeof(extrabuf);
} else {
iov[0].iov_base = buf;
iov[0].iov_len = *len;
}
msgh.msg_name = NULL;
msgh.msg_namelen = 0;
msgh.msg_iov = iov;
msgh.msg_iovlen = 1;
msgh.msg_control = cmsgbuf;
msgh.msg_controllen = CMSG_SIZE;
msgh.msg_flags = 0;
st = recvmsg(sock, &msgh, 0);
if(st < 0)
return -1;
*len = st;
h = CMSG_FIRSTHDR(&msgh);
/* Check if we received what we expected */
if(h == NULL
|| h->cmsg_len != CMSG_LEN(sizeof(int))
|| h->cmsg_level != SOL_SOCKET
|| h->cmsg_type != SCM_RIGHTS) {
return -2;
}
fd = ((int *)CMSG_DATA(h))[0];
if(fd < 0)
return -3;
return fd;
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment