]> andersk Git - test.git/commitdiff
Started working on support for WebSockets.
authorMarkus Gutschke <markus@shellinabox.com>
Mon, 29 Mar 2010 16:40:17 +0000 (16:40 +0000)
committerMarkus Gutschke <markus@shellinabox.com>
Mon, 29 Mar 2010 16:40:17 +0000 (16:40 +0000)
Fixed some compiler warnings when compiling with -Wextra

Thanks to Jan Jaeger's excellent bug report, made some changes
that should make it easier to build ShellInABox for OpenWRT.

29 files changed:
COPYING
ChangeLog
Makefile.am
Makefile.in
config.h
config.h.in
configure
configure.ac
debian/copyright
demo/vt100.js
libhttp/http.h
libhttp/httpconnection.c
libhttp/httpconnection.h
libhttp/libhttp.sym
libhttp/server.c
libhttp/server.h
libhttp/ssl.c
libhttp/url.c
shellinabox/launcher.c
shellinabox/privileges.c
shellinabox/service.c
shellinabox/service.h
shellinabox/session.c
shellinabox/shell_in_a_box.js
shellinabox/shell_in_a_box.jspp
shellinabox/shellinaboxd.c
shellinabox/usercss.c
shellinabox/vt100.js
shellinabox/vt100.jspp

diff --git a/COPYING b/COPYING
index 29922434498056d43bc1c0eda6693d9949251425..ad46cef5b8f98e647e355aa598181ee6b376eb01 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License version 2 as
index 2a519ac5caa80dea59402379ce44dce64cc8458f..339feb0364467bc7284b111246003b991511e117 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-03-29  Markus Gutschke  <markus@shellinabox.com>
+
+       * Started working on support for WebSockets.
+
+       * Fixed some compiler warnings when compiling with -Wextra
+
+       * Thanks to Jan Jaeger's excellent bug report, made some changes
+       that should make it easier to build ShellInABox for OpenWRT.
+
 2009-12-10  Markus Gutschke  <markus@shellinabox.com>
 
        * Add .note.GNU-stack to all object files so that the generated
index f0ab2f6748c935bcc23ab5bae0041d43e1729a15..ef5a89ccf04608959094cd13f9a327e79136da0d 100644 (file)
@@ -2,6 +2,8 @@ AM_CPPFLAGS          =
 AM_CFLAGS            = -g -std=gnu99 -Wall
 AM_LDFLAGS           = -g
 
+OBJCOPY             ?= objcopy
+
 noinst_LTLIBRARIES   = libhttp.la                                             \
                        liblogging.la
 noinst_DATA          = $(top_srcdir)/demo/demo.js
@@ -234,37 +236,37 @@ clean-local:
        -rm -rf GNU-stack
 
 .css.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 .gif.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 
 .html.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 
 .ico.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 
@@ -280,20 +282,20 @@ shellinabox/shell_in_a_box.o: shellinabox/shell_in_a_box.js config.h
             "$<" >"$@"
 
 .js.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 
 .wav.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 
index 75627b319cbd8e1ac4d3d00db7ef5cb18793dad1..5620d3e5d5ad5f520f57e925ee3791a6447705ff 100644 (file)
@@ -1152,6 +1152,8 @@ uninstall-man: uninstall-man1
        uninstall-man uninstall-man1
 
 
+OBJCOPY             ?= objcopy
+
 libtool: $(LIBTOOL_DEPS)
        $(SHELL) ./config.status --recheck
 
@@ -1247,35 +1249,35 @@ clean-local:
        -rm -rf GNU-stack
 
 .css.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 .gif.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 .html.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 .ico.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 shellinabox/shell_in_a_box.o: shellinabox/shell_in_a_box.js config.h
@@ -1290,19 +1292,19 @@ shellinabox/shell_in_a_box.o: shellinabox/shell_in_a_box.js config.h
             "$<" >"$@"
 
 .js.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 .wav.o:
