1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

refactor: change event lib minimal examples to serve as the test apps

This commit is contained in:
Andy Green 2018-04-30 19:17:32 +08:00
parent 0b52d92d12
commit f497562a62
36 changed files with 1204 additions and 750 deletions

View file

@ -1608,7 +1608,10 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
endif()
endif()
if (LWS_WITH_LIBEV)
# libev generates a big mess of warnings with gcc, maintainer claims gcc to blame
set_source_files_properties( lib/event-libs/libev/libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" )
endif()
if (NOT LWS_WITHOUT_SERVER)
@ -1651,9 +1654,8 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
""
""
"")
# libev generates a big mess of warnings with gcc, maintainers blame gcc
# libev generates a big mess of warnings with gcc, maintainer claims gcc to blame
set_source_files_properties( test-apps/test-server-libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" )
set_source_files_properties( lib/event-libs/libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" )
endif()
if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
@ -1671,7 +1673,7 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
#
# test-server-extpoll
#
if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL)
if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL AND NOT WIN32)
create_test_app(test-server-extpoll
"test-apps/test-server.c"
""
@ -1889,7 +1891,7 @@ endif(LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS)
endforeach()
endif()
endif()
endif(NOT LWS_WITHOUT_TESTAPPS)
endif((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
if (LWS_WITH_LWSWS)
list(APPEND LWSWS_SRCS

View file

@ -1794,10 +1794,8 @@ lws_context_destroy(struct lws_context *context)
struct lws wsi;
int n, m;
if (!context) {
lwsl_notice("%s: ctx %p\n", __func__, context);
if (!context)
return;
}
if (context->finalize_destroy_after_internal_loops_stopped) {
if (context->event_loop_ops->destroy_context2)
@ -1809,8 +1807,11 @@ lws_context_destroy(struct lws_context *context)
}
if (context->being_destroyed1) {
if (!context->being_destroyed2)
return lws_context_destroy2(context);
if (!context->being_destroyed2) {
lws_context_destroy2(context);
return;
}
lwsl_info("%s: ctx %p: already being destroyed\n",
__func__, context);
return;

View file

@ -43,8 +43,6 @@ event libs, eg,
```
#if defined(LWS_WITH_LIBUV)
#include "event-libs/libuv/private.h"
#else
#define LWS_LIBUV_ENABLED(context) (0)
#endif
```

View file

@ -177,9 +177,6 @@ elops_init_context_ev(struct lws_context *context,
static void
elops_accept_ev(struct lws *wsi)
{
struct lws_context *context = lws_get_context(wsi);
struct ev_io *r = &wsi->w_read.ev.watcher;
struct ev_io *w = &wsi->w_write.ev.watcher;
int fd;
if (wsi->role_ops->file_handle)
@ -187,10 +184,11 @@ elops_accept_ev(struct lws *wsi)
else
fd = wsi->desc.sockfd;
wsi->w_read.context = context;
wsi->w_write.context = context;
ev_io_init(r, lws_accept_cb, fd, EV_READ);
ev_io_init(w, lws_accept_cb, fd, EV_WRITE);
wsi->w_read.context = wsi->context;
wsi->w_write.context = wsi->context;
ev_io_init(&wsi->w_read.ev.watcher, lws_accept_cb, fd, EV_READ);
ev_io_init(&wsi->w_write.ev.watcher, lws_accept_cb, fd, EV_WRITE);
}
static void

View file

@ -25,6 +25,7 @@
struct lws_pt_eventlibs_libev {
struct ev_loop *io_loop;
struct ev_timer hrtimer;
};
struct lws_io_watcher_libev {

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
* Copyright (C) 2010-2018 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

View file

@ -25,6 +25,7 @@
struct lws_pt_eventlibs_libevent {
struct event_base *io_loop;
struct event *hrtimer;
};
struct lws_io_watcher_libevent {

View file

@ -62,3 +62,5 @@ struct lws_signal_watcher_libuv {
extern struct lws_event_loop_ops event_loop_ops_uv;
LWS_VISIBLE uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);

74
lib/event-libs/private.h Normal file
View file

@ -0,0 +1,74 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 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
*
* This is included from private-libwebsockets.h
*/
struct lws_event_loop_ops {
const char *name;
/* event loop-specific context init during context creation */
int (*init_context)(struct lws_context *context,
const struct lws_context_creation_info *info);
/* called during lws_destroy_context */
int (*destroy_context1)(struct lws_context *context);
/* called during lws_destroy_context2 */
int (*destroy_context2)(struct lws_context *context);
/* init vhost listening wsi */
int (*init_vhost_listen_wsi)(struct lws *wsi);
/* init the event loop for a pt */
int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
/* called at end of first phase of close_free_wsi() */
int (*wsi_logical_close)(struct lws *wsi);
/* return nonzero if client connect not allowed */
int (*check_client_connect_ok)(struct lws *wsi);
/* close handle manually */
void (*close_handle_manually)(struct lws *wsi);
/* event loop accept processing */
void (*accept)(struct lws *wsi);
/* control wsi active events */
void (*io)(struct lws *wsi, int flags);
/* run the event loop for a pt */
void (*run_pt)(struct lws_context *context, int tsi);
/* called before pt is destroyed */
void (*destroy_pt)(struct lws_context *context, int tsi);
/* called just before wsi is freed */
void (*destroy_wsi)(struct lws *wsi);
unsigned int periodic_events_available:1;
};
/* bring in event libs private declarations */
#if defined(LWS_WITH_POLL)
#include "event-libs/poll/private.h"
#endif
#if defined(LWS_WITH_LIBUV)
#include "event-libs/libuv/private.h"
#endif
#if defined(LWS_WITH_LIBEVENT)
#include "event-libs/libevent/private.h"
#endif
#if defined(LWS_WITH_LIBEV)
#include "event-libs/libev/private.h"
#endif

View file

@ -574,13 +574,14 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
* must go through and close all those first
*/
if (wsi->vhost) {
lws_vhost_lock(wsi->vhost);
if ((int)reason != -1)
lws_vhost_lock(wsi->vhost);
lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
wsi->dll_client_transaction_queue_head.next) {
struct lws *w = lws_container_of(d, struct lws,
dll_client_transaction_queue);
__lws_close_free_wsi(w, reason, "trans q leader closing");
__lws_close_free_wsi(w, -1, "trans q leader closing");
} lws_end_foreach_dll_safe(d, d1);
/*
@ -592,7 +593,8 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
* queue leader is closing.
*/
lws_dll_lws_remove(&wsi->dll_client_transaction_queue);
lws_vhost_unlock(wsi->vhost);
if ((int)reason !=-1)
lws_vhost_unlock(wsi->vhost);
}
#endif
@ -1030,6 +1032,7 @@ lws_buflist_use_segment(struct lws_buflist **head, size_t len)
void
lws_buflist_describe(struct lws_buflist **head, void *id)
{
struct lws_buflist *old;
int n = 0;
if (*head == NULL)
@ -1040,7 +1043,12 @@ lws_buflist_describe(struct lws_buflist **head, void *id)
(unsigned long long)(*head)->pos,
(unsigned long long)(*head)->len,
(unsigned long long)(*head)->len - (*head)->pos);
old = *head;
head = &((*head)->next);
if (*head == old) {
lwsl_err("%s: next points to self\n", __func__);
break;
}
n++;
}
}

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
* Copyright (C) 2010-2018 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
@ -4606,7 +4606,7 @@ lws_plat_recommended_rsa_bits(void);
* cleanly and at the moment all of its libuv objects have completed close.
*/
LWS_VISIBLE uv_loop_t *
LWS_VISIBLE LWS_EXTERN uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN void

View file

@ -57,8 +57,6 @@ lws_plat_pipe_signal(struct lws *wsi)
n = write(pt->dummy_pipe_fds[1], &buf, 1);
lwsl_debug("%s: fd %d %d\n", __func__, pt->dummy_pipe_fds[1], n);
return n != 1;
}

View file

@ -374,210 +374,11 @@ enum lws_ssl_capable_status {
/*
*
* ------ role ------
* ------ roles ------
*
*/
typedef uint32_t lws_wsi_state_t;
/*
* The wsi->role_ops pointer decides almost everything about what role the wsi
* will play, h2, raw, ws, etc.
*
* However there are a few additional flags needed that vary, such as if the
* role is a client or server side, if it has that concept. And the connection
* fulfilling the role, has a separate dynamic state.
*
* 31 16 15 0
* [ role flags ] [ state ]
*
* The role flags part is generally invariant for the lifetime of the wsi,
* although it can change if the connection role itself does, eg, if the
* connection upgrades from H1 -> WS1 the role flags may be changed at that
* point.
*
* The state part reflects the dynamic connection state, and the states are
* reused between roles.
*
* None of the internal role or state representations are made available outside
* of lws internals. Even for lws internals, if you add stuff here, please keep
* the constants inside this header only by adding necessary helpers here and
* use the helpers in the actual code. This is to ease any future refactors.
*
* Notice LWSIFR_ENCAP means we have a parent wsi that actually carries our
* data as a stream inside a different protocol.
*/
#define _RS 16
#define LWSIFR_CLIENT (0x1000 << _RS) /* client side */
#define LWSIFR_SERVER (0x2000 << _RS) /* server side */
#define LWSIFR_P_ENCAP_H2 (0x0100 << _RS) /* we are encapsulated by h2 */
enum lwsi_role {
LWSI_ROLE_MASK = (0xffff << _RS),
LWSI_ROLE_ENCAP_MASK = (0x0f00 << _RS),
};
#define lwsi_role(wsi) (wsi->wsistate & LWSI_ROLE_MASK)
#if !defined (_DEBUG)
#define lwsi_set_role(wsi, role) wsi->wsistate = \
(wsi->wsistate & (~LWSI_ROLE_MASK)) | role
#else
void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role);
#endif
#define lwsi_role_client(wsi) (!!(wsi->wsistate & LWSIFR_CLIENT))
#define lwsi_role_server(wsi) (!!(wsi->wsistate & LWSIFR_SERVER))
#define lwsi_role_h2_ENCAPSULATION(wsi) \
((wsi->wsistate & LWSI_ROLE_ENCAP_MASK) == LWSIFR_P_ENCAP_H2)
/* Pollout wants a callback in this state */
#define LWSIFS_POCB (0x100)
/* Before any protocol connection was established */
#define LWSIFS_NOT_EST (0x200)
enum lwsi_state {
/* Phase 1: pre-transport */
LRS_UNCONNECTED = LWSIFS_NOT_EST | 0,
LRS_WAITING_CONNECT = LWSIFS_NOT_EST | 1,
/* Phase 2: establishing intermediaries on top of transport */
LRS_WAITING_PROXY_REPLY = LWSIFS_NOT_EST | 2,
LRS_WAITING_SSL = LWSIFS_NOT_EST | 3,
LRS_WAITING_SOCKS_GREETING_REPLY = LWSIFS_NOT_EST | 4,
LRS_WAITING_SOCKS_CONNECT_REPLY = LWSIFS_NOT_EST | 5,
LRS_WAITING_SOCKS_AUTH_REPLY = LWSIFS_NOT_EST | 6,
/* Phase 3: establishing tls tunnel */
LRS_SSL_INIT = LWSIFS_NOT_EST | 7,
LRS_SSL_ACK_PENDING = LWSIFS_NOT_EST | 8,
LRS_PRE_WS_SERVING_ACCEPT = LWSIFS_NOT_EST | 9,
/* Phase 4: connected */
LRS_WAITING_SERVER_REPLY = LWSIFS_NOT_EST | 10,
LRS_H2_AWAIT_PREFACE = LWSIFS_NOT_EST | 11,
LRS_H2_AWAIT_SETTINGS = LWSIFS_NOT_EST |
LWSIFS_POCB | 12,
/* Phase 5: protocol logically established */
LRS_H2_CLIENT_SEND_SETTINGS = LWSIFS_POCB | 13,
LRS_H2_WAITING_TO_SEND_HEADERS = LWSIFS_POCB | 14,
LRS_DEFERRING_ACTION = LWSIFS_POCB | 15,
LRS_IDLING = 16,
LRS_H1C_ISSUE_HANDSHAKE = 17,
LRS_H1C_ISSUE_HANDSHAKE2 = 18,
LRS_ISSUE_HTTP_BODY = 19,
LRS_ISSUING_FILE = 20,
LRS_HEADERS = 21,
LRS_BODY = 22,
LRS_ESTABLISHED = LWSIFS_POCB | 23,
/* Phase 6: finishing */
LRS_WAITING_TO_SEND_CLOSE = LWSIFS_POCB | 24,
LRS_RETURNED_CLOSE = LWSIFS_POCB | 25,
LRS_AWAITING_CLOSE_ACK = LWSIFS_POCB | 26,
LRS_FLUSHING_BEFORE_CLOSE = LWSIFS_POCB | 27,
LRS_SHUTDOWN = 28,
/* Phase 7: dead */
LRS_DEAD_SOCKET = 29,
LRS_MASK = 0xffff
};
#define lwsi_state(wsi) ((enum lwsi_state)(wsi->wsistate & LRS_MASK))
#define lwsi_state_PRE_CLOSE(wsi) ((enum lwsi_state)(wsi->wsistate_pre_close & LRS_MASK))
#define lwsi_state_est(wsi) (!(wsi->wsistate & LWSIFS_NOT_EST))
#define lwsi_state_est_PRE_CLOSE(wsi) (!(wsi->wsistate_pre_close & LWSIFS_NOT_EST))
#define lwsi_state_can_handle_POLLOUT(wsi) (wsi->wsistate & LWSIFS_POCB)
#if !defined (_DEBUG)
#define lwsi_set_state(wsi, lrs) wsi->wsistate = \
(wsi->wsistate & (~LRS_MASK)) | lrs
#else
void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs);
#endif
/*
* internal role-specific ops
*/
struct lws_context_per_thread;
struct lws_role_ops {
const char *name;
const char *alpn;
/*
* After http headers have parsed, this is the last chance for a role
* to upgrade the connection to something else using the headers.
* ws-over-h2 is upgraded from h2 like this.
*/
int (*check_upgrades)(struct lws *wsi);
/* role-specific context init during context creation */
int (*init_context)(struct lws_context *context,
const struct lws_context_creation_info *info);
/* role-specific per-vhost init during vhost creation */
int (*init_vhost)(struct lws_vhost *vh,
const struct lws_context_creation_info *info);
/* role-specific per-vhost destructor during vhost destroy */
int (*destroy_vhost)(struct lws_vhost *vh);
/* generic 1Hz callback for the role itself */
int (*periodic_checks)(struct lws_context *context, int tsi,
time_t now);
/* chance for the role to force POLLIN without network activity */
int (*service_flag_pending)(struct lws_context *context, int tsi);
/* an fd using this role has POLLIN signalled */
int (*handle_POLLIN)(struct lws_context_per_thread *pt, struct lws *wsi,
struct lws_pollfd *pollfd);
/* an fd using the role wanted a POLLOUT callback and now has it */
int (*handle_POLLOUT)(struct lws *wsi);
/* perform user pollout */
int (*perform_user_POLLOUT)(struct lws *wsi);
/* do effective callback on writeable */
int (*callback_on_writable)(struct lws *wsi);
/* connection-specific tx credit in bytes */
lws_fileofs_t (*tx_credit)(struct lws *wsi);
/* role-specific write formatting */
int (*write_role_protocol)(struct lws *wsi, unsigned char *buf,
size_t len, enum lws_write_protocol *wp);
/* get encapsulation parent */
struct lws * (*encapsulation_parent)(struct lws *wsi);
/* role-specific destructor */
int (*alpn_negotiated)(struct lws *wsi, const char *alpn);
/* chance for the role to handle close in the protocol */
int (*close_via_role_protocol)(struct lws *wsi,
enum lws_close_status reason);
/* role-specific close processing */
int (*close_role)(struct lws_context_per_thread *pt, struct lws *wsi);
/* role-specific connection close processing */
int (*close_kill_connection)(struct lws *wsi,
enum lws_close_status reason);
/* role-specific destructor */
int (*destroy_role)(struct lws *wsi);
/*
* the callback reasons for WRITEABLE for client, server
* (just client applies if no concept of client or server)
*/
uint16_t writeable_cb[2];
/*
* the callback reasons for CLOSE for client, server
* (just client applies if no concept of client or server)
*/
uint16_t close_cb[2];
unsigned int file_handle:1; /* role operates on files not sockets */
};
#include "roles/private.h"
/* null-terminated array of pointers to roles lws built with */
extern const struct lws_role_ops *available_roles[];
@ -589,113 +390,13 @@ extern const struct lws_role_ops *available_roles[];
#define LWS_FOR_EVERY_AVAILABLE_ROLE_END }}
/* core roles */
extern struct lws_role_ops role_ops_raw_skt, role_ops_raw_file, role_ops_listen,
role_ops_pipe;
/* bring in role private declarations */
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
#include "roles/http/private.h"
#else
#define lwsi_role_http(wsi) (0)
#endif
#if defined(LWS_ROLE_H1)
#include "roles/h1/private.h"
#else
#define lwsi_role_h1(wsi) (0)
#endif
#if defined(LWS_ROLE_H2)
#include "roles/h2/private.h"
#else
#define lwsi_role_h2(wsi) (0)
#endif
#if defined(LWS_ROLE_WS)
#include "roles/ws/private.h"
#else
#define lwsi_role_ws(wsi) (0)
#endif
#if defined(LWS_ROLE_CGI)
#include "roles/cgi/private.h"
#else
#define lwsi_role_cgi(wsi) (0)
#endif
enum {
LWS_HP_RET_BAIL_OK,
LWS_HP_RET_BAIL_DIE,
LWS_HP_RET_USER_SERVICE,
LWS_HPI_RET_WSI_ALREADY_DIED, /* we closed it */
LWS_HPI_RET_HANDLED, /* no probs */
LWS_HPI_RET_PLEASE_CLOSE_ME, /* close it for us */
LWS_UPG_RET_DONE,
LWS_UPG_RET_CONTINUE,
LWS_UPG_RET_BAIL
};
/*
*
* ------ event_loop ops ------
*
*/
struct lws_event_loop_ops {
const char *name;
/* event loop-specific context init during context creation */
int (*init_context)(struct lws_context *context,
const struct lws_context_creation_info *info);
/* called during lws_destroy_context */
int (*destroy_context1)(struct lws_context *context);
/* called during lws_destroy_context2 */
int (*destroy_context2)(struct lws_context *context);
/* init vhost listening wsi */
int (*init_vhost_listen_wsi)(struct lws *wsi);
/* init the event loop for a pt */
int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
/* called at end of first phase of close_free_wsi() */
int (*wsi_logical_close)(struct lws *wsi);
/* return nonzero if client connect not allowed */
int (*check_client_connect_ok)(struct lws *wsi);
/* close handle manually */
void (*close_handle_manually)(struct lws *wsi);
/* event loop accept processing */
void (*accept)(struct lws *wsi);
/* control wsi active events */
void (*io)(struct lws *wsi, int flags);
/* run the event loop for a pt */
void (*run_pt)(struct lws_context *context, int tsi);
/* called before pt is destroyed */
void (*destroy_pt)(struct lws_context *context, int tsi);
/* called just before wsi is freed */
void (*destroy_wsi)(struct lws *wsi);
unsigned int periodic_events_available:1;
};
/* bring in event libs private declarations */
#if defined(LWS_WITH_POLL)
#include "event-libs/poll/private.h"
#endif
#if defined(LWS_WITH_LIBUV)
#include "event-libs/libuv/private.h"
#endif
#if defined(LWS_WITH_LIBEVENT)
#include "event-libs/libevent/private.h"
#endif
#if defined(LWS_WITH_LIBEV)
#include "event-libs/libev/private.h"
#endif
#include "event-libs/private.h"
/* enums of socks version */
enum socks_version {
@ -774,8 +475,6 @@ struct lws_ring {
struct lws_protocols;
struct lws;
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || defined(LWS_WITH_LIBEVENT)
struct lws_io_watcher {
#ifdef LWS_WITH_LIBEV
struct lws_io_watcher_libev ev;
@ -803,7 +502,6 @@ struct lws_signal_watcher {
#endif
struct lws_context *context;
};
#endif
#ifdef _WIN32
#define LWS_FD_HASH(fd) ((fd ^ (fd >> 8) ^ (fd >> 16)) % FD_HASHTABLE_MODULUS)

View file

@ -66,7 +66,7 @@ However when the declarations must be accessible to other things in lws build, e
the role adds members to `struct lws` when enabled, they should be in the role
directory in a file `private.h`.
Search for "bring in role private declarations" in `./lib/private-libwebsockets.h
Search for "bring in role private declarations" in `./lib/roles/private.h
and add your private role file there following the style used for the other roles,
eg,

View file

@ -314,11 +314,17 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
goto try_pollout;
}
/*
* We got here because there was specifically POLLIN...
* regardless of our buflist state, we need to get it,
* and either use it, or append to the buflist and use
* buflist head material.
*/
buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
switch (ebuf.len) {
case 0:
lwsl_info("%s: read 0 len a\n",
__func__);
lwsl_info("%s: read 0 len a\n", __func__);
wsi->seen_zero_length_recv = 1;
lws_change_pollfd(wsi, LWS_POLLIN, 0);
goto try_pollout;

View file

@ -279,11 +279,19 @@ drain:
lws_dll_lws_remove(&wsi->dll_buflist);
}
} else
if (n != ebuf.len &&
lws_buflist_append_segment(&wsi->buflist,
if (n != ebuf.len) {
m = lws_buflist_append_segment(&wsi->buflist,
(uint8_t *)ebuf.token + n,
ebuf.len - n) < 0)
return LWS_HPI_RET_PLEASE_CLOSE_ME;
ebuf.len - n);
if (m < 0)
return LWS_HPI_RET_PLEASE_CLOSE_ME;
if (m) {
lwsl_debug("%s: added %p to rxflow list\n",
__func__, wsi);
lws_dll_lws_add_front(&wsi->dll_buflist,
&pt->dll_head_buflist);
}
}
}
// lws_buflist_describe(&wsi->buflist, wsi);

View file

@ -123,10 +123,11 @@ lws_client_connect_2(struct lws *wsi)
}
#endif
lwsl_info("applying %p to txn queue on %p (wsistate 0x%x)\n", wsi, w,
w->wsistate);
lwsl_info("applying %p to txn queue on %p (wsistate 0x%x)\n",
wsi, w, w->wsistate);
/*
* ...let's add ourselves to his transaction queue...
* we are adding ourselves at the HEAD
*/
lws_dll_lws_add_front(&wsi->dll_client_transaction_queue,
&w->dll_client_transaction_queue_head);
@ -522,12 +523,15 @@ send_hs:
* LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
*
* If we are trying to do this too early, before the master
* connection has written his own headers,
* connection has written his own headers, then it will just
* wait in the queue until it's possible to send them.
*/
lws_callback_on_writable(wsi_piggyback);
lwsl_info("wsi %p: waiting to send headers\n", wsi);
lwsl_info("%s: wsi %p: waiting to send headers (parent state %x)\n",
__func__, wsi, lwsi_state(wsi_piggyback));
} else {
lwsl_info("wsi %p: client creating own connection\n", wsi);
lwsl_info("%s: wsi %p: client creating own connection\n",
__func__, wsi);
/* we are making our own connection */
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);

View file

@ -29,24 +29,26 @@ lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)
/*
* return self, or queued client wsi we are acting on behalf of
*
* That is the TAIL of the queue (new queue elements are added at the HEAD)
*/
struct lws *
lws_client_wsi_effective(struct lws *wsi)
{
struct lws *wsi_eff = wsi;
struct lws_dll_lws *d;
struct lws_dll_lws *tail = NULL;
if (!wsi->transaction_from_pipeline_queue ||
!wsi->dll_client_transaction_queue_head.next)
return wsi;
d = wsi->dll_client_transaction_queue_head.next;
if (d)
wsi_eff = lws_container_of(d, struct lws,
dll_client_transaction_queue);
lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
wsi->dll_client_transaction_queue_head.next) {
tail = d;
} lws_end_foreach_dll_safe(d, d1);
return wsi_eff;
return lws_container_of(tail, struct lws,
dll_client_transaction_queue);
}
/*
@ -97,34 +99,40 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
if ((pollfd->revents & LWS_POLLOUT) &&
wsi->keepalive_active &&
wsi->dll_client_transaction_queue_head.next) {
int found = 0;
struct lws *wfound = NULL;
lwsl_debug("%s: pollout HANDSHAKE2\n", __func__);
/* we have a transaction queue that wants to pipeline */
/*
* We have a transaction queued that wants to pipeline.
*
* We have to allow it to send headers strictly in the order
* that it was queued, ie, tail-first.
*/
lws_vhost_lock(wsi->vhost);
lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
wsi->dll_client_transaction_queue_head.next) {
struct lws *w = lws_container_of(d, struct lws,
dll_client_transaction_queue);
lwsl_notice("%s: %p states 0x%x\n", __func__, w, w->wsistate);
if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) {
/*
* pollfd has the master sockfd in it... we
* need to use that in HANDSHAKE2 to understand
* which wsi to actually write on
*/
lws_client_socket_service(w, pollfd, wsi);
lws_callback_on_writable(wsi);
found = 1;
break;
}
lwsl_debug("%s: %p states 0x%x\n", __func__, w, w->wsistate);
if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2)
wfound = w;
} lws_end_foreach_dll_safe(d, d1);
lws_vhost_unlock(wsi->vhost);
if (!found)
lwsl_err("%s: didn't find anything in HS2\n", __func__);
if (wfound) {
/*
* pollfd has the master sockfd in it... we
* need to use that in HANDSHAKE2 to understand
* which wsi to actually write on
*/
lws_client_socket_service(wfound, pollfd, wsi);
lws_callback_on_writable(wsi);
} else
lwsl_debug("%s: didn't find anything in txn q in HS2\n",
__func__);
lws_vhost_unlock(wsi->vhost);
return 0;
}

