[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