Browse Source

wswrap: WSWRAP_PORT envvar and wswrap script.

wswrapper.so will only interpose on the listen port specified in
WSWRAP_PORT.

Add simple wswrap script that sets the WSWRAP_PORT, LD_PRELOAD and
invokes the command line to wrap.
Joel Martin 14 years ago
parent
commit
70c585968b
2 changed files with 85 additions and 4 deletions
  1. 22 0
      utils/wswrap
  2. 63 4
      utils/wswrapper.c

+ 22 - 0
utils/wswrap

@@ -0,0 +1,22 @@
+#!/bin/bash
+
+usage() {
+    echo "Usage: $(basename $0) PORT CMDLINE"
+    echo
+    echo "    PORT     Port to wrap with WebSockets support"
+    echo "    CMDLINE  Command line to wrap"
+    exit 2
+}
+
+# Parameter defaults
+mydir=$(dirname ${0})
+
+# Process parameters
+#while [ "${1}" != "${1#-}" ]; do
+#    param=$1; shift
+#done
+
+export WSWRAP_PORT="${1}"; shift
+
+LD_PRELOAD=${mydir}/wswrapper.so "${@}"
+

+ 63 - 4
utils/wswrapper.c

@@ -1,3 +1,13 @@
+/*
+ * wswrap/wswrapper: Add WebSockets support to any service.
+ * Copyright 2010 Joel Martin
+ * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
+ *
+ * Use wswrap to run a program using the wrapper.
+ */
+
+/* WARNING: multi-threaded programs are not supported */
+
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -47,14 +57,25 @@ Connection: Upgrade\r\n\
 %sWebSocket-Protocol: sample\r\n\
 \r\n%s";
 
-/* WARNING: threading not supported */
+/*
+ * If WSWRAP_PORT environment variable is set then listen to the bind fd that
+ * matches WSWRAP_PORT, otherwise listen to the first socket fd that bind is
+ * called on.
+ */
+int   _WS_listen_fd  = 0;
+int   _WS_sockfd     = 0;
+
+typedef struct {
+    char _WS_rbuf[65536];
+    char _WS_sbuf[65536];
+} _WS_connection;
+
 int   _WS_bufsize    = 65536;
 char *_WS_rbuf       = NULL;
 char *_WS_sbuf       = NULL;
 int   _WS_rcarry_cnt = 0;
 char  _WS_rcarry[3]  = "";
 int   _WS_newframe   = 1;
-int   _WS_sockfd     = 0;
 
 int _WS_init() {
     if (! (_WS_rbuf = malloc(_WS_bufsize)) ) {
@@ -525,16 +546,48 @@ int socket(int domain, int type, int protocol)
 
     return (int) func(domain, type, protocol);
 }
+*/
 
 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
 {
     static void * (*func)();
+    struct sockaddr_in * addr_in = (struct sockaddr_in *)addr;
+    char * WSWRAP_PORT, * end;
+    int fd, envport, bindport = htons(addr_in->sin_port);
     if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "bind");
     DEBUG("bind(%d, _, %d) called\n", sockfd, addrlen);
 
-    return (int) func(sockfd, addr, addrlen);
+    fd = (int) func(sockfd, addr, addrlen);
+
+    if (addr_in->sin_family != AF_INET) {
+        // TODO: handle IPv6
+        DEBUG("bind, ignoring non-IPv4 socket\n");
+        return fd;
+    }
+
+    WSWRAP_PORT = getenv("WSWRAP_PORT");
+    if ((! WSWRAP_PORT) || (*WSWRAP_PORT == '\0')) {
+        // TODO: interpose on all sockets
+        DEBUG("bind, not interposing: WSWRAP_PORT is not set\n");
+        return fd;
+    }
+
+    envport = strtol(WSWRAP_PORT, &end, 10);
+    if ((envport == 0) || (*end != '\0')) {
+        MSG("bind, not interposing: WSWRAP_PORT is not a number\n");
+        return fd;
+    }
+
+    if (envport != bindport) {
+        DEBUG("bind, not interposing on port %d\n", bindport);
+        return fd;
+    }
+
+    MSG("bind, interposing on port: %d\n", envport);
+    _WS_listen_fd = envport;
+
+    return fd;
 }
-*/
 
 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
 {
@@ -545,7 +598,13 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
 
     fd = (int) func(sockfd, addr, addrlen);
 
+    if (_WS_listen_fd == 0) {
+        DEBUG("not interposing\n");
+        return fd;
+    }
+
     if (_WS_sockfd == 0) {
+        // TODO: not just first connection
         _WS_sockfd = fd;
 
         if (!_WS_rbuf) {