xpra icon
Bug tracker and wiki

Ticket #983: vsock-v3.patch

File vsock-v3.patch, 17.3 KB (added by Antoine Martin, 4 years ago)

updated patch

  • setup.py

     
    127127opengl_ENABLED = DEFAULT and client_ENABLED
    128128html5_ENABLED = DEFAULT and not WIN32 and not OSX
    129129
     130vsock_ENABLED           = sys.platform.startswith("linux")
    130131bencode_ENABLED         = DEFAULT
    131132cython_bencode_ENABLED  = DEFAULT
    132133clipboard_ENABLED       = DEFAULT and not PYTHON3
     
    201202            "dec_avcodec2", "csc_swscale",
    202203            "csc_opencl", "csc_cython", "csc_opencv", "csc_libyuv",
    203204            "memoryview",
    204             "bencode", "cython_bencode",
     205            "bencode", "cython_bencode", "vsock",
    205206            "clipboard",
    206207            "server", "client", "dbus", "x11", "gtk_x11",
    207208            "gtk2", "gtk3", "html5",
     
    23502351                ["xpra/net/bencode/cython_bencode.pyx", buffers_c],
    23512352                **bencode_pkgconfig))
    23522353
     2354if vsock_ENABLED:
     2355    vsock_pkgconfig = pkgconfig()
     2356    cython_add(Extension("xpra.net.vsock",
     2357                ["xpra/net/vsock.pyx"],
     2358                **vsock_pkgconfig))
    23532359
     2360
    23542361if ext_modules:
    23552362    from Cython.Build import cythonize
    23562363    #this causes Cython to fall over itself:
  • xpra/scripts/config.py

     
    273273                    "title"             : str,
    274274                    "username"          : str,
    275275                    "auth"              : str,
     276                    "vsock-auth"        : str,
    276277                    "tcp-auth"          : str,
    277278                    "wm-name"           : str,
    278279                    "session-name"      : str,
     
    387388                    "start-on-connect"          : list,
    388389                    "start-child-on-connect"    : list,
    389390                    "bind"              : list,
     391                    "bind-vsock"        : list,
    390392                    "bind-tcp"          : list,
    391393                    "env"               : list,
    392394               }
     
    452454                    "title"             : "@title@ on @client-machine@",
    453455                    "username"          : username,
    454456                    "auth"              : "",
     457                    "vsock-auth"        : "",
    455458                    "tcp-auth"          : "",
    456459                    "wm-name"           : DEFAULT_NET_WM_NAME,
    457460                    "session-name"      : "",
     
    557560                    "packet-encoders"   : ["all"],
    558561                    "key-shortcut"      : get_default_key_shortcuts(),
    559562                    "bind"              : bind_dirs,
     563                    "bind-vsock"        : [],
    560564                    "bind-tcp"          : [],
    561565                    "start"             : [],
    562566                    "start-child"       : [],
  • xpra/scripts/main.py

     
    2929    make_defaults_struct, parse_bool, print_bool, print_number, validate_config, has_sound_support, name_to_field
    3030
    3131
     32VSOCK_TIMEOUT = int(os.environ.get("XPRA_VSOCK_TIMEOUT", 5))
    3233SOCKET_TIMEOUT = int(os.environ.get("XPRA_SOCKET_TIMEOUT", 10))
    3334TCP_NODELAY = int(os.environ.get("XPRA_TCP_NODELAY", "1"))
    3435NO_ROOT_WARNING = int(os.environ.get("XPRA_NO_ROOT_WARNING", "0"))
     
    380381                            + " You may specify this option multiple times with different host and port combinations")
    381382    else:
    382383        ignore({"bind-tcp" : []})
     384    try:
     385        from xpra.net import vsock
     386    except:
     387        vsock = None
     388    if vsock:
     389        group.add_option("--bind-vsock", action="append",
     390                          dest="bind_vsock", default=list(defaults.bind_vsock or []),
     391                          metavar="[CID]:[PORT]",
     392                          help="Listen for connections over VSOCK (use --password-file to secure it)."
     393                            + " You may specify this option multiple times with different CID and port combinations")
     394    else:
     395        ignore({"bind-vsock" : []})
    383396    legacy_bool_parse("mdns")
    384397    if (supports_server or supports_shadow):
    385398        group.add_option("--mdns", action="store", metavar="yes|no",
     
    674687    group.add_option("--tcp-auth", action="store",
    675688                      dest="tcp_auth", default=defaults.tcp_auth,
    676689                      help="The authentication module to use for TCP sockets (default: '%default')")
     690    if vsock:
     691        group.add_option("--vsock-auth", action="store",
     692                         dest="vsock_auth", default=defaults.vsock_auth,
     693                         help="The authentication module to use for vsock sockets (default: '%default')")
     694    else:
     695        ignore({"vsock-auth" : ""})
    677696    if os.name=="posix":
    678697        group.add_option("--mmap-group", action="store_true",
    679698                          dest="mmap_group", default=defaults.mmap_group,
     
    10091028        return 128+signal.SIGINT
    10101029
    10111030
     1031def parse_vsock(vsock_str):
     1032    from xpra.net.vsock import STR_TO_CID, CID_ANY, PORT_ANY    #@UnresolvedImport
     1033    if not vsock_str.find(":")>=0:
     1034        raise InitException("invalid vsocket format '%s'" % vsock_str)
     1035    cid_str, port_str = vsock_str.split(":", 1)
     1036    if cid_str.lower() in ("auto", "any"):
     1037        cid = CID_ANY
     1038    else:
     1039        try:
     1040            cid = int(cid_str)
     1041        except ValueError:
     1042            cid = STR_TO_CID.get(cid_str.upper())
     1043            if cid is None:
     1044                raise InitException("invalid vsock cid '%s'" % cid_str)
     1045    if port_str.lower() in ("auto", "any"):
     1046        iport = PORT_ANY
     1047    else:
     1048        try:
     1049            iport = int(port_str)
     1050        except ValueError:
     1051            raise InitException("invalid vsock port '%s'" % port_str)
     1052    return cid, iport
     1053
    10121054def parse_display_name(error_cb, opts, display_name):
    10131055    desc = {"display_name" : display_name}
    10141056    if display_name.lower().startswith("ssh:") or display_name.lower().startswith("ssh/"):
     
    11721214            host = "127.0.0.1"
    11731215        desc["host"] = host
    11741216        return desc
     1217    elif display_name.startswith("vsock:"):
     1218        #use the vsock specified:
     1219        vsock_str = display_name[len("vsock:"):]
     1220        cid, iport = parse_vsock(vsock_str)
     1221        desc.update({
     1222                "type"          : "vsock",
     1223                "local"         : False,
     1224                "display"       : display_name,
     1225                "vsock"         : (cid, iport),
     1226                })
     1227        opts.display = display_name
     1228        return desc
    11751229    elif sys.platform.startswith("win") or display_name.startswith("named-pipe:"):
    11761230        pipe_name = display_name
    11771231        if display_name.startswith("named-pipe:"):
     
    12481302    except InitException:
    12491303        raise
    12501304    except Exception as e:
    1251         raise
    1252     #    traceback.print_stack()
    12531305        raise InitException("connection failed: %s" % e)
    12541306
    12551307def ssh_connect_failed(message):
     
    13911443        conn = NamedPipeConnection(pipe_name, pipe_handle)
    13921444        conn.timeout = SOCKET_TIMEOUT
    13931445
     1446    elif dtype == "vsock":
     1447        cid, iport = display_desc["vsock"]
     1448        from xpra.net.vsock import connect_vsocket
     1449        conn = connect_vsocket(cid=cid, port=iport)
     1450        conn.timeout = VSOCK_TIMEOUT
     1451
    13941452    elif dtype == "tcp":
    13951453        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    13961454        sock.settimeout(SOCKET_TIMEOUT)
  • xpra/scripts/server.py

     
    362362            tcp_sockets.add((host, iport))
    363363    return tcp_sockets
    364364
     365def setup_vsock_socket(cid, iport):
     366    from xpra.log import Logger
     367    log = Logger("network")
     368    try:
     369        from xpra.net.vsock import bind_vsocket     #@UnresolvedImport
     370        vsock_socket = bind_vsocket(cid=cid, port=iport)
     371    except Exception as e:
     372        raise InitException("failed to setup vsock socket on %s:%s %s" % (cid, iport, e))
     373    def cleanup_vsock_socket():
     374        log.info("closing vsock socket %s:%s", cid, iport)
     375        try:
     376            vsock_socket.close()
     377        except:
     378            pass
     379    _cleanups.append(cleanup_vsock_socket)
     380    return "vsock", vsock_socket, (cid, iport)
    365381
     382def parse_bind_vsock(bind_vsock):
     383    vsock_sockets = set()
     384    if bind_vsock:
     385        from xpra.scripts.main import parse_vsock
     386        for spec in bind_vsock:
     387            vsock_sockets.add(parse_vsock(spec))
     388    return vsock_sockets
     389
     390
    366391def normalize_local_display_name(local_display_name):
    367392    if not local_display_name.startswith(":"):
    368393        local_display_name = ":" + local_display_name
     
    10461071        socket = setup_tcp_socket(host, iport)
    10471072        sockets.append(socket)
    10481073        if opts.mdns:
    1049             mdns_recs.append(("tcp", bind_tcp))
     1074            rec = "tcp", [(host, iport)]
     1075            mdns_recs.append(rec)
    10501076
     1077    bind_vsock = parse_bind_vsock(opts.bind_vsock)
     1078    for cid, iport in bind_vsock:
     1079        socket = setup_vsock_socket(cid, iport)
     1080        sockets.append(socket)
     1081        if opts.mdns:
     1082            rec = "vsock", [("", iport)]
     1083            mdns_recs.append(rec)
     1084
    10511085    # Do this after writing out the shell script:
    10521086    if display_name[0] != 'S':
    10531087        os.environ["DISPLAY"] = display_name
  • xpra/net/vsock_client_test.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6
     7import sys
     8from xpra.net.vsock import connect_vsocket, CID_ANY, PORT_ANY       #@UnresolvedImport
     9
     10from xpra.log import Logger
     11log = Logger("network")
     12
     13
     14def main(args):
     15    cid = CID_ANY
     16    port = PORT_ANY
     17    if len(args)>0:
     18        cid = int(args[0])
     19    if len(args)>1:
     20        port = int(args[1])
     21
     22    vsock = connect_vsocket(cid=cid, port=port)
     23    log("vsock=%s", vsock)
     24    data = vsock.recv(1024)
     25    log("recv()=%s", data)
     26
     27if __name__ == "__main__":
     28    sys.exit(main(sys.argv[1:]))
  • xpra/net/vsock.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6#cython: boundscheck=False, wraparound=False, cdivision=True
     7
     8import socket as pysocket
     9import struct
     10from xpra.log import Logger
     11log = Logger("network")
     12
     13
     14cdef extern from "string.h":
     15    void *memset(void * ptr, int value, size_t num) nogil
     16
     17cdef extern from "unistd.h":
     18    int close(int fd)
     19
     20cdef extern from "sys/socket.h":
     21    int AF_VSOCK
     22    int SOCK_DGRAM
     23    int SOCK_STREAM
     24    cdef struct sockaddr:
     25        pass
     26    ctypedef int socklen_t
     27    int socket(int socket_family, int socket_type, int protocol)
     28    int bind(int sockfd, const sockaddr *addr, socklen_t addrlen)
     29    int getsockname(int sockfd, sockaddr *addr, socklen_t *addrlen)
     30    int accept(int sockfd, sockaddr *addr, socklen_t *addrlen)
     31    int connect(int sockfd, const sockaddr *addr, socklen_t addrlen)
     32
     33
     34cdef extern from "linux/vm_sockets.h":
     35    unsigned int VMADDR_CID_ANY
     36    unsigned int VMADDR_CID_HYPERVISOR
     37    unsigned int VMADDR_CID_HOST
     38    unsigned int VMADDR_PORT_ANY
     39
     40
     41    unsigned int SO_VM_SOCKETS_BUFFER_SIZE
     42    unsigned int SO_VM_SOCKETS_BUFFER_MIN_SIZE
     43    unsigned int SO_VM_SOCKETS_BUFFER_MAX_SIZE
     44    unsigned int SO_VM_SOCKETS_PEER_HOST_VM_ID
     45    unsigned int SO_VM_SOCKETS_TRUSTED
     46    unsigned int SO_VM_SOCKETS_CONNECT_TIMEOUT
     47    unsigned int SO_VM_SOCKETS_NONBLOCK_TXRX
     48
     49    ctypedef unsigned short __kernel_sa_family_t
     50    cdef struct sockaddr_vm:
     51        __kernel_sa_family_t svm_family
     52        unsigned short svm_reserved1
     53        unsigned int svm_port
     54        unsigned int svm_cid
     55
     56CID_ANY = VMADDR_CID_ANY
     57CID_HYPERVISOR = VMADDR_CID_HYPERVISOR
     58CID_HOST = VMADDR_CID_HOST
     59PORT_ANY = VMADDR_PORT_ANY
     60
     61CID_TYPES = {
     62             CID_ANY        : "ANY",
     63             CID_HYPERVISOR : "HYPERVISOR",
     64             CID_HOST       : "HOST",
     65             }
     66STR_TO_CID = {
     67              "ANY"         : CID_ANY,
     68              "HYPERVISOR"  : CID_HYPERVISOR,
     69              "HOST"        : CID_HOST,
     70              }
     71
     72SOCK_TYPES = {
     73              SOCK_STREAM   : "STREAM",
     74              SOCK_DGRAM    : "DGRAM",
     75              }
     76
     77
     78def bind_vsocket(sock_type=SOCK_STREAM, cid=VMADDR_CID_HOST, port=VMADDR_PORT_ANY):
     79    log("server_socket(%s)", (SOCK_TYPES.get(sock_type, sock_type), CID_TYPES.get(cid, cid), port))
     80    assert sock_type in (SOCK_STREAM, SOCK_DGRAM), "invalid socket type %s" % sock_type
     81    #assert cid in (VMADDR_CID_ANY, VMADDR_CID_HYPERVISOR, VMADDR_CID_HOST), "invalid cid %s" % cid
     82    assert port==VMADDR_PORT_ANY or (port>0 and port<65536)
     83    log("socket(AF_VSOCK, %s, 0)", SOCK_TYPES.get(sock_type, sock_type))
     84    cdef int sockfd = socket(AF_VSOCK, sock_type, 0)
     85    log("socket(..)=%i", sockfd)
     86    if sockfd<0:
     87        raise Exception("AF_VSOCK not supported")
     88    cdef sockaddr_vm vmsock
     89    memset(&vmsock, 0, sizeof(sockaddr_vm))
     90    vmsock.svm_family = AF_VSOCK
     91    vmsock.svm_cid = cid    #VMADDR_CID_HOST
     92    vmsock.svm_port = port
     93
     94    if bind(sockfd, <sockaddr*> &vmsock, sizeof(sockaddr_vm)):
     95        close(sockfd)
     96        raise Exception("failed to bind to AF_VSOCK socket %i:%i", cid, port)
     97
     98    cdef socklen_t socklen = sizeof(sockaddr_vm)
     99    if getsockname(sockfd, <sockaddr *> &vmsock, &socklen):
     100        close(sockfd)
     101        raise Exception("getsockname failed")
     102    log("cid=%s, port=%i", CID_TYPES.get(vmsock.svm_cid, vmsock.svm_cid), vmsock.svm_port)
     103    vsock = VSocket(sockfd)
     104    return vsock
     105
     106class VSocket(object):
     107    def __init__(self, sockfd):
     108        self.sockfd = sockfd
     109        self.sock = pysocket.fromfd(sockfd, AF_VSOCK, 0)
     110        self.address = None
     111
     112    def __getattr__(self, attr):
     113        return getattr(self.sock, attr)
     114
     115    def accept(self):
     116        cdef sockaddr_vm vmsock
     117        cdef socklen_t socklen = sizeof(sockaddr_vm)
     118        memset(&vmsock, 0, socklen)
     119        cdef int fd = accept(self.sockfd, <sockaddr*> &vmsock, &socklen)
     120        if fd<0:
     121            raise Exception("accept failed: %s" % fd)
     122        conn = pysocket.fromfd(fd, AF_VSOCK, 0)
     123        if getsockname(fd, <sockaddr *> &vmsock, &socklen):
     124            close(fd)
     125            raise Exception("getsockname failed")
     126        self.address = (vmsock.svm_cid, vmsock.svm_port)
     127        return VSocket(conn.fileno()), self.address
     128
     129    def getsockname(self):
     130        return self.address
     131
     132    def __repr__(self):
     133        return "VSocket(%s)" % self.sockfd
     134
     135
     136def connect_vsocket(sock_type=SOCK_STREAM, cid=VMADDR_CID_ANY, port=VMADDR_PORT_ANY):
     137    log("connect_vsocket(%s)", (cid, port, sock_type))
     138    assert sock_type in (SOCK_STREAM, SOCK_DGRAM), "invalid socket type %s" % sock_type
     139    #assert cid in (VMADDR_CID_ANY, VMADDR_CID_HYPERVISOR, VMADDR_CID_HOST), "invalid cid %s" % cid
     140    assert port==VMADDR_PORT_ANY or (port>0 and port<65536)
     141    log("socket(%i, %i, 0)", AF_VSOCK, sock_type)
     142    cdef int sockfd = socket(AF_VSOCK, sock_type, 0)
     143    log("socket(AF_VSOCK, SOCK_DGRAM, 0)=%i", sockfd)
     144    if sockfd<0:
     145        raise Exception("AF_VSOCK not supported")
     146
     147    cdef sockaddr_vm vmsock
     148    memset(&vmsock, 0, sizeof(sockaddr_vm))
     149    vmsock.svm_family = AF_VSOCK
     150    vmsock.svm_cid = cid
     151    vmsock.svm_port = port
     152
     153    if connect(sockfd, <sockaddr *> &vmsock, sizeof(sockaddr_vm)):
     154        raise Exception("failed to connect to server vsock %i:%i" % (cid, port))
     155
     156    vsock = VSocket(sockfd)
     157    return vsock
  • xpra/net/vsock_server_test.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6
     7import sys
     8from xpra.net.vsock import bind_vsocket, CID_HOST, PORT_ANY       #@UnresolvedImport
     9
     10from xpra.log import Logger
     11log = Logger("network")
     12
     13
     14def main(args):
     15    cid = CID_HOST
     16    port = PORT_ANY
     17    if len(args)>0:
     18        cid = int(args[0])
     19    if len(args)>1:
     20        port = int(args[1])
     21    #def server_vsocket(sock_type=SOCK_STREAM, cid=VMADDR_CID_HOST, port=VMADDR_PORT_ANY):
     22    sock = bind_vsocket(cid=cid, port=port)
     23    log("sock=%s", sock)
     24    #import time
     25    #time.sleep(10)
     26    sock.listen(1)
     27    log("listening")
     28    while True:
     29        connection, client_address = sock.accept()
     30        log("new connection! %s", (connection, client_address))
     31        data = connection.recv(1024)
     32        log("got data: %s" % data)
     33        connection.send("hello")
     34    return 0
     35
     36if __name__ == "__main__":
     37    sys.exit(main(sys.argv[1:]))