From: Marco G. <mar...@po...> - 2015-11-11 10:09:47
|
ctypes allows to write extensions in pure Python. It is also part of the Python's standard library and more portable across different implementations and versions. This is also a first step to support Python3. A compatibility layer to the old vdeplug_python is also supplied as like to the VdePlug module. --- vde-2/configure.ac | 15 --- vde-2/src/lib/python/Makefile.am | 15 +-- vde-2/src/lib/python/VdePlug.py | 96 ++------------- vde-2/src/lib/python/vdeplug.py | 219 +++++++++++++++++++++++++++++++++ vde-2/src/lib/python/vdeplug_python.c | 102 --------------- vde-2/src/lib/python/vdeplug_python.py | 15 +++ 6 files changed, 248 insertions(+), 214 deletions(-) create mode 100644 vde-2/src/lib/python/vdeplug.py delete mode 100644 vde-2/src/lib/python/vdeplug_python.c create mode 100644 vde-2/src/lib/python/vdeplug_python.py diff --git a/vde-2/configure.ac b/vde-2/configure.ac index c8f6d32..947aae6 100644 --- a/vde-2/configure.ac +++ b/vde-2/configure.ac @@ -223,21 +223,6 @@ AC_ARG_ENABLE([python], if test x"$enable_python" = x"yes"; then # check python AM_PATH_PYTHON([2.5]) - AC_PATH_PROG(PYTHON_CONFIG, python$PYTHON_VERSION-config) - if test x"$PYTHON_CONFIG" = x""; then - AC_PATH_PROG(PYTHON_CONFIG, python-config) - fi - if test x"$PYTHON_CONFIG" = x""; then - # not found, give up - enable_python=no - else - PYTHON_CFLAGS=`$PYTHON_CONFIG --includes` - PYTHON_LIBS=`$PYTHON_CONFIG --libs` - PYTHON_INCLUDES="$PYTHON_CFLAGS" - fi - AC_SUBST(PYTHON_CFLAGS) - AC_SUBST(PYTHON_INCLUDES) - AC_SUBST(PYTHON_LIBS) fi diff --git a/vde-2/src/lib/python/Makefile.am b/vde-2/src/lib/python/Makefile.am index b4d6e2b..4bfe5ef 100644 --- a/vde-2/src/lib/python/Makefile.am +++ b/vde-2/src/lib/python/Makefile.am @@ -1,12 +1,3 @@ -moddir = $(pythondir) - -AM_LIBTOOLFLAGS = --tag=disable-static - -LIBADD = $(top_builddir)/src/lib/libvdeplug.so - -mod_LTLIBRARIES = vdeplug_python.la -dist_python_SCRIPTS = VdePlug.py - -vdeplug_python_la_CFLAGS = -I$(top_srcdir)/include $(PYTHON_CFLAGS) $(PYTHON_INCLUDES) -vdeplug_python_la_LIBADD = $(PYTHON_LIBS) $(top_builddir)/src/lib/libvdeplug.la -vdeplug_python_la_LDFLAGS = -module -avoid-version +python_PYTHON = VdePlug.py \ + vdeplug.py \ + vdeplug_python.py diff --git a/vde-2/src/lib/python/VdePlug.py b/vde-2/src/lib/python/VdePlug.py index 241c832..8035855 100755 --- a/vde-2/src/lib/python/VdePlug.py +++ b/vde-2/src/lib/python/VdePlug.py @@ -1,89 +1,15 @@ -#!/usr/bin/python +from vdeplug import VdeStream, VdePlug +import warnings -''' - LibVdePlug/python wrapper - Copyright 2010 Daniele Lacamera +__all__ = ["VdeStream", "VdePlug"] - Released under the terms of GNU LGPL v. 2.1 - (see COPYING.libvdeplug in the main project directory) - -''' - -import vdeplug_python, os, sys, struct -from array import array - - -class VdeStream: - def __init__(self, parent, outf, frecv = None, ferr = None): - self.conn = parent - self.outf = outf - self.frecv = frecv - self.ferr = ferr - self.conn._streams.append(self) - if (self.frecv == None): - self.frecv=self.conn.send - - def recv(self, buf): - (toth, totl) = struct.unpack("BB", buf[0:2]) - tot = (toth << 8) + totl - buffer = buf[2:] - if (len(buffer) < tot): - sys.stderr.write("stream recv: wrong size %d, pkt is %d\n" % (tot, len(buffer))) - return -1 - elif (len(buffer) > tot): - self.frecv(buffer[0:tot]) - return self.recv(buffer[tot:]) # Recursion for remaining data - elif (self.frecv(buffer) < 0): - return -1 - - def send(self, buf): - if self.outf is None: - return -1 - lh = (len(buf)>>8) & 0xFF - ll = len(buf) & 0xFF - a = struct.pack("BB", lh, ll) - self.outf.write(a) - self.outf.write(buf) - self.outf.flush() - - - - - -class VdePlug: - - def __init__(self, sock=None, descr="Python", port=0, group=None, mode=0): - self._magic = vdeplug_python.open(sock, descr) - self._ctl = os.fdopen(vdeplug_python.ctlfd(self._magic)) - self._data = os.fdopen(vdeplug_python.datafd(self._magic), 'wb+', os.O_NONBLOCK) - self._streams = [] - - def ctlfd(self): - return self._ctl - - def datafd(self): - return self._data - - def send(self, buffer): - a = array('B', buffer) - r = self._data.write(a) - self._data.flush() - return r - - def recv(self, size): - return os.read(self._data.fileno(), size) - - def recvfrom_streams(self, buf): - for s in self._streams: - s.recv(buf) - - def sendto_streams(self, buf): - for s in self._streams: - s.send(buf) - - def close(self): - vdeplug_python.close(self._magic) - self._magic = None - +msg = """The module VdePlug is deprecated. Please use the module \ +vdeplug. Change your code as following: + try: + from vdeplug import VdePlug, VdeStream + except ImportError: + from VdePlug import VdePlug, VdeStream +""" +warnings.warn(msg, DeprecationWarning) diff --git a/vde-2/src/lib/python/vdeplug.py b/vde-2/src/lib/python/vdeplug.py new file mode 100644 index 0000000..6a63f08 --- /dev/null +++ b/vde-2/src/lib/python/vdeplug.py @@ -0,0 +1,219 @@ +# libvdeplug wrapper +# Copyright (C) 2015 Marco Giusti +# +# Released under the terms of GNU LGPL v. 2.1 +# (see COPYING.libvdeplug in the main project directory) + +import os +import ctypes +import ctypes.util + + +__all__ = ["LIBVDEPLUG_INTERFACE_VERSION", "VdeError", "open", "close", + "ctlfd", "datafd", "libvdeplug"] +__version__ = "0.1" + + +LIBVDEPLUG_INTERFACE_VERSION = 1 + + +# VdeError derives from RuntimeError only because of compatibility reasons + +class VdeError(EnvironmentError, RuntimeError): + + def __init__(self, *args): + if not args: + errno = ctypes.get_errno() + args = errno, os.strerror(errno) + super(VdeError, self).__init__(*args) + + +def open(sock, desc, port=0, group=None, mode=0o777): + """Open a VDE connection. + + @param sock: switch id (path) + @type sock: str + @param desc: description that appear in the port description on the + switch + @type desc: str + @param port: connect to a specific port of the switch [default=0] + @type port: int + @param group: change the ownership of the communication port to a specific + group (None=no change) [default=None] + @type group: str + @param mode: set communication port mode (if 0 standard socket mode + applies) [default=0] + @type mode: int + """ + + args = _VdeOpenArgs(int(port), str(group), int(mode)) + fd = libvdeplug.vde_open_real(sock, desc, LIBVDEPLUG_INTERFACE_VERSION, + ctypes.byref(args)) + if not fd: + raise VdeError() + return fd + + +def _invoke(func, conn): + i = func(conn) + if i < 0: + raise VdeError() + return i + + +def ctlfd(conn): + """ + for select/poll. the ctl socket is silent after the initial handshake. + when EOF the switch has closed the connection. + """ + + return _invoke(libvdeplug.vde_ctlfd, conn) + + +def datafd(conn): + """ + for select/poll when this fd receive data, there are packets to recv (call + vde_recv) + """ + + return _invoke(libvdeplug.vde_datafd, conn) + + +def close(conn): + """Close a connection.""" + + return _invoke(libvdeplug.vde_close, conn) + + +class Plug(object): + + def __init__(self, sock, desc, port=0, group=None, mode=0o777): + self._conn = open(sock, desc, port, group, mode) + try: + self._ctlfd = os.fdopen(ctlfd(self._conn)) + self._datafd = os.fdopen(datafd(self._conn), "wb+") + except: + self.close() + raise + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + def ctlfd(self): + return self._ctlfd + + def datafd(self): + return self._datafd + + def close(self): + close(self._conn) + + +class _VdeOpenArgs(ctypes.Structure): + + _fields_ = [("port", ctypes.c_int), + ("group", ctypes.c_char_p), + ("mode", ctypes.c_int)] + + +def _initializeModule(libvdeplug): + libvdeplug.vde_open_real.argtypes = [ctypes.c_char_p, ctypes.c_char_p, + ctypes.c_int, + ctypes.POINTER(_VdeOpenArgs)] + libvdeplug.vde_open_real.restype = ctypes.c_void_p + libvdeplug.vde_recv.argtypes = [ctypes.c_void_p, ctypes.c_void_p, + ctypes.c_size_t, ctypes.c_int] + libvdeplug.vde_recv.restype = ctypes.c_ssize_t + libvdeplug.vde_send.argtypes = [ctypes.c_void_p, ctypes.c_void_p, + ctypes.c_size_t, ctypes.c_int] + libvdeplug.vde_send.restype = ctypes.c_ssize_t + libvdeplug.vde_datafd.argtypes = [ctypes.c_void_p] + libvdeplug.vde_datafd.restype = ctypes.c_int + libvdeplug.vde_ctlfd.argtypes = [ctypes.c_void_p] + libvdeplug.vde_ctlfd.restype = ctypes.c_int + libvdeplug.vde_close.argtypes = [ctypes.c_void_p] + libvdeplug.vde_close.restype = ctypes.c_int + + +name = ctypes.util.find_library("vdeplug") +if not name: + raise ImportError("Can't find vdeplug library.") +libvdeplug = ctypes.CDLL(name, use_errno=True) +del name +_initializeModule(libvdeplug) + + +# old VdePlug compatibility + +# LibVdePlug/python wrapper +# Copyright 2010 Daniele Lacamera +# +# Released under the terms of GNU LGPL v. 2.1 +# (see COPYING.libvdeplug in the main project directory) + +import sys +import struct +from array import array + + +class VdePlug(Plug): + + def __init__(self, sock=None, descr="Python", port=0, group=None, mode=0): + super(VdePlug, self).__init__(sock, descr, port, group, mode) + self._streams = [] + + def send(self, buffer): + a = array("B", buffer) + r = self._datafd.write(a) + self._datafd.flush() + return r + + def recv(self, size): + return self._datafd.read(size) + + def recvfrom_streams(self, buf): + for s in self._streams: + s.recv(buf) + + def sendto_streams(self, buf): + for s in self._streams: + s.send(buf) + + +class VdeStream: + + def __init__(self, parent, outf, frecv=None, ferr=None): + self.conn = parent + self.outf = outf + self.frecv = frecv + self.ferr = ferr + self.conn._streams.append(self) + if self.frecv is None: + self.frecv = self.conn.send + + def recv(self, buf): + toth, totl = struct.unpack("BB", buf[0:2]) + tot = (toth << 8) + totl + buffer = buf[2:] + if len(buffer) < tot: + sys.stderr.write("stream recv: wrong size %d, pkt is %d\n" % + (tot, len(buffer))) + return -1 + elif len(buffer) > tot: + self.frecv(buffer[0:tot]) + return self.recv(buffer[tot:]) # Recursion for remaining data + elif self.frecv(buffer) < 0: + return -1 + + def send(self, buf): + if self.outf is None: + return -1 + lh = (len(buf) >> 8) & 0xFF + ll = len(buf) & 0xFF + a = struct.pack("BB", lh, ll) + self.outf.write(a) + self.outf.write(buf) + self.outf.flush() diff --git a/vde-2/src/lib/python/vdeplug_python.c b/vde-2/src/lib/python/vdeplug_python.c deleted file mode 100644 index 9d70e72..0000000 --- a/vde-2/src/lib/python/vdeplug_python.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * LibVdePlug/python wrapper - * Copyright © 2010 Daniele Lacamera - * - * Released under the terms of GNU LGPL v. 2.1 - * (see COPYING.libvdeplug in the main project directory) - * - */ -#include "Python.h" -#include <stdio.h> -#include "libvdeplug.h" - - -static PyObject *vdeplug_open(PyObject *self, PyObject *args) -{ - struct vde_open_args vde_args = {0,NULL,0777}; - char *vde_sock = NULL, *vde_descr = NULL; - VDECONN *ret; - - if (!PyArg_ParseTuple(args, "ss|isi", &vde_sock, &vde_descr, &vde_args.port, &vde_args.group, &vde_args.mode)) - goto failure; - - ret = vde_open_real(vde_sock, vde_descr, 1, &vde_args); - if (!ret) - goto failure; - else - return PyLong_FromUnsignedLong((unsigned long) ret); - - -failure: - return PyErr_SetFromErrno(PyExc_RuntimeError); -} - -static PyObject *vdeplug_ctlfd(PyObject *self, PyObject *args) -{ - VDECONN *conn; - unsigned long vde_magic = 0; - - if (!PyArg_ParseTuple(args, "k", &vde_magic)) - goto failure; - conn = (VDECONN *) vde_magic; - - if (!conn) - goto failure; - - return Py_BuildValue("i", vde_ctlfd(conn)); - -failure: - return PyErr_SetFromErrno(PyExc_RuntimeError); -} - -static PyObject *vdeplug_datafd(PyObject *self, PyObject *args) -{ - VDECONN *conn; - unsigned long vde_magic = 0; - - if (!PyArg_ParseTuple(args, "k", &vde_magic)) - goto failure; - conn = (VDECONN *) vde_magic; - - if (!conn) - goto failure; - - return Py_BuildValue("i", vde_datafd(conn)); - -failure: - return PyErr_SetFromErrno(PyExc_RuntimeError); -} - -static PyObject *vdeplug_close(PyObject *self, PyObject *args) -{ - VDECONN *conn; - unsigned long vde_magic = 0; - - if (!PyArg_ParseTuple(args, "k", &vde_magic)) - goto failure; - conn = (VDECONN *) vde_magic; - - if (!conn) - goto failure; - - return Py_BuildValue("i", vde_close(conn)); - -failure: - return PyErr_SetFromErrno(PyExc_RuntimeError); -} - - - -static PyMethodDef vdeplug_methods[] = { - {"open", vdeplug_open, METH_VARARGS}, - {"ctlfd", vdeplug_ctlfd, METH_VARARGS}, - {"datafd", vdeplug_datafd, METH_VARARGS}, - {"close", vdeplug_close, METH_VARARGS}, - {NULL, NULL} /* Sentinel */ -}; - -void initvdeplug_python(void) -{ - (void) Py_InitModule("vdeplug_python", vdeplug_methods); -// PyErr_SetString(PyExc_RuntimeError,"vdeplug error"); -} diff --git a/vde-2/src/lib/python/vdeplug_python.py b/vde-2/src/lib/python/vdeplug_python.py new file mode 100644 index 0000000..96738f3 --- /dev/null +++ b/vde-2/src/lib/python/vdeplug_python.py @@ -0,0 +1,15 @@ +from vdeplug import open, ctlfd, datafd, close +import warnings + + +__all__ = ["open", "ctlfd", "datafd", "close"] + +msg = """The module vdeplug_python is deprecated. Please use the module \ +vdeplug. Change your code as following: + + try: + import vdeplug as vp + except ImportError: + import vdeplug_python as vp +""" +warnings.warn(msg, DeprecationWarning) -- 2.1.4 |