[Spice-commits] 3 commits - common/vdcommon.h tests/clipboard.py vdagent/desktop_layout.cpp vdagent/desktop_layout.h vdagent/vdagent.vcproj vdservice/vdservice.cpp vdservice/vdservice.vcproj

Alon Levy alon at kemper.freedesktop.org
Fri Aug 27 07:44:32 PDT 2010


 common/vdcommon.h          |    2 
 tests/clipboard.py         |  308 +++++++++++++++++++++++++++++++++++++++++++++
 vdagent/desktop_layout.cpp |   19 --
 vdagent/desktop_layout.h   |    1 
 vdagent/vdagent.vcproj     |    8 +
 vdservice/vdservice.cpp    |   31 ++++
 vdservice/vdservice.vcproj |    4 
 7 files changed, 352 insertions(+), 21 deletions(-)

New commits:
commit 349e6a5bf8804b25c3af6e1f439122a7cc269cc2
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Aug 24 14:53:03 2010 +0300

    vdservice: don't start when no qxl device present

diff --git a/common/vdcommon.h b/common/vdcommon.h
index 1097720..24d18d6 100644
--- a/common/vdcommon.h
+++ b/common/vdcommon.h
@@ -63,5 +63,7 @@ typedef struct VDPipeState {
     VDPipeBuffer read;
 } VDPipeState;
 
+bool get_qxl_device_id(TCHAR* device_key, DWORD* device_id);
+
 #endif
 
diff --git a/vdagent/desktop_layout.cpp b/vdagent/desktop_layout.cpp
index 32502bc..b7a6b9c 100644
--- a/vdagent/desktop_layout.cpp
+++ b/vdagent/desktop_layout.cpp
@@ -17,6 +17,7 @@
 
 #include "desktop_layout.h"
 #include "vdlog.h"
+#include "vdcommon.h"
 
 void DisplayMode::set_res(DWORD width, DWORD height, DWORD depth)
 {
@@ -155,24 +156,6 @@ bool DesktopLayout::is_attached(LPCTSTR dev_name)
     return !!dev_mode.dmBitsPerPel;
 }
 
-bool DesktopLayout::get_qxl_device_id(WCHAR* device_key, DWORD* device_id)
-{
-    DWORD type = REG_BINARY;
-    DWORD size = sizeof(*device_id);
-    bool key_found = false;
-    HKEY key;
-
-    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, wcsstr(device_key, L"System"),
-                     0L, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
-        if (RegQueryValueEx(key, L"QxlDeviceID", NULL, &type, (LPBYTE)device_id, &size) ==
-                                                                             ERROR_SUCCESS) {
-            key_found = true;
-        }
-        RegCloseKey(key);
-    }
-    return key_found;
-}
-
 void DesktopLayout::init_dev_mode(DEVMODE* dev_mode, DisplayMode* mode, bool set_pos)
 {
     ZeroMemory(dev_mode, sizeof(DEVMODE));
diff --git a/vdagent/desktop_layout.h b/vdagent/desktop_layout.h
index a43ee49..fe70e36 100644
--- a/vdagent/desktop_layout.h
+++ b/vdagent/desktop_layout.h
@@ -72,7 +72,6 @@ public:
 private:
     void clean_displays();
     static bool is_attached(LPCTSTR dev_name);
-    static bool get_qxl_device_id(WCHAR* device_key, DWORD* device_id);
     static void init_dev_mode(DEVMODE* dev_mode, DisplayMode* mode, bool set_pos);
 
 private:
diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
index 108728b..2c91185 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -509,6 +509,10 @@
 				RelativePath="..\common\vdlog.cpp"
 				>
 			</File>
+			<File
+				RelativePath="..\common\vdcommon.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Header Files"
@@ -535,6 +539,10 @@
 				RelativePath="..\common\vdlog.h"
 				>
 			</File>
+			<File
+				RelativePath="..\common\vdcommon.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 6fec0c1..8cd485e 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -140,6 +140,27 @@ int supported_system_version()
     return 0;
 }
 