View file

@ -1342,7 +1342,7 @@ deal_body:
*/
while (1) {
ebuf.len = lws_buflist_next_segment_len(
ebuf.len = (int)lws_buflist_next_segment_len(
&wsi->buflist, (uint8_t **)&ebuf.token);
if (!ebuf.len)
break;
@ -1789,7 +1789,8 @@ lws_http_transaction_completed(struct lws *wsi)
}
#endif
} else {
lwsl_debug("%s: resetting and keeping ah as more pipeline stuff available\n", __func__);
lwsl_debug("%s: resetting and keeping ah as pipeline\n",
__func__);
lws_header_table_reset(wsi, 0);
/*
* If we kept the ah, we should restrict the amount
@ -1804,13 +1805,12 @@ lws_http_transaction_completed(struct lws *wsi)
if (wsi->http.ah)
wsi->http.ah->ues = URIES_IDLE;
lwsi_set_state(wsi, LRS_ESTABLISHED);
//lwsi_set_state(wsi, LRS_ESTABLISHED);
} else
if (lws_buflist_next_segment_len(&wsi->buflist, NULL))
if (lws_header_table_attach(wsi, 0))
lwsl_debug("acquired ah\n");
lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
lws_callback_on_writable(wsi);
@ -2063,6 +2063,7 @@ adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
{
struct lws_context_per_thread *pt;
struct lws_pollfd *pfd;
int n;
if (!wsi)
return NULL;
@ -2070,8 +2071,13 @@ adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
if (!readbuf || len == 0)
return wsi;
if (lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf, len) < 0)
pt = &wsi->context->pt[(int)wsi->tsi];
n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf, len);
if (n < 0)
goto bail;
if (n)
lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
/*
* we can't process the initial read data until we can attach an ah.
@ -2086,7 +2092,6 @@ adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
lwsl_notice("%s: calling service on readbuf ah\n", __func__);
pt = &wsi->context->pt[(int)wsi->tsi];
/* unlike a normal connect, we have the headers already
* (or the first part of them anyway).

273
lib/roles/private.h Normal file
View file

@ -0,0 +1,273 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 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
*
* This is included from private-libwebsockets.h
*/
typedef uint32_t lws_wsi_state_t;
/*
* The wsi->role_ops pointer decides almost everything about what role the wsi
* will play, h2, raw, ws, etc.
*
* However there are a few additional flags needed that vary, such as if the
* role is a client or server side, if it has that concept. And the connection
* fulfilling the role, has a separate dynamic state.
*
* 31 16 15 0
* [ role flags ] [ state ]
*
* The role flags part is generally invariant for the lifetime of the wsi,
* although it can change if the connection role itself does, eg, if the
* connection upgrades from H1 -> WS1 the role flags may be changed at that
* point.
*
* The state part reflects the dynamic connection state, and the states are
* reused between roles.
*
* None of the internal role or state representations are made available outside
* of lws internals. Even for lws internals, if you add stuff here, please keep
* the constants inside this header only by adding necessary helpers here and
* use the helpers in the actual code. This is to ease any future refactors.
*
* Notice LWSIFR_ENCAP means we have a parent wsi that actually carries our
* data as a stream inside a different protocol.
*/
#define _RS 16
#define LWSIFR_CLIENT (0x1000 << _RS) /* client side */
#define LWSIFR_SERVER (0x2000 << _RS) /* server side */
#define LWSIFR_P_ENCAP_H2 (0x0100 << _RS) /* we are encapsulated by h2 */
enum lwsi_role {
LWSI_ROLE_MASK = (0xffff << _RS),
LWSI_ROLE_ENCAP_MASK = (0x0f00 << _RS),
};
#define lwsi_role(wsi) (wsi->wsistate & LWSI_ROLE_MASK)
#if !defined (_DEBUG)
#define lwsi_set_role(wsi, role) wsi->wsistate = \
(wsi->wsistate & (~LWSI_ROLE_MASK)) | role
#else
void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role);
#endif
#define lwsi_role_client(wsi) (!!(wsi->wsistate & LWSIFR_CLIENT))
#define lwsi_role_server(wsi) (!!(wsi->wsistate & LWSIFR_SERVER))
#define lwsi_role_h2_ENCAPSULATION(wsi) \
((wsi->wsistate & LWSI_ROLE_ENCAP_MASK) == LWSIFR_P_ENCAP_H2)
/* Pollout wants a callback in this state */
#define LWSIFS_POCB (0x100)
/* Before any protocol connection was established */
#define LWSIFS_NOT_EST (0x200)
enum lwsi_state {
/* Phase 1: pre-transport */
LRS_UNCONNECTED = LWSIFS_NOT_EST | 0,
LRS_WAITING_CONNECT = LWSIFS_NOT_EST | 1,
/* Phase 2: establishing intermediaries on top of transport */
LRS_WAITING_PROXY_REPLY = LWSIFS_NOT_EST | 2,
LRS_WAITING_SSL = LWSIFS_NOT_EST | 3,
LRS_WAITING_SOCKS_GREETING_REPLY = LWSIFS_NOT_EST | 4,
LRS_WAITING_SOCKS_CONNECT_REPLY = LWSIFS_NOT_EST | 5,
LRS_WAITING_SOCKS_AUTH_REPLY = LWSIFS_NOT_EST | 6,
/* Phase 3: establishing tls tunnel */
LRS_SSL_INIT = LWSIFS_NOT_EST | 7,
LRS_SSL_ACK_PENDING = LWSIFS_NOT_EST | 8,
LRS_PRE_WS_SERVING_ACCEPT = LWSIFS_NOT_EST | 9,
/* Phase 4: connected */
LRS_WAITING_SERVER_REPLY = LWSIFS_NOT_EST | 10,
LRS_H2_AWAIT_PREFACE = LWSIFS_NOT_EST | 11,
LRS_H2_AWAIT_SETTINGS = LWSIFS_NOT_EST |
LWSIFS_POCB | 12,
/* Phase 5: protocol logically established */
LRS_H2_CLIENT_SEND_SETTINGS = LWSIFS_POCB | 13,
LRS_H2_WAITING_TO_SEND_HEADERS = LWSIFS_POCB | 14,
LRS_DEFERRING_ACTION = LWSIFS_POCB | 15,
LRS_IDLING = 16,
LRS_H1C_ISSUE_HANDSHAKE = 17,
LRS_H1C_ISSUE_HANDSHAKE2 = 18,
LRS_ISSUE_HTTP_BODY = 19,
LRS_ISSUING_FILE = 20,
LRS_HEADERS = 21,
LRS_BODY = 22,
LRS_ESTABLISHED = LWSIFS_POCB | 23,
/* Phase 6: finishing */
LRS_WAITING_TO_SEND_CLOSE = LWSIFS_POCB | 24,
LRS_RETURNED_CLOSE = LWSIFS_POCB | 25,
LRS_AWAITING_CLOSE_ACK = LWSIFS_POCB | 26,
LRS_FLUSHING_BEFORE_CLOSE = LWSIFS_POCB | 27,
LRS_SHUTDOWN = 28,
/* Phase 7: dead */
LRS_DEAD_SOCKET = 29,
LRS_MASK = 0xffff
};
#define lwsi_state(wsi) ((enum lwsi_state)(wsi->wsistate & LRS_MASK))
#define lwsi_state_PRE_CLOSE(wsi) ((enum lwsi_state)(wsi->wsistate_pre_close & LRS_MASK))
#define lwsi_state_est(wsi) (!(wsi->wsistate & LWSIFS_NOT_EST))
#define lwsi_state_est_PRE_CLOSE(wsi) (!(wsi->wsistate_pre_close & LWSIFS_NOT_EST))
#define lwsi_state_can_handle_POLLOUT(wsi) (wsi->wsistate & LWSIFS_POCB)
#if !defined (_DEBUG)
#define lwsi_set_state(wsi, lrs) wsi->wsistate = \
(wsi->wsistate & (~LRS_MASK)) | lrs
#else
void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs);
#endif
/*
* internal role-specific ops
*/
struct lws_context_per_thread;
struct lws_role_ops {
const char *name;
const char *alpn;
/*
* After http headers have parsed, this is the last chance for a role
* to upgrade the connection to something else using the headers.
* ws-over-h2 is upgraded from h2 like this.
*/
int (*check_upgrades)(struct lws *wsi);
/* role-specific context init during context creation */
int (*init_context)(struct lws_context *context,
const struct lws_context_creation_info *info);
/* role-specific per-vhost init during vhost creation */
int (*init_vhost)(struct lws_vhost *vh,
const struct lws_context_creation_info *info);
/* role-specific per-vhost destructor during vhost destroy */
int (*destroy_vhost)(struct lws_vhost *vh);
/* generic 1Hz callback for the role itself */
int (*periodic_checks)(struct lws_context *context, int tsi,
time_t now);
/* chance for the role to force POLLIN without network activity */
int (*service_flag_pending)(struct lws_context *context, int tsi);
/* an fd using this role has POLLIN signalled */
int (*handle_POLLIN)(struct lws_context_per_thread *pt, struct lws *wsi,
struct lws_pollfd *pollfd);
/* an fd using the role wanted a POLLOUT callback and now has it */
int (*handle_POLLOUT)(struct lws *wsi);
/* perform user pollout */
int (*perform_user_POLLOUT)(struct lws *wsi);
/* do effective callback on writeable */
int (*callback_on_writable)(struct lws *wsi);
/* connection-specific tx credit in bytes */
lws_fileofs_t (*tx_credit)(struct lws *wsi);
/* role-specific write formatting */
int (*write_role_protocol)(struct lws *wsi, unsigned char *buf,
size_t len, enum lws_write_protocol *wp);
/* get encapsulation parent */
struct lws * (*encapsulation_parent)(struct lws *wsi);
/* role-specific destructor */
int (*alpn_negotiated)(struct lws *wsi, const char *alpn);
/* chance for the role to handle close in the protocol */
int (*close_via_role_protocol)(struct lws *wsi,
enum lws_close_status reason);
/* role-specific close processing */
int (*close_role)(struct lws_context_per_thread *pt, struct lws *wsi);
/* role-specific connection close processing */
int (*close_kill_connection)(struct lws *wsi,
enum lws_close_status reason);
/* role-specific destructor */
int (*destroy_role)(struct lws *wsi);
/*
* the callback reasons for WRITEABLE for client, server
* (just client applies if no concept of client or server)
*/
uint16_t writeable_cb[2];
/*
* the callback reasons for CLOSE for client, server
* (just client applies if no concept of client or server)
*/
uint16_t close_cb[2];
unsigned int file_handle:1; /* role operates on files not sockets */
};
/* core roles */
extern struct lws_role_ops role_ops_raw_skt, role_ops_raw_file, role_ops_listen,
role_ops_pipe;
/* bring in role private declarations */
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
#include "roles/http/private.h"
#else
#define lwsi_role_http(wsi) (0)
#endif
#if defined(LWS_ROLE_H1)
#include "roles/h1/private.h"
#else
#define lwsi_role_h1(wsi) (0)
#endif
#if defined(LWS_ROLE_H2)
#include "roles/h2/private.h"
#else
#define lwsi_role_h2(wsi) (0)
#endif
#if defined(LWS_ROLE_WS)
#include "roles/ws/private.h"
#else
#define lwsi_role_ws(wsi) (0)
#endif
#if defined(LWS_ROLE_CGI)
#include "roles/cgi/private.h"
#else
#define lwsi_role_cgi(wsi) (0)
#endif
enum {
LWS_HP_RET_BAIL_OK,
LWS_HP_RET_BAIL_DIE,
LWS_HP_RET_USER_SERVICE,
LWS_HPI_RET_WSI_ALREADY_DIED, /* we closed it */
LWS_HPI_RET_HANDLED, /* no probs */
LWS_HPI_RET_PLEASE_CLOSE_ME, /* close it for us */
LWS_UPG_RET_DONE,
LWS_UPG_RET_CONTINUE,
LWS_UPG_RET_BAIL
};

