#
# Helper function for adding a test app.
#
- macro(create_test_app TEST_NAME MAIN_SRC)
+ macro(create_test_app TEST_NAME MAIN_SRC S2 S3 S4)
set(TEST_SRCS ${MAIN_SRC})
set(TEST_HDR)
-
+ if ("${S2}" STREQUAL "")
+ else()
+ list(APPEND TEST_SRCS ${S2})
+ endif()
+ if ("${S3}" STREQUAL "")
+ else()
+ list(APPEND TEST_SRCS ${S3})
+ endif()
+ if ("${S4}" STREQUAL "")
+ else()
+ list(APPEND TEST_SRCS ${S4})
+ endif()
if (WIN32)
list(APPEND TEST_SRCS
${WIN32_HELPERS_PATH}/getopt.c
# test-server
#
if (NOT LWS_WITHOUT_TEST_SERVER)
- create_test_app(test-server "test-server/test-server.c")
+ create_test_app(test-server "test-server/test-server.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c")
endif()
#
# test-server-extpoll
#
if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL)
- create_test_app(test-server-extpoll "test-server/test-server.c")
+ create_test_app(test-server-extpoll "test-server/test-server.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c")
# Set defines for this executable only.
set_property(
TARGET test-server-extpoll
# test-client
#
if (NOT LWS_WITHOUT_TEST_CLIENT)
- create_test_app(test-client "test-server/test-client.c")
+ create_test_app(test-client "test-server/test-client.c" "" "" "")
endif()
#
# test-fraggle
#
if (NOT LWS_WITHOUT_TEST_FRAGGLE)
- create_test_app(test-fraggle "test-server/test-fraggle.c")
+ create_test_app(test-fraggle "test-server/test-fraggle.c" "" "" "")
endif()
#
# test-ping
#
if (NOT LWS_WITHOUT_TEST_PING)
- create_test_app(test-ping "test-server/test-ping.c")
+ create_test_app(test-ping "test-server/test-ping.c" "" "" "")
endif()
#
# test-echo
#
if (NOT WITHOUT_TEST_ECHO)
- create_test_app(test-echo "test-server/test-echo.c")
+ create_test_app(test-echo "test-server/test-echo.c" "" "" "")
endif()
endif(NOT LWS_WITHOUT_CLIENT)
--- /dev/null
+/*
+ * libwebsockets-test-server - libwebsockets test implementation
+ *
+ * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include "test-server.h"
+
+/* dumb_increment protocol */
+
+int
+callback_dumb_increment(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
+ LWS_SEND_BUFFER_POST_PADDING];
+ struct per_session_data__dumb_increment *pss =
+ (struct per_session_data__dumb_increment *)user;
+ unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
+ int n, m;
+
+ switch (reason) {
+
+ case LWS_CALLBACK_ESTABLISHED:
+ pss->number = 0;
+ break;
+
+ case LWS_CALLBACK_SERVER_WRITEABLE:
+ n = sprintf((char *)p, "%d", pss->number++);
+ m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
+ if (m < n) {
+ lwsl_err("ERROR %d writing to di socket\n", n);
+ return -1;
+ }
+ if (close_testing && pss->number == 50) {
+ lwsl_info("close tesing limit, closing\n");
+ return -1;
+ }
+ break;
+
+ case LWS_CALLBACK_RECEIVE:
+ if (len < 6)
+ break;
+ if (strcmp((const char *)in, "reset\n") == 0)
+ 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(wsi);
+ /* you could return non-zero here and kill the connection */
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * libwebsockets-test-server - libwebsockets test implementation
+ *
+ * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include "test-server.h"
+
+/*
+ * This demo server shows how to use libwebsockets for one or more
+ * websocket protocols in the same server
+ *
+ * It defines the following websocket protocols:
+ *
+ * dumb-increment-protocol: once the socket is opened, an incrementing
+ * ascii string is sent down it every 50ms.
+ * If you send "reset\n" on the websocket, then
+ * the incrementing number is reset to 0.
+ *
+ * lws-mirror-protocol: copies any received packet to every connection also
+ * using this protocol, including the sender
+ */
+
+enum demo_protocols {
+ /* always first */
+ PROTOCOL_HTTP = 0,
+
+ PROTOCOL_DUMB_INCREMENT,
+ PROTOCOL_LWS_MIRROR,
+
+ /* always last */
+ DEMO_PROTOCOL_COUNT
+};
+
+/*
+ * We take a strict whitelist approach to stop ../ attacks
+ */
+struct serveable {
+ const char *urlpath;
+ const char *mimetype;
+};
+
+/*
+ * 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
+ */
+void
+dump_handshake_info(struct libwebsocket *wsi)
+{
+ int n = 0;
+ char buf[256];
+ const unsigned char *c;
+
+ do {
+ c = lws_token_to_string(n);
+ if (!c) {
+ n++;
+ continue;
+ }
+
+ if (!lws_hdr_total_length(wsi, n)) {
+ n++;
+ continue;
+ }
+
+ lws_hdr_copy(wsi, buf, sizeof buf, n);
+
+ fprintf(stderr, " %s = %s\n", (char *)c, buf);
+ n++;
+ } while (c);
+}
+
+const char * get_mimetype(const char *file)
+{
+ int n = strlen(file);
+
+ if (n < 5)
+ return NULL;
+
+ if (!strcmp(&file[n - 4], ".ico"))
+ return "image/x-icon";
+
+ if (!strcmp(&file[n - 4], ".png"))
+ return "image/png";
+
+ if (!strcmp(&file[n - 5], ".html"))
+ return "text/html";
+
+ return NULL;
+}
+
+/* this protocol server (always the first one) handles HTTP,
+ *
+ * Some misc callbacks that aren't associated with a protocol also turn up only
+ * here on the first protocol server.
+ */
+
+int callback_http(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason, void *user,
+ void *in, size_t len)
+{
+ struct per_session_data__http *pss =
+ (struct per_session_data__http *)user;
+ static unsigned char buffer[4096];
+ struct stat stat_buf;
+ char leaf_path[1024];
+ const char *mimetype;
+ char *other_headers;
+ unsigned char *end;
+ struct timeval tv;
+ unsigned char *p;
+ char buf[256];
+ char b64[64];
+ int n, m;
+
+#ifdef EXTERNAL_POLL
+ struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *)in;
+#endif
+
+ switch (reason) {
+ case LWS_CALLBACK_HTTP:
+
+ dump_handshake_info(wsi);
+
+ if (len < 1) {
+ libwebsockets_return_http_status(context, wsi,
+ HTTP_STATUS_BAD_REQUEST, NULL);
+ goto try_to_reuse;
+ }
+
+ /* this example server has no concept of directories */
+ if (strchr((const char *)in + 1, '/')) {
+ libwebsockets_return_http_status(context, wsi,
+ HTTP_STATUS_FORBIDDEN, NULL);
+ goto try_to_reuse;
+ }
+
+ /* if a legal POST URL, let it continue and accept data */
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
+ return 0;
+
+ /* check for the "send a big file by hand" example case */
+
+ if (!strcmp((const char *)in, "/leaf.jpg")) {
+ if (strlen(resource_path) > sizeof(leaf_path) - 10)
+ return -1;
+ sprintf(leaf_path, "%s/leaf.jpg", resource_path);
+
+ /* well, let's demonstrate how to send the hard way */
+
+ p = buffer + LWS_SEND_BUFFER_PRE_PADDING;
+ end = p + sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
+#ifdef _WIN32
+ pss->fd = open(leaf_path, O_RDONLY | _O_BINARY);
+#else
+ pss->fd = open(leaf_path, O_RDONLY);
+#endif
+
+ if (pss->fd < 0)
+ return -1;
+
+ if (fstat(pss->fd, &stat_buf) < 0)
+ return -1;
+
+ /*
+ * we will send a big jpeg file, but it could be
+ * anything. Set the Content-Type: appropriately
+ * so the browser knows what to do with it.
+ *
+ * Notice we use the APIs to build the header, which
+ * will do the right thing for HTTP 1/1.1 and HTTP2
+ * depending on what connection it happens to be working
+ * on
+ */
+ if (lws_add_http_header_status(context, wsi, 200, &p, end))
+ return 1;
+ if (lws_add_http_header_by_token(context, wsi,
+ WSI_TOKEN_HTTP_SERVER,
+ (unsigned char *)"libwebsockets",
+ 13, &p, end))
+ return 1;
+ if (lws_add_http_header_by_token(context, wsi,
+ WSI_TOKEN_HTTP_CONTENT_TYPE,
+ (unsigned char *)"image/jpeg",
+ 10, &p, end))
+ return 1;
+ if (lws_add_http_header_content_length(context, wsi,
+ stat_buf.st_size, &p, end))
+ return 1;
+ if (lws_finalize_http_header(context, wsi, &p, end))
+ return 1;
+
+ /*
+ * send the http headers...
+ * this won't block since it's the first payload sent
+ * on the connection since it was established
+ * (too small for partial)
+ *
+ * Notice they are sent using LWS_WRITE_HTTP_HEADERS
+ * which also means you can't send body too in one step,
+ * this is mandated by changes in HTTP2
+ */
+
+ n = libwebsocket_write(wsi,
+ buffer + LWS_SEND_BUFFER_PRE_PADDING,
+ p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
+ LWS_WRITE_HTTP_HEADERS);
+
+ if (n < 0) {
+ close(pss->fd);
+ return -1;
+ }
+ /*
+ * book us a LWS_CALLBACK_HTTP_WRITEABLE callback
+ */
+ libwebsocket_callback_on_writable(context, wsi);
+ break;
+ }
+
+ /* if not, send a file the easy way */
+ strcpy(buf, resource_path);
+ if (strcmp(in, "/")) {
+ if (*((const char *)in) != '/')
+ strcat(buf, "/");
+ strncat(buf, in, sizeof(buf) - strlen(resource_path));
+ } else /* default file to serve */
+ strcat(buf, "/test.html");
+ buf[sizeof(buf) - 1] = '\0';
+
+ /* refuse to serve files we don't understand */
+ mimetype = get_mimetype(buf);
+ if (!mimetype) {
+ lwsl_err("Unknown mimetype for %s\n", buf);
+ libwebsockets_return_http_status(context, wsi,
+ HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
+ return -1;
+ }
+
+ /* demostrates how to set a cookie on / */
+
+ other_headers = NULL;
+ n = 0;
+ if (!strcmp((const char *)in, "/") &&
+ !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
+ /* this isn't very unguessable but it'll do for us */
+ gettimeofday(&tv, NULL);
+ n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000",
+ (unsigned int)tv.tv_sec,
+ (unsigned int)tv.tv_usec);
+
+ p = (unsigned char *)leaf_path;
+
+ if (lws_add_http_header_by_name(context, wsi,
+ (unsigned char *)"set-cookie:",
+ (unsigned char *)b64, n, &p,
+ (unsigned char *)leaf_path + sizeof(leaf_path)))
+ return 1;
+ n = (char *)p - leaf_path;
+ other_headers = leaf_path;
+ }
+
+ n = libwebsockets_serve_http_file(context, wsi, buf,
+ mimetype, other_headers, n);
+ if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
+ return -1; /* error or can't reuse connection: close the socket */
+
+ /*
+ * notice that the sending of the file completes asynchronously,
+ * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
+ * it's done
+ */
+
+ break;
+
+ case LWS_CALLBACK_HTTP_BODY:
+ strncpy(buf, in, 20);
+ buf[20] = '\0';
+ if (len < 20)
+ buf[len] = '\0';
+
+ lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n",
+ (const char *)buf, (int)len);
+
+ break;
+
+ case LWS_CALLBACK_HTTP_BODY_COMPLETION:
+ lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
+ /* the whole of the sent body arrived, close or reuse the connection */
+ libwebsockets_return_http_status(context, wsi,
+ HTTP_STATUS_OK, NULL);
+ goto try_to_reuse;
+
+ case LWS_CALLBACK_HTTP_FILE_COMPLETION:
+ goto try_to_reuse;
+
+ case LWS_CALLBACK_HTTP_WRITEABLE:
+ /*
+ * we can send more of whatever it is we were sending
+ */
+ do {
+ /* we'd like the send this much */
+ n = sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
+
+ /* but if the peer told us he wants less, we can adapt */
+ m = lws_get_peer_write_allowance(wsi);
+
+ /* -1 means not using a protocol that has this info */
+ if (m == 0)
+ /* right now, peer can't handle anything */
+ goto later;
+
+ if (m != -1 && m < n)
+ /* he couldn't handle that much */
+ n = m;
+
+ n = read(pss->fd, buffer + LWS_SEND_BUFFER_PRE_PADDING,
+ n);
+ /* problem reading, close conn */
+ if (n < 0)
+ goto bail;
+ /* sent it all, close conn */
+ if (n == 0)
+ goto flush_bail;
+ /*
+ * To support HTTP2, must take care about preamble space
+ *
+ * identification of when we send the last payload frame
+ * is handled by the library itself if you sent a
+ * content-length header
+ */
+ m = libwebsocket_write(wsi,
+ buffer + LWS_SEND_BUFFER_PRE_PADDING,
+ n, LWS_WRITE_HTTP);
+ if (m < 0)
+ /* write failed, close conn */
+ goto bail;
+
+ /*
+ * http2 won't do this
+ */
+ if (m != n)
+ /* partial write, adjust */
+ if (lseek(pss->fd, m - n, SEEK_CUR) < 0)
+ goto bail;
+
+ if (m) /* while still active, extend timeout */
+ libwebsocket_set_timeout(wsi,
+ PENDING_TIMEOUT_HTTP_CONTENT, 5);
+
+ /* if we have indigestion, let him clear it before eating more */
+ if (lws_partial_buffered(wsi))
+ break;
+
+ } while (!lws_send_pipe_choked(wsi));
+
+later:
+ libwebsocket_callback_on_writable(context, wsi);
+ break;
+flush_bail:
+ /* true if still partial pending */
+ if (lws_partial_buffered(wsi)) {
+ libwebsocket_callback_on_writable(context, wsi);
+ break;
+ }
+ close(pss->fd);
+ goto try_to_reuse;
+
+bail:
+ close(pss->fd);
+ return -1;
+
+ /*
+ * callback for confirming to continue with client IP appear in
+ * protocol 0 callback since no websocket protocol has been agreed
+ * yet. You can just ignore this if you won't filter on client IP
+ * since the default uhandled callback return is 0 meaning let the
+ * connection continue.
+ */
+ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
+
+ /* if we returned non-zero from here, we kill the connection */
+ break;
+
+#ifdef EXTERNAL_POLL
+ /*
+ * callbacks for managing the external poll() array appear in
+ * protocol 0 callback
+ */
+
+ case LWS_CALLBACK_LOCK_POLL:
+ /*
+ * lock mutex to protect pollfd state
+ * called before any other POLL related callback
+ */
+ break;
+
+ case LWS_CALLBACK_UNLOCK_POLL:
+ /*
+ * unlock mutex to protect pollfd state when
+ * called after any other POLL related callback
+ */
+ break;
+
+ case LWS_CALLBACK_ADD_POLL_FD:
+
+ if (count_pollfds >= max_poll_elements) {
+ lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
+ return 1;
+ }
+
+ fd_lookup[pa->fd] = count_pollfds;
+ pollfds[count_pollfds].fd = pa->fd;
+ pollfds[count_pollfds].events = pa->events;
+ pollfds[count_pollfds++].revents = 0;
+ break;
+
+ case LWS_CALLBACK_DEL_POLL_FD:
+ if (!--count_pollfds)
+ break;
+ m = fd_lookup[pa->fd];
+ /* have the last guy take up the vacant slot */
+ pollfds[m] = pollfds[count_pollfds];
+ fd_lookup[pollfds[count_pollfds].fd] = m;
+ break;
+
+ case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
+ pollfds[fd_lookup[pa->fd]].events = pa->events;
+ break;
+#endif
+
+ case LWS_CALLBACK_GET_THREAD_ID:
+ /*
+ * if you will call "libwebsocket_callback_on_writable"
+ * from a different thread, return the caller thread ID
+ * here so lws can use this information to work out if it
+ * should signal the poll() loop to exit and restart early
+ */
+
+ /* return pthread_getthreadid_np(); */
+
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+
+ /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */
+try_to_reuse:
+ if (lws_http_transaction_completed(wsi))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * libwebsockets-test-server - libwebsockets test implementation
+ *
+ * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include "test-server.h"
+
+/* lws-mirror_protocol */
+
+#define MAX_MESSAGE_QUEUE 32
+
+struct a_message {
+ void *payload;
+ size_t len;
+};
+
+static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
+static int ringbuffer_head;
+
+int
+callback_lws_mirror(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ struct per_session_data__lws_mirror *pss =
+ (struct per_session_data__lws_mirror *)user;
+ int n;
+
+ switch (reason) {
+
+ case LWS_CALLBACK_ESTABLISHED:
+ lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
+ pss->ringbuffer_tail = ringbuffer_head;
+ pss->wsi = wsi;
+ break;
+
+ case LWS_CALLBACK_PROTOCOL_DESTROY:
+ lwsl_notice("%s: mirror protocol cleaning up\n", __func__);
+ for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
+ if (ringbuffer[n].payload)
+ free(ringbuffer[n].payload);
+ break;
+
+ case LWS_CALLBACK_SERVER_WRITEABLE:
+ if (close_testing)
+ break;
+ while (pss->ringbuffer_tail != ringbuffer_head) {
+
+ n = libwebsocket_write(wsi, (unsigned char *)
+ ringbuffer[pss->ringbuffer_tail].payload +
+ LWS_SEND_BUFFER_PRE_PADDING,
+ ringbuffer[pss->ringbuffer_tail].len,
+ LWS_WRITE_TEXT);
+ if (n < 0) {
+ lwsl_err("ERROR %d writing to mirror socket\n", n);
+ return -1;
+ }
+ if (n < ringbuffer[pss->ringbuffer_tail].len)
+ lwsl_err("mirror partial write %d vs %d\n",
+ n, ringbuffer[pss->ringbuffer_tail].len);
+
+ if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
+ pss->ringbuffer_tail = 0;
+ else
+ pss->ringbuffer_tail++;
+
+ if (((ringbuffer_head - pss->ringbuffer_tail) &
+ (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
+ libwebsocket_rx_flow_allow_all_protocol(
+ libwebsockets_get_protocol(wsi));
+
+ if (lws_partial_buffered(wsi) || lws_send_pipe_choked(wsi)) {
+ libwebsocket_callback_on_writable(context, wsi);
+ break;
+ }
+ /*
+ * for tests with chrome on same machine as client and
+ * server, this is needed to stop chrome choking
+ */
+#ifdef _WIN32
+ Sleep(1);
+#else
+ usleep(1);
+#endif
+ }
+ break;
+
+ case LWS_CALLBACK_RECEIVE:
+ if (((ringbuffer_head - pss->ringbuffer_tail) &
+ (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
+ lwsl_err("dropping!\n");
+ goto choke;
+ }
+
+ if (ringbuffer[ringbuffer_head].payload)
+ free(ringbuffer[ringbuffer_head].payload);
+
+ ringbuffer[ringbuffer_head].payload =
+ malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
+ LWS_SEND_BUFFER_POST_PADDING);
+ ringbuffer[ringbuffer_head].len = len;
+ memcpy((char *)ringbuffer[ringbuffer_head].payload +
+ LWS_SEND_BUFFER_PRE_PADDING, in, len);
+ if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
+ ringbuffer_head = 0;
+ else
+ ringbuffer_head++;
+
+ if (((ringbuffer_head - pss->ringbuffer_tail) &
+ (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
+ goto done;
+
+choke:
+ lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
+ libwebsocket_rx_flow_control(wsi, 0);
+
+done:
+ libwebsocket_callback_on_writable_all_protocol(
+ 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(wsi);
+ /* you could return non-zero here and kill the connection */
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
/*
* libwebsockets-test-server - libwebsockets test implementation
*
- * Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
-#include "lws_config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <assert.h>
+#include "test-server.h"
-#include "../lib/libwebsockets.h"
-
-#ifdef _WIN32
-#include <io.h>
-#ifdef EXTERNAL_POLL
-#define poll WSAPoll
-#endif
-#include "gettimeofday.h"
-#else
-#include <syslog.h>
-#include <sys/time.h>
-#include <unistd.h>
-#endif
-
-static int close_testing;
+int close_testing;
int max_poll_elements;
#ifdef EXTERNAL_POLL
int *fd_lookup;
int count_pollfds;
#endif
-static volatile int force_exit = 0;
-static struct libwebsocket_context *context;
+volatile int force_exit = 0;
+struct libwebsocket_context *context;
+
+/* http server gets files from this path */
+#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
+char *resource_path = LOCAL_RESOURCE_PATH;
/*
* This demo server shows how to use libwebsockets for one or more
DEMO_PROTOCOL_COUNT
};
-
-#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
-char *resource_path = LOCAL_RESOURCE_PATH;
-
-/*
- * We take a strict whitelist approach to stop ../ attacks
- */
-
-struct serveable {
- const char *urlpath;
- const char *mimetype;
-};
-
-struct per_session_data__http {
- int fd;
-};
-
-/*
- * 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 libwebsocket *wsi)
-{
- int n = 0;
- char buf[256];
- const unsigned char *c;
-
- do {
- c = lws_token_to_string(n);
- if (!c) {
- n++;
- continue;
- }
-
- if (!lws_hdr_total_length(wsi, n)) {
- n++;
- continue;
- }
-
- lws_hdr_copy(wsi, buf, sizeof buf, n);
-
- fprintf(stderr, " %s = %s\n", (char *)c, buf);
- n++;
- } while (c);
-}
-
-const char * get_mimetype(const char *file)
-{
- int n = strlen(file);
-
- if (n < 5)
- return NULL;
-
- if (!strcmp(&file[n - 4], ".ico"))
- return "image/x-icon";
-
- if (!strcmp(&file[n - 4], ".png"))
- return "image/png";
-
- if (!strcmp(&file[n - 5], ".html"))
- return "text/html";
-
- return NULL;
-}
-
-/* this protocol server (always the first one) just knows how to do HTTP */
-
-static int callback_http(struct libwebsocket_context *context,
- struct libwebsocket *wsi,
- enum libwebsocket_callback_reasons reason, void *user,
- void *in, size_t len)
-{
- char buf[256];
- char leaf_path[1024];
- char b64[64];
- struct timeval tv;
- int n, m;
- unsigned char *p;
- char *other_headers;
- static unsigned char buffer[4096];
- struct stat stat_buf;
- struct per_session_data__http *pss =
- (struct per_session_data__http *)user;
- const char *mimetype;
-#ifdef EXTERNAL_POLL
- struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *)in;
-#endif
- unsigned char *end;
- switch (reason) {
- case LWS_CALLBACK_HTTP:
-
- dump_handshake_info(wsi);
-
- if (len < 1) {
- libwebsockets_return_http_status(context, wsi,
- HTTP_STATUS_BAD_REQUEST, NULL);
- goto try_to_reuse;
- }
-
- /* this example server has no concept of directories */
- if (strchr((const char *)in + 1, '/')) {
- libwebsockets_return_http_status(context, wsi,
- HTTP_STATUS_FORBIDDEN, NULL);
- goto try_to_reuse;
- }
-
- /* if a legal POST URL, let it continue and accept data */
- if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
- return 0;
-
- /* check for the "send a big file by hand" example case */
-
- if (!strcmp((const char *)in, "/leaf.jpg")) {
- if (strlen(resource_path) > sizeof(leaf_path) - 10)
- return -1;
- sprintf(leaf_path, "%s/leaf.jpg", resource_path);
-
- /* well, let's demonstrate how to send the hard way */
-
- p = buffer + LWS_SEND_BUFFER_PRE_PADDING;
- end = p + sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
-#ifdef _WIN32
- pss->fd = open(leaf_path, O_RDONLY | _O_BINARY);
-#else
- pss->fd = open(leaf_path, O_RDONLY);
-#endif
-
- if (pss->fd < 0)
- return -1;
-
- if (fstat(pss->fd, &stat_buf) < 0)
- return -1;
-
- /*
- * we will send a big jpeg file, but it could be
- * anything. Set the Content-Type: appropriately
- * so the browser knows what to do with it.
- *
- * Notice we use the APIs to build the header, which
- * will do the right thing for HTTP 1/1.1 and HTTP2
- * depending on what connection it happens to be working
- * on
- */
- if (lws_add_http_header_status(context, wsi, 200, &p, end))
- return 1;
- if (lws_add_http_header_by_token(context, wsi,
- WSI_TOKEN_HTTP_SERVER,
- (unsigned char *)"libwebsockets",
- 13, &p, end))
- return 1;
- if (lws_add_http_header_by_token(context, wsi,
- WSI_TOKEN_HTTP_CONTENT_TYPE,
- (unsigned char *)"image/jpeg",
- 10, &p, end))
- return 1;
- if (lws_add_http_header_content_length(context, wsi,
- stat_buf.st_size, &p, end))
- return 1;
- if (lws_finalize_http_header(context, wsi, &p, end))
- return 1;
-
- /*
- * send the http headers...
- * this won't block since it's the first payload sent
- * on the connection since it was established
- * (too small for partial)
- *
- * Notice they are sent using LWS_WRITE_HTTP_HEADERS
- * which also means you can't send body too in one step,
- * this is mandated by changes in HTTP2
- */
-
- n = libwebsocket_write(wsi,
- buffer + LWS_SEND_BUFFER_PRE_PADDING,
- p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
- LWS_WRITE_HTTP_HEADERS);
-
- if (n < 0) {
- close(pss->fd);
- return -1;
- }
- /*
- * book us a LWS_CALLBACK_HTTP_WRITEABLE callback
- */
- libwebsocket_callback_on_writable(context, wsi);
- break;
- }
-
- /* if not, send a file the easy way */
- strcpy(buf, resource_path);
- if (strcmp(in, "/")) {
- if (*((const char *)in) != '/')
- strcat(buf, "/");
- strncat(buf, in, sizeof(buf) - strlen(resource_path));
- } else /* default file to serve */
- strcat(buf, "/test.html");
- buf[sizeof(buf) - 1] = '\0';
-
- /* refuse to serve files we don't understand */
- mimetype = get_mimetype(buf);
- if (!mimetype) {
- lwsl_err("Unknown mimetype for %s\n", buf);
- libwebsockets_return_http_status(context, wsi,
- HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
- return -1;
- }
-
- /* demostrates how to set a cookie on / */
-
- other_headers = NULL;
- n = 0;
- if (!strcmp((const char *)in, "/") &&
- !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
- /* this isn't very unguessable but it'll do for us */
- gettimeofday(&tv, NULL);
- n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000",
- (unsigned int)tv.tv_sec,
- (unsigned int)tv.tv_usec);
-
- p = (unsigned char *)leaf_path;
-
- if (lws_add_http_header_by_name(context, wsi,
- (unsigned char *)"set-cookie:",
- (unsigned char *)b64, n, &p,
- (unsigned char *)leaf_path + sizeof(leaf_path)))
- return 1;
- n = (char *)p - leaf_path;
- other_headers = leaf_path;
- }
-
- n = libwebsockets_serve_http_file(context, wsi, buf,
- mimetype, other_headers, n);
- if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
- return -1; /* error or can't reuse connection: close the socket */
-
- /*
- * notice that the sending of the file completes asynchronously,
- * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
- * it's done
- */
-
- break;
-
- case LWS_CALLBACK_HTTP_BODY:
- strncpy(buf, in, 20);
- buf[20] = '\0';
- if (len < 20)
- buf[len] = '\0';
-
- lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n",
- (const char *)buf, (int)len);
-
- break;
-
- case LWS_CALLBACK_HTTP_BODY_COMPLETION:
- lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
- /* the whole of the sent body arrived, close or reuse the connection */
- libwebsockets_return_http_status(context, wsi,
- HTTP_STATUS_OK, NULL);
- goto try_to_reuse;
-
- case LWS_CALLBACK_HTTP_FILE_COMPLETION:
-// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
- /* kill the connection after we sent one file */
- goto try_to_reuse;
-
- case LWS_CALLBACK_HTTP_WRITEABLE:
- /*
- * we can send more of whatever it is we were sending
- */
- do {
- /* we'd like the send this much */
- n = sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
-
- /* but if the peer told us he wants less, we can adapt */
- m = lws_get_peer_write_allowance(wsi);
-
- /* -1 means not using a protocol that has this info */
- if (m == 0)
- /* right now, peer can't handle anything */
- goto later;
-
- if (m != -1 && m < n)
- /* he couldn't handle that much */
- n = m;
-
- n = read(pss->fd, buffer + LWS_SEND_BUFFER_PRE_PADDING,
- n);
- /* problem reading, close conn */
- if (n < 0)
- goto bail;
- /* sent it all, close conn */
- if (n == 0)
- goto flush_bail;
- /*
- * To support HTTP2, must take care about preamble space
- *
- * identification of when we send the last payload frame
- * is handled by the library itself if you sent a
- * content-length header
- */
- m = libwebsocket_write(wsi,
- buffer + LWS_SEND_BUFFER_PRE_PADDING,
- n, LWS_WRITE_HTTP);
- if (m < 0)
- /* write failed, close conn */
- goto bail;
-
- /*
- * http2 won't do this
- */
- if (m != n)
- /* partial write, adjust */
- if (lseek(pss->fd, m - n, SEEK_CUR) < 0)
- goto bail;
-
- if (m) /* while still active, extend timeout */
- libwebsocket_set_timeout(wsi,
- PENDING_TIMEOUT_HTTP_CONTENT, 5);
-
- /* if we have indigestion, let him clear it before eating more */
- if (lws_partial_buffered(wsi))
- break;
-
- } while (!lws_send_pipe_choked(wsi));
-
-later:
- libwebsocket_callback_on_writable(context, wsi);
- break;
-flush_bail:
- /* true if still partial pending */
- if (lws_partial_buffered(wsi)) {
- libwebsocket_callback_on_writable(context, wsi);
- break;
- }
- close(pss->fd);
- goto try_to_reuse;
-
-bail:
- close(pss->fd);
- return -1;
-
- /*
- * callback for confirming to continue with client IP appear in
- * protocol 0 callback since no websocket protocol has been agreed
- * yet. You can just ignore this if you won't filter on client IP
- * since the default uhandled callback return is 0 meaning let the
- * connection continue.
- */
-
- case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
-
- /* if we returned non-zero from here, we kill the connection */
- break;
-
-#ifdef EXTERNAL_POLL
- /*
- * callbacks for managing the external poll() array appear in
- * protocol 0 callback
- */
-
- case LWS_CALLBACK_LOCK_POLL:
- /*
- * lock mutex to protect pollfd state
- * called before any other POLL related callback
- */
- break;
-
- case LWS_CALLBACK_UNLOCK_POLL:
- /*
- * unlock mutex to protect pollfd state when
- * called after any other POLL related callback
- */
- break;
-
- case LWS_CALLBACK_ADD_POLL_FD:
-
- if (count_pollfds >= max_poll_elements) {
- lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
- return 1;
- }
-
- fd_lookup[pa->fd] = count_pollfds;
- pollfds[count_pollfds].fd = pa->fd;
- pollfds[count_pollfds].events = pa->events;
- pollfds[count_pollfds++].revents = 0;
- break;
-
- case LWS_CALLBACK_DEL_POLL_FD:
- if (!--count_pollfds)
- break;
- m = fd_lookup[pa->fd];
- /* have the last guy take up the vacant slot */
- pollfds[m] = pollfds[count_pollfds];
- fd_lookup[pollfds[count_pollfds].fd] = m;
- break;
-
- case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
- pollfds[fd_lookup[pa->fd]].events = pa->events;
- break;
-
-#endif
-
- case LWS_CALLBACK_GET_THREAD_ID:
- /*
- * if you will call "libwebsocket_callback_on_writable"
- * from a different thread, return the caller thread ID
- * here so lws can use this information to work out if it
- * should signal the poll() loop to exit and restart early
- */
-
- /* return pthread_getthreadid_np(); */
-
- break;
-
- default:
- break;
- }
-
- return 0;
-
-try_to_reuse:
- if (lws_http_transaction_completed(wsi))
- return -1;
-
- return 0;
-}
-
-
-/* dumb_increment protocol */
-
-/*
- * one of these is auto-created for each connection and a pointer to the
- * appropriate instance is passed to the callback in the user parameter
- *
- * for this example protocol we use it to individualize the count for each
- * connection.
- */
-
-struct per_session_data__dumb_increment {
- int number;
-};
-
-static int
-callback_dumb_increment(struct libwebsocket_context *context,
- struct libwebsocket *wsi,
- enum libwebsocket_callback_reasons reason,
- void *user, void *in, size_t len)
-{
- int n, m;
- unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
- LWS_SEND_BUFFER_POST_PADDING];
- unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
- struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user;
-
- switch (reason) {
-
- case LWS_CALLBACK_ESTABLISHED:
- lwsl_info("callback_dumb_increment: "
- "LWS_CALLBACK_ESTABLISHED\n");
- pss->number = 0;
- break;
-
- case LWS_CALLBACK_SERVER_WRITEABLE:
- n = sprintf((char *)p, "%d", pss->number++);
- m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
- if (m < n) {
- lwsl_err("ERROR %d writing to di socket\n", n);
- return -1;
- }
- if (close_testing && pss->number == 50) {
- lwsl_info("close tesing limit, closing\n");
- return -1;
- }
- break;
-
- case LWS_CALLBACK_RECEIVE:
-// fprintf(stderr, "rx %d\n", (int)len);
- if (len < 6)
- break;
- if (strcmp((const char *)in, "reset\n") == 0)
- 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(wsi);
- /* you could return non-zero here and kill the connection */
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-
-/* lws-mirror_protocol */
-
-#define MAX_MESSAGE_QUEUE 32
-
-struct per_session_data__lws_mirror {
- struct libwebsocket *wsi;
- int ringbuffer_tail;
-};
-
-struct a_message {
- void *payload;
- size_t len;
-};
-
-static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
-static int ringbuffer_head;
-
-static int
-callback_lws_mirror(struct libwebsocket_context *context,
- struct libwebsocket *wsi,
- enum libwebsocket_callback_reasons reason,
- void *user, void *in, size_t len)
-{
- int n;
- struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user;
-
- switch (reason) {
-
- case LWS_CALLBACK_ESTABLISHED:
- lwsl_info("callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n");
- pss->ringbuffer_tail = ringbuffer_head;
- pss->wsi = wsi;
- break;
-
- case LWS_CALLBACK_PROTOCOL_DESTROY:
- lwsl_notice("mirror protocol cleaning up\n");
- for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
- if (ringbuffer[n].payload)
- free(ringbuffer[n].payload);
- break;
-
- case LWS_CALLBACK_SERVER_WRITEABLE:
- if (close_testing)
- break;
- while (pss->ringbuffer_tail != ringbuffer_head) {
-
- n = libwebsocket_write(wsi, (unsigned char *)
- ringbuffer[pss->ringbuffer_tail].payload +
- LWS_SEND_BUFFER_PRE_PADDING,
- ringbuffer[pss->ringbuffer_tail].len,
- LWS_WRITE_TEXT);
- if (n < 0) {
- lwsl_err("ERROR %d writing to mirror socket\n", n);
- return -1;
- }
- if (n < ringbuffer[pss->ringbuffer_tail].len)
- lwsl_err("mirror partial write %d vs %d\n",
- n, ringbuffer[pss->ringbuffer_tail].len);
-
- if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
- pss->ringbuffer_tail = 0;
- else
- pss->ringbuffer_tail++;
-
- if (((ringbuffer_head - pss->ringbuffer_tail) &
- (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
- libwebsocket_rx_flow_allow_all_protocol(
- libwebsockets_get_protocol(wsi));
-
- // lwsl_debug("tx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1));
-
- if (lws_partial_buffered(wsi) || lws_send_pipe_choked(wsi)) {
- libwebsocket_callback_on_writable(context, wsi);
- break;
- }
- /*
- * for tests with chrome on same machine as client and
- * server, this is needed to stop chrome choking
- */
-#ifdef _WIN32
- Sleep(1);
-#else
- usleep(1);
-#endif
- }
- break;
-
- case LWS_CALLBACK_RECEIVE:
-
- if (((ringbuffer_head - pss->ringbuffer_tail) &
- (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
- lwsl_err("dropping!\n");
- goto choke;
- }
-
- if (ringbuffer[ringbuffer_head].payload)
- free(ringbuffer[ringbuffer_head].payload);
-
- ringbuffer[ringbuffer_head].payload =
- malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
- LWS_SEND_BUFFER_POST_PADDING);
- ringbuffer[ringbuffer_head].len = len;
- memcpy((char *)ringbuffer[ringbuffer_head].payload +
- LWS_SEND_BUFFER_PRE_PADDING, in, len);
- if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
- ringbuffer_head = 0;
- else
- ringbuffer_head++;
-
- if (((ringbuffer_head - pss->ringbuffer_tail) &
- (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
- goto done;
-
-choke:
- lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
- libwebsocket_rx_flow_control(wsi, 0);
-
-// lwsl_debug("rx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1));
-done:
- libwebsocket_callback_on_writable_all_protocol(
- 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(wsi);
- /* you could return non-zero here and kill the connection */
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-
/* list of supported protocols and callbacks */
static struct libwebsocket_protocols protocols[] = {
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
- { "allow-non-ssl", no_argument, NULL, 'a' },
+ { "allow-non-ssl", no_argument, NULL, 'a' },
{ "interface", required_argument, NULL, 'i' },
{ "closetest", no_argument, NULL, 'c' },
{ "libev", no_argument, NULL, 'e' },
- #ifndef LWS_NO_DAEMONIZE
+#ifndef LWS_NO_DAEMONIZE
{ "daemonize", no_argument, NULL, 'D' },
#endif
- { "resource_path", required_argument, NULL, 'r' },
+ { "resource_path", required_argument, NULL, 'r' },
{ NULL, 0, 0, 0 }
};
int main(int argc, char **argv)
{
+ struct lws_context_creation_info info;
+ char interface_name[128] = "";
+ unsigned int ms, oldms = 0;
+ const char *iface = NULL;
char cert_path[1024];
char key_path[1024];
- int n = 0;
+ int debug_level = 7;
int use_ssl = 0;
int opts = 0;
- char interface_name[128] = "";
- const char *iface = NULL;
+ int n = 0;
#ifndef _WIN32
int syslog_options = LOG_PID | LOG_PERROR;
#endif
- unsigned int ms, oldms = 0;
- struct lws_context_creation_info info;
-
- int debug_level = 7;
#ifndef LWS_NO_DAEMONIZE
- int daemonize = 0;
+// int daemonize = 0;
#endif
+ /*
+ * take care to zero down the info struct, he contains random garbaage
+ * from the stack otherwise
+ */
memset(&info, 0, sizeof info);
info.port = 7681;
#ifndef LWS_NO_EXTENSIONS
info.extensions = libwebsocket_get_internal_extensions();
#endif
- if (!use_ssl) {
- info.ssl_cert_filepath = NULL;
- info.ssl_private_key_filepath = NULL;
- } else {
+
+ info.ssl_cert_filepath = NULL;
+ info.ssl_private_key_filepath = NULL;
+
+ if (use_ssl) {
if (strlen(resource_path) > sizeof(cert_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
if ((ms - oldms) > 50) {
- libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_DUMB_INCREMENT]);
+ libwebsocket_callback_on_writable_all_protocol(
+ &protocols[PROTOCOL_DUMB_INCREMENT]);
oldms = ms;
}
#ifdef EXTERNAL_POLL
-
/*
* this represents an existing server's single poll action
* which also includes libwebsocket sockets
if (n < 0)
continue;
-
if (n)
for (n = 0; n < count_pollfds; n++)
if (pollfds[n].revents)
--- /dev/null
+#include "lws_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "../lib/libwebsockets.h"
+
+#ifdef _WIN32
+#include <io.h>
+#ifdef EXTERNAL_POLL
+#define poll WSAPoll
+#endif
+#include "gettimeofday.h"
+#else
+#include <syslog.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+extern int close_testing;
+extern int max_poll_elements;
+
+#ifdef EXTERNAL_POLL
+extern struct libwebsocket_pollfd *pollfds;
+extern int *fd_lookup;
+extern int count_pollfds;
+#endif
+extern volatile int force_exit;
+extern struct libwebsocket_context *context;
+extern char *resource_path;
+
+struct per_session_data__http {
+ int fd;
+};
+
+/*
+ * one of these is auto-created for each connection and a pointer to the
+ * appropriate instance is passed to the callback in the user parameter
+ *
+ * for this example protocol we use it to individualize the count for each
+ * connection.
+ */
+
+struct per_session_data__dumb_increment {
+ int number;
+};
+
+struct per_session_data__lws_mirror {
+ struct libwebsocket *wsi;
+ int ringbuffer_tail;
+};
+
+extern int callback_http(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+extern int callback_lws_mirror(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+extern int callback_dumb_increment(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+
+extern void
+dump_handshake_info(struct libwebsocket *wsi);
\ No newline at end of file