diff --git a/README.md b/README.md
index ccf51ea..4d1b1e5 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,23 @@ Running in Chrome before and after connecting:
See more screenshots here.
+### Projects/Companies using noVNC
+
+* [Sentry Data Systems](http://www.sentryds.com): uses noVNC in the
+ [Datanex Cloud Computing Platform](http://www.sentryds.com/products/datanex/).
+
+* [Ganeti Web Manager](http://code.osuosl.org/projects/ganeti-webmgr):
+ Feature [#1935](http://code.osuosl.org/issues/1935).
+
+* [Archipel](http://archipelproject.org):
+ [Video demo](http://antoinemercadal.fr/archipelblog/wp-content/themes/ArchipelWPTemplate/video_youtube.php?title=VNC%20Demonstration&id=te_bzW574Zo)
+
+* [openQRM](http://www.openqrm.com/): VNC plugin available
+ by request. Probably included in [version
+ 4.8](http://www.openqrm.com/?q=node/15). [Video
+ demo](http://www.openqrm-enterprise.com/news/details/article/remote-vm-console-plugin-available.html).
+
+
### Browser Requirements
* HTML5 Canvas: Except for Internet Explorer, most
diff --git a/docs/links b/docs/links
index 64ea754..8cb4da1 100644
--- a/docs/links
+++ b/docs/links
@@ -35,6 +35,10 @@ Cursor appearance/style (for Cursor pseudo-encoding):
https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
+RDP Protocol specification:
+ http://msdn.microsoft.com/en-us/library/cc240445(v=PROT.10).aspx
+
+
Related projects:
guacamole: http://guacamole.sourceforge.net/
diff --git a/include/canvas.js b/include/canvas.js
index 03a1e68..e28c3b0 100644
--- a/include/canvas.js
+++ b/include/canvas.js
@@ -109,6 +109,7 @@ function constructor() {
if (! conf.ctx) { conf.ctx = c.getContext('2d'); }
ctx = conf.ctx;
+ Util.Debug("User Agent: " + navigator.userAgent);
if (UE.gecko) { Util.Debug("Browser: gecko " + UE.gecko); }
if (UE.webkit) { Util.Debug("Browser: webkit " + UE.webkit); }
if (UE.trident) { Util.Debug("Browser: trident " + UE.trident); }
@@ -216,7 +217,7 @@ function constructor() {
}
/* Translate DOM key down/up event to keysym value */
-function getKeysym(e) {
+that.getKeysym = function(e) {
var evt, keysym;
evt = (e ? e : window.event);
@@ -362,24 +363,24 @@ function onMouseMove(e) {
}
function onKeyDown(e) {
- //Util.Debug("keydown: " + getKeysym(e));
+ //Util.Debug("keydown: " + that.getKeysym(e));
if (! conf.focused) {
return true;
}
if (c_keyPress) {
- c_keyPress(getKeysym(e), 1);
+ c_keyPress(that.getKeysym(e), 1);
}
Util.stopEvent(e);
return false;
}
function onKeyUp(e) {
- //Util.Debug("keyup: " + getKeysym(e));
+ //Util.Debug("keyup: " + that.getKeysym(e));
if (! conf.focused) {
return true;
}
if (c_keyPress) {
- c_keyPress(getKeysym(e), 0);
+ c_keyPress(that.getKeysym(e), 0);
}
Util.stopEvent(e);
return false;
diff --git a/include/rfb.js b/include/rfb.js
index 7536ddc..6adccd4 100644
--- a/include/rfb.js
+++ b/include/rfb.js
@@ -254,7 +254,8 @@ function constructor() {
Util.Info("Using native WebSockets");
updateState('loaded', 'noVNC ready: native WebSockets, ' + rmode);
} else {
- Util.Warn("Using web-socket-js flash bridge");
+ Util.Warn("Using web-socket-js bridge. Flash version: " +
+ Util.Flash.version);
if ((! Util.Flash) ||
(Util.Flash.version < 9)) {
updateState('fatal', "WebSockets or Adobe Flash is required");
diff --git a/tests/keyboard.html b/tests/keyboard.html
new file mode 100644
index 0000000..2d6df05
--- /dev/null
+++ b/tests/keyboard.html
@@ -0,0 +1,67 @@
+
+
Input Test
+
+
+
+ Canvas:
+
+
+
+ Results:
+
+
+
+
+
+
+
+
+
+
diff --git a/utils/websocket.c b/utils/websocket.c
index 4a124f1..f73bb22 100644
--- a/utils/websocket.c
+++ b/utils/websocket.c
@@ -187,6 +187,7 @@ int ws_socket_free(ws_ctx_t *ctx) {
ctx->ssl_ctx = NULL;
}
if (ctx->sockfd) {
+ shutdown(ctx->sockfd, SHUT_RDWR);
close(ctx->sockfd);
ctx->sockfd = 0;
}
@@ -350,26 +351,30 @@ ws_ctx_t *do_handshake(int sock) {
handshake[len] = 0;
if (len == 0) {
handler_msg("ignoring empty handshake\n");
- close(sock);
return NULL;
} else if (bcmp(handshake, "", 22) == 0) {
len = recv(sock, handshake, 1024, 0);
handshake[len] = 0;
handler_msg("sending flash policy response\n");
send(sock, policy_response, sizeof(policy_response), 0);
- close(sock);
return NULL;
} else if ((bcmp(handshake, "\x16", 1) == 0) ||
(bcmp(handshake, "\x80", 1) == 0)) {
// SSL
- if (! settings.cert) { return NULL; }
+ if (!settings.cert) {
+ handler_msg("SSL connection but no cert specified\n");
+ return NULL;
+ } else if (access(settings.cert, R_OK) != 0) {
+ handler_msg("SSL connection but '%s' not found\n",
+ settings.cert);
+ return NULL;
+ }
ws_ctx = ws_socket_ssl(sock, settings.cert, settings.key);
if (! ws_ctx) { return NULL; }
scheme = "wss";
handler_msg("using SSL socket\n");
} else if (settings.ssl_only) {
handler_msg("non-SSL connection disallowed\n");
- close(sock);
return NULL;
} else {
ws_ctx = ws_socket(sock);
@@ -380,14 +385,12 @@ ws_ctx_t *do_handshake(int sock) {
len = ws_recv(ws_ctx, handshake, 4096);
if (len == 0) {
handler_emsg("Client closed during handshake\n");
- close(sock);
return NULL;
}
handshake[len] = 0;
if (!parse_handshake(handshake, &headers)) {
handler_emsg("Invalid WS request\n");
- close(sock);
return NULL;
}
@@ -524,8 +527,7 @@ void start_server() {
if (pid == 0) { // handler process
ws_ctx = do_handshake(csock);
if (ws_ctx == NULL) {
- close(csock);
- handler_msg("No connection after handshake");
+ handler_msg("No connection after handshake\n");
break; // Child process exits
}
@@ -533,13 +535,22 @@ void start_server() {
if (pipe_error) {
handler_emsg("Closing due to SIGPIPE\n");
}
- close(csock);
- handler_msg("handler exit\n");
break; // Child process exits
} else { // parent process
settings.handler_id += 1;
}
}
+ if (pid == 0) {
+ if (ws_ctx) {
+ ws_socket_free(ws_ctx);
+ } else {
+ shutdown(csock, SHUT_RDWR);
+ close(csock);
+ }
+ handler_msg("handler exit\n");
+ } else {
+ handler_msg("wsproxy exit\n");
+ }
}
diff --git a/utils/websocket.py b/utils/websocket.py
index b4bc01e..70748c1 100755
--- a/utils/websocket.py
+++ b/utils/websocket.py
@@ -112,6 +112,11 @@ def do_handshake(sock):
sock.close()
return False
elif handshake[0] in ("\x16", "\x80"):
+ if not os.path.exists(settings['cert']):
+ handler_msg("SSL connection but '%s' not found"
+ % settings['cert'])
+ sock.close()
+ return False
retsock = ssl.wrap_socket(
sock,
server_side=True,
diff --git a/utils/wsproxy.c b/utils/wsproxy.c
index dc8b5f7..5ba2206 100644
--- a/utils/wsproxy.c
+++ b/utils/wsproxy.c
@@ -257,6 +257,10 @@ int main(int argc, char *argv[])
};
settings.cert = realpath("self.pem", NULL);
+ if (!settings.cert) {
+ /* Make sure it's always set to something */
+ settings.cert = "self.pem";
+ }
settings.key = "";
while (1) {
@@ -326,9 +330,11 @@ int main(int argc, char *argv[])
}
if (ssl_only) {
- if (!settings.cert || !access(settings.cert, R_OK)) {
- usage("SSL only and cert file not found\n");
+ if (!access(settings.cert, R_OK)) {
+ usage("SSL only and cert file '%s' not found\n", settings.cert);
}
+ } else if (access(settings.cert, R_OK) != 0) {
+ fprintf(stderr, "Warning: '%s' not found\n", settings.cert);
}
//printf(" verbose: %d\n", settings.verbose);
diff --git a/utils/wsproxy.py b/utils/wsproxy.py
index c5339b7..378e474 100755
--- a/utils/wsproxy.py
+++ b/utils/wsproxy.py
@@ -162,6 +162,8 @@ if __name__ == '__main__':
if options.ssl_only and not os.path.exists(options.cert):
parser.error("SSL only and %s not found" % options.cert)
+ elif not os.path.exists(options.cert):
+ print "Warning: %s not found" % options.cert
settings['verbose'] = options.verbose
settings['listen_host'] = host