View file

@ -568,7 +568,7 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
{
uint8_t *buffer = *buf, mask[4];
struct lws_tokens ebuf;
unsigned int avail = len;
unsigned int avail = (unsigned int)len;
#if !defined(LWS_WITHOUT_EXTENSIONS)
unsigned int old_packet_length = (int)wsi->ws->rx_packet_length;
#endif

View file

@ -351,33 +351,64 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
return timeout_ms;
}
/*
* POLLIN said there is something... we must read it, and either use it; or
* if other material already in the buflist append it and return the buflist
* head material.
*/
int
lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
struct lws_tokens *ebuf)
{
ebuf->len = (int)lws_buflist_next_segment_len(&wsi->buflist,
(uint8_t **)&ebuf->token);
if (!ebuf->len) {
ebuf->token = (char *)pt->serv_buf;
ebuf->len = lws_ssl_capable_read(wsi, pt->serv_buf,
wsi->context->pt_serv_buf_size);
int n, prior = (int)lws_buflist_next_segment_len(&wsi->buflist, NULL);
// if (ebuf->len > 0)
// lwsl_hexdump_notice(ebuf->token, ebuf->len);
ebuf->token = (char *)pt->serv_buf;
ebuf->len = lws_ssl_capable_read(wsi, pt->serv_buf,
wsi->context->pt_serv_buf_size);
return 0; /* fresh */
if (ebuf->len == LWS_SSL_CAPABLE_MORE_SERVICE && prior)
goto get_from_buflist;
if (ebuf->len <= 0)
return 0;
/* nothing in buflist already? Then just use what we read */
if (!prior)
return 0;
/* stash what we read */
n = lws_buflist_append_segment(&wsi->buflist, (uint8_t *)ebuf->token,
ebuf->len);
if (n < 0)
return -1;
if (n) {
lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
}
return 1; /* buffered */
/* get the first buflist guy in line */
get_from_buflist:
ebuf->len = (int)lws_buflist_next_segment_len(&wsi->buflist,
(uint8_t **)&ebuf->token);
return 1; /* came from buflist */
}
int
lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
int buffered)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int m;
/* it's in the buflist; we didn't use any */
if (!used && buffered)
return 0;
if (used && buffered) {
m = lws_buflist_use_segment(&wsi->buflist, used);
@ -394,10 +425,17 @@ lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
/* any remainder goes on the buflist */
if (used != ebuf->len &&
lws_buflist_append_segment(&wsi->buflist, (uint8_t *)ebuf->token +
used, ebuf->len - used) < 0)
return 1; /* OOM */
if (used != ebuf->len) {
m = lws_buflist_append_segment(&wsi->buflist,
(uint8_t *)ebuf->token + used,
ebuf->len - used);
if (m < 0)
return 1; /* OOM */
if (m) {
lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
}
}
return 0;
}