-       @echo objcopy "$<" "$@"
-       @objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`   \
+       @echo $(OBJCOPY) "$<" "$@"
+       @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
          "$<" "$@"
        @-printf '\000' >GNU-stack &&                                         \
-         objcopy --add-section .note.GNU-stack=GNU-stack "$@";               \
+         $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@";            \
          rm -f GNU-stack
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
index 15dd68f5d9715550768205f9d07c8e05a07c51a4..0b51859eaef60f4d41c78fca0d8111ba0ef969c0 100644 (file)
--- a/config.h
+++ b/config.h
@@ -25,6 +25,9 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #define HAVE_INTTYPES_H 1
 
+/* Define to 1 if you have support for isnan */
+#define HAVE_ISNAN 1
+
 /* Define to 1 if you have the <libutil.h> header file. */
 /* #undef HAVE_LIBUTIL_H */
 
 #define STDC_HEADERS 1
 
 /* Most recent revision number in the version control system */
-#define VCS_REVISION "200"
+#define VCS_REVISION "202"
 
 /* Version number of package */
 #define VERSION "2.10"
index 692ce14559c45b996a7ea2a4e2cdb9ee08567562..000e338d9592f56dc80d440d8945b71f50c7fb51 100644 (file)
@@ -24,6 +24,9 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
+/* Define to 1 if you have support for isnan */
+#undef HAVE_ISNAN
+
 /* Define to 1 if you have the <libutil.h> header file. */
 #undef HAVE_LIBUTIL_H
 
index 1626dd109edc3887312095dac960794f819c541b..b6178194ad59302cc5dddf22595989ef03160b42 100755 (executable)
--- a/configure
+++ b/configure
@@ -2325,7 +2325,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
-VCS_REVISION=200
+VCS_REVISION=202
 
 
 cat >>confdefs.h <<_ACEOF
@@ -10682,6 +10682,25 @@ if ac_fn_c_try_link "$LINENO"; then :
 
 $as_echo "#define HAVE_SIGWAIT 1" >>confdefs.h
 
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <math.h>
+int
+main ()
+{
+isnan(0.0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_ISNAN 1" >>confdefs.h
+
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
index a42b0e50dca1828b624f1bec5e54433f259ef361..70ffbc4c71f7a69304bdd1b7192f01e1aa3933f0 100644 (file)
@@ -2,7 +2,7 @@ AC_PREREQ(2.57)
 
 dnl This is the one location where the authoritative version number is stored
 AC_INIT(shellinabox, 2.10, markus@shellinabox.com)
-VCS_REVISION=200
+VCS_REVISION=202
 AC_SUBST(VCS_REVISION)
 AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
                    [Most recent revision number in the version control system])
@@ -55,6 +55,12 @@ AC_TRY_LINK([#include <pthread.h>
             [AC_DEFINE(HAVE_SIGWAIT, 1,
                        Define to 1 if you have a working sigwait)])
 
+dnl Not every system has support for isnan()
+AC_TRY_LINK([#include <math.h>],
+            [isnan(0.0);],
+            [AC_DEFINE(HAVE_ISNAN, 1,
+                       Define to 1 if you have support for isnan)])
+
 dnl On some systems, calling /bin/login does not work. Disable the LOGIN
 dnl feature, if the user tells us that it does not do the right thing.
 AC_ARG_ENABLE(login,
index f86ac29f70c497cd8c35199242e9078aacfd3cca..cf4aaf732e0e422d8a9460017606c64eeb870077 100644 (file)
@@ -5,7 +5,7 @@ It was downloaded from http://shellinabox.com/
 
 Upstream Author: markus@shellinabox.com
 
-Copyright (c) 2008-2009, Markus Gutschke
+Copyright (c) 2008-2010, Markus Gutschke
 All rights reserved.
 
 This program is free software; you can redistribute it and/or modify
index c46e0c0a1f3e78d3c2acfc2e60eee4f57a7d8230..e6fbf7980510456e10d0ad5c53c93d1fdd380104 100644 (file)
@@ -1,5 +1,5 @@
 // VT100.js -- JavaScript based terminal emulator
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -1955,8 +1955,8 @@ VT100.prototype.toggleBell = function() {
 };
 
 VT100.prototype.about = function() {
-  alert("VT100 Terminal Emulator " + "2.10 (revision 200)" +
-        "\nCopyright 2008-2009 by Markus Gutschke\n" +
+  alert("VT100 Terminal Emulator " + "2.10 (revision 202)" +
+        "\nCopyright 2008-2010 by Markus Gutschke\n" +
         "For more information check http://shellinabox.com");
 };
 
index e7840fa668359a273c4becb87a5244c09f7f0311..cec2fe09a6f40d88d14874419e6839e29ee4cbf7 100644 (file)
@@ -1,5 +1,5 @@
 // http.h -- Library for implementing embedded custom HTTP servers
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
 #define HTTP_SUSPEND       3
 #define HTTP_PARTIAL_REPLY 4
 
+#define WS_START_OF_FRAME    0x0100
+#define WS_END_OF_FRAME      0x0200
+#define WS_CONNECTION_OPENED 0xFF00
+#define WS_CONNECTION_CLOSED 0x7F00
+
 #define NO_MSG             "\001"
+#define BINARY_MSG         "\001%d%p"
 
 #define NOINTR(x) ({ int i__; while ((i__ = (x)) < 0 && errno == EINTR); i__;})
 
@@ -77,6 +83,9 @@ void serverRegisterHttpHandler(Server *server, const char *url,
 void serverRegisterStreamingHttpHandler(Server *server, const char *url,
                                int (*handler)(HttpConnection *, void *),
                                void *arg);
+void serverRegisterWebSocketHandler(Server *server, const char *url,
+              int (*handler)(HttpConnection *, void *, int, const char *, int),
+              void *arg);
 ServerConnection *serverAddConnection(Server *server, int fd,
                               int (*handleConnection)(ServerConnection *,
                                                       void *arg, short *events,
@@ -109,6 +118,10 @@ void *httpSetPrivate(HttpConnection *http, void *private);
 void httpSendReply(HttpConnection *http, int code,
                    const char *msg, const char *fmt, ...)
   __attribute__((format(printf, 4, 5)));
+void httpSendWebSocketTextMsg(HttpConnection *http, int type, const char *fmt,
+                              ...) __attribute__((format(printf, 3, 4)));
+void httpSendWebSocketBinaryMsg(HttpConnection *http, int type,
+                                const void *buf, int len);
 void httpExitLoop(HttpConnection *http, int exitAll);
 Server *httpGetServer(const HttpConnection *http);
 ServerConnection *httpGetServerConnection(const HttpConnection *);
index c8e69f6d39ded29314d2e25d39956a9a6d8b4ee9..ad391fa93b304d62dd46be1eadbf18b1783d75b3 100644 (file)
@@ -1,5 +1,5 @@
 // httpconnection.c -- Manage state machine for HTTP connections
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -66,6 +66,9 @@
 #ifdef HAVE_STRLCAT
 #define strncat(a,b,c) ({ char *_a = (a); strlcat(_a, (b), (c)+1); _a; })
 #endif
+#ifndef HAVE_ISNAN
+#define isnan(x) ({ typeof(x) _x = (x); _x != _x; })
+#endif
 #define max(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b);                  \
                      _a > _b ? _a : _b; })
 
@@ -223,8 +226,9 @@ static char *strcasestr(const char *haystack, const char *needle) {
 
 static int httpFinishCommand(struct HttpConnection *http) {
   int rc            = HTTP_DONE;
-  if (http->callback && !http->done) {
-    rc              = http->callback(http, http->arg, NULL, 0);
+  if ((http->callback || http->websocketHandler) && !http->done) {
+    rc              = http->callback ? http->callback(http, http->arg, NULL, 0)
+       : http->websocketHandler(http, http->arg, WS_CONNECTION_CLOSED, NULL,0);
     check(rc != HTTP_SUSPEND);
     check(rc != HTTP_PARTIAL_REPLY);
     http->callback  = NULL;
@@ -267,6 +271,7 @@ static int httpFinishCommand(struct HttpConnection *http) {
 }
 
 static void httpDestroyHeaders(void *arg, char *key, char *value) {
+  (void)arg;
   free(key);
   free(value);
 }
@@ -296,7 +301,7 @@ static char *getPeerName(int fd, int *port, int numericHosts) {
 }
 
 static void httpSetState(struct HttpConnection *http, int state) {
-  if (state == http->state) {
+  if (state == (int)http->state) {
     return;
   }
 
@@ -372,7 +377,9 @@ void initHttpConnection(struct HttpConnection *http, struct Server *server,
   http->msgOffset          = 0;
   http->totalWritten       = 0;
   http->expecting          = 0;
+  http->websocketType      = WS_UNDEFINED;
   http->callback           = NULL;
+  http->websocketHandler   = NULL;
   http->arg                = NULL;
   http->private            = NULL;
   http->code               = 200;
@@ -388,8 +395,12 @@ void initHttpConnection(struct HttpConnection *http, struct Server *server,
 void destroyHttpConnection(struct HttpConnection *http) {
   if (http) {
     if (http->isSuspended || http->isPartialReply) {
-      if (http->callback && !http->done) {
-        http->callback(http, http->arg, NULL, 0);
+      if (!http->done) {
+        if (http->callback) {
+          http->callback(http, http->arg, NULL, 0);
+        } else if (http->websocketHandler) {
+          http->websocketHandler(http, http->arg, WS_CONNECTION_CLOSED,NULL,0);
+        }
       }
       http->callback       = NULL;
       http->isSuspended    = 0;
@@ -774,41 +785,41 @@ void httpTransferPartialReply(struct HttpConnection *http, char *msg, int len){
 static int httpHandleCommand(struct HttpConnection *http,
                              const struct Trie *handlers) {
   debug("Handling \"%s\" \"%s\"", http->method, http->path);
-  const char *contentLength                = getFromHashMap(&http->header,
-                                                            "content-length");
+  const char *contentLength                  = getFromHashMap(&http->header,
+                                                             "content-length");
   if (contentLength != NULL && *contentLength) {
     char *endptr;
-    http->expecting                        = strtol(contentLength,
-                                                    &endptr, 10);
+    http->expecting                          = strtol(contentLength,
+                                                      &endptr, 10);
     if (*endptr) {
       // Invalid length. Read until end of stream and then close
       // connection.
-      http->expecting                      = -1;
+      http->expecting                        = -1;
     }
   } else {
       // Unknown length. Read until end of stream and then close
       // connection.
-    http->expecting                        = -1;
+    http->expecting                          = -1;
   }
   if (!strcmp(http->method, "OPTIONS")) {
-    char *response                         = stringPrintf(NULL,
+    char *response                           = stringPrintf(NULL,
                                                 "HTTP/1.1 200 OK\r\n"
                                                 "Content-Length: 0\r\n"
                                                 "Allow: GET, POST, OPTIONS\r\n"
                                                 "\r\n");
     httpTransfer(http, response, strlen(response));
     if (http->expecting < 0) {
-      http->expecting                      = 0;
+      http->expecting                        = 0;
     }
     return HTTP_READ_MORE;
   } else if (!strcmp(http->method, "GET")) {
     if (http->expecting < 0) {
-      http->expecting                      = 0;
+      http->expecting                        = 0;
     }
   } else if (!strcmp(http->method, "POST")) {
   } else if (!strcmp(http->method, "HEAD")) {
     if (http->expecting < 0) {
-      http->expecting                      = 0;
+      http->expecting                        = 0;
     }
   } else if (!strcmp(http->method, "PUT")    ||
              !strcmp(http->method, "DELETE") ||
@@ -820,52 +831,116 @@ static int httpHandleCommand(struct HttpConnection *http,
     httpSendReply(http, 501, "Method Not Implemented", NO_MSG);
     return HTTP_DONE;
   }
-  const char *host                         = getFromHashMap(&http->header,
-                                                            "host");
+  const char *host                           = getFromHashMap(&http->header,
+                                                              "host");
   if (host) {
-    for (char ch; (ch = *host) != '\000'; host++) {
+    for (char ch, *ptr = (char *)host; (ch = *ptr) != '\000'; ptr++) {
       if (ch == ':') {
-        *(char *)host                      = '\000';
+        *ptr                                 = '\000';
         break;
       }
       if (ch != '-' && ch != '.' &&
           (ch < '0' ||(ch > '9' && ch < 'A') ||
-          (ch > 'Z' && ch < 'a')|| ch > 'z')) {
+          (ch > 'Z' && ch < 'a')||(ch > 'z' && ch <= 0x7E))) {
         httpSendReply(http, 400, "Bad Request", NO_MSG);
         return HTTP_DONE;
       }
     }
   }
+
   char *diff;
   struct HttpHandler *h = (struct HttpHandler *)getFromTrie(handlers,
                                                             http->path, &diff);
+
   if (h) {
-    check(diff);
-    while (diff > http->path && diff[-1] == '/') {
-      diff--;
-    }
-    if (!*diff || *diff == '/' || *diff == '?' || *diff == '#') {
-      check(!http->matchedPath);
-      check(!http->pathInfo);
-      check(!http->query);
-
-      check(http->matchedPath              = malloc(diff - http->path + 1));
-      memcpy(http->matchedPath, http->path, diff - http->path);
-      http->matchedPath[diff - http->path] = '\000';
-
-      const char *query = strchr(diff, '?');
-      if (*diff && *diff != '?') {
-        const char *endOfInfo              = query
-                                             ? query : strrchr(diff, '\000');
-        check(http->pathInfo               = malloc(endOfInfo - diff + 1));
-        memcpy(http->pathInfo, diff, endOfInfo - diff);
-        http->pathInfo[endOfInfo - diff]   = '\000';
+    if (h->websocketHandler) {
+      // Check for WebSocket handshake
+      const char *upgrade                    = getFromHashMap(&http->header,
+                                                              "upgrade");
+      if (upgrade && !strcmp(upgrade, "WebSocket")) {
+        const char *connection               = getFromHashMap(&http->header,
+                                                              "connection");
+        if (connection && !strcmp(connection, "Upgrade")) {
+          const char *origin                 = getFromHashMap(&http->header,
+                                                              "origin");
+          if (origin) {
+            for (const char *ptr = origin; *ptr; ptr++) {
+              if ((unsigned char)*ptr < ' ') {
+                goto bad_ws_upgrade;
+              }
+            }
+
+            const char *protocol             = getFromHashMap(&http->header,
+                                                         "websocket-protocol");
+            if (protocol) {
+              for (const char *ptr = protocol; *ptr; ptr++) {
+                if ((unsigned char)*ptr < ' ') {
+                  goto bad_ws_upgrade;
+                }
+              }
+            }
+            char *port                       = NULL;
+            if (http->port != (http->sslHndl ? 443 : 80)) {
+              port                           = stringPrintf(NULL,
+                                                            ":%d", http->port);
+            }
+            char *response                   = stringPrintf(NULL,
+              "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
+              "Upgrade: WebSocket\r\n"
+              "Connection: Upgrade\r\n"
+              "WebSocket-Origin: %s\r\n"
+              "WebSocket-Location: %s://%s%s%s\r\n"
+              "%s%s%s"
+              "\r\n",
+              origin,
+              http->sslHndl ? "wss" : "ws", host && *host ? host : "localhost",
+              port ? port : "", http->path,
+              protocol ? "WebSocket-Protocol: " : "",
+              protocol ? protocol : "",
+              protocol ? "\r\n" : "");
+            free(port);
+            debug("Switching to WebSockets");
+            httpTransfer(http, response, strlen(response));
+            if (http->expecting < 0) {
+              http->expecting                = 0;
+            }
+            http->websocketHandler           = h->websocketHandler;
+            httpSetState(http, WEBSOCKET);
+            return HTTP_READ_MORE;
+          }
+        }
       }
+    }
+  bad_ws_upgrade:;
 
-      if (query) {
-        check(http->query                  = strdup(query + 1));
+    if (h->handler) {
+      check(diff);
+      while (diff > http->path && diff[-1] == '/') {
+        diff--;
+      }
+      if (!*diff || *diff == '/' || *diff == '?' || *diff == '#') {
+        check(!http->matchedPath);
+        check(!http->pathInfo);
+        check(!http->query);
+
+        check(http->matchedPath              = malloc(diff - http->path + 1));
+        memcpy(http->matchedPath, http->path, diff - http->path);
+        http->matchedPath[diff - http->path] = '\000';
+
+        const char *query = strchr(diff, '?');
+        if (*diff && *diff != '?') {
+          const char *endOfInfo              = query
+                                               ? query : strrchr(diff, '\000');
+          check(http->pathInfo               = malloc(endOfInfo - diff + 1));
+          memcpy(http->pathInfo, diff, endOfInfo - diff);
+          http->pathInfo[endOfInfo - diff]   = '\000';
+        }
+
+        if (query) {
+          check(http->query                  = strdup(query + 1));
+        }
+        return h->handler(http, h->arg);
       }
-      return h->handler(http, h->arg);
     }
   }
   httpSendReply(http, 404, "File Not Found", NO_MSG);
@@ -1011,13 +1086,20 @@ static int httpParseHeaders(struct HttpConnection *http,
         serverSetTimeout(connection, CONNECTION_TIMEOUT);
       }
       check(!http->done);
-      if (!http->expecting && http->callback) {
-        rc             = http->callback(http, http->arg, "", 0);
-        if (rc != HTTP_READ_MORE) {
-          goto retry;
+      if (!http->expecting) {
+        if (http->callback) {
+          rc                 = http->callback(http, http->arg, "", 0);
+          if (rc != HTTP_READ_MORE) {
+            goto retry;
+          }
+        } else if (http->websocketHandler) {
+          http->websocketHandler(http, http->arg, WS_CONNECTION_OPENED,
+                                 NULL, 0);
         }
       }
-      httpSetState(http, http->expecting ? PAYLOAD : COMMAND);
+      if (http->state != WEBSOCKET) {
+        httpSetState(http, http->expecting ? PAYLOAD : COMMAND);
+      }
       break;
     case HTTP_SUSPEND:
       http->isSuspended    = 1;
@@ -1187,6 +1269,140 @@ static int httpParsePayload(struct HttpConnection *http, int offset,
   return consumed;
 }
 
+static int httpHandleWebSocket(struct HttpConnection *http, int offset,
+                               const char *buf, int bytes) {
+  check(http->websocketHandler);
+  int ch                          = 0x00;
+  while (bytes > offset) {
+    if (http->websocketType & WS_UNDEFINED) {
+      ch                          = httpGetChar(http, buf, bytes, &offset);
+      check(ch >= 0);
+      if (http->websocketType & 0xFF) {
+        // Reading another byte of length information.
+        if (http->expecting > 0xFFFFFF) {
+          return 0;
+        }
+        http->expecting           = (128 * http->expecting) + (ch & 0x7F);
+        if ((ch & 0x80) == 0) {
+          // Done reading length information.
+          http->websocketType    &= ~WS_UNDEFINED;
+
+          // ch is used to detect when we read the terminating byte in text
+          // mode. In binary mode, it must be set to something other than 0xFF.
+          ch                      = 0x00;
+        }
+      } else {
+        // Reading first byte of frame.
+        http->websocketType       = (ch & 0xFF) | WS_START_OF_FRAME;
+        if (ch & 0x80) {
+          // For binary data, we have to read the length before we can start
+          // processing payload.
+          http->websocketType    |= WS_UNDEFINED;
+          http->expecting         = 0;
+        }
+      }
+    } else if (http->websocketType & 0x80) {
+      // Binary data
+      if (http->expecting) {
+        if (offset < 0) {
+        handle_partial:
+          check(-offset <= http->partialLength);
+          int len                 = -offset;
+          if (len >= http->expecting) {
+            len                   = http->expecting;
+            http->websocketType  |= WS_END_OF_FRAME;
+          }
+          if (len &&
+              http->websocketHandler(http, http->arg, http->websocketType,
+                                  http->partial + http->partialLength + offset,
+                                  len) != HTTP_DONE) {
+            return 0;
+          }
+
+          if (ch == 0xFF) {
+            // In text mode, we jump to handle_partial, when we find the
+            // terminating 0xFF byte. If so, we should try to consume it now.
+            if (len < http->partialLength) {
+              len++;
+              http->websocketType = WS_UNDEFINED;
+            }
+          }
+
+          if (len == http->partialLength) {
+            free(http->partial);
+            http->partial         = NULL;
+            http->partialLength   = 0;
+          } else {
+            memmove(http->partial, http->partial + len,
+                    http->partialLength - len);
+            http->partialLength  -= len;
+          }
+          offset                 += len;
+          http->expecting        -= len;
+        } else {
+        handle_buffered:;
+          int len                 = bytes - offset;
+          if (len >= http->expecting) {
+            len                   = http->expecting;
+            http->websocketType  |= WS_END_OF_FRAME;
+          }
+          if (len &&
+              http->websocketHandler(http, http->arg, http->websocketType,
+                                     buf + offset, len) != HTTP_DONE) {
+            return 0;
+          }
+
+          if (ch == 0xFF) {
+            // In text mode, we jump to handle_buffered, when we find the
+            // terminating 0xFF byte. If so, we should consume it now.
+            check(offset + len < bytes);
+            len++;
+            http->websocketType   = WS_UNDEFINED;
+          }
+          offset                 += len;
+          http->expecting        -= len;
+        }
+        http->websocketType      &= ~(WS_START_OF_FRAME | WS_END_OF_FRAME);
+      } else {
+        // Read all data. Go back to looking for a new frame header.
+        http->websocketType       = WS_UNDEFINED;
+      }
+    } else {
+      // Process text data until we find a 0xFF bytes.
+      int i                       = offset;
+
+      // If we have partial data, process that first.
+      while (i < 0) {
+        ch                        = httpGetChar(http, buf, bytes, &i);
+        check(ch != -1);
+
+        // Terminate when we either find the 0xFF, or we have reached the end
+        // of partial data.
+        if (ch == 0xFF || !i) {
+          // Set WS_END_OF_FRAME, iff we have found the 0xFF marker.
+          http->expecting         = i - offset - (ch == 0xFF);
+          goto handle_partial;
+        }
+      }
+
+      // Read all remaining buffered bytes (i.e. positive offset).
+      while (bytes > i) {
+        ch                        = httpGetChar(http, buf, bytes, &i);
+        check(ch != -1);
+
+        // Terminate when we either find the 0xFF, or we have reached the end
+        // of buffered data.
+        if (ch == 0xFF || bytes == i) {
+          // Set WS_END_OF_FRAME, iff we have found the 0xFF marker.
+          http->expecting         = i - offset - (ch == 0xFF);
+          goto handle_buffered;
+        }
+      }
+    }
+  }
+  return 1;
+}
+
 int httpHandleConnection(struct ServerConnection *connection, void *http_,
                          short *events, short revents) {
   struct HttpConnection *http        = (struct HttpConnection *)http_;
@@ -1219,6 +1435,7 @@ int httpHandleConnection(struct ServerConnection *connection, void *http_,
         bytes                        = 0;
       }
     }
+
     if (bytes > 0 && http->state == SNIFFING_SSL) {
       // Assume that all legitimate HTTP commands start with a sequence of
       // letters followed by a space character. If we don't see this pattern,
@@ -1241,7 +1458,7 @@ int httpHandleConnection(struct ServerConnection *connection, void *http_,
                                        strcmp(method, "CONNECT");
           http->state                = COMMAND;
           break;
-        } else if (j >= sizeof(method)-1 ||
+        } else if (j >= (int)sizeof(method)-1 ||
                    ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z') {
           isSSL                      = 1;
           http->state                = COMMAND;
@@ -1262,6 +1479,7 @@ int httpHandleConnection(struct ServerConnection *connection, void *http_,
         }
       }
     }
+
     if (bytes > 0 || (eof && http->partial)) {
       check(!!http->partial == !!http->partialLength);
       int  offset                    = -http->partialLength;
@@ -1331,7 +1549,16 @@ int httpHandleConnection(struct ServerConnection *connection, void *http_,
             consumed                 = len;
             pushBack                 = bytes - offset - len;
           }
+        } else if (http->state == WEBSOCKET) {
+          if (!httpHandleWebSocket(http, offset, buf, bytes)) {
+            httpCloseRead(http);
+            break;
+          }
+          consumed                  += bytes - offset;
+        } else {
+          check(0);
         }
+
         if (pushBack) {
           check(offset + pushBack == bytes);
           if (offset >= 0) {
@@ -1383,6 +1610,7 @@ int httpHandleConnection(struct ServerConnection *connection, void *http_,
         break;
       case PAYLOAD:
       case DISCARD_PAYLOAD:
+      case WEBSOCKET:
         http->expecting              = 0;
         httpCloseRead(http);
         httpSetState(http, COMMAND);
@@ -1563,6 +1791,89 @@ void httpSendReply(struct HttpConnection *http, int code,
   }
 }
 
+void httpSendWebSocketTextMsg(struct HttpConnection *http, int type,
+                              const char *fmt, ...) {
+  check(type >= 0 && type <= 0x7F);
+  va_list ap;
+  va_start(ap, fmt);
+  char *buf;
+  int len;
+  if (strcmp(fmt, BINARY_MSG)) {
+    // Send a printf() style text message
+    buf              = vStringPrintf(NULL, fmt, ap);
+    len              = strlen(buf);
+  } else {
+    // Send a binary message
+    len              = va_arg(ap, int);
+    buf              = va_arg(ap, char *);
+  }
+  va_end(ap);
+  check(len >= 0 && len < 0x60000000);
+
+  // We assume that all input data is directly mapped in the range 0..255
+  // (e.g. ISO-8859-1). In order to transparently send it over a web socket,
+  // we have to encode it in UTF-8.
+  int utf8Len        = len + 2;
+  for (int i = 0; i < len; ++i) {
+    if (buf[i] & 0x80) {
+      ++utf8Len;
+    }
+  }
+  char *utf8;
+  check(utf8         = malloc(utf8Len));
+  utf8[0]            = type;
+  for (int i = 0, j = 1; i < len; ++i) {
+    unsigned char ch = buf[i];
+    if (ch & 0x80) {
+      utf8[j++]      = 0xC0 + (ch >> 6);
+      utf8[j++]      = 0x80 + (ch & 0x3F);
+    } else {
+      utf8[j++]      = ch;
+    }
+    check(j < utf8Len);
+  }
+  utf8[utf8Len-1]    = '\xFF';
+
+  // Free our temporary buffer, if we actually did allocate one.
+  if (strcmp(fmt, BINARY_MSG)) {
+    free(buf);
+  }
+
+  // Send to browser.
+  httpTransfer(http, utf8, utf8Len);
+}
+
+void httpSendWebSocketBinaryMsg(struct HttpConnection *http, int type,
+                                const void *buf, int len) {
+  check(type >= 0x80 && type <= 0xFF);
+  check(len > 0 && len < 0x7FFFFFF0);
+
+  // Allocate buffer for header and payload.
+  char *data;
+  check(data  = malloc(len + 6));
+  data[0]     = type;
+
+  // Convert length to base-128.
+  int i       = 0;
+  int l       = len;
+  do {
+    data[++i] = 0x80 + (l & 0x7F);
+    l        /= 128;
+  } while (l);
+  data[i]    &= 0x7F;
+
+  // Reverse digits, so that they are big-endian.
+  for (int j = 0; j < i/2; ++j) {
+    char ch   = data[1+j];
+    data[1+j] = data[i-j];
+    data[i-j] = ch;
+  }
+
+  // Transmit header and payload.
+  memmove(data + i + 1, buf, len);
+  httpTransfer(http, data, len + i + 1);
+}
+
 void httpExitLoop(struct HttpConnection *http, int exitAll) {
   serverExitLoop(http->server, exitAll);
 }
index 2c1e9cd899ef714b1f89405af4087945b29878bd..d0207c4511c7a816c2e3bfb34fce2daedcf04f8e 100644 (file)
@@ -1,5 +1,5 @@
 // httpconnection.h -- Manage state machine for HTTP connections
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
 #define HTTP_SUSPEND       3
 #define HTTP_PARTIAL_REPLY 4
 
+#define WS_UNDEFINED       0x1000
+#define WS_START_OF_FRAME  0x0100
+#define WS_END_OF_FRAME    0x0200
+
 #define NO_MSG             "\001"
 
 struct HttpConnection {
@@ -71,7 +75,8 @@ struct HttpConnection {
   int                     isSuspended;
   int                     isPartialReply;
   int                     done;
-  enum { SNIFFING_SSL, COMMAND, HEADERS, PAYLOAD, DISCARD_PAYLOAD } state;
+  enum { SNIFFING_SSL, COMMAND, HEADERS, PAYLOAD, DISCARD_PAYLOAD,
+         WEBSOCKET } state;
   char                    *peerName;
   int                     peerPort;
   char                    *url;
@@ -91,8 +96,11 @@ struct HttpConnection {
   int                     msgOffset;
   int                     totalWritten;
   int                     expecting;
+  int                     websocketType;
   int                     (*callback)(struct HttpConnection *, void *,
                                       const char *,int);
+  int                     (*websocketHandler)(struct HttpConnection *, void *,
+                                              int, const char *, int);
   void                    *arg;
   void                    *private;
   int                     code;
@@ -104,6 +112,8 @@ struct HttpConnection {
 struct HttpHandler {
   int (*handler)(struct HttpConnection *, void *);
   int (*streamingHandler)(struct HttpConnection *, void *, const char *, int);
+  int (*websocketHandler)(struct HttpConnection *, void *, int,
+                          const char *, int);
   void *arg, *streamingArg;
   
 };
@@ -128,6 +138,11 @@ void *httpSetPrivate(struct HttpConnection *http, void *private);
 void httpSendReply(struct HttpConnection *http, int code,
                    const char *msg, const char *fmt, ...)
   __attribute__((format(printf, 4, 5)));
+void httpSendWebSocketTextMsg(struct HttpConnection *http, int type,
+                              const char *fmt, ...)
+  __attribute__((format(printf, 3, 4)));
+void httpSendWebSocketBinaryMsg(struct HttpConnection *http, int type,
+                                const void *buf, int len);
 void httpExitLoop(struct HttpConnection *http, int exitAll);
 struct Server *httpGetServer(const struct HttpConnection *http);
 struct ServerConnection *httpGetServerConnection(const struct HttpConnection*);
index 4eb0bbc584e050e4db9b3d3254bfc1ac40839749..c8fed826c46eb717540a8d6044d5328c6acbd5d6 100644 (file)
@@ -5,6 +5,7 @@ serverGetListeningPort
 serverGetFd
 serverRegisterHttpHandler
 serverRegisterStreamingHttpHandler
+serverRegisterWebSocketHandler
 serverAddConnection
 serverDeleteConnection
 serverSetTimeout
@@ -24,6 +25,8 @@ httpSetCallback
 httpGetPrivate
 httpSetPrivate
 httpSendReply
+httpSendWebSocketTextMsg
+httpSendWebSocketBinaryMsg
 httpExitLoop
 httpGetServer
 httpGetServerConnection
index f52a269c0b400a7c3c304c01786f9dc512ccd1dc..41dfcb0175f6b081d929b1bf52674db7a9e10de0 100644 (file)
@@ -1,5 +1,5 @@
 // server.c -- Generic server that can deal with HTTP connections
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -129,6 +129,7 @@ static int serverCollectHandler(struct HttpConnection *http, void *handler_) {
 }
 
 static void serverDestroyHandlers(void *arg, char *value) {
+  (void)arg;
   free(value);
 }
 
@@ -143,6 +144,7 @@ void serverRegisterHttpHandler(struct Server *server, const char *url,
     h->handler          = serverCollectHandler;
     h->arg              = h;
     h->streamingHandler = handler;
+    h->websocketHandler = NULL;
     h->streamingArg     = arg;
     addToTrie(&server->handlers, url, (char *)h);
   }
@@ -158,13 +160,31 @@ void serverRegisterStreamingHttpHandler(struct Server *server, const char *url,
     check(h             = malloc(sizeof(struct HttpHandler)));
     h->handler          = handler;
     h->streamingHandler = NULL;
+    h->websocketHandler = NULL;
     h->streamingArg     = NULL;
     h->arg              = arg;
     addToTrie(&server->handlers, url, (char *)h);
   }
 }
 
+void serverRegisterWebSocketHandler(struct Server *server, const char *url,
+       int (*handler)(struct HttpConnection *, void *, int, const char *, int),
+       void *arg) {
+  if (!handler) {
+    addToTrie(&server->handlers, url, NULL);
+  } else {
+    struct HttpHandler *h;
+    check(h             = malloc(sizeof(struct HttpHandler)));
+    h->handler          = NULL;
+    h->streamingHandler = NULL;
+    h->websocketHandler = handler;
+    h->arg              = arg;
+    addToTrie(&server->handlers, url, (char *)h);
+  }
+}
+
 static int serverQuitHandler(struct HttpConnection *http, void *arg) {
+  (void)arg;
   httpSendReply(http, 200, "Good Bye", NO_MSG);
   httpExitLoop(http, 1);
   return HTTP_DONE;
index bb879fb95ee98499b984d1320869ad2aaeae251b..8d3141fee2cf97743a904c95b92f4c5a535feb59 100644 (file)
@@ -1,5 +1,5 @@
 // server.h -- Generic server that can deal with HTTP connections
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -93,6 +93,9 @@ void serverRegisterHttpHandler(struct Server *server, const char *url,
 void serverRegisterStreamingHttpHandler(struct Server *server, const char *url,
                                int (*handler)(struct HttpConnection *, void *),
                                void *arg);
+void serverRegisterWebSocketHandler(struct Server *server, const char *url,
+       int (*handler)(struct HttpConnection *, void *, int, const char *, int),
+       void *arg);
 struct ServerConnection *serverAddConnection(struct Server *server, int fd,
                             int (*handleConnection)(struct ServerConnection *c,
                                                     void *arg, short *events,
index 3c3df21b2840c67fe002da9d77ca92ada2ad4064..64f2158cad6defaec06f5848dcaf53eaffbc45f1 100644 (file)
@@ -1,5 +1,5 @@
 // ssl.c -- Support functions that find and load SSL support, if available
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -288,11 +288,11 @@ static void loadSSL(void) {
     { { &d2i_X509 },                    "d2i_X509" },
     { { &X509_free },                   "X509_free" }
   };
-  for (int i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
+  for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
     if (!(*symbols[i].var = loadSymbol("libssl.so", symbols[i].fn))) {
       debug("Failed to load SSL support. Could not find \"%s\"",
             symbols[i].fn);
-      for (int j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) {
+      for (unsigned j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) {
         *symbols[j].var = NULL;
       }
       return;
@@ -361,7 +361,7 @@ static const unsigned char *sslSecureReadASCIIFileToMem(int fd) {
   check((buf          = malloc(bufSize)) != NULL);
   for (;;) {
     check(len < bufSize - 1);
-    size_t  readLen   = bufSize - len - 1;
+    ssize_t readLen   = bufSize - len - 1;
     ssize_t bytesRead = NOINTR(read(fd, buf + len, readLen));
     if (bytesRead > 0) {
       len            += bytesRead;
@@ -414,7 +414,7 @@ static const unsigned char *sslPEMtoASN1(const unsigned char *pem,
     return NULL;
   }
   unsigned char *ret;
-  size_t maxSize     = (((end - ptr)*6)+7)/8;
+  ssize_t maxSize    = (((end - ptr)*6)+7)/8;
   check((ret         = malloc(maxSize)) != NULL);
   unsigned char *out = ret;
   unsigned bits      = 0;
@@ -542,6 +542,7 @@ static int sslSetCertificateFromFile(SSL_CTX *context,
 
 #ifdef HAVE_TLSEXT
 static int sslSNICallback(SSL *sslHndl, int *al, struct SSLSupport *ssl) {
+  (void)al;
   check(!ERR_peek_error());
   const char *name        = SSL_get_servername(sslHndl,
                                                TLSEXT_NAMETYPE_host_name);
@@ -603,7 +604,7 @@ static int sslSNICallback(SSL *sslHndl, int *al, struct SSLSupport *ssl) {
   }
   free(serverName);
   if (context != ssl->sslContext) {
-    check(SSL_set_SSL_CTX(sslHndl, context) > 0);
+    check(SSL_set_SSL_CTX(sslHndl, context));
   }
   check(!ERR_peek_error());
   return SSL_TLSEXT_ERR_OK;
@@ -616,6 +617,8 @@ static int sslSNICallback(SSL *sslHndl, int *al, struct SSLSupport *ssl) {
 static int gethostbyname_r(const char *name, struct hostent *ret,
                            char *buf, size_t buflen,
                            struct hostent **result, int *h_errnop) {
+  (void)buf;
+  (void)buflen;
   if (result) {
     *result          = NULL;
   }
index 78bcec590824983ec7106f25bd37f2ae2536847d..088eea73d760b54cc4424f62f2f7fedf15622d98 100644 (file)
@@ -1,5 +1,5 @@
 // url.c -- Object representing uniform resource locators
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -87,6 +87,7 @@ static char *urlUnescape(char *s) {
 }
 
 static void urlDestroyHashMapEntry(void *arg, char *key, char *value) {
+  (void)arg;
   free(key);
   free(value);
 }
index 7c458509f341b48a57c7fe2582beb4f470a6e775..f3aff9e7dd00d3bfda43e80244cbe1d2c5fa8048 100644 (file)
@@ -1,5 +1,5 @@
 // launcher.c -- Launch services from a privileged process
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -321,7 +321,7 @@ static void loadPAM(void) {
     { { &pam_start },             "libpam.so",      "pam_start"         },
     { { &misc_conv },             "libpam_misc.so", "misc_conv"         }
   };
-  for (int i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
+  for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
     if (!(*symbols[i].var = loadSymbol(symbols[i].lib, symbols[i].fn))) {
 #if defined(HAVE_SECURITY_PAM_CLIENT_H)
       if (!strcmp(symbols[i].fn, "pam_binary_handler_fn")) {
@@ -336,7 +336,7 @@ static void loadPAM(void) {
       }
       debug("Failed to load PAM support. Could not find \"%s\"",
             symbols[i].fn);
-      for (int j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) {
+      for (unsigned j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) {
         *symbols[j].var = NULL;
       }
       break;
@@ -419,7 +419,7 @@ int launchChild(int service, struct Session *session, const char *url) {
   }
 
   struct LaunchRequest *request;
-  size_t len           = sizeof(struct LaunchRequest) + strlen(u) + 1;
+  ssize_t len          = sizeof(struct LaunchRequest) + strlen(u) + 1;
   check(request        = calloc(len, 1));
   request->service     = service;
   request->width       = session->width;
@@ -538,6 +538,8 @@ void deleteUtmp(struct Utmp *utmp) {
 }
 
 static void destroyUtmpHashEntry(void *arg, char *key, char *value) {
+  (void)arg;
+  (void)key;
   deleteUtmp((struct Utmp *)value);
 }
 
@@ -765,6 +767,9 @@ static const struct passwd *getPWEnt(uid_t uid) {
 }
 
 static void sigAlrmHandler(int sig, siginfo_t *info, void *unused) {
+  (void)sig;
+  (void)info;
+  (void)unused;
   puts("\nLogin timed out after 60 seconds.");
   _exit(1);
 }
@@ -958,7 +963,7 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
   }
 
   if (restricted &&
-      (service->uid != restricted || service->gid != pw->pw_gid)) {
+      (service->uid != (int)restricted || service->gid != (int)pw->pw_gid)) {
     puts("\nAccess denied!");
 #if defined(HAVE_SECURITY_PAM_APPL_H)
     if (service->authUser != 2 /* SSH */) {
@@ -1004,7 +1009,7 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
       if (i == ngroups) {
         groups[ngroups++]      = service->gid;
         break;
-      } else if (groups[i] == service->gid) {
+      } else if ((int)groups[i] == service->gid) {
         break;
       }
     }
@@ -1047,6 +1052,7 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
 }
 
 static void destroyVariableHashEntry(void *arg, char *key, char *value) {
+  (void)arg;
   free(key);
   free(value);
 }
@@ -1054,6 +1060,9 @@ static void destroyVariableHashEntry(void *arg, char *key, char *value) {
 static void execService(int width, int height, struct Service *service,
                         const char *peerName, char **environment,
                         const char *url) {
+  (void)width;
+  (void)height;
+
   // Create a hash table with all the variables that we can expand. This
   // includes all environment variables being passed to the child.
   HashMap *vars;
@@ -1346,7 +1355,10 @@ static void childProcess(struct Service *service, int width, int height,
     pam_handle_t *pam           = internalLogin(service, utmp, &environment);
 #if defined(HAVE_SECURITY_PAM_APPL_H)
     if (pam && !geteuid()) {
-      check(pam_open_session(pam, PAM_SILENT) == PAM_SUCCESS);
+      if (pam_open_session(pam, PAM_SILENT) != PAM_SUCCESS) {
+        fprintf(stderr, "Access denied.\n");
+        _exit(1);
+      }
       pid_t pid                 = fork();
       switch (pid) {
       case -1:
@@ -1409,6 +1421,9 @@ static void childProcess(struct Service *service, int width, int height,
 }
 
 static void sigChildHandler(int sig, siginfo_t *info, void *unused) {
+  (void)sig;
+  (void)info;
+  (void)unused;
 }
 
 static void launcherDaemon(int fd) {
index 61268a248f504289bb751f6632c50088facfe60e..b7a9f6bbd9b012064fe84efcf8eba9f5447b81da 100644 (file)
@@ -1,5 +1,5 @@
 // privileges.c -- Manage process privileges
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -76,7 +76,7 @@ static void removeGroupPrivileges(int showError) {
     getresuid(&ru, &eu, &su);
 
     // Try to switch the user-provided group.
-    if ((ru && runAsGroup != rg) ||
+    if ((ru && runAsGroup != (int)rg) ||
         setresgid(runAsGroup, runAsGroup, runAsGroup)) {
       if (showError) {
         fatal("Only privileged users can change their group memberships");
@@ -110,7 +110,7 @@ void lowerPrivileges(void) {
 
   if (runAsUser >= 0) {
     // Try to switch to the user-provided user id.
-    if (r && runAsUser != r) {
+    if (r && runAsUser != (int)r) {
       fatal("Only privileged users can change their user id");
     }
     check(!setresuid(runAsUser, runAsUser, -1));
@@ -136,7 +136,7 @@ void dropPrivileges(void) {
 
   if (runAsUser >= 0) {
     // Try to switch to the user-provided user id.
-    if ((r && runAsUser != r) ||
+    if ((r && runAsUser != (int)r) ||
         setresuid(runAsUser, runAsUser, runAsUser)) {
       fatal("Only privileged users can change their user id.");
     }
index ca05fafec23385baa4a596fa1f79a5d8586a4102..a9e9b4cf8900c904250711faf86145127b96a4ae 100644 (file)
@@ -1,5 +1,5 @@
 // service.c -- Service descriptions
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -243,9 +243,15 @@ void deleteService(struct Service *service) {
 }
 
 void destroyServiceHashEntry(void *arg, char *key, char *value) {
+  (void)arg;
+  (void)key;
+  (void)value;
 }
 
 static int enumerateServicesHelper(void *arg, const char *key, char **value) {
+  (void)arg;
+  (void)key;
+
   check(services              = realloc(services,
                                     ++numServices * sizeof(struct Service *)));
   services[numServices-1]     = *(struct Service **)value;
index 24a4281e2975661b28665b07982fae5f62f9d78f..46fd47ac3dbf80457bc9dd9f3ac64d37d1d6d1c8 100644 (file)
@@ -1,5 +1,5 @@
 // service.h -- Service descriptions
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -55,8 +55,8 @@ struct Service {
   int        useHomeDir;
   int        authUser;
   int        useDefaultShell;
-  int        uid;
-  int        gid;
+  int        uid; /* Can be -1 */
+  int        gid; /* Can be -1 */
   const char *user;
   const char *group;
   const char *cwd;
index d9c749cf075c9caa5698cb56aad69c7c8c2915be..6644f2953a4747eab957f9c65d0d7dc8dde10499 100644 (file)
@@ -1,5 +1,5 @@
 // session.c -- Session management for HTTP/HTTPS connections
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -153,6 +153,9 @@ void finishAllSessions(void) {
 }
 
 static void destroySessionHashEntry(void *arg, char *key, char *value) {
+  (void)arg;
+  (void)key;
+
   deleteSession((struct Session *)value);
 }
 
@@ -167,7 +170,7 @@ char *newSessionKey(void) {
   char *ptr          = sessionKey;
   int count          = 0;
   int bits           = 0;
-  for (int i = 0;;) {
+  for (unsigned i = 0;;) {
     bits             = (bits << 8) | buf[i];
     count           += 8;
   drain:
index c5801250744ff27aff477f75f2383ec11b78dc0b..63b079a854531ebb1cf5ddce478a6051b2982380 100644 (file)
@@ -1,5 +1,5 @@
 // ShellInABox.js -- Use XMLHttpRequest to provide an AJAX terminal emulator.
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -358,8 +358,8 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
 };
 
 ShellInABox.prototype.about = function() {
-  alert("Shell In A Box version " + "2.10 (revision 200)" +
-        "\nCopyright 2008-2009 by Markus Gutschke\n" +
+  alert("Shell In A Box version " + "2.10 (revision 202)" +
+        "\nCopyright 2008-2010 by Markus Gutschke\n" +
         "For more information check http://shellinabox.com" +
         (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?
          "\n\n" +
index f86288012ab106bba94c91fd8e1830bbde12a5d2..11a893e3fe6c80f4c6c7aa495395be71144e2377 100644 (file)
@@ -1,5 +1,5 @@
 // ShellInABox.js -- Use XMLHttpRequest to provide an AJAX terminal emulator.
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -359,7 +359,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
 
 ShellInABox.prototype.about = function() {
   alert("Shell In A Box version " + VERSION +
-        "\nCopyright 2008-2009 by Markus Gutschke\n" +
+        "\nCopyright 2008-2010 by Markus Gutschke\n" +
         "For more information check http://shellinabox.com" +
         (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?
          "\n\n" +
index a1078821dc452370ad48d2c6021ac7d3b9a50011..0b5637714cf98e177da3e54a055454a20f2e2d14 100644 (file)
@@ -1,6 +1,6 @@
 // shellinaboxd.c -- A custom web server that makes command line applications
 //                   available as AJAX web applications.
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -257,6 +257,7 @@ static void sessionDone(void *arg) {
 
 static int handleSession(struct ServerConnection *connection, void *arg,
                          short *events, short revents) {
+  (void)events;
   struct Session *session       = (struct Session *)arg;
   session->connection           = connection;
   int len                       = MAX_RESPONSE - session->len;
@@ -311,6 +312,7 @@ static int invalidatePendingHttpSession(void *arg, const char *key,
 
 static int dataHandler(HttpConnection *http, struct Service *service,
                        const char *buf, int len, URL *url) {
+  (void)len;
   if (!buf) {
     // Somebody unexpectedly closed our http connection (e.g. because of a
     // timeout). This is the last notification that we will get.
@@ -514,13 +516,13 @@ static void serveStaticFile(HttpConnection *http, const char *contentType,
           // Remember the beginning of the "[if ...]" statement
           ifPtr                  = ptr;
         }
-      } else if (ifPtr && !elsePtr && eol - ptr >= strlen(tag) + 7 &&
+      } else if (ifPtr && !elsePtr && eol - ptr >= (ssize_t)strlen(tag) + 7 &&
                  !memcmp(ptr, "[else ", 6) &&
                  !memcmp(ptr + 6, tag, strlen(tag)) &&
                  ptr[6 + strlen(tag)] == ']') {
         // Found an "[else ...]" statement. Remember where it started.
         elsePtr                  = ptr;
-      } else if (ifPtr && eol - ptr >= strlen(tag) + 8 &&
+      } else if (ifPtr && eol - ptr >= (ssize_t)strlen(tag) + 8 &&
                  !memcmp(ptr, "[endif ", 7) &&
                  !memcmp(ptr + 7, tag, strlen(tag)) &&
                  ptr[7 + strlen(tag)] == ']') {
@@ -810,6 +812,7 @@ static void usage(void) {
 }
 
 static void destroyExternalFileHashEntry(void *arg, char *key, char *value) {
+  (void)arg;
   free(key);
   free(value);
 }
@@ -938,7 +941,7 @@ static void parseArgs(int argc, char * const argv[]) {
                                      st.st_size + 2));
         char *newData      = strrchr(cssStyleSheet, '\000');
         *newData++         = '\n';
-        if (fread(newData, 1, st.st_size, css) != st.st_size) {
+        if (fread(newData, st.st_size, 1, css) != 1) {
           fatal("Failed to read style sheet \"%s\"", optarg);
         }
         newData[st.st_size]= '\000';
@@ -1149,7 +1152,7 @@ static void parseArgs(int argc, char * const argv[]) {
 
 static void removeLimits() {
   static int res[] = { RLIMIT_CPU, RLIMIT_DATA, RLIMIT_FSIZE, RLIMIT_NPROC };
-  for (int i = 0; i < sizeof(res)/sizeof(int); i++) {
+  for (unsigned i = 0; i < sizeof(res)/sizeof(int); i++) {
     struct rlimit rl;
     getrlimit(res[i], &rl);
     if (rl.rlim_max < RLIM_INFINITY) {
index e94be7440c593f7cc67b077d50213d9a81b5aa1d..6be9b3e700253b6a0c2170c1d801e0dce015e573 100644 (file)
@@ -1,5 +1,5 @@
 // usercss.c -- Defines user-selectable CSS options
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -60,6 +60,9 @@
 static struct HashMap *defines;
 
 static void definesDestructor(void *arg, char *key, char *value) {
+  (void)arg;
+  (void)value;
+
   free(key);
 }
 
@@ -73,7 +76,7 @@ static void readStylesheet(struct UserCSS *userCSS, const char *filename,
   FILE *fp;
   check(fp                = fdopen(fd, "r"));
   check(*style            = malloc(st.st_size + 1));
-  check(fread(*style, 1, st.st_size, fp) == st.st_size);
+  check(fread(*style, st.st_size, 1, fp) == 1);
   (*style)[st.st_size]    = '\000';
   *len                    = st.st_size;
   fclose(fp);
index c46e0c0a1f3e78d3c2acfc2e60eee4f57a7d8230..e6fbf7980510456e10d0ad5c53c93d1fdd380104 100644 (file)
@@ -1,5 +1,5 @@
 // VT100.js -- JavaScript based terminal emulator
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -1955,8 +1955,8 @@ VT100.prototype.toggleBell = function() {
 };
 
 VT100.prototype.about = function() {
-  alert("VT100 Terminal Emulator " + "2.10 (revision 200)" +
-        "\nCopyright 2008-2009 by Markus Gutschke\n" +
+  alert("VT100 Terminal Emulator " + "2.10 (revision 202)" +
+        "\nCopyright 2008-2010 by Markus Gutschke\n" +
         "For more information check http://shellinabox.com");
 };
 
index bbbadcaec1c6c3207a67e1470310231bfbdccac1..4d83daaba78a1392310820b3671784ec48f2cc80 100644 (file)
@@ -1,5 +1,5 @@
 // VT100.js -- JavaScript based terminal emulator
-// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
+// Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
@@ -1956,7 +1956,7 @@ VT100.prototype.toggleBell = function() {
 
 VT100.prototype.about = function() {
   alert("VT100 Terminal Emulator " + VERSION +
-        "\nCopyright 2008-2009 by Markus Gutschke\n" +
+        "\nCopyright 2008-2010 by Markus Gutschke\n" +
         "For more information check http://shellinabox.com");
 };
 
This page took 0.160344 seconds and 5 git commands to generate.