minimize library footprint for embedded server-only
case
+--without-server Don't build the server part of the library nor the
+ test apps that need the server part. Useful to
+ minimize library footprint for embedded client-only
+ case
+
--without-daemonize Don't build daemonize.c / lws_daemonize
--disable-debug Remove all debug logging below lwsl_warn in severity
#
#
#
+AC_ARG_WITH(server,
+ [ --without-server dont build the client part of the library ],
+ [ no_server=yes
+ ])
+
+if test "x$no_server" = "xyes" ; then
+CFLAGS="$CFLAGS -DLWS_NO_SERVER"
+fi
+AM_CONDITIONAL(NO_SERVER, test x$no_server = xyes)
+
+
+
+#
+#
+#
AC_ARG_WITH(daemonize,
[ --without-daemonize dont build the daemonization api ],
[ no_daemonize=yes
lib_LTLIBRARIES=libwebsockets.la
include_HEADERS=libwebsockets.h
dist_libwebsockets_la_SOURCES=libwebsockets.c \
- handshake.c \
parsers.c \
+ handshake.c \
libwebsockets.h \
base64-decode.c \
output.c \
client-handshake.c
endif
+if NO_SERVER
+else
+dist_libwebsockets_la_SOURCES+= server.c \
+ server-handshake.c
+endif
+
if USE_BUILTIN_GETIFADDRS
dist_libwebsockets_la_SOURCES += getifaddrs.c
endif
/*
* libwebsockets - small server side websockets and web server implementation
*
- * Copyright (C) 2010 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2013 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
#include "private-libwebsockets.h"
-#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
-#define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \
- p += wsi->utf8_token[tok].token_len; }
-
-static int
-interpret_key(const char *key, unsigned long *result)
-{
- char digits[20];
- int digit_pos = 0;
- const char *p = key;
- unsigned int spaces = 0;
- unsigned long acc = 0;
- int rem = 0;
-
- while (*p) {
- if (!isdigit(*p)) {
- p++;
- continue;
- }
- if (digit_pos == sizeof(digits) - 1)
- return -1;
- digits[digit_pos++] = *p++;
- }
- digits[digit_pos] = '\0';
- if (!digit_pos)
- return -2;
-
- while (*key) {
- if (*key == ' ')
- spaces++;
- key++;
- }
-
- if (!spaces)
- return -3;
-
- p = &digits[0];
- while (*p) {
- rem = (rem * 10) + ((*p++) - '0');
- acc = (acc * 10) + (rem / spaces);
- rem -= (rem / spaces) * spaces;
- }
-
- if (rem) {
- lwsl_warn("nonzero handshake remainder\n");
- return -1;
- }
-
- *result = acc;
-
- return 0;
-}
-
-
-static int
-handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi)
-{
- unsigned long key1, key2;
- unsigned char sum[16];
- char *response;
- char *p;
- int n;
-
- /* Confirm we have all the necessary pieces */
-
- if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
- !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
- !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
- !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
- !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
- /* completed header processing, but missing some bits */
- goto bail;
-
- /* allocate the per-connection user memory (if any) */
- if (wsi->protocol->per_session_data_size &&
- !libwebsocket_ensure_user_space(wsi))
- goto bail;
-
- /* create the response packet */
-
- /* make a buffer big enough for everything */
-
- response = (char *)malloc(256 +
- wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
- wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
- wsi->utf8_token[WSI_TOKEN_HOST].token_len +
- wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
- wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
- wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
- if (!response) {
- lwsl_err("Out of memory for response buffer\n");
- goto bail;
- }
-
- p = response;
- LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
- "Upgrade: WebSocket\x0d\x0a"
- "Connection: Upgrade\x0d\x0a"
- "Sec-WebSocket-Origin: ");
- strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
- p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
-#ifdef LWS_OPENSSL_SUPPORT
- if (wsi->ssl) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://");
- } else {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
- }
-#else
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
-#endif
-
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST);
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI);
-
- if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
- }
-
- LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
-
- /* convert the two keys into 32-bit integers */
-
- if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
- goto bail;
- if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
- goto bail;
-
- /* lay them out in network byte order (MSB first */
-
- sum[0] = (unsigned char)(key1 >> 24);
- sum[1] = (unsigned char)(key1 >> 16);
- sum[2] = (unsigned char)(key1 >> 8);
- sum[3] = (unsigned char)(key1);
- sum[4] = (unsigned char)(key2 >> 24);
- sum[5] = (unsigned char)(key2 >> 16);
- sum[6] = (unsigned char)(key2 >> 8);
- sum[7] = (unsigned char)(key2);
-
- /* follow them with the challenge token we were sent */
-
- memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
-
- /*
- * compute the md5sum of that 16-byte series and use as our
- * payload after our headers
- */
-
- MD5(sum, 16, (unsigned char *)p);
- p += 16;
-
- /* it's complete: go ahead and send it */
-
- lwsl_parser("issuing response packet %d len\n", (int)(p - response));
-#ifdef _DEBUG
- fwrite(response, 1, p - response, stderr);
-#endif
- n = libwebsocket_write(wsi, (unsigned char *)response,
- p - response, LWS_WRITE_HTTP);
- if (n < 0) {
- lwsl_debug("handshake_00: ERROR writing to socket\n");
- goto bail;
- }
-
- /* alright clean up and set ourselves into established state */
-
- free(response);
- wsi->state = WSI_STATE_ESTABLISHED;
- wsi->lws_rx_parse_state = LWS_RXPS_NEW;
-
- /* notify user code that we're ready to roll */
-
- if (wsi->protocol->callback)
- wsi->protocol->callback(wsi->protocol->owning_server,
- wsi, LWS_CALLBACK_ESTABLISHED,
- wsi->user_space, NULL, 0);
-
- return 0;
-
-bail:
- return -1;
-}
-
-/*
- * Perform the newer BASE64-encoded handshake scheme
- */
-
-static int
-handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
-{
- static const char *websocket_magic_guid_04 =
- "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- static const char *websocket_magic_guid_04_masking =
- "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
- char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
- char nonce_buf[256];
- char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37];
- unsigned char hash[20];
- int n;
- char *response;
- char *p;
- char *m = mask_summing_buf;
- int nonce_len = 0;
- int accept_len;
- char *c;
- char ext_name[128];
- struct libwebsocket_extension *ext;
- int ext_count = 0;
- int more = 1;
-
- if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
- !wsi->utf8_token[WSI_TOKEN_KEY].token_len) {
- lwsl_parser("handshake_04 missing pieces\n");
- /* completed header processing, but missing some bits */
- goto bail;
- }
-
- if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >=
- MAX_WEBSOCKET_04_KEY_LEN) {
- lwsl_warn("Client sent handshake key longer "
- "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN);
- goto bail;
- }
-
- strcpy(accept_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
- strcpy(accept_buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len,
- websocket_magic_guid_04);
-
- SHA1((unsigned char *)accept_buf,
- wsi->utf8_token[WSI_TOKEN_KEY].token_len +
- strlen(websocket_magic_guid_04), hash);
-
- accept_len = lws_b64_encode_string((char *)hash, 20, accept_buf,
- sizeof accept_buf);
- if (accept_len < 0) {
- lwsl_warn("Base64 encoded hash too long\n");
- goto bail;
- }
-
- /* allocate the per-connection user memory (if any) */
- if (wsi->protocol->per_session_data_size &&
- !libwebsocket_ensure_user_space(wsi))
- goto bail;
-
- /* create the response packet */
-
- /* make a buffer big enough for everything */
-
- response = (char *)malloc(256 +
- wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
- wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
- wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
- if (!response) {
- lwsl_err("Out of memory for response buffer\n");
- goto bail;
- }
-
- p = response;
- LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
- "Upgrade: WebSocket\x0d\x0a"
- "Connection: Upgrade\x0d\x0a"
- "Sec-WebSocket-Accept: ");
- strcpy(p, accept_buf);
- p += accept_len;
-
- if (wsi->ietf_spec_revision == 4) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: ");
-
- /* select the nonce */
-
- n = libwebsockets_get_random(wsi->protocol->owning_server,
- hash, 16);
- if (n != 16) {
- lwsl_err("Unable to read random device %s %d\n",
- SYSTEM_RANDOM_FILEPATH, n);
- if (wsi->user_space)
- free(wsi->user_space);
- goto bail;
- }
-
- /* encode the nonce */
-
- nonce_len = lws_b64_encode_string((const char *)hash, 16,
- nonce_buf, sizeof nonce_buf);
- if (nonce_len < 0) {
- lwsl_err("Failed to base 64 encode the nonce\n");
- if (wsi->user_space)
- free(wsi->user_space);
- goto bail;
- }
-
- /* apply the nonce */
-
- strcpy(p, nonce_buf);
- p += nonce_len;
- }
-
- if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
- }
-
- /*
- * Figure out which extensions the client has that we want to
- * enable on this connection, and give him back the list
- */
-
- if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) {
-
- /*
- * break down the list of client extensions
- * and go through them
- */
-
- c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token;
- lwsl_parser("wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token = %s\n",
- wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token);
- wsi->count_active_extensions = 0;
- n = 0;
- while (more) {
-
- if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
- ext_name[n] = *c++;
- if (n < sizeof(ext_name) - 1)
- n++;
- continue;
- }
- ext_name[n] = '\0';
- if (!*c)
- more = 0;
- else {
- c++;
- if (!n)
- continue;
- }
-
- /* check a client's extension against our support */
-
- ext = wsi->protocol->owning_server->extensions;
-
- while (ext && ext->callback) {
-
- if (strcmp(ext_name, ext->name)) {
- ext++;
- continue;
- }
-
- /*
- * oh, we do support this one he
- * asked for... but let's ask user
- * code if it's OK to apply it on this
- * particular connection + protocol
- */
-
- n = wsi->protocol->owning_server->
- protocols[0].callback(
- wsi->protocol->owning_server,
- wsi,
- LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
- wsi->user_space, ext_name, 0);
-
- /*
- * zero return from callback means
- * go ahead and allow the extension,
- * it's what we get if the callback is
- * unhandled
- */
-
- if (n) {
- ext++;
- continue;
- }
-
- /* apply it */
-
- if (ext_count)
- *p++ = ',';
- else
- LWS_CPYAPP(p,
- "\x0d\x0aSec-WebSocket-Extensions: ");
- p += sprintf(p, "%s", ext_name);
- ext_count++;
-
- /* instantiate the extension on this conn */
-
- wsi->active_extensions_user[
- wsi->count_active_extensions] =
- malloc(ext->per_session_data_size);
- if (wsi->active_extensions_user[
- wsi->count_active_extensions] == NULL) {
- lwsl_err("Out of mem\n");
- free(response);
- goto bail;
- }
- memset(wsi->active_extensions_user[
- wsi->count_active_extensions], 0,
- ext->per_session_data_size);
-
- wsi->active_extensions[
- wsi->count_active_extensions] = ext;
-
- /* allow him to construct his context */
-
- ext->callback(wsi->protocol->owning_server,
- ext, wsi,
- LWS_EXT_CALLBACK_CONSTRUCT,
- wsi->active_extensions_user[
- wsi->count_active_extensions], NULL, 0);
-
- wsi->count_active_extensions++;
- lwsl_parser("wsi->count_active_extensions <- %d\n",
- wsi->count_active_extensions);
-
- ext++;
- }
-
- n = 0;
- }
- }
-
- /* end of response packet */
-
- LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
-
- if (wsi->ietf_spec_revision == 4) {
-
- /*
- * precompute the masking key the client will use from the SHA1
- * hash of ( base 64 client key we were sent, concatenated with
- * the bse 64 nonce we sent, concatenated with a magic constant
- * guid specified by the 04 standard )
- *
- * We store the hash in the connection's wsi ready to use with
- * undoing the masking the client has done on framed data it
- * sends (we send our data to the client in clear).
- */
-
- strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
- m += wsi->utf8_token[WSI_TOKEN_KEY].token_len;
- strcpy(m, nonce_buf);
- m += nonce_len;
- strcpy(m, websocket_magic_guid_04_masking);
- m += strlen(websocket_magic_guid_04_masking);
-
- SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
- wsi->masking_key_04);
- }
-
- if (!lws_any_extension_handled(context, wsi,
- LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
- response, p - response)) {
-
- /* okay send the handshake response accepting the connection */
-
- lwsl_parser("issuing response packet %d len\n", (int)(p - response));
- #ifdef DEBUG
- fwrite(response, 1, p - response, stderr);
- #endif
- n = libwebsocket_write(wsi, (unsigned char *)response,
- p - response, LWS_WRITE_HTTP);
- if (n < 0) {
- lwsl_debug("handshake_0405: ERROR writing to socket\n");
- goto bail;
- }
-
- }
-
- /* alright clean up and set ourselves into established state */
-
- free(response);
- wsi->state = WSI_STATE_ESTABLISHED;
- wsi->lws_rx_parse_state = LWS_RXPS_NEW;
- wsi->rx_packet_length = 0;
-
- /* notify user code that we're ready to roll */
-
- if (wsi->protocol->callback)
- wsi->protocol->callback(wsi->protocol->owning_server,
- wsi, LWS_CALLBACK_ESTABLISHED,
- wsi->user_space, NULL, 0);
-
- return 0;
-
-
-bail:
- return -1;
-}
-
-
/*
* -04 of the protocol (actually the 80th version) has a radically different
* handshake. The 04 spec gives the following idea
break;
}
#endif
+#ifndef LWS_NO_SERVER
/* LWS_CONNMODE_WS_SERVING */
+ extern int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi);
+ extern int handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi);
+
for (n = 0; n < len; n++)
libwebsocket_parse(wsi, *buf++);
lwsl_parser("accepted v%02d connection\n",
wsi->ietf_spec_revision);
-
+#endif
break;
case WSI_STATE_AWAITING_CLOSE_ACK:
break;
}
#endif
+#ifndef LWS_NO_SERVER
/* LWS_CONNMODE_WS_SERVING */
if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0)
goto bail;
-
+#endif
break;
default:
lwsl_err("libwebsocket_read: Unhandled state\n");
return 0;
}
-#ifdef LWS_OPENSSL_SUPPORT
-static void
-libwebsockets_decode_ssl_error(void)
-{
- char buf[256];
- u_long err;
-
- while ((err = ERR_get_error()) != 0) {
- ERR_error_string_n(err, buf, sizeof(buf));
- lwsl_err("*** %s\n", buf);
- }
-}
-#endif
-
-
-static int
-interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen)
-{
- int rc = -1;
-#ifdef WIN32
- /* TODO */
-#else
- struct ifaddrs *ifr;
- struct ifaddrs *ifc;
- struct sockaddr_in *sin;
-
- getifaddrs(&ifr);
- for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
- if (strcmp(ifc->ifa_name, ifname))
- continue;
- if (ifc->ifa_addr == NULL)
- continue;
- sin = (struct sockaddr_in *)ifc->ifa_addr;
- if (sin->sin_family != AF_INET)
- continue;
- memcpy(addr, sin, addrlen);
- rc = 0;
- }
-
- freeifaddrs(ifr);
-#endif
- return rc;
-}
void
libwebsocket_close_and_free_session(struct libwebsocket_context *context,
for (n = 0; n < WSI_TOKEN_COUNT; n++)
if (wsi->utf8_token[n].token)
free(wsi->utf8_token[n].token);
-
+#ifndef LWS_NO_CLIENT
if (wsi->c_address)
free(wsi->c_address);
-
+#endif
if (wsi->rxflow_buffer)
free(wsi->rxflow_buffer);
}
}
-struct libwebsocket *
-libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
-{
- struct libwebsocket *new_wsi;
- int n;
-
- new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
- if (new_wsi == NULL) {
- lwsl_err("Out of memory for new connection\n");
- return NULL;
- }
-
- memset(new_wsi, 0, sizeof(struct libwebsocket));
- new_wsi->count_active_extensions = 0;
- new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
-
- /* intialize the instance struct */
-
- new_wsi->state = WSI_STATE_HTTP;
- new_wsi->name_buffer_pos = 0;
- new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
-
- for (n = 0; n < WSI_TOKEN_COUNT; n++) {
- new_wsi->utf8_token[n].token = NULL;
- new_wsi->utf8_token[n].token_len = 0;
- }
-
- /*
- * these can only be set once the protocol is known
- * we set an unestablished connection's protocol pointer
- * to the start of the supported list, so it can look
- * for matching ones during the handshake
- */
- new_wsi->protocol = context->protocols;
- new_wsi->user_space = NULL;
-
- /*
- * Default protocol is 76 / 00
- * After 76, there's a header specified to inform which
- * draft the client wants, when that's seen we modify
- * the individual connection's spec revision accordingly
- */
- new_wsi->ietf_spec_revision = 0;
-
- return new_wsi;
-}
-
-
/**
* libwebsocket_service_fd() - Service polled socket with something waiting
* @context: Websocket context
libwebsocket_service_fd(struct libwebsocket_context *context,
struct pollfd *pollfd)
{
+ struct libwebsocket *wsi;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 +
MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
- struct libwebsocket *wsi;
- struct libwebsocket *new_wsi;
int n;
int m;
- ssize_t len;
- int accept_fd;
- unsigned int clilen;
- struct sockaddr_in cli_addr;
struct timeval tv;
int more = 1;
struct lws_tokens eff_buf;
- int opt = 1;
#ifndef LWS_NO_CLIENT
extern int lws_client_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct pollfd *pollfd);
#endif
+#ifndef LWS_NO_SERVER
+ extern int lws_server_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct pollfd *pollfd);
+#endif
/*
* you can call us with pollfd = NULL to just allow the once-per-second
* global timeout checks; if less than a second since the last check
switch (wsi->mode) {
+#ifndef LWS_NO_SERVER
case LWS_CONNMODE_HTTP_SERVING:
-
- /* handle http headers coming in */
-
- /* any incoming data ready? */
-
- if (pollfd->revents & POLLIN) {
-
- #ifdef LWS_OPENSSL_SUPPORT
- if (wsi->ssl)
- len = SSL_read(wsi->ssl, buf, sizeof buf);
- else
- #endif
- len = recv(pollfd->fd, buf, sizeof buf, 0);
-
- if (len < 0) {
- lwsl_debug("Socket read returned %d\n", len);
- if (errno != EINTR && errno != EAGAIN)
- libwebsocket_close_and_free_session(context,
- wsi, LWS_CLOSE_STATUS_NOSTATUS);
- return 0;
- }
- if (!len) {
- libwebsocket_close_and_free_session(context, wsi,
- LWS_CLOSE_STATUS_NOSTATUS);
- return 0;
- }
-
- n = libwebsocket_read(context, wsi, buf, len);
- if (n < 0)
- /* we closed wsi */
- return 0;
- }
-
- /* this handles POLLOUT for http serving fragments */
-
- if (!(pollfd->revents & POLLOUT))
- break;
-
- /* one shot */
- pollfd->events &= ~POLLOUT;
-
- if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
- break;
-
- if (libwebsockets_serve_http_file_fragment(context, wsi) < 0)
- libwebsocket_close_and_free_session(context, wsi,
- LWS_CLOSE_STATUS_NOSTATUS);
- else
- if (wsi->state == WSI_STATE_HTTP && wsi->protocol->callback)
- if (user_callback_handle_rxflow(wsi->protocol->callback, context, wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION, wsi->user_space,
- wsi->filepath, wsi->filepos))
- libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
- break;
-
case LWS_CONNMODE_SERVER_LISTENER:
-
- /* pollin means a client has connected to us then */
-
- if (!(pollfd->revents & POLLIN))
- break;
-
- /* listen socket got an unencrypted connection... */
-
- clilen = sizeof(cli_addr);
- accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
- &clilen);
- if (accept_fd < 0) {
- lwsl_warn("ERROR on accept: %s\n", strerror(errno));
- break;
- }
-
- /* Disable Nagle */
- opt = 1;
- setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY,
- (const void *)&opt, sizeof(opt));
-
- /*
- * look at who we connected to and give user code a chance
- * to reject based on client IP. There's no protocol selected
- * yet so we issue this to protocols[0]
- */
-
- if ((context->protocols[0].callback)(context, wsi,
- LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
- (void *)(long)accept_fd, NULL, 0)) {
- lwsl_debug("Callback denied network connection\n");
- compatible_close(accept_fd);
- break;
- }
-
- new_wsi = libwebsocket_create_new_server_wsi(context);
- if (new_wsi == NULL) {
- compatible_close(accept_fd);
- break;
- }
-
- new_wsi->sock = accept_fd;
-
-
-#ifdef LWS_OPENSSL_SUPPORT
- new_wsi->ssl = NULL;
-
- if (context->use_ssl) {
-
- new_wsi->ssl = SSL_new(context->ssl_ctx);
- if (new_wsi->ssl == NULL) {
- lwsl_err("SSL_new failed: %s\n",
- ERR_error_string(SSL_get_error(
- new_wsi->ssl, 0), NULL));
- libwebsockets_decode_ssl_error();
- free(new_wsi);
- compatible_close(accept_fd);
- break;
- }
-
- SSL_set_ex_data(new_wsi->ssl,
- openssl_websocket_private_data_index, context);
-
- SSL_set_fd(new_wsi->ssl, accept_fd);
-
- n = SSL_accept(new_wsi->ssl);
- if (n != 1) {
- /*
- * browsers seem to probe with various
- * ssl params which fail then retry
- * and succeed
- */
- lwsl_debug("SSL_accept failed skt %u: %s\n",
- pollfd->fd,
- ERR_error_string(SSL_get_error(
- new_wsi->ssl, n), NULL));
- SSL_free(
- new_wsi->ssl);
- free(new_wsi);
- compatible_close(accept_fd);
- break;
- }
-
- lwsl_debug("accepted new SSL conn "
- "port %u on fd=%d SSL ver %s\n",
- ntohs(cli_addr.sin_port), accept_fd,
- SSL_get_version(new_wsi->ssl));
-
- } else
-#endif
- lwsl_debug("accepted new conn port %u on fd=%d\n",
- ntohs(cli_addr.sin_port), accept_fd);
-
- insert_wsi_socket_into_fds(context, new_wsi);
- break;
-
case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
-
- /* as we are listening, POLLIN means accept() is needed */
-
- if (!(pollfd->revents & POLLIN))
- break;
-
- /* listen socket got an unencrypted connection... */
-
- clilen = sizeof(cli_addr);
- accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
- &clilen);
- if (accept_fd < 0) {
- lwsl_warn("ERROR on accept %d\n", accept_fd);
- return 0;
- }
-
- /* create a dummy wsi for the connection and add it */
-
- new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
- if (new_wsi == NULL) {
- lwsl_err("Out of mem\n");
- goto bail_prox_listener;
- }
- memset(new_wsi, 0, sizeof (struct libwebsocket));
- new_wsi->sock = accept_fd;
- new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
- new_wsi->state = WSI_STATE_ESTABLISHED;
- new_wsi->count_active_extensions = 0;
- /* note which protocol we are proxying */
- new_wsi->protocol_index_for_broadcast_proxy =
- wsi->protocol_index_for_broadcast_proxy;
-
- insert_wsi_socket_into_fds(context, new_wsi);
- break;
-
-bail_prox_listener:
- compatible_close(accept_fd);
- break;
-
case LWS_CONNMODE_BROADCAST_PROXY:
-
- /* handle session socket closed */
-
- if (pollfd->revents & (POLLERR | POLLHUP)) {
-
- lwsl_debug("Session Socket %p (fd=%d) dead\n",
- (void *)wsi, pollfd->fd);
-
- libwebsocket_close_and_free_session(context, wsi,
- LWS_CLOSE_STATUS_NORMAL);
- return 0;
- }
-
- /*
- * either extension code with stuff to spill, or the user code,
- * requested a callback when it was OK to write
- */
-
- if (pollfd->revents & POLLOUT)
- if (lws_handle_POLLOUT_event(context, wsi,
- pollfd) < 0) {
- libwebsocket_close_and_free_session(
- context, wsi, LWS_CLOSE_STATUS_NORMAL);
- return 0;
- }
-
- /* any incoming data ready? */
-
- if (!(pollfd->revents & POLLIN))
- break;
-
- /* get the issued broadcast payload from the socket */
-
- len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
- MAX_BROADCAST_PAYLOAD);
- if (len < 0) {
- lwsl_err("Error reading broadcast payload\n");
- break;
- }
-
- /* broadcast it to all guys with this protocol index */
-
- for (n = 0; n < context->fds_count; n++) {
-
- new_wsi = context->lws_lookup[context->fds[n].fd];
- if (new_wsi == NULL)
- continue;
-
- /* only to clients we are serving to */
-
- if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
- continue;
-
- /*
- * never broadcast to non-established
- * connection
- */
-
- if (new_wsi->state != WSI_STATE_ESTABLISHED)
- continue;
-
- /*
- * only broadcast to connections using
- * the requested protocol
- */
-
- if (new_wsi->protocol->protocol_index !=
- wsi->protocol_index_for_broadcast_proxy)
- continue;
-
- /* broadcast it to this connection */
-
- user_callback_handle_rxflow(new_wsi->protocol->callback, context, new_wsi,
- LWS_CALLBACK_BROADCAST,
- new_wsi->user_space,
- buf + LWS_SEND_BUFFER_PRE_PADDING, len);
- }
- break;
-
+ return lws_server_socket_service(context, wsi, pollfd);
+#endif
case LWS_CONNMODE_WS_SERVING:
case LWS_CONNMODE_WS_CLIENT:
return wsi->sock;
}
-
+#ifdef LWS_NO_SERVER
+int
+_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
+{
+ return 0;
+}
+#else
int
_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
{
return 1;
}
+#endif
/**
* libwebsocket_rx_flow_control() - Enable and disable socket servicing for
{
int n;
int m;
- int sockfd = 0;
int fd;
struct sockaddr_in serv_addr, cli_addr;
int opt = 1;
struct libwebsocket_context *context = NULL;
unsigned int slen;
char *p;
- char hostname[1024] = "";
-// struct hostent *he;
struct libwebsocket *wsi;
- struct sockaddr sa;
#ifdef LWS_OPENSSL_SUPPORT
SSL_METHOD *method;
openssl_websocket_private_data_index = 0;
#endif
- if (options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME) {
-
- strcpy(context->canonical_hostname, "unknown");
+ strcpy(context->canonical_hostname, "unknown");
- } else {
+#ifndef LWS_NO_SERVER
+ if (!(options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) {
+ struct sockaddr sa;
+ char hostname[1024] = "";
/* find canonical hostname */
strncpy(context->canonical_hostname, hostname,
sizeof context->canonical_hostname - 1);
- // lwsl_debug("context->canonical_hostname = %s\n",
- // context->canonical_hostname);
+ lwsl_info(" canonical_hostname = %s\n", context->canonical_hostname);
}
+#endif
/* split the proxy ads:port if given */
*p = '\0';
context->http_proxy_port = atoi(p + 1);
- lwsl_debug("Using proxy %s:%u\n",
+ lwsl_info(" Proxy %s:%u\n",
context->http_proxy_address,
context->http_proxy_port);
}
+#ifndef LWS_NO_SERVER
if (port) {
#ifdef LWS_OPENSSL_SUPPORT
"serving unencrypted\n");
#endif
}
+#endif
/* ignore SIGPIPE */
#ifdef WIN32
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
SSL_CTX_set_cipher_list(context->ssl_ctx, CIPHERS_LIST_STRING);
+#ifndef LWS_NO_CLIENT
+
/* client context */
if (port == CONTEXT_PORT_NO_LISTEN) {
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
context->ssl_client_ctx, NULL, 0);
}
+#endif
/* as a server, are we requiring clients to identify themselves? */
if (lws_b64_selftest())
return NULL;
+#ifndef LWS_NO_SERVER
/* set up our external listening socket we serve on */
if (port) {
+ extern int interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen);
+ int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
listen(sockfd, LWS_SOMAXCONN);
lwsl_info(" Listening on port %d\n", port);
}
+#endif
/*
* drop any root privs for this process
/*
* libwebsockets - small server side websockets and web server implementation
*
- * Copyright (C) 2010 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2013 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
#include <io.h>
#endif
-static const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {
-
- /* win32 can't do C99 */
-
-/* [WSI_TOKEN_GET_URI] = */{ "GET ", 4 },
-/* [WSI_TOKEN_HOST] = */{ "Host:", 5 },
-/* [WSI_TOKEN_CONNECTION] = */{ "Connection:", 11 },
-/* [WSI_TOKEN_KEY1] = */{ "Sec-WebSocket-Key1:", 19 },
-/* [WSI_TOKEN_KEY2] = */{ "Sec-WebSocket-Key2:", 19 },
-/* [WSI_TOKEN_PROTOCOL] = */{ "Sec-WebSocket-Protocol:", 23 },
-/* [WSI_TOKEN_UPGRADE] = */{ "Upgrade:", 8 },
-/* [WSI_TOKEN_ORIGIN] = */{ "Origin:", 7 },
-/* [WSI_TOKEN_DRAFT] = */{ "Sec-WebSocket-Draft:", 20 },
-/* [WSI_TOKEN_CHALLENGE] = */{ "\x0d\x0a", 2 },
-
-/* [WSI_TOKEN_KEY] = */{ "Sec-WebSocket-Key:", 18 },
-/* [WSI_TOKEN_VERSION] = */{ "Sec-WebSocket-Version:", 22 },
-/* [WSI_TOKEN_SWORIGIN]= */{ "Sec-WebSocket-Origin:", 21 },
-
-/* [WSI_TOKEN_EXTENSIONS] = */{ "Sec-WebSocket-Extensions:", 25 },
-
-/* [WSI_TOKEN_ACCEPT] = */{ "Sec-WebSocket-Accept:", 21 },
-/* [WSI_TOKEN_NONCE] = */{ "Sec-WebSocket-Nonce:", 20 },
-/* [WSI_TOKEN_HTTP] = */{ "HTTP/1.1 ", 9 },
-/* [WSI_TOKEN_MUXURL] = */{ "", -1 },
-
-};
unsigned char lextable[] = {
/* pos 0: state 0 */
return wsi->frame_is_binary;
}
-
int
libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
{
}
-
-
int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
unsigned char *buf, size_t len)
{
/* 07 specific */
char this_frame_masked;
+ enum connection_mode mode;
+
+#ifndef LWS_NO_CLIENT
/* client support */
char initial_handshake_hash_base64[30];
- enum connection_mode mode;
char *c_path;
char *c_host;
char *c_origin;
char *c_address;
int c_port;
-
+#endif
#ifdef LWS_OPENSSL_SUPPORT
SSL *ssl;
--- /dev/null
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2013 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 "private-libwebsockets.h"
+
+#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
+#define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \
+ p += wsi->utf8_token[tok].token_len; }
+
+static int
+interpret_key(const char *key, unsigned long *result)
+{
+ char digits[20];
+ int digit_pos = 0;
+ const char *p = key;
+ unsigned int spaces = 0;
+ unsigned long acc = 0;
+ int rem = 0;
+
+ while (*p) {
+ if (!isdigit(*p)) {
+ p++;
+ continue;
+ }
+ if (digit_pos == sizeof(digits) - 1)
+ return -1;
+ digits[digit_pos++] = *p++;
+ }
+ digits[digit_pos] = '\0';
+ if (!digit_pos)
+ return -2;
+
+ while (*key) {
+ if (*key == ' ')
+ spaces++;
+ key++;
+ }
+
+ if (!spaces)
+ return -3;
+
+ p = &digits[0];
+ while (*p) {
+ rem = (rem * 10) + ((*p++) - '0');
+ acc = (acc * 10) + (rem / spaces);
+ rem -= (rem / spaces) * spaces;
+ }
+
+ if (rem) {
+ lwsl_warn("nonzero handshake remainder\n");
+ return -1;
+ }
+
+ *result = acc;
+
+ return 0;
+}
+
+
+int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi)
+{
+ unsigned long key1, key2;
+ unsigned char sum[16];
+ char *response;
+ char *p;
+ int n;
+
+ /* Confirm we have all the necessary pieces */
+
+ if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
+ !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
+ !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
+ !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
+ !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
+ /* completed header processing, but missing some bits */
+ goto bail;
+
+ /* allocate the per-connection user memory (if any) */
+ if (wsi->protocol->per_session_data_size &&
+ !libwebsocket_ensure_user_space(wsi))
+ goto bail;
+
+ /* create the response packet */
+
+ /* make a buffer big enough for everything */
+
+ response = (char *)malloc(256 +
+ wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
+ wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
+ wsi->utf8_token[WSI_TOKEN_HOST].token_len +
+ wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
+ wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
+ wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
+ if (!response) {
+ lwsl_err("Out of memory for response buffer\n");
+ goto bail;
+ }
+
+ p = response;
+ LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
+ "Upgrade: WebSocket\x0d\x0a"
+ "Connection: Upgrade\x0d\x0a"
+ "Sec-WebSocket-Origin: ");
+ strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
+ p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
+#ifdef LWS_OPENSSL_SUPPORT
+ if (wsi->ssl) {
+ LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://");
+ } else {
+ LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
+ }
+#else
+ LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
+#endif
+
+ LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST);
+ LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI);
+
+ if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
+ LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
+ LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
+ }
+
+ LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
+
+ /* convert the two keys into 32-bit integers */
+
+ if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
+ goto bail;
+ if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
+ goto bail;
+
+ /* lay them out in network byte order (MSB first */
+
+ sum[0] = (unsigned char)(key1 >> 24);
+ sum[1] = (unsigned char)(key1 >> 16);
+ sum[2] = (unsigned char)(key1 >> 8);
+ sum[3] = (unsigned char)(key1);
+ sum[4] = (unsigned char)(key2 >> 24);
+ sum[5] = (unsigned char)(key2 >> 16);
+ sum[6] = (unsigned char)(key2 >> 8);
+ sum[7] = (unsigned char)(key2);
+
+ /* follow them with the challenge token we were sent */
+
+ memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
+
+ /*
+ * compute the md5sum of that 16-byte series and use as our
+ * payload after our headers
+ */
+
+ MD5(sum, 16, (unsigned char *)p);
+ p += 16;
+
+ /* it's complete: go ahead and send it */
+
+ lwsl_parser("issuing response packet %d len\n", (int)(p - response));
+#ifdef _DEBUG
+ fwrite(response, 1, p - response, stderr);
+#endif
+ n = libwebsocket_write(wsi, (unsigned char *)response,
+ p - response, LWS_WRITE_HTTP);
+ if (n < 0) {
+ lwsl_debug("handshake_00: ERROR writing to socket\n");
+ goto bail;
+ }
+
+ /* alright clean up and set ourselves into established state */
+
+ free(response);
+ wsi->state = WSI_STATE_ESTABLISHED;
+ wsi->lws_rx_parse_state = LWS_RXPS_NEW;
+
+ /* notify user code that we're ready to roll */
+
+ if (wsi->protocol->callback)
+ wsi->protocol->callback(wsi->protocol->owning_server,
+ wsi, LWS_CALLBACK_ESTABLISHED,
+ wsi->user_space, NULL, 0);
+
+ return 0;
+
+bail:
+ return -1;
+}
+
+/*
+ * Perform the newer BASE64-encoded handshake scheme
+ */
+
+int
+handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
+{
+ static const char *websocket_magic_guid_04 =
+ "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ static const char *websocket_magic_guid_04_masking =
+ "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
+ char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
+ char nonce_buf[256];
+ char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37];
+ unsigned char hash[20];
+ int n;
+ char *response;
+ char *p;
+ char *m = mask_summing_buf;
+ int nonce_len = 0;
+ int accept_len;
+ char *c;
+ char ext_name[128];
+ struct libwebsocket_extension *ext;
+ int ext_count = 0;
+ int more = 1;
+
+ if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
+ !wsi->utf8_token[WSI_TOKEN_KEY].token_len) {
+ lwsl_parser("handshake_04 missing pieces\n");
+ /* completed header processing, but missing some bits */
+ goto bail;
+ }
+
+ if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >=
+ MAX_WEBSOCKET_04_KEY_LEN) {
+ lwsl_warn("Client sent handshake key longer "
+ "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN);
+ goto bail;
+ }
+
+ strcpy(accept_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
+ strcpy(accept_buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len,
+ websocket_magic_guid_04);
+
+ SHA1((unsigned char *)accept_buf,
+ wsi->utf8_token[WSI_TOKEN_KEY].token_len +
+ strlen(websocket_magic_guid_04), hash);
+
+ accept_len = lws_b64_encode_string((char *)hash, 20, accept_buf,
+ sizeof accept_buf);
+ if (accept_len < 0) {
+ lwsl_warn("Base64 encoded hash too long\n");
+ goto bail;
+ }
+
+ /* allocate the per-connection user memory (if any) */
+ if (wsi->protocol->per_session_data_size &&
+ !libwebsocket_ensure_user_space(wsi))
+ goto bail;
+
+ /* create the response packet */
+
+ /* make a buffer big enough for everything */
+
+ response = (char *)malloc(256 +
+ wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
+ wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
+ wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
+ if (!response) {
+ lwsl_err("Out of memory for response buffer\n");
+ goto bail;
+ }
+
+ p = response;
+ LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
+ "Upgrade: WebSocket\x0d\x0a"
+ "Connection: Upgrade\x0d\x0a"
+ "Sec-WebSocket-Accept: ");
+ strcpy(p, accept_buf);
+ p += accept_len;
+
+ if (wsi->ietf_spec_revision == 4) {
+ LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: ");
+
+ /* select the nonce */
+
+ n = libwebsockets_get_random(wsi->protocol->owning_server,
+ hash, 16);
+ if (n != 16) {
+ lwsl_err("Unable to read random device %s %d\n",
+ SYSTEM_RANDOM_FILEPATH, n);
+ if (wsi->user_space)
+ free(wsi->user_space);
+ goto bail;
+ }
+
+ /* encode the nonce */
+
+ nonce_len = lws_b64_encode_string((const char *)hash, 16,
+ nonce_buf, sizeof nonce_buf);
+ if (nonce_len < 0) {
+ lwsl_err("Failed to base 64 encode the nonce\n");
+ if (wsi->user_space)
+ free(wsi->user_space);
+ goto bail;
+ }
+
+ /* apply the nonce */
+
+ strcpy(p, nonce_buf);
+ p += nonce_len;
+ }
+
+ if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
+ LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
+ LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
+ }
+
+ /*
+ * Figure out which extensions the client has that we want to
+ * enable on this connection, and give him back the list
+ */
+
+ if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) {
+
+ /*
+ * break down the list of client extensions
+ * and go through them
+ */
+
+ c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token;
+ lwsl_parser("wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token = %s\n",
+ wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token);
+ wsi->count_active_extensions = 0;
+ n = 0;
+ while (more) {
+
+ if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
+ ext_name[n] = *c++;
+ if (n < sizeof(ext_name) - 1)
+ n++;
+ continue;
+ }
+ ext_name[n] = '\0';
+ if (!*c)
+ more = 0;
+ else {
+ c++;
+ if (!n)
+ continue;
+ }
+
+ /* check a client's extension against our support */
+
+ ext = wsi->protocol->owning_server->extensions;
+
+ while (ext && ext->callback) {
+
+ if (strcmp(ext_name, ext->name)) {
+ ext++;
+ continue;
+ }
+
+ /*
+ * oh, we do support this one he
+ * asked for... but let's ask user
+ * code if it's OK to apply it on this
+ * particular connection + protocol
+ */
+
+ n = wsi->protocol->owning_server->
+ protocols[0].callback(
+ wsi->protocol->owning_server,
+ wsi,
+ LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
+ wsi->user_space, ext_name, 0);
+
+ /*
+ * zero return from callback means
+ * go ahead and allow the extension,
+ * it's what we get if the callback is
+ * unhandled
+ */
+
+ if (n) {
+ ext++;
+ continue;
+ }
+
+ /* apply it */
+
+ if (ext_count)
+ *p++ = ',';
+ else
+ LWS_CPYAPP(p,
+ "\x0d\x0aSec-WebSocket-Extensions: ");
+ p += sprintf(p, "%s", ext_name);
+ ext_count++;
+
+ /* instantiate the extension on this conn */
+
+ wsi->active_extensions_user[
+ wsi->count_active_extensions] =
+ malloc(ext->per_session_data_size);
+ if (wsi->active_extensions_user[
+ wsi->count_active_extensions] == NULL) {
+ lwsl_err("Out of mem\n");
+ free(response);
+ goto bail;
+ }
+ memset(wsi->active_extensions_user[
+ wsi->count_active_extensions], 0,
+ ext->per_session_data_size);
+
+ wsi->active_extensions[
+ wsi->count_active_extensions] = ext;
+
+ /* allow him to construct his context */
+
+ ext->callback(wsi->protocol->owning_server,
+ ext, wsi,
+ LWS_EXT_CALLBACK_CONSTRUCT,
+ wsi->active_extensions_user[
+ wsi->count_active_extensions], NULL, 0);
+
+ wsi->count_active_extensions++;
+ lwsl_parser("wsi->count_active_extensions <- %d\n",
+ wsi->count_active_extensions);
+
+ ext++;
+ }
+
+ n = 0;
+ }
+ }
+
+ /* end of response packet */
+
+ LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
+
+ if (wsi->ietf_spec_revision == 4) {
+
+ /*
+ * precompute the masking key the client will use from the SHA1
+ * hash of ( base 64 client key we were sent, concatenated with
+ * the bse 64 nonce we sent, concatenated with a magic constant
+ * guid specified by the 04 standard )
+ *
+ * We store the hash in the connection's wsi ready to use with
+ * undoing the masking the client has done on framed data it
+ * sends (we send our data to the client in clear).
+ */
+
+ strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
+ m += wsi->utf8_token[WSI_TOKEN_KEY].token_len;
+ strcpy(m, nonce_buf);
+ m += nonce_len;
+ strcpy(m, websocket_magic_guid_04_masking);
+ m += strlen(websocket_magic_guid_04_masking);
+
+ SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
+ wsi->masking_key_04);
+ }
+
+ if (!lws_any_extension_handled(context, wsi,
+ LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
+ response, p - response)) {
+
+ /* okay send the handshake response accepting the connection */
+
+ lwsl_parser("issuing response packet %d len\n", (int)(p - response));
+ #ifdef DEBUG
+ fwrite(response, 1, p - response, stderr);
+ #endif
+ n = libwebsocket_write(wsi, (unsigned char *)response,
+ p - response, LWS_WRITE_HTTP);
+ if (n < 0) {
+ lwsl_debug("handshake_0405: ERROR writing to socket\n");
+ goto bail;
+ }
+
+ }
+
+ /* alright clean up and set ourselves into established state */
+
+ free(response);
+ wsi->state = WSI_STATE_ESTABLISHED;
+ wsi->lws_rx_parse_state = LWS_RXPS_NEW;
+ wsi->rx_packet_length = 0;
+
+ /* notify user code that we're ready to roll */
+
+ if (wsi->protocol->callback)
+ wsi->protocol->callback(wsi->protocol->owning_server,
+ wsi, LWS_CALLBACK_ESTABLISHED,
+ wsi->user_space, NULL, 0);
+
+ return 0;
+
+
+bail:
+ return -1;
+}
+
--- /dev/null
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2013 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 "private-libwebsockets.h"
+
+#ifdef WIN32
+#include <tchar.h>
+#include <io.h>
+#else
+#ifdef LWS_BUILTIN_GETIFADDRS
+#include <getifaddrs.h>
+#else
+#include <ifaddrs.h>
+#endif
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+#ifdef LWS_OPENSSL_SUPPORT
+extern int openssl_websocket_private_data_index;
+
+static void
+libwebsockets_decode_ssl_error(void)
+{
+ char buf[256];
+ u_long err;
+
+ while ((err = ERR_get_error()) != 0) {
+ ERR_error_string_n(err, buf, sizeof(buf));
+ lwsl_err("*** %s\n", buf);
+ }
+}
+#endif
+
+int
+interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen)
+{
+ int rc = -1;
+#ifdef WIN32
+ /* TODO */
+#else
+ struct ifaddrs *ifr;
+ struct ifaddrs *ifc;
+ struct sockaddr_in *sin;
+
+ getifaddrs(&ifr);
+ for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
+ if (strcmp(ifc->ifa_name, ifname))
+ continue;
+ if (ifc->ifa_addr == NULL)
+ continue;
+ sin = (struct sockaddr_in *)ifc->ifa_addr;
+ if (sin->sin_family != AF_INET)
+ continue;
+ memcpy(addr, sin, addrlen);
+ rc = 0;
+ }
+
+ freeifaddrs(ifr);
+#endif
+ return rc;
+}
+
+struct libwebsocket *
+libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
+{
+ struct libwebsocket *new_wsi;
+ int n;
+
+ new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
+ if (new_wsi == NULL) {
+ lwsl_err("Out of memory for new connection\n");
+ return NULL;
+ }
+
+ memset(new_wsi, 0, sizeof(struct libwebsocket));
+ new_wsi->count_active_extensions = 0;
+ new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
+
+ /* intialize the instance struct */
+
+ new_wsi->state = WSI_STATE_HTTP;
+ new_wsi->name_buffer_pos = 0;
+ new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
+
+ for (n = 0; n < WSI_TOKEN_COUNT; n++) {
+ new_wsi->utf8_token[n].token = NULL;
+ new_wsi->utf8_token[n].token_len = 0;
+ }
+
+ /*
+ * these can only be set once the protocol is known
+ * we set an unestablished connection's protocol pointer
+ * to the start of the supported list, so it can look
+ * for matching ones during the handshake
+ */
+ new_wsi->protocol = context->protocols;
+ new_wsi->user_space = NULL;
+
+ /*
+ * Default protocol is 76 / 00
+ * After 76, there's a header specified to inform which
+ * draft the client wants, when that's seen we modify
+ * the individual connection's spec revision accordingly
+ */
+ new_wsi->ietf_spec_revision = 0;
+
+ return new_wsi;
+}
+
+int lws_server_socket_service(struct libwebsocket_context *context,
+ struct libwebsocket *wsi, struct pollfd *pollfd)
+{
+ unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 +
+ MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
+ struct libwebsocket *new_wsi;
+ int accept_fd;
+ unsigned int clilen;
+ struct sockaddr_in cli_addr;
+ int n;
+ int opt = 1;
+ ssize_t len;
+
+ switch (wsi->mode) {
+
+ case LWS_CONNMODE_HTTP_SERVING:
+
+ /* handle http headers coming in */
+
+ /* any incoming data ready? */
+
+ if (pollfd->revents & POLLIN) {
+
+ #ifdef LWS_OPENSSL_SUPPORT
+ if (wsi->ssl)
+ len = SSL_read(wsi->ssl, buf, sizeof buf);
+ else
+ #endif
+ len = recv(pollfd->fd, buf, sizeof buf, 0);
+
+ if (len < 0) {
+ lwsl_debug("Socket read returned %d\n", len);
+ if (errno != EINTR && errno != EAGAIN)
+ libwebsocket_close_and_free_session(context,
+ wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ return 0;
+ }
+ if (!len) {
+ libwebsocket_close_and_free_session(context, wsi,
+ LWS_CLOSE_STATUS_NOSTATUS);
+ return 0;
+ }
+
+ n = libwebsocket_read(context, wsi, buf, len);
+ if (n < 0)
+ /* we closed wsi */
+ return 0;
+ }
+
+ /* this handles POLLOUT for http serving fragments */
+
+ if (!(pollfd->revents & POLLOUT))
+ break;
+
+ /* one shot */
+ pollfd->events &= ~POLLOUT;
+
+ if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
+ break;
+
+ if (libwebsockets_serve_http_file_fragment(context, wsi) < 0)
+ libwebsocket_close_and_free_session(context, wsi,
+ LWS_CLOSE_STATUS_NOSTATUS);
+ else
+ if (wsi->state == WSI_STATE_HTTP && wsi->protocol->callback)
+ if (user_callback_handle_rxflow(wsi->protocol->callback, context, wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION, wsi->user_space,
+ wsi->filepath, wsi->filepos))
+ libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ break;
+
+ case LWS_CONNMODE_SERVER_LISTENER:
+
+ /* pollin means a client has connected to us then */
+
+ if (!(pollfd->revents & POLLIN))
+ break;
+
+ /* listen socket got an unencrypted connection... */
+
+ clilen = sizeof(cli_addr);
+ accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
+ &clilen);
+ if (accept_fd < 0) {
+ lwsl_warn("ERROR on accept: %s\n", strerror(errno));
+ break;
+ }
+
+ /* Disable Nagle */
+ opt = 1;
+ setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY,
+ (const void *)&opt, sizeof(opt));
+
+ /*
+ * look at who we connected to and give user code a chance
+ * to reject based on client IP. There's no protocol selected
+ * yet so we issue this to protocols[0]
+ */
+
+ if ((context->protocols[0].callback)(context, wsi,
+ LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
+ (void *)(long)accept_fd, NULL, 0)) {
+ lwsl_debug("Callback denied network connection\n");
+ compatible_close(accept_fd);
+ break;
+ }
+
+ new_wsi = libwebsocket_create_new_server_wsi(context);
+ if (new_wsi == NULL) {
+ compatible_close(accept_fd);
+ break;
+ }
+
+ new_wsi->sock = accept_fd;
+
+
+#ifdef LWS_OPENSSL_SUPPORT
+ new_wsi->ssl = NULL;
+
+ if (context->use_ssl) {
+
+ new_wsi->ssl = SSL_new(context->ssl_ctx);
+ if (new_wsi->ssl == NULL) {
+ lwsl_err("SSL_new failed: %s\n",
+ ERR_error_string(SSL_get_error(
+ new_wsi->ssl, 0), NULL));
+ libwebsockets_decode_ssl_error();
+ free(new_wsi);
+ compatible_close(accept_fd);
+ break;
+ }
+
+ SSL_set_ex_data(new_wsi->ssl,
+ openssl_websocket_private_data_index, context);
+
+ SSL_set_fd(new_wsi->ssl, accept_fd);
+
+ n = SSL_accept(new_wsi->ssl);
+ if (n != 1) {
+ /*
+ * browsers seem to probe with various
+ * ssl params which fail then retry
+ * and succeed
+ */
+ lwsl_debug("SSL_accept failed skt %u: %s\n",
+ pollfd->fd,
+ ERR_error_string(SSL_get_error(
+ new_wsi->ssl, n), NULL));
+ SSL_free(
+ new_wsi->ssl);
+ free(new_wsi);
+ compatible_close(accept_fd);
+ break;
+ }
+
+ lwsl_debug("accepted new SSL conn "
+ "port %u on fd=%d SSL ver %s\n",
+ ntohs(cli_addr.sin_port), accept_fd,
+ SSL_get_version(new_wsi->ssl));
+
+ } else
+#endif
+ lwsl_debug("accepted new conn port %u on fd=%d\n",
+ ntohs(cli_addr.sin_port), accept_fd);
+
+ insert_wsi_socket_into_fds(context, new_wsi);
+ break;
+
+ case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
+
+ /* as we are listening, POLLIN means accept() is needed */
+
+ if (!(pollfd->revents & POLLIN))
+ break;
+
+ /* listen socket got an unencrypted connection... */
+
+ clilen = sizeof(cli_addr);
+ accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
+ &clilen);
+ if (accept_fd < 0) {
+ lwsl_warn("ERROR on accept %d\n", accept_fd);
+ return 0;
+ }
+
+ /* create a dummy wsi for the connection and add it */
+
+ new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
+ if (new_wsi == NULL) {
+ lwsl_err("Out of mem\n");
+ goto bail_prox_listener;
+ }
+ memset(new_wsi, 0, sizeof (struct libwebsocket));
+ new_wsi->sock = accept_fd;
+ new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
+ new_wsi->state = WSI_STATE_ESTABLISHED;
+ new_wsi->count_active_extensions = 0;
+ /* note which protocol we are proxying */
+ new_wsi->protocol_index_for_broadcast_proxy =
+ wsi->protocol_index_for_broadcast_proxy;
+
+ insert_wsi_socket_into_fds(context, new_wsi);
+ break;
+
+bail_prox_listener:
+ compatible_close(accept_fd);
+ break;
+
+ case LWS_CONNMODE_BROADCAST_PROXY:
+
+ /* handle session socket closed */
+
+ if (pollfd->revents & (POLLERR | POLLHUP)) {
+
+ lwsl_debug("Session Socket %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+
+ libwebsocket_close_and_free_session(context, wsi,
+ LWS_CLOSE_STATUS_NORMAL);
+ return 0;
+ }
+
+ /*
+ * either extension code with stuff to spill, or the user code,
+ * requested a callback when it was OK to write
+ */
+
+ if (pollfd->revents & POLLOUT)
+ if (lws_handle_POLLOUT_event(context, wsi,
+ pollfd) < 0) {
+ libwebsocket_close_and_free_session(
+ context, wsi, LWS_CLOSE_STATUS_NORMAL);
+ return 0;
+ }
+
+ /* any incoming data ready? */
+
+ if (!(pollfd->revents & POLLIN))
+ break;
+
+ /* get the issued broadcast payload from the socket */
+
+ len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
+ MAX_BROADCAST_PAYLOAD);
+ if (len < 0) {
+ lwsl_err("Error reading broadcast payload\n");
+ break;
+ }
+
+ /* broadcast it to all guys with this protocol index */
+
+ for (n = 0; n < context->fds_count; n++) {
+
+ new_wsi = context->lws_lookup[context->fds[n].fd];
+ if (new_wsi == NULL)
+ continue;
+
+ /* only to clients we are serving to */
+
+ if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
+ continue;
+
+ /*
+ * never broadcast to non-established
+ * connection
+ */
+
+ if (new_wsi->state != WSI_STATE_ESTABLISHED)
+ continue;
+
+ /*
+ * only broadcast to connections using
+ * the requested protocol
+ */
+
+ if (new_wsi->protocol->protocol_index !=
+ wsi->protocol_index_for_broadcast_proxy)
+ continue;
+
+ /* broadcast it to this connection */
+
+ user_callback_handle_rxflow(new_wsi->protocol->callback, context, new_wsi,
+ LWS_CALLBACK_BROADCAST,
+ new_wsi->user_space,
+ buf + LWS_SEND_BUFFER_PRE_PADDING, len);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
-bin_PROGRAMS=libwebsockets-test-server libwebsockets-test-server-extpoll
+bin_PROGRAMS=
if NO_CLIENT
else
-bin_PROGRAMS+=libwebsockets-test-client libwebsockets-test-fraggle
+bin_PROGRAMS+= libwebsockets-test-client
+if NO_SERVER
+else
+bin_PROGRAMS+= libwebsockets-test-fraggle
+endif
endif
+if NO_SERVER
+else
+bin_PROGRAMS+=libwebsockets-test-server libwebsockets-test-server-extpoll
+endif
+
+if NO_SERVER
+else
libwebsockets_test_server_SOURCES=test-server.c
libwebsockets_test_server_CFLAGS=
libwebsockets_test_server_LDADD=-L../lib -lwebsockets -lz
libwebsockets_test_server_extpoll_SOURCES=test-server.c
libwebsockets_test_server_extpoll_CFLAGS=$(AM_CFLAGS) -DEXTERNAL_POLL
libwebsockets_test_server_extpoll_LDADD=-L../lib -lwebsockets -lz
+endif
if NO_CLIENT
else
libwebsockets_test_client_SOURCES=test-client.c
libwebsockets_test_client_CFLAGS=
libwebsockets_test_client_LDADD=-L../lib -lwebsockets -lz
+if NO_SERVER
+else
libwebsockets_test_fraggle_SOURCES=test-fraggle.c
libwebsockets_test_fraggle_CFLAGS=
libwebsockets_test_fraggle_LDADD=-L../lib -lwebsockets -lz
endif
+endif
-if MINGW
+if MINGW
+if NO_SERVER
+else
libwebsockets_test_server_CFLAGS+= -w -I../win32port/win32helpers
libwebsockets_test_server_extpoll_CFLAGS+= -w -I../win32port/win32helpers
+endif
if NO_CLIENT
else
libwebsockets_test_client_CFLAGS+= -w -I../win32port/win32helpers
+if NO_SERVER
+else
libwebsockets_test_fraggle_CFLAGS+= -w -I../win32port/win32helpers
endif
+endif
+if NO_SERVER
+else
libwebsockets_test_server_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
libwebsockets_test_server_extpoll_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
+endif
if NO_CLIENT
else
libwebsockets_test_client_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
+if NO_SERVER
+else
libwebsockets_test_fraggle_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
endif
+endif
else
+if NO_SERVER
+else
libwebsockets_test_server_CFLAGS+= -Werror
libwebsockets_test_server_extpoll_CFLAGS+= -Werror
+endif
if NO_CLIENT
else
libwebsockets_test_client_CFLAGS+= -Werror
+if NO_SERVER
+else
libwebsockets_test_fraggle_CFLAGS+= -Werror
endif
+endif
endif
+if NO_SERVER
+else
libwebsockets_test_server_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
libwebsockets_test_server_extpoll_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+endif
if NO_CLIENT
else
libwebsockets_test_client_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+if NO_SERVER
+else
libwebsockets_test_fraggle_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
endif
+endif
if NOPING
else