View file

@ -316,9 +316,11 @@ int main(int argc, char **argv)
}
lws_context_destroy(context);
(void)budget;
#if (UV_VERSION_MAJOR > 0) // Travis...
while ((n = uv_loop_close(&loop)) && --budget)
uv_run(&loop, UV_RUN_ONCE);
#endif
fprintf(stderr, "lwsws exited cleanly: %d\n", n);

View file

@ -33,9 +33,9 @@ wait $SPID 2>/dev/null
if [ -z "$TRAVIS_OS_NAME" ] ; then
SPID=""
spawn "" $5/http-server/minimal-http-server-libuv $1/lws-minimal-http-server-libuv -s
spawn "" $5/http-server/minimal-http-server-eventlib $1/lws-minimal-http-server-eventlib --uv -s
dotest $1 $2 localhost-suv -l
spawn $SPID $5/http-server/minimal-http-server-libuv $1/lws-minimal-http-server-libuv -s
spawn $SPID $5/http-server/minimal-http-server-eventlib $1/lws-minimal-http-server-eventlib --uv -s
dotest $1 $2 localhost-suv-h1 -l --h1
kill $SPID 2>/dev/null

View file

@ -94,7 +94,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
return 0; /* don't passthru */
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %d\n", u->index);
lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %p: idx %d\n",
wsi, u->index);
client_wsi[u->index] = NULL;
if (++completed == COUNT) {
if (!failed)
@ -166,7 +167,7 @@ lws_try_client_connection(struct lws_client_connect_info *i, int m)
interrupted = 1;
}
} else
lwsl_user("started connection %d\n", m);
lwsl_user("started connection %p: idx %d\n", client_wsi[m], m);
}
int main(int argc, const char **argv)
@ -201,7 +202,6 @@ int main(int argc, const char **argv)
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
info.max_http_header_pool = 20;
#if defined(LWS_WITH_MBEDTLS)
/*
@ -237,6 +237,9 @@ int main(int argc, const char **argv)
i.address = "warmcat.com";
}
if ((p = lws_cmdline_option(argc, argv, "--port")))
i.port = atoi(p);
i.host = i.address;
i.origin = i.address;
i.method = "GET";
@ -267,7 +270,7 @@ int main(int argc, const char **argv)
if (m == (int)LWS_ARRAY_SIZE(client_wsi) - 1)
next = us() + 1000000;
else
next = us() + 100000;
next = us() + 300000;
}
}

View file

@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 2.8)
include(CheckCSourceCompiles)
set(SAMP lws-minimal-http-server-libuv-foreign)
set(SRCS minimal-http-server-libuv-foreign.c)
set(SAMP lws-minimal-http-server-eventlib-foreign)
set(SRCS minimal-http-server-eventlib-foreign.c)
# If we are being built as part of lws, confirm current build config supports
# reqconfig, else skip building ourselves.
@ -63,16 +63,25 @@ ENDMACRO()
set(requirements 1)
require_lws_config(LWS_ROLE_H1 1 requirements)
require_lws_config(LWS_WITH_LIBUV 1 requirements)
require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\n#include <uv.h>\nint main(void) {\n#if (UV_VERSION_MAJOR > 0)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_RECENT_LIBUV)
if (NOT HAS_RECENT_LIBUV)
if (LWS_WITH_MINIMAL_EXAMPLES)
message("libuv is too old (pre- 1.0)")
else()
message(FATAL_ERROR "libuv is too old (pre- 1.0)")
endif()
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBUV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBUV)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBEVENT)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEVENT)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBEV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEV)
if (LWS_WITH_LIBUV)
set(extralibs ${extralibs} uv)
endif()
if (LWS_WITH_LIBEVENT)
set(extralibs ${extralibs} event)
endif()
if (LWS_WITH_LIBEV)
set(extralibs ${extralibs} ev)
endif()
message("Extra libs: ${extralibs}")
if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV)
set(requirements 0)
endif()
@ -80,9 +89,9 @@ if (requirements)
add_executable(${SAMP} ${SRCS})
if (websockets_shared)
target_link_libraries(${SAMP} websockets_shared uv)
target_link_libraries(${SAMP} websockets_shared ${extralibs})
add_dependencies(${SAMP} websockets_shared)
else()
target_link_libraries(${SAMP} websockets uv)
target_link_libraries(${SAMP} websockets ${extralibs})
endif()
endif()

View file

@ -1,4 +1,19 @@
# lws minimal http server libuv foreign
# lws minimal http server eventlib foreign
Commandline option|Meaning
---|---
-d <loglevel>|Debug verbosity in decimal, eg, -d15
--uv|Use the libuv event library (lws must have been configured with `-DLWS_WITH_LIBUV=1`)
--event|Use the libevent library (lws must have been configured with `-DLWS_WITH_LIBEVENT=1`)
--ev|Use the libev event library (lws must have been configured with `-DLWS_WITH_LIBEV=1`)
Notice libevent and libev cannot coexist in the one library. But all the other combinations are OK.
x|libuv|libevent|libev
---|---|---|---
libuv|-|OK|OK
libevent|OK|-|no
libev|OK|no|-
This demonstrates having lws take part in a libuv loop owned by
something else, with its own objects running in the loop.

View file

@ -0,0 +1,424 @@
/*
* lws-minimal-http-server-eventlib-foreign
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* This demonstrates the most minimal http server you can make with lws that
* uses a libuv event loop created outside lws. It shows how lws can
* participate in someone else's event loop and clean up after itself.
*
* You choose the event loop to work with at runtime, by giving the
* --uv, --event or --ev switch. Lws has to have been configured to build the
* selected event lib support.
*
* To keep it simple, it serves stuff from the subdirectory
* "./mount-origin" of the directory it was started in.
* You can change that by changing mount.origin below.
*/
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
struct lws_context_creation_info info;
static struct lws_context *context;
static int lifetime = 5, reported;
static void foreign_timer_service(void *foreign_loop);
enum {
TEST_STATE_CREATE_LWS_CONTEXT,
TEST_STATE_DESTROY_LWS_CONTEXT,
TEST_STATE_EXIT
};
static int sequence = TEST_STATE_CREATE_LWS_CONTEXT;
static const struct lws_http_mount mount = {
/* .mount_next */ NULL, /* linked-list "next" */
/* .mountpoint */ "/", /* mountpoint URL */
/* .origin */ "./mount-origin", /* serve from dir */
/* .def */ "index.html", /* default filename */
/* .protocol */ NULL,
/* .cgienv */ NULL,
/* .extra_mimetypes */ NULL,
/* .interpret */ NULL,
/* .cgi_timeout */ 0,
/* .cache_max_age */ 0,
/* .auth_mask */ 0,
/* .cache_reusable */ 0,
/* .cache_revalidate */ 0,
/* .cache_intermediaries */ 0,
/* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */
/* .mountpoint_len */ 1, /* char count */
/* .basic_auth_login_file */ NULL,
};
static void
signal_cb(int signum)
{
lwsl_notice("Signal %d caught, exiting...\n", signum);
switch (signum) {
case SIGTERM:
case SIGINT:
break;
default:
break;
}
lws_context_destroy(context);
}
/*
* The event-loop specific foreign loop code, one set for each event loop lib
*
* Only the code in this section is specific to the event library used.
*/
#if defined(LWS_WITH_LIBUV)
static uv_loop_t loop_uv;
static uv_timer_t timer_outer_uv;
static uv_signal_t sighandler_uv;
static void
timer_cb_uv(uv_timer_t *t)
{
foreign_timer_service(&loop_uv);
}
static void
signal_cb_uv(uv_signal_t *watcher, int signum)
{
signal_cb(signum);
}
static void
foreign_event_loop_init_and_run_libuv(void)
{
/* we create and start our "foreign loop" */
#if (UV_VERSION_MAJOR > 0) // Travis...
uv_loop_init(&loop_uv);
#endif
uv_signal_init(&loop_uv, &sighandler_uv);
uv_signal_start(&sighandler_uv, signal_cb_uv, SIGINT);
uv_timer_init(&loop_uv, &timer_outer_uv);
#if (UV_VERSION_MAJOR > 0) // Travis...
uv_timer_start(&timer_outer_uv, timer_cb_uv, 0, 1000);
#else
(void)timer_cb_uv;
#endif
uv_run(&loop_uv, UV_RUN_DEFAULT);
}
static void
foreign_event_loop_stop_libuv(void)
{
uv_stop(&loop_uv);
}
static void
foreign_event_loop_cleanup_libuv(void)
{
/* cleanup the foreign loop assets */
uv_timer_stop(&timer_outer_uv);
uv_close((uv_handle_t*)&timer_outer_uv, NULL);
uv_signal_stop(&sighandler_uv);
uv_close((uv_handle_t *)&sighandler_uv, NULL);
uv_run(&loop_uv, UV_RUN_DEFAULT);
#if (UV_VERSION_MAJOR > 0) // Travis...
uv_loop_close(&loop_uv);
#endif
}
#endif
#if defined(LWS_WITH_LIBEVENT)
static struct event_base *loop_event;
static struct event *timer_outer_event;
static struct event *sighandler_event;
static void
timer_cb_event(int fd, short event, void *arg)
{
foreign_timer_service(loop_event);
}
static void
signal_cb_event(int fd, short event, void *arg)
{
signal_cb((int)(lws_intptr_t)arg);
}
static void
foreign_event_loop_init_and_run_libevent(void)
{
struct timeval tv;
/* we create and start our "foreign loop" */
tv.tv_sec = 1;
tv.tv_usec = 0;
loop_event = event_base_new();
sighandler_event = evsignal_new(loop_event, SIGINT, signal_cb_event,
(void*)SIGINT);
timer_outer_event = event_new(loop_event, -1, EV_PERSIST,
timer_cb_event, NULL);
//evtimer_new(loop_event, timer_cb_event, NULL);
evtimer_add(timer_outer_event, &tv);
event_base_loop(loop_event, 0);
}
static void
foreign_event_loop_stop_libevent(void)
{
event_base_loopexit(loop_event, NULL);
}
static void
foreign_event_loop_cleanup_libevent(void)
{
/* cleanup the foreign loop assets */
evtimer_del(timer_outer_event);
event_free(timer_outer_event);
evsignal_del(sighandler_event);
event_free(sighandler_event);
event_base_loop(loop_event, 0);
event_base_free(loop_event);
}
#endif
#if defined(LWS_WITH_LIBEV)
static struct ev_loop *loop_ev;
static struct ev_timer timer_outer_ev;
static struct ev_signal sighandler_ev;
static void
timer_cb_ev(struct ev_loop *loop, struct ev_timer *watcher, int revents)
{
foreign_timer_service(loop_ev);
}
static void
signal_cb_ev(struct ev_loop *loop, struct ev_signal *watcher, int revents)
{
signal_cb(watcher->signum);
}
static void
foreign_event_loop_init_and_run_libev(void)
{
/* we create and start our "foreign loop" */
loop_ev = ev_loop_new(0);
ev_signal_init(&sighandler_ev, signal_cb_ev, SIGINT);
ev_signal_start(loop_ev, &sighandler_ev);
ev_timer_init(&timer_outer_ev, timer_cb_ev, 0, 1);
ev_timer_start(loop_ev, &timer_outer_ev);
ev_run(loop_ev, 0);
}
static void
foreign_event_loop_stop_libev(void)
{
ev_break(loop_ev, EVBREAK_ALL);
}
static void
foreign_event_loop_cleanup_libev(void)
{
/* cleanup the foreign loop assets */
ev_timer_stop(loop_ev, &timer_outer_ev);
ev_signal_stop(loop_ev, &sighandler_ev);
ev_run(loop_ev, UV_RUN_DEFAULT);
ev_loop_destroy(loop_ev);
}
#endif
/* this is called at 1Hz using a foreign loop timer */
static void
foreign_timer_service(void *foreign_loop)
{
void *foreign_loops[1];
lwsl_user("Foreign 1Hz timer\n");
if (sequence == TEST_STATE_EXIT && !context && !reported) {
/*
* at this point the lws_context_destroy() we did earlier
* has completed and the entire context is wholly destroyed
*/
lwsl_user("lws_destroy_context() done, continuing for 5s\n");
reported = 1;
}
if (--lifetime)
return;
switch (sequence++) {
case TEST_STATE_CREATE_LWS_CONTEXT:
/* this only has to exist for the duration of create context */
foreign_loops[0] = foreign_loop;
info.foreign_loops = foreign_loops;
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return;
}
lwsl_user("LWS Context created and will be active for 10s\n");
lifetime = 11;
break;
case TEST_STATE_DESTROY_LWS_CONTEXT:
/* cleanup the lws part */
lwsl_user("Destroying lws context and continuing loop for 5s\n");
lws_context_destroy(context);
lifetime = 6;
break;
case TEST_STATE_EXIT:
lwsl_user("Deciding to exit foreign loop too\n");
#if defined(LWS_WITH_LIBUV)
if (info.options & LWS_SERVER_OPTION_LIBUV)
foreign_event_loop_stop_libuv();
#endif
#if defined(LWS_WITH_LIBEVENT)
if (info.options & LWS_SERVER_OPTION_LIBEVENT)
foreign_event_loop_stop_libevent();
#endif
#if defined(LWS_WITH_LIBEV)
if (info.options & LWS_SERVER_OPTION_LIBEV)
foreign_event_loop_stop_libev();
#endif
break;
default:
break;
}
}
int main(int argc, const char **argv)
{
const char *p;
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
/* for LLL_ verbosity above NOTICE to be built into lws,
* lws must have been configured and built with
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
/* | LLL_DEBUG */;
if ((p = lws_cmdline_option(argc, argv, "-d")))
logs = atoi(p);
lws_set_log_level(logs, NULL);
lwsl_user("LWS minimal http server libuv + foreign loop |"
" visit http://localhost:7681\n");
/*
* We prepare the info here, but don't use it until later in the
* timer callback, to demonstrate the independence of the foreign loop
* and lws.
*/
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.port = 7681;
info.mounts = &mount;
info.error_document_404 = "/404.html";
info.pcontext = &context;
if (lws_cmdline_option(argc, argv, "-s")) {
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.ssl_cert_filepath = "localhost-100y.cert";
info.ssl_private_key_filepath = "localhost-100y.key";
}
if (lws_cmdline_option(argc, argv, "--uv"))
info.options |= LWS_SERVER_OPTION_LIBUV;
else
if (lws_cmdline_option(argc, argv, "--event"))
info.options |= LWS_SERVER_OPTION_LIBEVENT;
else
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else {
lwsl_err("This app only makes sense when used\n");
lwsl_err(" with a foreign loop, --uv, --event, or --ev\n");
return 1;
}
lwsl_user(" This app creates a foreign event loop with a timer +\n");
lwsl_user(" signalhandler, and performs a test in three phases:\n");
lwsl_user("\n");
lwsl_user(" 1) 5s: Runs the loop with just the timer\n");
lwsl_user(" 2) 10s: create an lws context serving on localhost:7681\n");
lwsl_user(" using the same foreign loop. Destroy it after 10s.\n");
lwsl_user(" 3) 5s: Run the loop again with just the timer\n");
lwsl_user("\n");
lwsl_user(" Finally close only the timer and signalhandler and\n");
lwsl_user(" exit the loop cleanly\n");
lwsl_notice("%s\n", info.ssl_cert_filepath);
/* foreign loop specific startup and run */
#if defined(LWS_WITH_LIBUV)
if (info.options & LWS_SERVER_OPTION_LIBUV)
foreign_event_loop_init_and_run_libuv();
#endif
#if defined(LWS_WITH_LIBEVENT)
if (info.options & LWS_SERVER_OPTION_LIBEVENT)
foreign_event_loop_init_and_run_libevent();
#endif
#if defined(LWS_WITH_LIBEV)
if (info.options & LWS_SERVER_OPTION_LIBEV)
foreign_event_loop_init_and_run_libev();
#endif
lws_context_destroy(context);
/* foreign loop specific cleanup and exit */
#if defined(LWS_WITH_LIBUV)
if (info.options & LWS_SERVER_OPTION_LIBUV)
foreign_event_loop_cleanup_libuv();
#endif
#if defined(LWS_WITH_LIBEVENT)
if (info.options & LWS_SERVER_OPTION_LIBEVENT)
foreign_event_loop_cleanup_libevent();
#endif
#if defined(LWS_WITH_LIBEV)
if (info.options & LWS_SERVER_OPTION_LIBEV)
foreign_event_loop_cleanup_libev();
#endif
lwsl_user("%s: exiting...\n", __func__);
return 0;
}

