mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
1359 lines
41 KiB
C
1359 lines
41 KiB
C
/******************************************************************************
|
|
* utils.c
|
|
*
|
|
* Copyright (c) 2004, K A Fraser
|
|
*/
|
|
|
|
#include <Python.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/poll.h>
|
|
#include <netinet/in.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <xc.h>
|
|
|
|
#include <hypervisor-if.h>
|
|
#include "domain_controller.h"
|
|
|
|
#include <asm-xen/proc_cmd.h>
|
|
|
|
/* Needed for Python versions earlier than 2.3. */
|
|
#ifndef PyMODINIT_FUNC
|
|
#define PyMODINIT_FUNC DL_EXPORT(void)
|
|
#endif
|
|
|
|
/* NB. The following should be kept in sync with the kernel's evtchn driver. */
|
|
#define EVTCHN_DEV_NAME "/dev/xen/evtchn"
|
|
#define EVTCHN_DEV_MAJOR 10
|
|
#define EVTCHN_DEV_MINOR 200
|
|
#define PORT_NORMAL 0x0000 /* A standard event notification. */
|
|
#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */
|
|
#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */
|
|
/* /dev/xen/evtchn ioctls: */
|
|
/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
|
|
#define EVTCHN_RESET _IO('E', 1)
|
|
/* EVTCHN_BIND: Bind to teh specified event-channel port. */
|
|
#define EVTCHN_BIND _IO('E', 2)
|
|
/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
|
|
#define EVTCHN_UNBIND _IO('E', 3)
|
|
|
|
/* Size of a machine page frame. */
|
|
#define PAGE_SIZE 4096
|
|
|
|
|
|
/*
|
|
* *********************** NOTIFIER ***********************
|
|
*/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD;
|
|
int evtchn_fd;
|
|
} xu_notifier_object;
|
|
|
|
static PyObject *xu_notifier_read(PyObject *self, PyObject *args)
|
|
{
|
|
xu_notifier_object *xun = (xu_notifier_object *)self;
|
|
u16 v;
|
|
int bytes;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 )
|
|
{
|
|
if ( errno == EINTR )
|
|
continue;
|
|
if ( errno == EAGAIN )
|
|
goto none;
|
|
return PyErr_SetFromErrno(PyExc_IOError);
|
|
}
|
|
|
|
if ( bytes == sizeof(v) )
|
|
return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK);
|
|
|
|
none:
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
|
|
{
|
|
xu_notifier_object *xun = (xu_notifier_object *)self;
|
|
u16 v;
|
|
int idx;
|
|
|
|
if ( !PyArg_ParseTuple(args, "i", &idx) )
|
|
return NULL;
|
|
|
|
v = (u16)idx;
|
|
|
|
(void)write(xun->evtchn_fd, &v, sizeof(v));
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
|
|
{
|
|
xu_notifier_object *xun = (xu_notifier_object *)self;
|
|
int idx;
|
|
|
|
if ( !PyArg_ParseTuple(args, "i", &idx) )
|
|
return NULL;
|
|
|
|
if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 )
|
|
return PyErr_SetFromErrno(PyExc_IOError);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
|
|
{
|
|
xu_notifier_object *xun = (xu_notifier_object *)self;
|
|
int idx;
|
|
|
|
if ( !PyArg_ParseTuple(args, "i", &idx) )
|
|
return NULL;
|
|
|
|
if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
|
|
return PyErr_SetFromErrno(PyExc_IOError);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
|
|
{
|
|
xu_notifier_object *xun = (xu_notifier_object *)self;
|
|
return PyInt_FromLong(xun->evtchn_fd);
|
|
}
|
|
|
|
static PyMethodDef xu_notifier_methods[] = {
|
|
{ "read",
|
|
(PyCFunction)xu_notifier_read,
|
|
METH_VARARGS,
|
|
"Read a (@port, @type) pair.\n" },
|
|
|
|
{ "unmask",
|
|
(PyCFunction)xu_notifier_unmask,
|
|
METH_VARARGS,
|
|
"Unmask notifications for a @port.\n" },
|
|
|
|
{ "bind",
|
|
(PyCFunction)xu_notifier_bind,
|
|
METH_VARARGS,
|
|
"Get notifications for a @port.\n" },
|
|
|
|
{ "unbind",
|
|
(PyCFunction)xu_notifier_unbind,
|
|
METH_VARARGS,
|
|
"No longer get notifications for a @port.\n" },
|
|
|
|
{ "fileno",
|
|
(PyCFunction)xu_notifier_fileno,
|
|
METH_VARARGS,
|
|
"Return the file descriptor for the notification channel.\n" },
|
|
|
|
{ NULL, NULL, 0, NULL }
|
|
};
|
|
|
|
staticforward PyTypeObject xu_notifier_type;
|
|
|
|
static PyObject *xu_notifier_new(PyObject *self, PyObject *args)
|
|
{
|
|
xu_notifier_object *xun;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
xun = PyObject_New(xu_notifier_object, &xu_notifier_type);
|
|
|
|
reopen:
|
|
xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
|
|
if ( xun->evtchn_fd == -1 )
|
|
{
|
|
if ( (errno == ENOENT) &&
|
|
((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
|
|
(mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
|
|
(EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) )
|
|
goto reopen;
|
|
PyObject_Del((PyObject *)xun);
|
|
return PyErr_SetFromErrno(PyExc_IOError);
|
|
}
|
|
|
|
return (PyObject *)xun;
|
|
}
|
|
|
|
static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
|
|
{
|
|
if ( strcmp(name, "EXCEPTION") == 0 )
|
|
return PyInt_FromLong(PORT_EXCEPTION);
|
|
if ( strcmp(name, "NORMAL") == 0 )
|
|
return PyInt_FromLong(PORT_NORMAL);
|
|
return Py_FindMethod(xu_notifier_methods, obj, name);
|
|
}
|
|
|
|
static void xu_notifier_dealloc(PyObject *self)
|
|
{
|
|
xu_notifier_object *xun = (xu_notifier_object *)self;
|
|
(void)close(xun->evtchn_fd);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyTypeObject xu_notifier_type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0,
|
|
"notifier",
|
|
sizeof(xu_notifier_object),
|
|
0,
|
|
xu_notifier_dealloc, /* tp_dealloc */
|
|
NULL, /* tp_print */
|
|
xu_notifier_getattr, /* tp_getattr */
|
|
NULL, /* tp_setattr */
|
|
NULL, /* tp_compare */
|
|
NULL, /* tp_repr */
|
|
NULL, /* tp_as_number */
|
|
NULL, /* tp_as_sequence */
|
|
NULL, /* tp_as_mapping */
|
|
NULL /* tp_hash */
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* *********************** MESSAGE ***********************
|
|
*/
|
|
|
|
#define TYPE(_x,_y) (((_x)<<8)|(_y))
|
|
#define P2C(_struct, _field, _ctype) \
|
|
do { \
|
|
PyObject *obj; \
|
|
if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \
|
|
{ \
|
|
if ( PyInt_Check(obj) ) \
|
|
{ \
|
|
((_struct *)&xum->msg.msg[0])->_field = \
|
|
(_ctype)PyInt_AsLong(obj); \
|
|
dict_items_parsed++; \
|
|
} \
|
|
else if ( PyLong_Check(obj) ) \
|
|
{ \
|
|
((_struct *)&xum->msg.msg[0])->_field = \
|
|
(_ctype)PyLong_AsUnsignedLongLong(obj); \
|
|
dict_items_parsed++; \
|
|
} \
|
|
} \
|
|
xum->msg.length = sizeof(_struct); \
|
|
} while ( 0 )
|
|
#define C2P(_struct, _field, _pytype, _ctype) \
|
|
do { \
|
|
PyObject *obj = Py ## _pytype ## _From ## _ctype \
|
|
(((_struct *)&xum->msg.msg[0])->_field); \
|
|
if ( dict == NULL ) dict = PyDict_New(); \
|
|
PyDict_SetItemString(dict, #_field, obj); \
|
|
} while ( 0 )
|
|
|
|
typedef struct {
|
|
PyObject_HEAD;
|
|
control_msg_t msg;
|
|
} xu_message_object;
|
|
|
|
static PyObject *xu_message_append_payload(PyObject *self, PyObject *args)
|
|
{
|
|
xu_message_object *xum = (xu_message_object *)self;
|
|
char *str;
|
|
int len;
|
|
|
|
if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
|
|
return NULL;
|
|
|
|
if ( (len + xum->msg.length) > sizeof(xum->msg.msg) )
|
|
{
|
|
PyErr_SetString(PyExc_RuntimeError, "out of space in control message");
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&xum->msg.msg[xum->msg.length], str, len);
|
|
xum->msg.length += len;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args)
|
|
{
|
|
xu_message_object *xum = (xu_message_object *)self;
|
|
PyObject *payload;
|
|
int dict_items_parsed = 0;
|
|
|
|
if ( !PyArg_ParseTuple(args, "O", &payload) )
|
|
return NULL;
|
|
|
|
if ( !PyDict_Check(payload) )
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "payload is not a dictionary");
|
|
return NULL;
|
|
}
|
|
|
|
switch ( TYPE(xum->msg.type, xum->msg.subtype) )
|
|
{
|
|
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
|
|
P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32);
|
|
break;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
|
|
P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
|
|
break;
|
|
}
|
|
|
|
if ( dict_items_parsed != PyDict_Size(payload) )
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "payload contains bad items");
|
|
return NULL;
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_message_get_payload(PyObject *self, PyObject *args)
|
|
{
|
|
xu_message_object *xum = (xu_message_object *)self;
|
|
PyObject *dict = NULL;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
switch ( TYPE(xum->msg.type, xum->msg.subtype) )
|
|
{
|
|
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED):
|
|
C2P(blkif_fe_interface_status_changed_t, handle, Int, Long);
|
|
C2P(blkif_fe_interface_status_changed_t, status, Int, Long);
|
|
C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
|
|
C2P(blkif_fe_driver_status_changed_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT):
|
|
C2P(blkif_fe_interface_connect_t, handle, Int, Long);
|
|
C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT):
|
|
C2P(blkif_fe_interface_disconnect_t, handle, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE):
|
|
C2P(blkif_be_create_t, domid, Int, Long);
|
|
C2P(blkif_be_create_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_create_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY):
|
|
C2P(blkif_be_destroy_t, domid, Int, Long);
|
|
C2P(blkif_be_destroy_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_destroy_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
|
|
C2P(blkif_be_connect_t, domid, Int, Long);
|
|
C2P(blkif_be_connect_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_connect_t, shmem_frame, Int, Long);
|
|
C2P(blkif_be_connect_t, evtchn, Int, Long);
|
|
C2P(blkif_be_connect_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT):
|
|
C2P(blkif_be_disconnect_t, domid, Int, Long);
|
|
C2P(blkif_be_disconnect_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_disconnect_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE):
|
|
C2P(blkif_be_vbd_create_t, domid, Int, Long);
|
|
C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_vbd_create_t, vdevice, Int, Long);
|
|
C2P(blkif_be_vbd_create_t, readonly, Int, Long);
|
|
C2P(blkif_be_vbd_create_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY):
|
|
C2P(blkif_be_vbd_destroy_t, domid, Int, Long);
|
|
C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long);
|
|
C2P(blkif_be_vbd_destroy_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW):
|
|
C2P(blkif_be_vbd_grow_t, domid, Int, Long);
|
|
C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_vbd_grow_t, vdevice, Int, Long);
|
|
C2P(blkif_be_vbd_grow_t, extent.sector_start,
|
|
Long, UnsignedLongLong);
|
|
C2P(blkif_be_vbd_grow_t, extent.sector_length,
|
|
Long, UnsignedLongLong);
|
|
C2P(blkif_be_vbd_grow_t, extent.device, Int, Long);
|
|
C2P(blkif_be_vbd_grow_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK):
|
|
C2P(blkif_be_vbd_shrink_t, domid, Int, Long);
|
|
C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long);
|
|
C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long);
|
|
C2P(blkif_be_vbd_shrink_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED):
|
|
C2P(blkif_be_driver_status_changed_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED):
|
|
C2P(netif_fe_interface_status_changed_t, handle, Int, Long);
|
|
C2P(netif_fe_interface_status_changed_t, status, Int, Long);
|
|
C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
|
|
C2P(netif_fe_driver_status_changed_t, status, Int, Long);
|
|
C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT):
|
|
C2P(netif_fe_interface_connect_t, handle, Int, Long);
|
|
C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long);
|
|
C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT):
|
|
C2P(netif_fe_interface_disconnect_t, handle, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE):
|
|
C2P(netif_be_create_t, domid, Int, Long);
|
|
C2P(netif_be_create_t, netif_handle, Int, Long);
|
|
C2P(netif_be_create_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
|
|
C2P(netif_be_destroy_t, domid, Int, Long);
|
|
C2P(netif_be_destroy_t, netif_handle, Int, Long);
|
|
C2P(netif_be_destroy_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
|
|
C2P(netif_be_connect_t, domid, Int, Long);
|
|
C2P(netif_be_connect_t, netif_handle, Int, Long);
|
|
C2P(netif_be_connect_t, tx_shmem_frame, Int, Long);
|
|
C2P(netif_be_connect_t, rx_shmem_frame, Int, Long);
|
|
C2P(netif_be_connect_t, evtchn, Int, Long);
|
|
C2P(netif_be_connect_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT):
|
|
C2P(netif_be_disconnect_t, domid, Int, Long);
|
|
C2P(netif_be_disconnect_t, netif_handle, Int, Long);
|
|
C2P(netif_be_disconnect_t, status, Int, Long);
|
|
return dict;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED):
|
|
C2P(netif_be_driver_status_changed_t, status, Int, Long);
|
|
return dict;
|
|
}
|
|
|
|
return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length);
|
|
}
|
|
|
|
static PyObject *xu_message_get_header(PyObject *self, PyObject *args)
|
|
{
|
|
xu_message_object *xum = (xu_message_object *)self;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
return Py_BuildValue("{s:i,s:i,s:i}",
|
|
"type", xum->msg.type,
|
|
"subtype", xum->msg.subtype,
|
|
"id", xum->msg.id);
|
|
}
|
|
|
|
static PyMethodDef xu_message_methods[] = {
|
|
{ "append_payload",
|
|
(PyCFunction)xu_message_append_payload,
|
|
METH_VARARGS,
|
|
"Append @str to the message payload.\n" },
|
|
|
|
{ "set_response_fields",
|
|
(PyCFunction)xu_message_set_response_fields,
|
|
METH_VARARGS,
|
|
"Fill in the response fields in a message that was passed to us.\n" },
|
|
|
|
{ "get_payload",
|
|
(PyCFunction)xu_message_get_payload,
|
|
METH_VARARGS,
|
|
"Return the message payload in string form.\n" },
|
|
|
|
{ "get_header",
|
|
(PyCFunction)xu_message_get_header,
|
|
METH_VARARGS,
|
|
"Returns a dictionary of values for @type, @subtype, and @id.\n" },
|
|
|
|
{ NULL, NULL, 0, NULL }
|
|
};
|
|
|
|
staticforward PyTypeObject xu_message_type;
|
|
|
|
static PyObject *xu_message_new(PyObject *self, PyObject *args)
|
|
{
|
|
xu_message_object *xum;
|
|
int type, subtype, id, dict_items_parsed = 0;
|
|
PyObject *payload = NULL;
|
|
|
|
if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) )
|
|
return NULL;
|
|
|
|
xum = PyObject_New(xu_message_object, &xu_message_type);
|
|
|
|
xum->msg.type = type;
|
|
xum->msg.subtype = subtype;
|
|
xum->msg.id = id;
|
|
xum->msg.length = 0;
|
|
|
|
if ( payload == NULL )
|
|
return (PyObject *)xum;
|
|
|
|
if ( !PyDict_Check(payload) )
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "payload is not a dictionary");
|
|
PyObject_Del((PyObject *)xum);
|
|
return NULL;
|
|
}
|
|
|
|
switch ( TYPE(type, subtype) )
|
|
{
|
|
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED):
|
|
P2C(blkif_fe_interface_status_changed_t, handle, u32);
|
|
P2C(blkif_fe_interface_status_changed_t, status, u32);
|
|
P2C(blkif_fe_interface_status_changed_t, evtchn, u16);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE):
|
|
P2C(blkif_be_create_t, domid, u32);
|
|
P2C(blkif_be_create_t, blkif_handle, u32);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY):
|
|
P2C(blkif_be_destroy_t, domid, u32);
|
|
P2C(blkif_be_destroy_t, blkif_handle, u32);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
|
|
P2C(blkif_be_connect_t, domid, u32);
|
|
P2C(blkif_be_connect_t, blkif_handle, u32);
|
|
P2C(blkif_be_connect_t, shmem_frame, memory_t);
|
|
P2C(blkif_be_connect_t, evtchn, u16);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT):
|
|
P2C(blkif_be_disconnect_t, domid, u32);
|
|
P2C(blkif_be_disconnect_t, blkif_handle, u32);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE):
|
|
P2C(blkif_be_vbd_create_t, domid, u32);
|
|
P2C(blkif_be_vbd_create_t, blkif_handle, u32);
|
|
P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t);
|
|
P2C(blkif_be_vbd_create_t, readonly, u16);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY):
|
|
P2C(blkif_be_vbd_destroy_t, domid, u32);
|
|
P2C(blkif_be_vbd_destroy_t, blkif_handle, u32);
|
|
P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW):
|
|
P2C(blkif_be_vbd_grow_t, domid, u32);
|
|
P2C(blkif_be_vbd_grow_t, blkif_handle, u32);
|
|
P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t);
|
|
P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t);
|
|
P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t);
|
|
P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t);
|
|
break;
|
|
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK):
|
|
P2C(blkif_be_vbd_shrink_t, domid, u32);
|
|
P2C(blkif_be_vbd_shrink_t, blkif_handle, u32);
|
|
P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t);
|
|
break;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED):
|
|
P2C(netif_fe_interface_status_changed_t, handle, u32);
|
|
P2C(netif_fe_interface_status_changed_t, status, u32);
|
|
P2C(netif_fe_interface_status_changed_t, evtchn, u16);
|
|
P2C(netif_fe_interface_status_changed_t, mac[0], u8);
|
|
P2C(netif_fe_interface_status_changed_t, mac[1], u8);
|
|
P2C(netif_fe_interface_status_changed_t, mac[2], u8);
|
|
P2C(netif_fe_interface_status_changed_t, mac[3], u8);
|
|
P2C(netif_fe_interface_status_changed_t, mac[4], u8);
|
|
P2C(netif_fe_interface_status_changed_t, mac[5], u8);
|
|
break;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE):
|
|
P2C(netif_be_create_t, domid, u32);
|
|
P2C(netif_be_create_t, netif_handle, u32);
|
|
P2C(netif_be_create_t, mac[0], u8);
|
|
P2C(netif_be_create_t, mac[1], u8);
|
|
P2C(netif_be_create_t, mac[2], u8);
|
|
P2C(netif_be_create_t, mac[3], u8);
|
|
P2C(netif_be_create_t, mac[4], u8);
|
|
P2C(netif_be_create_t, mac[5], u8);
|
|
break;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
|
|
P2C(netif_be_destroy_t, domid, u32);
|
|
P2C(netif_be_destroy_t, netif_handle, u32);
|
|
break;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
|
|
P2C(netif_be_connect_t, domid, u32);
|
|
P2C(netif_be_connect_t, netif_handle, u32);
|
|
P2C(netif_be_connect_t, tx_shmem_frame, memory_t);
|
|
P2C(netif_be_connect_t, rx_shmem_frame, memory_t);
|
|
P2C(netif_be_connect_t, evtchn, u16);
|
|
break;
|
|
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT):
|
|
P2C(netif_be_disconnect_t, domid, u32);
|
|
P2C(netif_be_disconnect_t, netif_handle, u32);
|
|
break;
|
|
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
|
|
P2C(netif_fe_driver_status_changed_t, status, u32);
|
|
P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
|
|
}
|
|
|
|
if ( dict_items_parsed != PyDict_Size(payload) )
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "payload contains bad items");
|
|
PyObject_Del((PyObject *)xum);
|
|
return NULL;
|
|
}
|
|
|
|
return (PyObject *)xum;
|
|
}
|
|
|
|
static PyObject *xu_message_getattr(PyObject *obj, char *name)
|
|
{
|
|
xu_message_object *xum;
|
|
if ( strcmp(name, "MAX_PAYLOAD") == 0 )
|
|
return PyInt_FromLong(sizeof(xum->msg.msg));
|
|
return Py_FindMethod(xu_message_methods, obj, name);
|
|
}
|
|
|
|
static void xu_message_dealloc(PyObject *self)
|
|
{
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyTypeObject xu_message_type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0,
|
|
"message",
|
|
sizeof(xu_message_object),
|
|
0,
|
|
xu_message_dealloc, /* tp_dealloc */
|
|
NULL, /* tp_print */
|
|
xu_message_getattr, /* tp_getattr */
|
|
NULL, /* tp_setattr */
|
|
NULL, /* tp_compare */
|
|
NULL, /* tp_repr */
|
|
NULL, /* tp_as_number */
|
|
NULL, /* tp_as_sequence */
|
|
NULL, /* tp_as_mapping */
|
|
NULL /* tp_hash */
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* *********************** PORT ***********************
|
|
*/
|
|
|
|
static control_if_t *map_control_interface(int fd, unsigned long pfn)
|
|
{
|
|
char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
|
|
MAP_SHARED, fd, pfn * PAGE_SIZE);
|
|
if ( vaddr == MAP_FAILED )
|
|
return NULL;
|
|
return (control_if_t *)(vaddr + 2048);
|
|
}
|
|
static void unmap_control_interface(int fd, control_if_t *c)
|
|
{
|
|
char *vaddr = (char *)c - 2048;
|
|
(void)munmap(vaddr, PAGE_SIZE);
|
|
}
|
|
|
|
typedef struct {
|
|
PyObject_HEAD;
|
|
int mem_fd;
|
|
int xc_handle;
|
|
u32 remote_dom;
|
|
int local_port, remote_port;
|
|
control_if_t *interface;
|
|
CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
|
|
CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
|
|
} xu_port_object;
|
|
|
|
static PyObject *port_error;
|
|
|
|
static PyObject *xu_port_notify(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
(void)xc_evtchn_send(xup->xc_handle, xup->local_port);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
xu_message_object *xum;
|
|
CONTROL_RING_IDX c = xup->tx_req_cons;
|
|
control_if_t *cif = xup->interface;
|
|
control_msg_t *cmsg;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( (c == cif->tx_req_prod) ||
|
|
((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
|
|
{
|
|
PyErr_SetString(port_error, "no request to read");
|
|
return NULL;
|
|
}
|
|
|
|
cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
|
|
xum = PyObject_New(xu_message_object, &xu_message_type);
|
|
memcpy(&xum->msg, cmsg, sizeof(*cmsg));
|
|
if ( xum->msg.length > sizeof(xum->msg.msg) )
|
|
xum->msg.length = sizeof(xum->msg.msg);
|
|
xup->tx_req_cons++;
|
|
return (PyObject *)xum;
|
|
}
|
|
|
|
static PyObject *xu_port_write_request(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
xu_message_object *xum;
|
|
CONTROL_RING_IDX p = xup->rx_req_prod;
|
|
control_if_t *cif = xup->interface;
|
|
control_msg_t *cmsg;
|
|
|
|
if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
|
|
return NULL;
|
|
|
|
if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "expected a xend.utils.message");
|
|
return NULL;
|
|
}
|
|
|
|
if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
|
|
{
|
|
PyErr_SetString(port_error, "no space to write request");
|
|
return NULL;
|
|
}
|
|
|
|
cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
|
|
memcpy(cmsg, &xum->msg, sizeof(*cmsg));
|
|
|
|
xup->rx_req_prod = cif->rx_req_prod = p + 1;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_port_read_response(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
xu_message_object *xum;
|
|
CONTROL_RING_IDX c = xup->rx_resp_cons;
|
|
control_if_t *cif = xup->interface;
|
|
control_msg_t *cmsg;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
|
|
{
|
|
PyErr_SetString(port_error, "no response to read");
|
|
return NULL;
|
|
}
|
|
|
|
cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)];
|
|
xum = PyObject_New(xu_message_object, &xu_message_type);
|
|
memcpy(&xum->msg, cmsg, sizeof(*cmsg));
|
|
if ( xum->msg.length > sizeof(xum->msg.msg) )
|
|
xum->msg.length = sizeof(xum->msg.msg);
|
|
xup->rx_resp_cons++;
|
|
return (PyObject *)xum;
|
|
}
|
|
|
|
static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
xu_message_object *xum;
|
|
CONTROL_RING_IDX p = xup->tx_resp_prod;
|
|
control_if_t *cif = xup->interface;
|
|
control_msg_t *cmsg;
|
|
|
|
if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
|
|
return NULL;
|
|
|
|
if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "expected a xend.utils.message");
|
|
return NULL;
|
|
}
|
|
|
|
if ( p == xup->tx_req_cons )
|
|
{
|
|
PyErr_SetString(port_error, "no space to write response");
|
|
return NULL;
|
|
}
|
|
|
|
cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)];
|
|
memcpy(cmsg, &xum->msg, sizeof(*cmsg));
|
|
|
|
xup->tx_resp_prod = cif->tx_resp_prod = p + 1;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
CONTROL_RING_IDX c = xup->tx_req_cons;
|
|
control_if_t *cif = xup->interface;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( (c == cif->tx_req_prod) ||
|
|
((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
|
|
return PyInt_FromLong(0);
|
|
|
|
return PyInt_FromLong(1);
|
|
}
|
|
|
|
static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
CONTROL_RING_IDX p = xup->rx_req_prod;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
|
|
return PyInt_FromLong(0);
|
|
|
|
return PyInt_FromLong(1);
|
|
}
|
|
|
|
static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
CONTROL_RING_IDX c = xup->rx_resp_cons;
|
|
control_if_t *cif = xup->interface;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
|
|
return PyInt_FromLong(0);
|
|
|
|
return PyInt_FromLong(1);
|
|
}
|
|
|
|
static PyObject *xu_port_space_to_write_response(
|
|
PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
CONTROL_RING_IDX p = xup->tx_resp_prod;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( p == xup->tx_req_cons )
|
|
return PyInt_FromLong(0);
|
|
|
|
return PyInt_FromLong(1);
|
|
}
|
|
|
|
static PyMethodDef xu_port_methods[] = {
|
|
{ "notify",
|
|
(PyCFunction)xu_port_notify,
|
|
METH_VARARGS,
|
|
"Send a notification to the remote end.\n" },
|
|
|
|
{ "read_request",
|
|
(PyCFunction)xu_port_read_request,
|
|
METH_VARARGS,
|
|
"Read a request message from the control interface.\n" },
|
|
|
|
{ "write_request",
|
|
(PyCFunction)xu_port_write_request,
|
|
METH_VARARGS,
|
|
"Write a request message to the control interface.\n" },
|
|
|
|
{ "read_response",
|
|
(PyCFunction)xu_port_read_response,
|
|
METH_VARARGS,
|
|
"Read a response message from the control interface.\n" },
|
|
|
|
{ "write_response",
|
|
(PyCFunction)xu_port_write_response,
|
|
METH_VARARGS,
|
|
"Write a response message to the control interface.\n" },
|
|
|
|
{ "request_to_read",
|
|
(PyCFunction)xu_port_request_to_read,
|
|
METH_VARARGS,
|
|
"Returns TRUE if there is a request message to read.\n" },
|
|
|
|
{ "space_to_write_request",
|
|
(PyCFunction)xu_port_space_to_write_request,
|
|
METH_VARARGS,
|
|
"Returns TRUE if there is space to write a request message.\n" },
|
|
|
|
{ "response_to_read",
|
|
(PyCFunction)xu_port_response_to_read,
|
|
METH_VARARGS,
|
|
"Returns TRUE if there is a response message to read.\n" },
|
|
|
|
{ "space_to_write_response",
|
|
(PyCFunction)xu_port_space_to_write_response,
|
|
METH_VARARGS,
|
|
"Returns TRUE if there is space to write a response message.\n" },
|
|
|
|
{ NULL, NULL, 0, NULL }
|
|
};
|
|
|
|
staticforward PyTypeObject xu_port_type;
|
|
|
|
static PyObject *xu_port_new(PyObject *self, PyObject *args)
|
|
{
|
|
xu_port_object *xup;
|
|
u32 dom;
|
|
int port1, port2;
|
|
xc_dominfo_t info;
|
|
|
|
if ( !PyArg_ParseTuple(args, "i", &dom) )
|
|
return NULL;
|
|
|
|
xup = PyObject_New(xu_port_object, &xu_port_type);
|
|
|
|
if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 )
|
|
{
|
|
PyErr_SetString(port_error, "Could not open '/dev/mem'");
|
|
goto fail1;
|
|
}
|
|
|
|
/* Set the General-Purpose Subject whose page frame will be mapped. */
|
|
(void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom);
|
|
|
|
if ( (xup->xc_handle = xc_interface_open()) == -1 )
|
|
{
|
|
PyErr_SetString(port_error, "Could not open Xen control interface");
|
|
goto fail2;
|
|
}
|
|
|
|
if ( dom == 0 )
|
|
{
|
|
/*
|
|
* The control-interface event channel for DOM0 is already set up.
|
|
* We use an ioctl to discover the port at our end of the channel.
|
|
*/
|
|
port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL);
|
|
port2 = -1; /* We don't need the remote end of the DOM0 link. */
|
|
if ( port1 < 0 )
|
|
{
|
|
PyErr_SetString(port_error, "Could not open channel to DOM0");
|
|
goto fail3;
|
|
}
|
|
}
|
|
else if ( xc_evtchn_bind_interdomain(xup->xc_handle,
|
|
DOMID_SELF, dom,
|
|
&port1, &port2) != 0 )
|
|
{
|
|
PyErr_SetString(port_error, "Could not open channel to domain");
|
|
goto fail3;
|
|
}
|
|
|
|
if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) ||
|
|
(info.domid != dom) )
|
|
{
|
|
PyErr_SetString(port_error, "Failed to obtain domain status");
|
|
goto fail4;
|
|
}
|
|
|
|
xup->interface =
|
|
map_control_interface(xup->mem_fd, info.shared_info_frame);
|
|
if ( xup->interface == NULL )
|
|
{
|
|
PyErr_SetString(port_error, "Failed to map domain control interface");
|
|
goto fail4;
|
|
}
|
|
|
|
xup->interface->tx_resp_prod = 0;
|
|
xup->interface->rx_req_prod = 0;
|
|
xup->interface->tx_req_prod = 0;
|
|
xup->interface->rx_resp_prod = 0;
|
|
|
|
xup->tx_req_cons = 0;
|
|
xup->tx_resp_prod = 0;
|
|
xup->rx_req_prod = 0;
|
|
xup->rx_resp_cons = 0;
|
|
xup->remote_dom = dom;
|
|
xup->local_port = port1;
|
|
xup->remote_port = port2;
|
|
|
|
return (PyObject *)xup;
|
|
|
|
|
|
fail4:
|
|
(void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1);
|
|
fail3:
|
|
(void)xc_interface_close(xup->xc_handle);
|
|
fail2:
|
|
(void)close(xup->mem_fd);
|
|
fail1:
|
|
PyObject_Del((PyObject *)xup);
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *xu_port_getattr(PyObject *obj, char *name)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)obj;
|
|
if ( strcmp(name, "local_port") == 0 )
|
|
return PyInt_FromLong(xup->local_port);
|
|
if ( strcmp(name, "remote_port") == 0 )
|
|
return PyInt_FromLong(xup->remote_port);
|
|
if ( strcmp(name, "remote_dom") == 0 )
|
|
return PyInt_FromLong(xup->remote_dom);
|
|
return Py_FindMethod(xu_port_methods, obj, name);
|
|
}
|
|
|
|
static void xu_port_dealloc(PyObject *self)
|
|
{
|
|
xu_port_object *xup = (xu_port_object *)self;
|
|
unmap_control_interface(xup->mem_fd, xup->interface);
|
|
if ( xup->remote_dom != 0 )
|
|
(void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port);
|
|
(void)xc_interface_close(xup->xc_handle);
|
|
(void)close(xup->mem_fd);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyTypeObject xu_port_type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0,
|
|
"port",
|
|
sizeof(xu_port_object),
|
|
0,
|
|
xu_port_dealloc, /* tp_dealloc */
|
|
NULL, /* tp_print */
|
|
xu_port_getattr, /* tp_getattr */
|
|
NULL, /* tp_setattr */
|
|
NULL, /* tp_compare */
|
|
NULL, /* tp_repr */
|
|
NULL, /* tp_as_number */
|
|
NULL, /* tp_as_sequence */
|
|
NULL, /* tp_as_mapping */
|
|
NULL /* tp_hash */
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* *********************** BUFFER ***********************
|
|
*/
|
|
|
|
#define BUFSZ 65536
|
|
#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1))
|
|
typedef unsigned int BUF_IDX;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD;
|
|
char *buf;
|
|
unsigned int prod, cons;
|
|
} xu_buffer_object;
|
|
|
|
static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max)
|
|
{
|
|
PyObject *str1, *str2;
|
|
int len1, len2, c = MASK_BUF_IDX(xub->cons);
|
|
|
|
len1 = xub->prod - xub->cons;
|
|
if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */
|
|
len1 = BUFSZ - c;
|
|
if ( len1 > max ) /* clip to specified maximum */
|
|
len1 = max;
|
|
if ( len1 < 0 ) /* sanity */
|
|
len1 = 0;
|
|
|
|
if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL )
|
|
return NULL;
|
|
|
|
if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) )
|
|
{
|
|
len2 = max - len1;
|
|
if ( len2 > MASK_BUF_IDX(xub->prod) )
|
|
len2 = MASK_BUF_IDX(xub->prod);
|
|
if ( len2 > 0 )
|
|
{
|
|
str2 = PyString_FromStringAndSize(&xub->buf[0], len2);
|
|
if ( str2 == NULL )
|
|
return NULL;
|
|
PyString_ConcatAndDel(&str1, str2);
|
|
if ( str1 == NULL )
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return str1;
|
|
}
|
|
|
|
static PyObject *xu_buffer_peek(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
int max = 1024;
|
|
|
|
if ( !PyArg_ParseTuple(args, "|i", &max) )
|
|
return NULL;
|
|
|
|
return __xu_buffer_peek(xub, max);
|
|
}
|
|
|
|
static PyObject *xu_buffer_read(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
PyObject *str;
|
|
int max = 1024;
|
|
|
|
if ( !PyArg_ParseTuple(args, "|i", &max) )
|
|
return NULL;
|
|
|
|
if ( (str = __xu_buffer_peek(xub, max)) != NULL )
|
|
xub->cons += PyString_Size(str);
|
|
|
|
return str;
|
|
}
|
|
|
|
static PyObject *xu_buffer_discard(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
int max, len;
|
|
|
|
if ( !PyArg_ParseTuple(args, "i", &max) )
|
|
return NULL;
|
|
|
|
len = xub->prod - xub->cons;
|
|
if ( len > max )
|
|
len = max;
|
|
if ( len < 0 )
|
|
len = 0;
|
|
|
|
xub->cons += len;
|
|
|
|
return PyInt_FromLong(len);
|
|
}
|
|
|
|
static PyObject *xu_buffer_write(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
char *str;
|
|
int len, len1, len2;
|
|
|
|
if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
|
|
return NULL;
|
|
|
|
len1 = len;
|
|
if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
|
|
len1 = BUFSZ - MASK_BUF_IDX(xub->prod);
|
|
if ( len1 > (BUFSZ - (xub->prod - xub->cons)) )
|
|
len1 = BUFSZ - (xub->prod - xub->cons);
|
|
|
|
if ( len1 == 0 )
|
|
return PyInt_FromLong(0);
|
|
|
|
memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1);
|
|
xub->prod += len1;
|
|
|
|
if ( len1 < len )
|
|
{
|
|
len2 = len - len1;
|
|
if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
|
|
len2 = BUFSZ - MASK_BUF_IDX(xub->prod);
|
|
if ( len2 > (BUFSZ - (xub->prod - xub->cons)) )
|
|
len2 = BUFSZ - (xub->prod - xub->cons);
|
|
if ( len2 != 0 )
|
|
{
|
|
memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2);
|
|
xub->prod += len2;
|
|
return PyInt_FromLong(len1 + len2);
|
|
}
|
|
}
|
|
|
|
return PyInt_FromLong(len1);
|
|
}
|
|
|
|
static PyObject *xu_buffer_empty(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( xub->cons == xub->prod )
|
|
return PyInt_FromLong(1);
|
|
|
|
return PyInt_FromLong(0);
|
|
}
|
|
|
|
static PyObject *xu_buffer_full(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
if ( (xub->prod - xub->cons) == BUFSZ )
|
|
return PyInt_FromLong(1);
|
|
|
|
return PyInt_FromLong(0);
|
|
}
|
|
|
|
static PyMethodDef xu_buffer_methods[] = {
|
|
{ "peek",
|
|
(PyCFunction)xu_buffer_peek,
|
|
METH_VARARGS,
|
|
"Peek up to @max bytes from the buffer. Returns a string.\n" },
|
|
|
|
{ "read",
|
|
(PyCFunction)xu_buffer_read,
|
|
METH_VARARGS,
|
|
"Read up to @max bytes from the buffer. Returns a string.\n" },
|
|
|
|
{ "discard",
|
|
(PyCFunction)xu_buffer_discard,
|
|
METH_VARARGS,
|
|
"Discard up to @max bytes from the buffer. Returns number of bytes.\n" },
|
|
|
|
{ "write",
|
|
(PyCFunction)xu_buffer_write,
|
|
METH_VARARGS,
|
|
"Write @string into buffer. Return number of bytes written.\n" },
|
|
|
|
{ "empty",
|
|
(PyCFunction)xu_buffer_empty,
|
|
METH_VARARGS,
|
|
"Return TRUE if the buffer is empty.\n" },
|
|
|
|
{ "full",
|
|
(PyCFunction)xu_buffer_full,
|
|
METH_VARARGS,
|
|
"Return TRUE if the buffer is full.\n" },
|
|
|
|
{ NULL, NULL, 0, NULL }
|
|
};
|
|
|
|
staticforward PyTypeObject xu_buffer_type;
|
|
|
|
static PyObject *xu_buffer_new(PyObject *self, PyObject *args)
|
|
{
|
|
xu_buffer_object *xub;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
xub = PyObject_New(xu_buffer_object, &xu_buffer_type);
|
|
|
|
if ( (xub->buf = malloc(BUFSZ)) == NULL )
|
|
{
|
|
PyObject_Del((PyObject *)xub);
|
|
return NULL;
|
|
}
|
|
|
|
xub->prod = xub->cons = 0;
|
|
|
|
return (PyObject *)xub;
|
|
}
|
|
|
|
static PyObject *xu_buffer_getattr(PyObject *obj, char *name)
|
|
{
|
|
return Py_FindMethod(xu_buffer_methods, obj, name);
|
|
}
|
|
|
|
static void xu_buffer_dealloc(PyObject *self)
|
|
{
|
|
xu_buffer_object *xub = (xu_buffer_object *)self;
|
|
free(xub->buf);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
static PyTypeObject xu_buffer_type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0,
|
|
"buffer",
|
|
sizeof(xu_buffer_object),
|
|
0,
|
|
xu_buffer_dealloc, /* tp_dealloc */
|
|
NULL, /* tp_print */
|
|
xu_buffer_getattr, /* tp_getattr */
|
|
NULL, /* tp_setattr */
|
|
NULL, /* tp_compare */
|
|
NULL, /* tp_repr */
|
|
NULL, /* tp_as_number */
|
|
NULL, /* tp_as_sequence */
|
|
NULL, /* tp_as_mapping */
|
|
NULL /* tp_hash */
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* *********************** MODULE WRAPPER ***********************
|
|
*/
|
|
|
|
static void handle_child_death(int dummy)
|
|
{
|
|
while ( waitpid(-1, NULL, WNOHANG) > 0 )
|
|
continue;
|
|
}
|
|
|
|
static PyObject *xu_autoreap(PyObject *self, PyObject *args)
|
|
{
|
|
struct sigaction sa;
|
|
|
|
if ( !PyArg_ParseTuple(args, "") )
|
|
return NULL;
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
sa.sa_handler = handle_child_death;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
|
|
(void)sigaction(SIGCHLD, &sa, NULL);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyMethodDef xu_methods[] = {
|
|
{ "notifier", xu_notifier_new, METH_VARARGS,
|
|
"Create a new notifier." },
|
|
{ "message", xu_message_new, METH_VARARGS,
|
|
"Create a new communications message." },
|
|
{ "port", xu_port_new, METH_VARARGS,
|
|
"Create a new communications port." },
|
|
{ "buffer", xu_buffer_new, METH_VARARGS,
|
|
"Create a new ring buffer." },
|
|
{ "autoreap", xu_autoreap, METH_VARARGS,
|
|
"Ensure that zombie children are automatically reaped by the OS." },
|
|
{ NULL, NULL, 0, NULL }
|
|
};
|
|
|
|
PyMODINIT_FUNC initutils(void)
|
|
{
|
|
PyObject *m, *d;
|
|
|
|
m = Py_InitModule("xend.utils", xu_methods);
|
|
|
|
d = PyModule_GetDict(m);
|
|
port_error = PyErr_NewException("xend.utils.PortError", NULL, NULL);
|
|
PyDict_SetItemString(d, "PortError", port_error);
|
|
}
|