+bool has_qxl_device()
+{
+    DISPLAY_DEVICE dev_info;
+    bool ret = false;
+    DWORD dev_id = 0;
+    DWORD qxl_id;
+
+    ZeroMemory(&dev_info, sizeof(dev_info));
+    dev_info.cb = sizeof(dev_info);
+    while (EnumDisplayDevices(NULL, dev_id, &dev_info, 0)) {
+        if (wcsstr(dev_info.DeviceString, L"QXL") != NULL
+            && get_qxl_device_id(dev_info.DeviceKey, &qxl_id)) {
+            vd_printf("found QXL device at id %d, qxl_id %d", dev_id, qxl_id);
+            ret = true;
+            break;
+        }
+        dev_id++;
+    }
+    return ret;
+}
+
 VDService::VDService()
     : _status_handle (0)
     , _vdi_port (NULL)
@@ -338,8 +359,10 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[])
         swprintf_s(log_path, MAX_PATH, VD_SERVICE_LOG_PATH, temp_path);
         s->_log = VDLog::get(log_path);
     }
+
     vd_printf("***Service started***");
     log_version();
+
     if (!SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS)) {
         vd_printf("SetPriorityClass failed %u", GetLastError());
     }
@@ -369,8 +392,12 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[])
     status->dwCurrentState = SERVICE_RUNNING;
     SetServiceStatus(s->_status_handle, status);
 
-    s->_running = true;
-    s->execute();
+    if (has_qxl_device()) {
+        s->_running = true;
+        s->execute();
+    } else {
+        vd_printf("didn't find any qxl devices\n");
+    }
 
     // service was stopped
     status->dwCurrentState = SERVICE_STOP_PENDING;
diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj
index 85d5c8e..61fbedc 100644
--- a/vdservice/vdservice.vcproj
+++ b/vdservice/vdservice.vcproj
@@ -531,6 +531,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\common\vdcommon.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\vdservice.cpp"
 				>
 			</File>
commit 53133102f6133379746fbf8c98719b192409e6f6
Merge: f064c62... 5833dc9...
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Aug 24 11:07:53 2010 +0300

    Merge branch 'master' of git://anongit.freedesktop.org/spice/win32/vd_agent

commit f064c627efa2fa22c883e633c1e4373a20f71517
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 23 19:43:39 2010 +0300

    clipboard tester