View file

@ -1,201 +0,0 @@
/*
* lws-minimal-http-server-libuv-foreign
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* This demonstrates the most minimal http server you can make with lws that
* uses a libuv event loop created outside lws. It shows how lws can
* participate in someone else's event loop and clean up after itself.
*
* To keep it simple, it serves stuff from the subdirectory
* "./mount-origin" of the directory it was started in.
* You can change that by changing mount.origin below.
*/
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
static struct lws_context *context;
static uv_loop_t loop;
static int lifetime = 5, reported;
struct lws_context_creation_info info;
enum {
TEST_STATE_CREATE_LWS_CONTEXT,
TEST_STATE_DESTROY_LWS_CONTEXT,
TEST_STATE_EXIT
};
static int sequence = TEST_STATE_CREATE_LWS_CONTEXT;
static const struct lws_http_mount mount = {
/* .mount_next */ NULL, /* linked-list "next" */
/* .mountpoint */ "/", /* mountpoint URL */
/* .origin */ "./mount-origin", /* serve from dir */
/* .def */ "index.html", /* default filename */
/* .protocol */ NULL,
/* .cgienv */ NULL,
/* .extra_mimetypes */ NULL,
/* .interpret */ NULL,
/* .cgi_timeout */ 0,
/* .cache_max_age */ 0,
/* .auth_mask */ 0,
/* .cache_reusable */ 0,
/* .cache_revalidate */ 0,
/* .cache_intermediaries */ 0,
/* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */
/* .mountpoint_len */ 1, /* char count */
/* .basic_auth_login_file */ NULL,
};
void signal_cb(uv_signal_t *watcher, int signum)
{
lwsl_notice("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
case SIGTERM:
case SIGINT:
break;
default:
signal(SIGABRT, SIG_DFL);
abort();
break;
}
if (context)
lws_context_destroy(context);
}
/* this logs once a second to show that the foreign loop assets are working */
static void
timer_cb(uv_timer_t *t)
{
void *foreign_loops[1];
foreign_loops[0] = &loop;
info.foreign_loops = foreign_loops;
lwsl_user("Foreign 1Hz timer\n");
if (sequence == TEST_STATE_EXIT && !context && !reported) {
/*
* at this point the lws_context_destroy() we did earlier
* has completed and the entire context is wholly destroyed
*/
lwsl_user("lws_destroy_context() completed, continuing for 5s\n");
reported = 1;
}
if (--lifetime)
return;
switch (sequence++) {
case TEST_STATE_CREATE_LWS_CONTEXT:
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return;
}
lwsl_user("LWS Context created and active for 10s\n");
lifetime = 11;
break;
case TEST_STATE_DESTROY_LWS_CONTEXT:
/* cleanup the lws part */
lwsl_user("Destroying lws context and continuing loop for 5s\n");
lws_context_destroy(context);
lifetime = 6;
break;
case TEST_STATE_EXIT:
lwsl_user("Deciding to exit foreign loop too\n");
uv_stop(&loop);
break;
default:
break;
}
}
int main(int argc, const char **argv)
{
uv_timer_t timer_outer;
uv_signal_t sighandler;
const char *p;
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
/* for LLL_ verbosity above NOTICE to be built into lws,
* lws must have been configured and built with
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
/* | LLL_DEBUG */;
if ((p = lws_cmdline_option(argc, argv, "-d")))
logs = atoi(p);
lws_set_log_level(logs, NULL);
lwsl_user("LWS minimal http server libuv + foreign loop |"
" visit http://localhost:7681\n");
/*
* We prepare the info here, but don't use it until later in the
* timer callback, to demonstrate the independence of the foreign loop
* and lws.
*/
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.port = 7681;
info.mounts = &mount;
info.error_document_404 = "/404.html";
info.options = LWS_SERVER_OPTION_LIBUV;
info.pcontext = &context;
if (lws_cmdline_option(argc, argv, "-s")) {
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.ssl_cert_filepath = "localhost-100y.cert";
info.ssl_private_key_filepath = "localhost-100y.key";
}
info.pcontext = &context;
lwsl_user(" This app creates a uv loop with a timer + signalhandler, and\n");
lwsl_user(" performs a test in three phases:\n");
lwsl_user("\n");
lwsl_user(" 1) 5s: Runs the loop with just the timer\n");
lwsl_user(" 2) 10s: create an lws context serving on localhost:7681\n");
lwsl_user(" using the same uv loop. Destroy it after 10s.\n");
lwsl_user(" 3) 5s: Run the loop again with just the timer\n");
lwsl_user("\n");
lwsl_user(" Finally close only the timer and signalhandler and\n");
lwsl_user(" exit the loop cleanly\n");
/* we create and start our "foreign loop" */
uv_loop_init(&loop);
uv_signal_init(&loop, &sighandler);
uv_signal_start(&sighandler, signal_cb, SIGINT);
uv_timer_init(&loop, &timer_outer);
uv_timer_start(&timer_outer, timer_cb, 0, 1000);
uv_run(&loop, UV_RUN_DEFAULT);
/* in the case we hit ^C while lws still exists */
lws_context_destroy(context);
/* cleanup the foreign loop assets */
uv_timer_stop(&timer_outer);
uv_close((uv_handle_t*)&timer_outer, NULL);
uv_signal_stop(&sighandler);
uv_close((uv_handle_t *)&sighandler, NULL);
uv_run(&loop, UV_RUN_DEFAULT);
uv_loop_close(&loop);
lwsl_user("%s: exiting...\n", __func__);
return 0;
}

