optimize extpoll fd delete
[profile/ivi/libwebsockets.git] / test-server / test-server-extpoll.c
index 725fb95..5025f4d 100644 (file)
 #include <getopt.h>
 #include <string.h>
 #include <sys/time.h>
+#ifdef __MINGW32__
+#include "../win32port/win32helpers/websock-w32.h"
+#else
+#ifdef __MINGW64__
+#include "../win32port/win32helpers/websock-w32.h"
+#else
 #include <poll.h>
+#endif
+#endif
 
 #include "../lib/libwebsockets.h"
 
@@ -68,11 +76,12 @@ enum demo_protocols {
 };
 
 
-#define LOCAL_RESOURCE_PATH DATADIR"/libwebsockets-test-server"
+#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
 
 /* this protocol server (always the first one) just knows how to do HTTP */
 
-static int callback_http(struct libwebsocket *wsi,
+static int callback_http(struct libwebsocket_context * this,
+               struct libwebsocket *wsi,
                enum libwebsocket_callback_reasons reason, void *user,
                                                           void *in, size_t len)
 {
@@ -96,7 +105,8 @@ static int callback_http(struct libwebsocket *wsi,
                if (libwebsockets_serve_http_file(wsi,
                                  LOCAL_RESOURCE_PATH"/test.html", "text/html"))
                        fprintf(stderr, "Failed to send HTTP file\n");
-               break;
+               /* we are done with this connnection */
+               return 1;
 
        /*
         * callback for confirming to continue with client IP appear in
@@ -129,13 +139,18 @@ static int callback_http(struct libwebsocket *wsi,
                break;
 
        case LWS_CALLBACK_DEL_POLL_FD:
-               for (n = 0; n < count_pollfds; n++)
-                       if (pollfds[n].fd == (int)(long)user)
-                               while (n < count_pollfds) {
-                                       pollfds[n] = pollfds[n + 1];
-                                       n++;
-                               }
-               count_pollfds--;
+               for (n = 0; n < count_pollfds; n++) {
+                       if (pollfds[n].fd != (int)(long)user)
+                               continue;
+                       /*
+                        * swap the end guy into our vacant slot...
+                        * works ok if n is the end guy
+                        */
+                       pollfds[n] = pollfds[count_pollfds - 1];
+                       pollfds[count_pollfds - 1].fd = -1;
+                       count_pollfds--;
+                       break;
+               }
                break;
 
        case LWS_CALLBACK_SET_MODE_POLL_FD:
@@ -157,6 +172,51 @@ static int callback_http(struct libwebsocket *wsi,
        return 0;
 }
 
+/*
+ * this is just an example of parsing handshake headers, you don't need this
+ * in your code unless you will filter allowing connections by the header
+ * content
+ */
+
+static void
+dump_handshake_info(struct lws_tokens *lwst)
+{
+       int n;
+       static const char *token_names[] = {
+               [WSI_TOKEN_GET_URI] = "GET URI",
+               [WSI_TOKEN_HOST] = "Host",
+               [WSI_TOKEN_CONNECTION] = "Connection",
+               [WSI_TOKEN_KEY1] = "key 1",
+               [WSI_TOKEN_KEY2] = "key 2",
+               [WSI_TOKEN_PROTOCOL] = "Protocol",
+               [WSI_TOKEN_UPGRADE] = "Upgrade",
+               [WSI_TOKEN_ORIGIN] = "Origin",
+               [WSI_TOKEN_DRAFT] = "Draft",
+               [WSI_TOKEN_CHALLENGE] = "Challenge",
+
+               /* new for 04 */
+               [WSI_TOKEN_KEY] = "Key",
+               [WSI_TOKEN_VERSION] = "Version",
+               [WSI_TOKEN_SWORIGIN] = "Sworigin",
+
+               /* new for 05 */
+               [WSI_TOKEN_EXTENSIONS] = "Extensions",
+
+               /* client receives these */
+               [WSI_TOKEN_ACCEPT] = "Accept",
+               [WSI_TOKEN_NONCE] = "Nonce",
+               [WSI_TOKEN_HTTP] = "Http",
+               [WSI_TOKEN_MUXURL]      = "MuxURL",
+       };
+       
+       for (n = 0; n < WSI_TOKEN_COUNT; n++) {
+               if (lwst[n].token == NULL)
+                       continue;
+
+               fprintf(stderr, "    %s = %s\n", token_names[n], lwst[n].token);
+       }
+}
+
 /* dumb_increment protocol */
 
 /*
@@ -172,7 +232,8 @@ struct per_session_data__dumb_increment {
 };
 
 static int
-callback_dumb_increment(struct libwebsocket *wsi,
+callback_dumb_increment(struct libwebsocket_context * this,
+                       struct libwebsocket *wsi,
                        enum libwebsocket_callback_reasons reason,
                                               void *user, void *in, size_t len)
 {
@@ -198,7 +259,7 @@ callback_dumb_increment(struct libwebsocket *wsi,
                n = sprintf((char *)p, "%d", pss->number++);
                n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
                if (n < 0) {
-                       fprintf(stderr, "ERROR writing to socket");
+                       fprintf(stderr, "ERROR %d writing to socket\n", n);
                        return 1;
                }
                break;
@@ -211,6 +272,17 @@ callback_dumb_increment(struct libwebsocket *wsi,
                        pss->number = 0;
                break;
 
+       /*
+        * this just demonstrates how to use the protocol filter. If you won't
+        * study and reject connections based on header content, you don't need
+        * to handle this callback
+        */
+
+       case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
+               dump_handshake_info((struct lws_tokens *)(long)user);
+               /* you could return non-zero here and kill the connection */
+               break;
+
        default:
                break;
        }
@@ -238,7 +310,8 @@ static int ringbuffer_head;
 
 
 static int
-callback_lws_mirror(struct libwebsocket *wsi,
+callback_lws_mirror(struct libwebsocket_context * this,
+                       struct libwebsocket *wsi,
                        enum libwebsocket_callback_reasons reason,
                                               void *user, void *in, size_t len)
 {
@@ -250,10 +323,10 @@ callback_lws_mirror(struct libwebsocket *wsi,
        case LWS_CALLBACK_ESTABLISHED:
                pss->ringbuffer_tail = ringbuffer_head;
                pss->wsi = wsi;
-               libwebsocket_callback_on_writable(wsi);
+               libwebsocket_callback_on_writable(this, wsi);
                break;
 
-       case LWS_CALLBACK_CLIENT_WRITEABLE:
+       case LWS_CALLBACK_SERVER_WRITEABLE:
 
                if (pss->ringbuffer_tail != ringbuffer_head) {
 
@@ -264,7 +337,7 @@ callback_lws_mirror(struct libwebsocket *wsi,
                                                                LWS_WRITE_TEXT);
 
                        if (n < 0) {
-                               fprintf(stderr, "ERROR writing to socket");
+                               fprintf(stderr, "ERROR %d writing to socket\n", n);
                                exit(1);
                        }
 
@@ -277,7 +350,7 @@ callback_lws_mirror(struct libwebsocket *wsi,
                                  MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
                                libwebsocket_rx_flow_control(wsi, 1);
 
-                       libwebsocket_callback_on_writable(wsi);
+                       libwebsocket_callback_on_writable(this, wsi);
 
                }
                break;
@@ -312,6 +385,17 @@ callback_lws_mirror(struct libwebsocket *wsi,
                                               libwebsockets_get_protocol(wsi));
                break;
 
+       /*
+        * this just demonstrates how to use the protocol filter. If you won't
+        * study and reject connections based on header content, you don't need
+        * to handle this callback
+        */
+
+       case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
+               dump_handshake_info((struct lws_tokens *)(long)user);
+               /* you could return non-zero here and kill the connection */
+               break;
+
        default:
                break;
        }
@@ -324,32 +408,34 @@ callback_lws_mirror(struct libwebsocket *wsi,
 
 static struct libwebsocket_protocols protocols[] = {
        /* first protocol must always be HTTP handler */
-       [PROTOCOL_HTTP] = {
-               .name = "http-only",
-               .callback = callback_http,
+
+       {
+               "http-only",            /* name */
+               callback_http,          /* callback */
+               0                       /* per_session_data_size */
        },
-       [PROTOCOL_DUMB_INCREMENT] = {
-               .name = "dumb-increment-protocol",
-               .callback = callback_dumb_increment,
-               .per_session_data_size =
-                               sizeof(struct per_session_data__dumb_increment),
+       {
+               "dumb-increment-protocol",
+               callback_dumb_increment,
+               sizeof(struct per_session_data__dumb_increment),
        },
-       [PROTOCOL_LWS_MIRROR] = {
-               .name = "lws-mirror-protocol",
-               .callback = callback_lws_mirror,
-               .per_session_data_size =
-                               sizeof(struct per_session_data__lws_mirror),
+       {
+               "lws-mirror-protocol",
+               callback_lws_mirror,
+               sizeof(struct per_session_data__lws_mirror)
        },
-       [DEMO_PROTOCOL_COUNT] = {  /* end of list */
-               .callback = NULL
+       {
+               NULL, NULL, 0           /* End of list */
        }
 };
 
 static struct option options[] = {
        { "help",       no_argument,            NULL, 'h' },
+       { "debug",      required_argument,      NULL, 'd' },
        { "port",       required_argument,      NULL, 'p' },
        { "ssl",        no_argument,            NULL, 's' },
        { "killmask",   no_argument,            NULL, 'k' },
+       { "interface",  required_argument,      NULL, 'i' },
        { NULL, 0, 0, 0 }
 };
 
@@ -357,9 +443,9 @@ int main(int argc, char **argv)
 {
        int n = 0;
        const char *cert_path =
-                           LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
+                          LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
        const char *key_path =
-                       LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
+                      LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
        unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
                                                  LWS_SEND_BUFFER_POST_PADDING];
        int port = 7681;
@@ -367,16 +453,21 @@ int main(int argc, char **argv)
        struct libwebsocket_context *context;
        int opts = 0;
        unsigned int oldus = 0;
+       char interface_name[128] = "";
+       const char *interface_ptr = NULL;
 
        fprintf(stderr, "libwebsockets test server with external poll()\n"
                        "(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
                                                    "licensed under LGPL2.1\n");
 
        while (n >= 0) {
-               n = getopt_long(argc, argv, "khsp:", options, NULL);
+               n = getopt_long(argc, argv, "i:khsp:d:", options, NULL);
                if (n < 0)
                        continue;
                switch (n) {
+               case 'd':
+                       lws_set_log_level(atoi(optarg), NULL);
+                       break;
                case 's':
                        use_ssl = 1;
                        break;
@@ -386,9 +477,15 @@ int main(int argc, char **argv)
                case 'p':
                        port = atoi(optarg);
                        break;
+               case 'i':
+                       strncpy(interface_name, optarg, sizeof interface_name);
+                       interface_name[(sizeof interface_name) - 1] = '\0';
+                       interface_ptr = interface_name;
+                       break;
                case 'h':
                        fprintf(stderr, "Usage: test-server "
-                                            "[--port=<p>] [--ssl]\n");
+                                       "[--port=<p>] [--ssl] "
+                                       "[-d <log bitfield>]\n");
                        exit(1);
                }
        }
@@ -396,8 +493,10 @@ int main(int argc, char **argv)
        if (!use_ssl)
                cert_path = key_path = NULL;
 
-       context = libwebsocket_create_context(port, protocols, cert_path,
-                                               key_path, -1, -1, opts);
+       context = libwebsocket_create_context(port, interface_ptr, protocols,
+                                       libwebsocket_internal_extensions,
+                                       cert_path, key_path, NULL, -1, -1,
+                                       opts, NULL);
        if (context == NULL) {
                fprintf(stderr, "libwebsocket init failed\n");
                return -1;
@@ -430,8 +529,9 @@ int main(int argc, char **argv)
                                        * match anything under libwebsockets
                                        * control
                                        */
-                                       libwebsocket_service_fd(context,
-                                                                  &pollfds[n]);
+                                       if (libwebsocket_service_fd(context,
+                                                                 &pollfds[n]))
+                                               goto done;
 
                /* do our broadcast periodically */