diff --git a/tests/clipboard.py b/tests/clipboard.py
new file mode 100755
index 0000000..f70aece
--- /dev/null
+++ b/tests/clipboard.py
@@ -0,0 +1,308 @@
+"""
+Usage:
+ run with --help
+
+Example invocations:
+
+Test client paste:
+ guest side, listen for connection, compare paste to socketed data.
+ python clipboard.py --server
+ host side, connect to other side, paste messages of 20000 bytes (defaults to 1000, settable with -N).
+ python clipboard.py --client --dest <guest ip> --paste -n 20000
+
+To test guest paste, put --paste on guest invocation and remove from client.
+"""
+
+import sys
+import hashlib
+import socket
+import random
+import os
+import cPickle
+import subprocess
+import time
+
+first_port = 9876
+ports_tried = 10
+
+N = 1000
+
+verbose = False
+opts = None    # options set from command line
+
+global xsel_process
+xsel_process = None
+
+def win_set_pastebuffer(msg, aType=None):
+    import win32clipboard as w
+    import win32con
+    if aType is None:
+        aType = win32con.CF_TEXT
+    w.OpenClipboard()
+    w.EmptyClipboard()
+    w.SetClipboardData(aType, msg) 
+    w.CloseClipboard()
+
+def win_get_pastebuffer():
+    import win32clipboard as w
+    import win32con
+    w.OpenClipboard()
+    d = w.GetClipboardData(win32con.CF_TEXT)
+    w.CloseClipboard()
+    return d
+
+def x11_get_pastebuffer():
+    s=subprocess.Popen('xsel', stdout=subprocess.PIPE)
+    sel = s.stdout.read()
+    s.wait()
+    return sel
+
+def x11_set_pastebuffer(msg):
+    global spicec_window
+    global console_window
+    global xsel_process
+    if xsel_process:
+        if verbose:
+            print "killing %s" % xsel_process.pid
+        xsel_process.terminate()
+        xsel_process.wait()
+    xsel_process = subprocess.Popen('xsel', stdin=subprocess.PIPE)
+    xsel_process.stdin.write(msg)
+    xsel_process.stdin.close()
+    time.sleep(opts.target_pre_activate)
+    # now activate spice window so the text is actually sent to the guest
+    spicec_window.activate(0) # needs a timestamp, can't figure out the real one, zero works with a warning
+    time.sleep(opts.target_post_activate)
+    console_window.activate(0)
+    time.sleep(opts.console_post_activate)
+    # we kill xsel on the next iteration (thereby killing the pastebuffer)
+
+def get_both_windows():
+    import wnck
+    import gtk
+    import gobject
+    def getonce():
+        s = wnck.screen_get_default()
+        ws = s.get_windows()
+        return ws
+    w = [w for w in getonce() if w.get_name().startswith('SPICEc:0')]
+    # run gtk event loop long enough to register all window names
+    gobject.idle_add(gtk.main_quit)
+    gtk.main()
+    w = [w for w in getonce() if w.get_name().startswith('SPICEc:0')]
+    if len(w) != 1:
+        if len(w) > 1:
+            print "more then one spice window:", w
+            import pdb; pdb.set_trace()
+        else:
+            print "no spice windows"
+            import pdb; pdb.set_trace()
+            sys.exit(-1)
+    return w[0], wnck.screen_get_default().get_active_window()
+
+if sys.platform == 'win32':
+    set_pastebuffer = win_set_pastebuffer
+    get_pastebuffer = win_get_pastebuffer
+else:
+    global spicec_window
+    global console_window
+    spicec_window, console_window = get_both_windows()
+    set_pastebuffer = x11_set_pastebuffer
+    get_pastebuffer = x11_get_pastebuffer
+
+def compute_md5(msg):
+    return hashlib.md5(msg).hexdigest()
+
+def set_and_md5(msg):
+    h = compute_md5(msg)
+    set_pastebuffer(msg)
+    return h
+
+def paste_and_md5_random_string(n):
+    s = random.randint(0,1000)
+    msg = ''.join([str(x+s) for x in xrange(n)])[:n]
+    return set_and_md5(msg), msg
+
+def getsock(HOST, PORT):
+    s = None
+    for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM):
+        af, socktype, proto, canonname, sa = res
+        try:
+            s = socket.socket(af, socktype, proto)
+        except socket.error, msg:
+            s = None
+            continue
+        try:
+            s.connect(sa)
+        except socket.error, msg:
+            s.close()
+            s = None
+            continue
+        break
+    return s
+
+def client(opts):
+    print "starting client - %s:%s-%s" % (opts.dest, first_port, first_port+ports_tried-1)
+    for p in xrange(first_port, first_port + ports_tried):
+        s=getsock(opts.dest, p)
+        if s:
+            break
+    print "port = %s" % p
+    if not s:
+        print "could not open socket"
+        exit(-1)
+    return s
+
+def paste_many(s, n, N):
+    print ">>> start pasting <<<"
+    for i in xrange(N):
+        if i % 10 == 0:
+            print "%s/%s" % (i, N)
+        md5, msg = paste_and_md5_random_string(n)
+        s.send(cPickle.dumps((md5,msg)) + '\n')
+        answer = cPickle.loads(s.recv(1024))
+        if answer != md5:
+            print "%s: failed: sent %s, got %s" % (i, md5, answer)
+            break
+    print "%s passed" % N
+
+def sign_pasted(s, paste=False):
+    print ">>> start signing <<<"
+    i = 0
+    last_paste = ''
+    while True:
+        i += 1
+        pasted_md5, pasted_from_file = pickle_from_socket(s)
+        pastebuffer = get_pastebuffer()
+        waits = 0
+        # sometimes it takes a while for the new paste buffer to register
+        # - needs further investigation
+        while ((last_paste == pastebuffer
+               or not set(pastebuffer) <= numbers)
+               and waits < 30):
+            print "!",pastebuffer[:20]
+            waits += 1
+            time.sleep(0.2)
+            pastebuffer = get_pastebuffer()
+        last_paste = pastebuffer
+   
+        if pastebuffer != pasted_from_file:
+            import pdb; pdb.set_trace()
+        computed_md5 = compute_md5(pastebuffer)
+        s.send(cPickle.dumps(computed_md5) + '\n')
+        if computed_md5 != pasted_md5:
+            print "%s: error on text of length %s" % (i, len(pastebuffer))
+            import pdb; pdb.set_trace()
+        if verbose:
+            print i
+
+def getopts():
+    global verbose
+    import optparse
+    import sys
+    parser = optparse.OptionParser()
+    parser.add_option('--paste', action='store_true', help="do paste to other side (if not present sign other side and send back)")
+    parser.add_option('--server', action='store_true', help="listen to socket")
+    parser.add_option('--client', action='store_true', help="connect to socket")
+    parser.add_option('--paste1', action='store_true', help="do a single send")
+    parser.add_option('--sleep1', type='float', help="sleep after paste1")
+    parser.add_option('--get1', action='store_true', help="do a single read")
+    parser.add_option('--dest', help="destination address for client")
+    parser.add_option('-N', default=N, type='int', help="set number of iterations")
+    parser.add_option('-n', default=100, type='int', help="set length of test strings")
+    parser.add_option('-v', action='count', default=False, help="be more verbose")
+    parser.add_option('--target_pre_activate', type='float', default=0.1, help='time to sleep before target activation')
+    parser.add_option('--target_post_activate', type='float', default=0.1, help='time to sleep after target activation')
+    parser.add_option('--console_post_activate', type='float', default=0.1, help='time to sleep before console activation')
+    opts, rest = parser.parse_args(sys.argv[1:])
+    if opts.v is not None:
+        verbose = opts.v
+    is_server = opts.server
+    if opts.client and opts.dest is None:
+        parser.print_help()
+        raise SystemExit
+    return is_server, opts
+
+def accept_one(port):
+    HOST = None
+    PORT = port
+    s = None
+    for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
+                                  socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
+        af, socktype, proto, canonname, sa = res
+        try:
+            s = socket.socket(af, socktype, proto)
+        except socket.error, msg:
+            print msg
+            s = None
+            continue
+        try:
+            s.bind(sa)
+            s.listen(1)
+        except socket.error, msg:
+            print msg
+            s.close()
+            s = None
+            continue
+        break
+    if s is None:
+        print 'could not open socket'
+        return None
+    conn, addr = s.accept()
+    print 'Connected by', addr
+    return conn
+
+numbers = set('0123456789')
+
+def pickle_from_socket(s):
+    """ for buffers larger then a certain size you get multiple
+    intermediate results from recv - concat them together """
+    getmore = True
+    r = []
+    while getmore:
+      r.append(s.recv(1024*1024))
+      if r[-1] == '':
+        print "socket closed, exiting"
+        sys.exit(0)
+      try:
+        res = cPickle.loads(''.join(r))
+      except:
+        pass
+      else:
+        break
+    return res
+
+def run_socket(s, opts):
+    if opts.paste:
+        paste_many(s, n=opts.n, N=opts.N)
+    else:
+        sign_pasted(s)
+
+def run_client(opts):
+    run_socket(client(opts), opts=opts)
+
+def run_server(opts):
+    import sys
+    for p in xrange(first_port, first_port+ports_tried):
+        s = accept_one(p)
+        if s:
+           break
+    assert(s is not None)
+    print "port = %s" % p
+    run_socket(s, opts)
+
+if __name__ == '__main__':
+    is_server, opts = getopts()
+    if opts.paste1:
+        paste_and_md5_random_string(opts.n)
+        if opts.sleep1:
+            time.sleep(opts.sleep1)
+    elif opts.get1:
+        pastebuffer = get_pastebuffer()
+        computed_md5 = compute_md5(pastebuffer)
+        print "got %d bytes, md5 = %s" % (len(pastebuffer), computed_md5)
+    elif is_server:
+        run_server(opts)
+    else:
+        run_client(opts)
+


More information about the Spice-commits mailing list