View file

@ -3,10 +3,10 @@
<body>
<img src="libwebsockets.org-logo.png"><br>
Hello from the <b>minimal http server libuv foreign loop example</b>.
Hello from the <b>minimal http server eventlib foreign loop example</b>.
<br>
The timer messages in the console are coming from<br>
a timer on the libuv loop set up before the lws context<br>
a timer on the event library lib loop set up before the lws context<br>
started using it.
</body>
</html>

View file

@ -1,13 +1,13 @@
/*
* lws-minimal-http-server-libuv
* lws-minimal-http-server-eventlib
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* This demonstrates the most minimal http server you can make with lws using
* the libuv event loop.
* This demonstrates a minimal http[s] server that can work with any of the
* supported event loop backends, or the default poll() one.
*
* To keep it simple, it serves stuff from the subdirectory
* "./mount-origin" of the directory it was started in.
@ -42,22 +42,22 @@ static const struct lws_http_mount mount = {
void signal_cb(void *handle, int signum)
{
uv_signal_t *watcher = (uv_signal_t *)handle;
lwsl_notice("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
switch (signum) {
case SIGTERM:
case SIGINT:
break;
default:
signal(SIGABRT, SIG_DFL);
abort();
lwsl_err("%s: signal %d\n", __func__, signum);
break;
}
lws_context_destroy(context);
}
void sigint_handler(int sig)
{
signal_cb(NULL, sig);
}
int main(int argc, const char **argv)
{
struct lws_context_creation_info info;
@ -74,19 +74,32 @@ int main(int argc, const char **argv)
logs = atoi(p);
lws_set_log_level(logs, NULL);
lwsl_user("LWS minimal http server libuv [-s (ssl)] | visit http://localhost:7681\n");
lwsl_user("LWS minimal http server eventlib | visit http://localhost:7681\n");
lwsl_user(" [-s (ssl)] [--uv (libuv)] [--ev (libev)] [--event (libevent)]\n");
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.port = 7681;
info.mounts = &mount;
info.error_document_404 = "/404.html";
info.pcontext = &context;
info.signal_cb = signal_cb;
if (lws_cmdline_option(argc, argv, "-s")) {
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.ssl_cert_filepath = "localhost-100y.cert";
info.ssl_private_key_filepath = "localhost-100y.key";
}
info.options |= LWS_SERVER_OPTION_LIBUV;
info.signal_cb = signal_cb;
if (lws_cmdline_option(argc, argv, "--uv"))
info.options |= LWS_SERVER_OPTION_LIBUV;
else
if (lws_cmdline_option(argc, argv, "--event"))
info.options |= LWS_SERVER_OPTION_LIBEVENT;
else
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else
signal(SIGINT, sigint_handler);
context = lws_create_context(&info);
if (!context) {
@ -94,8 +107,10 @@ int main(int argc, const char **argv)
return 1;
}
lws_service(context, 0);
while (!lws_service(context, 0))
;
lwsl_info("calling external context destroy\n");
lws_context_destroy(context);
return 0;

View file

@ -79,6 +79,11 @@ dotest() {
if [ -e $2/$MYTEST/$T.result ] ; then
R=`cat $2/$MYTEST/$T.result`
cat $2/$MYTEST/$T.log | tail -n 3 > $2/$MYTEST/$T.time
if [ $R -ne 0 ] ; then
echo
cat $2/$MYTEST/$T.log
echo
fi
fi
feedback $MYTEST $R $T

View file

@ -68,6 +68,8 @@ file_upload_cb(void *data, const char *name, const char *filename,
(struct per_session_data__post_demo *)data;
#if !defined(LWS_WITH_ESP32)
int n;
(void)n;
#endif
switch (state) {
@ -92,7 +94,7 @@ file_upload_cb(void *data, const char *name, const char *filename,
#if !defined(LWS_WITH_ESP32)
n = write((int)(long long)pss->fd, buf, len);
lwsl_notice("%s: write %d says %d\n", __func__, len, n);
lwsl_info("%s: write %d says %d\n", __func__, len, n);
#else
lwsl_notice("%s: Received chunk size %d\n", __func__, len);
#endif

View file

@ -16,6 +16,10 @@ LOG=/tmp/lwslog
A=`which libwebsockets-test-server`
INSTALLED=`dirname $A`
SHAREDIR=$INSTALLED/../share/libwebsockets-test-server
CORPUS=$SHAREDIR/test.html
CPID=
LEN=0
@ -28,24 +32,26 @@ function check {
#dd if=$LOG bs=1 skip=$LEN 2>/dev/null
if [ "$1" = "default" ] ; then
diff /tmp/lwscap $INSTALLED/../share/libwebsockets-test-server/test.html > /dev/null
diff /tmp/lwscap $CORPUS > /dev/null
if [ $? -ne 0 ] ; then
echo "FAIL: got something other than test.html back"
echo "FAIL: got something other than $CORPUS back"
exit 1
fi
fi
if [ "$1" = "defaultplusforbidden" ] ; then
cat $INSTALLED/../share/libwebsockets-test-server/test.html > /tmp/plusforb
cat $CORPUS > /tmp/plusforb
echo -e -n "HTTP/1.0 403 Forbidden\x0d\x0acontent-type: text/html\x0d\x0acontent-length: 38\x0d\x0a\x0d\x0a<html><body><h1>403</h1></body></html>" >> /tmp/plusforb
diff /tmp/lwscap /tmp/plusforb > /dev/null
if [ $? -ne 0 ] ; then
cat $INSTALLED/../share/libwebsockets-test-server/test.html > /tmp/plusforb
cat $CORPUS > /tmp/plusforb
echo -e -n "HTTP/1.1 403 Forbidden\x0d\x0acontent-type: text/html\x0d\x0acontent-length: 38\x0d\x0a\x0d\x0a<html><body><h1>403</h1></body></html>" >> /tmp/plusforb
diff /tmp/lwscap /tmp/plusforb > /dev/null
if [ $? -ne 0 ] ; then
echo "FAIL: got something other than test.html + forbidden back"
echo "FAIL: got something other than $CORPUS + forbidden back"
tail -n 10 /tmp/lwscap
tail -n 100 $LOG
exit 1
fi
fi
@ -58,8 +64,16 @@ function check {
fi
fi
if [ "$1" = "notfound" ] ; then
if [ -z "`grep '<h1>404</h1>' /tmp/lwscap`" ] ; then
echo "FAIL: should have told not found"
exit 1
fi
fi
if [ "$1" = "rejected" ] ; then
if [ -z "`grep '<h1>406</h1>' /tmp/lwscap`" ] ; then
if [ -z "`grep '<h1>404</h1>' /tmp/lwscap`" ] ; then
echo "FAIL: should have told forbidden (test server has no dirs)"
exit 1
fi
@ -67,7 +81,7 @@ function check {
if [ "$1" = "media" ] ; then
if [ -z "`grep '<h1>415</h1>' /tmp/lwscap`" ] ; then
if [ -z "`grep '<h1>404</h1>' /tmp/lwscap`" ] ; then
echo "FAIL: should have told unknown media type"
exit 1
fi
@ -126,6 +140,7 @@ echo
echo "---- /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F"
rm -f /tmp/lwscap
echo -n -e "GET /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
cat /tmp/lwscap
check 1 "UPDATE_SETTINGS=1"
check 2 "Root_Channels_1_Channel_name_http_post=?"
check 3 "Root_Channels_1_Channel_location_http_post=?"
@ -147,16 +162,16 @@ check 1 "key1_2=value1"
check
echo
echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=1)"
echo "---- ? processing (%2f%2e%2e%2f%2e./xxtest.html?arg=1)"
rm -f /tmp/lwscap
echo -n -e "GET %2f%2e%2e%2f%2e./test.html?arg=1 HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
echo -n -e "GET %2f%2e%2e%2f%2e./xxtest.html?arg=1 HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check 1 "arg=1"
check
echo
echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=/../.)"
echo "---- ? processing (%2f%2e%2e%2f%2e./xxtest.html?arg=/../.)"
rm -f /tmp/lwscap
echo -n -e "GET %2f%2e%2e%2f%2e./test.html?arg=/../. HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
echo -n -e "GET %2f%2e%2e%2f%2e./xxtest.html?arg=/../. HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check 1 "arg=/../."
check
@ -167,23 +182,23 @@ check
echo
echo "---- spam more than the name buffer of crap"
dd if=/dev/urandom bs=1 count=80 2>/dev/null | nc -i1s $SERVER $PORT
dd if=/dev/urandom bs=1 count=80 2>/dev/null | nc -i1 $SERVER $PORT
check
echo
echo "---- spam 10MB of crap"
dd if=/dev/urandom bs=1 count=655360 | nc -i1s $SERVER $PORT
dd if=/dev/urandom bs=1 count=655360 | nc -i1 $SERVER $PORT
check
echo
echo "---- malformed URI"
echo "GET nonsense................................................................................................................" \
| nc -i1s $SERVER $PORT
| nc -i1 $SERVER $PORT
check
echo
echo "---- missing URI"
echo -n -e "GET HTTP/1.0\x0d\x0a\x0d\x0a" | nc -i1s $SERVER $PORT >/tmp/lwscap
echo -n -e "GET HTTP/1.0\x0d\x0a\x0d\x0a" | nc -i1 $SERVER $PORT >/tmp/lwscap
check
echo
@ -210,7 +225,7 @@ echo -n -e "GET blah HTTP/1.0\x0d\x0a...........................................
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
| nc -i1s $SERVER $PORT
| nc -i1 $SERVER $PORT
check
echo
@ -232,28 +247,13 @@ echo -n -e "GET ................................................................
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
| nc -i1s $SERVER $PORT
| nc -i1 $SERVER $PORT
check
echo
echo "---- good request but http payload coming too (test.html served then forbidden)"
echo -n -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
"......................................................................................................................." \
| nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
| cat - /dev/zero | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check defaultplusforbidden
check
@ -261,7 +261,8 @@ echo
echo "---- nonexistent file"
rm -f /tmp/lwscap
echo -n -e "GET /nope HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check media
cat /tmp/lwscap
check notfound
check
echo
@ -275,7 +276,7 @@ echo
echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)"
rm -f /tmp/lwscap
echo -n -e "GET /../../../../etc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check rejected
check notfound
check
echo
@ -317,21 +318,21 @@ echo
echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)"
rm -f /tmp/lwscap
echo -e -n "GET /%2e%2e%2f../../../etc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check rejected
check notfound
check
echo
echo "---- directory attack 8 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)"
rm -f /tmp/lwscap
echo -e -n "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check rejected
check notfound
check
echo
echo "---- http/1.1 pipelining"
rm -f /tmp/lwscap
wget -O/tmp/lwsdump http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html 2>&1 | grep "Downloaded: 8 files" > /tmp/lwscap
good=`cat $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html | md5sum | cut -d' ' -f1`
good=`cat $CORPUS $CORPUS $CORPUS $CORPUS $CORPUS $CORPUS $CORPUS $CORPUS | md5sum | cut -d' ' -f1`
if [ "$good" != "`md5sum /tmp/lwsdump | cut -d' ' -f 1`" ] ; then
echo "FAIL: mismatched content good=$good received=`md5sum /tmp/lwsdump`"
exit 1
@ -551,13 +552,11 @@ for i in \
R=`rm -f /tmp/lwscap ; echo -n -e "GET $i HTTP/1.0\r\n\r\n" | nc localhost 7681 2>/dev/null >/tmp/lwscap; head -n1 /tmp/lwscap| cut -d' ' -f2`
#cat /tmp/lwscap | head -n1
#echo ==== $R
if [ "$R" != "403" ]; then
U=`cat $LOG | grep lws_http_serve | tail -n 1 | cut -d':' -f6 | cut -d' ' -f2`
# echo $U
U=`cat $LOG | grep Method: | tail -n 1 | cut -d"'" -f4 | sed "s|\\'||g"`
echo "- \"$i\" -> $R \"$U\"" >>/tmp/results
else
echo "- \"$i\" -> $R" >>/tmp/results
@ -565,36 +564,36 @@ fi
done
cat <<EOF >/tmp/lwsresult1
- "/..../" -> 406 "/..../"
- "/.../." -> 406 "/.../"
- "/...//" -> 406 "/.../"
- "/.../a" -> 406 "/.../a"
- "/.../w" -> 406 "/.../w"
- "/.../?" -> 406 "/.../"
- "/..../" -> 404 "/..../"
- "/.../." -> 404 "/.../"
- "/...//" -> 404 "/.../"
- "/.../a" -> 404 "/.../a"
- "/.../w" -> 404 "/.../w"
- "/.../?" -> 404 "/.../"
- "/.../%" -> 403
- "/../.." -> 200 "/"
- "/.././" -> 200 "/"
- "/../.a" -> 415 "/.a"
- "/../.w" -> 415 "/.w"
- "/../.a" -> 404 "/.a"
- "/../.w" -> 404 "/.w"
- "/../.." -> 200 "/"
- "/../.%" -> 403
- "/..//." -> 200 "/"
- "/..///" -> 200 "/"
- "/..//a" -> 415 "/a"
- "/..//w" -> 415 "/w"
- "/..//a" -> 404 "/a"
- "/..//w" -> 404 "/w"
- "/..//?" -> 200 "/"
- "/..//%" -> 403
- "/../a." -> 415 "/a."
- "/../a/" -> 406 "/a/"
- "/../aa" -> 415 "/aa"
- "/../aw" -> 415 "/aw"
- "/../a?" -> 415 "/a"
- "/../a." -> 404 "/a."
- "/../a/" -> 404 "/a/"
- "/../aa" -> 404 "/aa"
- "/../aw" -> 404 "/aw"
- "/../a?" -> 404 "/a"
- "/../a%" -> 403
- "/../w." -> 415 "/w."
- "/../w/" -> 406 "/w/"
- "/../wa" -> 415 "/wa"
- "/../ww" -> 415 "/ww"
- "/../w?" -> 415 "/w"
- "/../w." -> 404 "/w."
- "/../w/" -> 404 "/w/"
- "/../wa" -> 404 "/wa"
- "/../ww" -> 404 "/ww"
- "/../w?" -> 404 "/w"
- "/../w%" -> 403
- "/../?." -> 200 "/"
- "/../?/" -> 200 "/"
@ -608,49 +607,49 @@ cat <<EOF >/tmp/lwsresult1
- "/../%w" -> 403
- "/../%?" -> 403
- "/../%%" -> 403
- "/./..." -> 415 "/..."
- "/./..." -> 404 "/..."
- "/./../" -> 200 "/"
- "/./..a" -> 415 "/..a"
- "/./..w" -> 415 "/..w"
- "/./..a" -> 404 "/..a"
- "/./..w" -> 404 "/..w"
- "/./..?" -> 200 "/"
- "/./..%" -> 403
- "/.//.." -> 200 "/"
- "/.a../" -> 406 "/.a../"
- "/.a../" -> 404 "/.a../"
- "/.a/.." -> 200 "/"
- "/.w../" -> 406 "/.w../"
- "/.w../" -> 404 "/.w../"
- "/.w/.." -> 200 "/"
- "/.?../" -> 415 "/."
- "/.?../" -> 404 "/."
- "/../.." -> 200 "/"
- "/.%../" -> 403
- "/.%/.." -> 403
- "//...." -> 415 "/...."
- "//.../" -> 406 "/.../"
- "//...a" -> 415 "/...a"
- "//...w" -> 415 "/...w"
- "//...?" -> 415 "/..."
- "//...." -> 404 "/...."
- "//.../" -> 404 "/.../"
- "//...a" -> 404 "/...a"
- "//...w" -> 404 "/...w"
- "//...?" -> 404 "/..."
- "//...%" -> 403
- "//../." -> 200 "/"
- "//..//" -> 200 "/"
- "//../a" -> 415 "/a"
- "//../w" -> 415 "/w"
- "//../a" -> 404 "/a"
- "//../w" -> 404 "/w"
- "//../?" -> 200 "/"
- "//../%" -> 403
- "//..a." -> 415 "/..a."
- "//..a/" -> 406 "/..a/"
- "//..aa" -> 415 "/..aa"
- "//..aw" -> 415 "/..aw"
- "//..a?" -> 415 "/..a"
- "//..a." -> 404 "/..a."
- "//..a/" -> 404 "/..a/"
- "//..aa" -> 404 "/..aa"
- "//..aw" -> 404 "/..aw"
- "//..a?" -> 404 "/..a"
- "//..a%" -> 403
- "//..w." -> 415 "/..w."
- "//..w/" -> 406 "/..w/"
- "//..wa" -> 415 "/..wa"
- "//..ww" -> 415 "/..ww"
- "//..w?" -> 415 "/..w"
- "//..w." -> 404 "/..w."
- "//..w/" -> 404 "/..w/"
- "//..wa" -> 404 "/..wa"
- "//..ww" -> 404 "/..ww"
- "//..w?" -> 404 "/..w"
- "//..w%" -> 403
- "//..?." -> 200 "/"
- "//..?/" -> 200 "/"
- "//..?a" -> 415 "/a"
- "//..?w" -> 415 "/w"
- "//..?a" -> 404 "/a"
- "//..?w" -> 404 "/w"
- "//..??" -> 200 "/"
- "//..?%" -> 403
- "//..%." -> 403
@ -660,65 +659,65 @@ cat <<EOF >/tmp/lwsresult1
- "//..%?" -> 403
- "//..%%" -> 403
- "//./.." -> 200 "/"
- "///..." -> 415 "/..."
- "///..." -> 404 "/..."
- "///../" -> 200 "/"
- "///..a" -> 415 "/..a"
- "///..w" -> 415 "/..w"
- "///..a" -> 404 "/..a"
- "///..w" -> 404 "/..w"
- "///..?" -> 200 "/"
- "///..%" -> 403
- "////.." -> 200 "/"
- "//a../" -> 406 "/a../"
- "//a../" -> 404 "/a../"
- "//a/.." -> 200 "/"
- "//w../" -> 406 "/w../"
- "//w../" -> 404 "/w../"
- "//w/.." -> 200 "/"
- "//?../" -> 200 "/"
- "//?/.." -> 200 "/"
- "//%../" -> 403
- "//%/.." -> 403
- "/a.../" -> 406 "/a.../"
- "/a../." -> 406 "/a../"
- "/a..//" -> 406 "/a../"
- "/a../a" -> 406 "/a../a"
- "/a../w" -> 406 "/a../w"
- "/a../?" -> 406 "/a../"
- "/a.../" -> 404 "/a.../"
- "/a../." -> 404 "/a../"
- "/a..//" -> 404 "/a../"
- "/a../a" -> 404 "/a../a"
- "/a../w" -> 404 "/a../w"
- "/a../?" -> 404 "/a../"
- "/a../%" -> 403
- "/a./.." -> 200 "/"
- "/a/..." -> 406 "/a/..."
- "/a/..." -> 404 "/a/..."
- "/a/../" -> 200 "/"
- "/a/..a" -> 406 "/a/..a"
- "/a/..w" -> 406 "/a/..w"
- "/a/..a" -> 404 "/a/..a"
- "/a/..w" -> 404 "/a/..w"
- "/a/..?" -> 200 "/"
- "/a/..%" -> 403
- "/a//.." -> 200 "/"
- "/aa../" -> 406 "/aa../"
- "/aa../" -> 404 "/aa../"
- "/aa/.." -> 200 "/"
- "/aw../" -> 406 "/aw../"
- "/aw../" -> 404 "/aw../"
- "/aw/.." -> 200 "/"
- "/a?../" -> 415 "/a"
- "/a?/.." -> 415 "/a"
- "/a?../" -> 404 "/a"
- "/a?/.." -> 404 "/a"
- "/a%../" -> 403
- "/a%/.." -> 403
- "/w.../" -> 406 "/w.../"
- "/w../." -> 406 "/w../"
- "/w..//" -> 406 "/w../"
- "/w../a" -> 406 "/w../a"
- "/w../w" -> 406 "/w../w"
- "/w../?" -> 406 "/w../"
- "/w.../" -> 404 "/w.../"
- "/w../." -> 404 "/w../"
- "/w..//" -> 404 "/w../"
- "/w../a" -> 404 "/w../a"
- "/w../w" -> 404 "/w../w"
- "/w../?" -> 404 "/w../"
- "/w../%" -> 403
- "/w./.." -> 200 "/"
- "/w/..." -> 406 "/w/..."
- "/w/..." -> 404 "/w/..."
- "/w/../" -> 200 "/"
- "/w/..a" -> 406 "/w/..a"
- "/w/..w" -> 406 "/w/..w"
- "/w/..a" -> 404 "/w/..a"
- "/w/..w" -> 404 "/w/..w"
- "/w/..?" -> 200 "/"
- "/w/..%" -> 403
- "/w//.." -> 200 "/"
- "/wa../" -> 406 "/wa../"
- "/wa../" -> 404 "/wa../"
- "/wa/.." -> 200 "/"
- "/ww../" -> 406 "/ww../"
- "/ww../" -> 404 "/ww../"
- "/ww/.." -> 200 "/"
- "/w?../" -> 415 "/w"
- "/w?/.." -> 415 "/w"
- "/w?../" -> 404 "/w"
- "/w?/.." -> 404 "/w"
- "/w%../" -> 403
- "/w%/.." -> 403
- "/?.../" -> 200 "/"
@ -767,13 +766,13 @@ cat <<EOF >/tmp/lwsresult1
- "/%?/.." -> 403
- "/%%../" -> 403
- "/%%/.." -> 403
- "/a/w/../a" -> 406 "/a/a"
- "/path/to/dir/../other/dir" -> 406 "/path/to/other/dir"
- "/a/w/../a" -> 404 "/a/a"
- "/path/to/dir/../other/dir" -> 404 "/path/to/other/dir"
EOF
if [ "`md5sum /tmp/results | cut -d' ' -f 1`" != "`md5sum /tmp/lwsresult1 | cut -d' ' -f1`" ] ; then
echo "Differences..."
diff -urN /tmp/results /tmp/lwsresult1
diff -urN /tmp/lwsresult1 /tmp/results
exit 1
else
echo "OK"

View file

@ -14,7 +14,7 @@ else
sudo make install &&
../minimal-examples/selftests.sh &&
../scripts/h2spec.sh &&
../test-apps/attack.sh &&
../scripts/attack.sh &&
../scripts/h2load.sh &&
../scripts/autobahn-test.sh
else

View file

@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>
int close_testing;
int max_poll_elements;
@ -77,12 +78,69 @@ char crl_path[1024] = "";
#include "../plugins/protocol_post_demo.c"
#endif
static int
lws_callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
void *in, size_t len)
{
const unsigned char *c;
char buf[1024];
int n = 0, hlen;
switch (reason) {
case LWS_CALLBACK_HTTP:
/* non-mount-handled accesses will turn up here */
/* dump the headers */
do {
c = lws_token_to_string(n);
if (!c) {
n++;
continue;
}
hlen = lws_hdr_total_length(wsi, n);
if (!hlen || hlen > (int)sizeof(buf) - 1) {
n++;
continue;
}
lws_hdr_copy(wsi, buf, sizeof buf, n);
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, " %s = %s\n", (char *)c, buf);
n++;
} while (c);
/* dump the individual URI Arg parameters */
n = 0;
while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf),
WSI_TOKEN_HTTP_URI_ARGS, n) > 0) {
lwsl_notice("URI Arg %d: %s\n", ++n, buf);
}
if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
return -1;
if (lws_http_transaction_completed(wsi))
return -1;
return 0;
default:
break;
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
}
/* list of supported protocols and callbacks */
static struct lws_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{ "http-only", lws_callback_http_dummy, 0, 0, },
{ "http-only", lws_callback_http, 0, 0, },
#if defined(LWS_ROLE_WS)
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,