return 0;
}
+int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len)
+{
+ int n;
+
+ switch (wsi->mode) {
+ case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
+ case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
+ case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
+ case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
+ case LWS_CONNMODE_WS_CLIENT:
+ for (n = 0; n < len; n++)
+ if (libwebsocket_client_rx_sm(wsi, *(*buf)++)) {
+ lwsl_debug("client_rx_sm failed\n");
+ return 1;
+ }
+ return 0;
+ default:
+ break;
+ }
+ return 0;
+}
+
int lws_client_socket_service(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
{
struct libwebsocket *wsi, unsigned char *buf, size_t len)
{
size_t n;
-#ifndef LWS_NO_SERVER
- struct allocated_headers *ah;
- char *uri_ptr = NULL;
- int uri_len = 0;
- char content_length_str[32];
-#endif
switch (wsi->state) {
case WSI_STATE_HTTP_BODY:
-#ifndef LWS_NO_SERVER
http_postbody:
-#endif
while (len--) {
if (wsi->u.http.content_length_seen >= wsi->u.http.content_length)
lwsl_parser("issuing %d bytes to parser\n", (int)len);
-#ifndef LWS_NO_CLIENT
- switch (wsi->mode) {
- case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
- case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
- case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
- case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
- case LWS_CONNMODE_WS_CLIENT:
- for (n = 0; n < len; n++)
- if (libwebsocket_client_rx_sm(wsi, *buf++)) {
- lwsl_debug("client_rx_sm failed\n");
- goto bail;
- }
- return 0;
- default:
- break;
- }
-#endif
-#ifndef LWS_NO_SERVER
- /* LWS_CONNMODE_WS_SERVING */
-
- while (len--) {
- if (libwebsocket_parse(wsi, *buf++)) {
- lwsl_info("libwebsocket_parse failed\n");
- goto bail_nuke_ah;
- }
-
- if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
- continue;
-
- lwsl_parser("libwebsocket_parse sees parsing complete\n");
-
- wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT;
- libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-
- /* is this websocket protocol or normal http 1.0? */
-
- if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) ||
- !lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
-
- /* it's not websocket.... shall we accept it as http? */
-
- if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
- !lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
- lwsl_warn("Missing URI in HTTP request\n");
- goto bail_nuke_ah;
- }
-
- if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
- lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
- lwsl_warn("GET and POST methods?\n");
- goto bail_nuke_ah;
- }
-
- if (libwebsocket_ensure_user_space(wsi))
- goto bail_nuke_ah;
-
- if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
- uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
- uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
- lwsl_info("HTTP GET request for '%s'\n",
- lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
-
- }
- if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
- lwsl_info("HTTP POST request for '%s'\n",
- lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI));
- uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI);
- uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
- }
-
- /*
- * Hm we still need the headers so the
- * callback can look at leaders like the URI, but we
- * need to transition to http union state.... hold a
- * copy of u.hdr.ah and deallocate afterwards
- */
- ah = wsi->u.hdr.ah;
-
- /* union transition */
- memset(&wsi->u, 0, sizeof(wsi->u));
- wsi->mode = LWS_CONNMODE_HTTP_SERVING_ACCEPTED;
- wsi->state = WSI_STATE_HTTP;
- wsi->u.http.fd = LWS_INVALID_FILE;
-
- /* expose it at the same offset as u.hdr */
- wsi->u.http.ah = ah;
-
- /* HTTP header had a content length? */
-
- wsi->u.http.content_length = 0;
- if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
- wsi->u.http.content_length = 100 * 1024 * 1024;
-
- if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
- lws_hdr_copy(wsi, content_length_str,
- sizeof(content_length_str) - 1,
- WSI_TOKEN_HTTP_CONTENT_LENGTH);
- wsi->u.http.content_length = atoi(content_length_str);
- }
-
- if (wsi->u.http.content_length > 0) {
- wsi->u.http.body_index = 0;
- n = wsi->protocol->rx_buffer_size;
- if (!n)
- n = LWS_MAX_SOCKET_IO_BUF;
- wsi->u.http.post_buffer = malloc(n);
- if (!wsi->u.http.post_buffer) {
- lwsl_err("Unable to allocate post buffer\n");
- n = -1;
- goto cleanup;
- }
- }
-
- n = 0;
- if (wsi->protocol->callback)
- n = wsi->protocol->callback(context, wsi,
- LWS_CALLBACK_FILTER_HTTP_CONNECTION,
- wsi->user_space, uri_ptr, uri_len);
-
- if (!n) {
- /*
- * if there is content supposed to be coming,
- * put a timeout on it having arrived
- */
- libwebsocket_set_timeout(wsi,
- PENDING_TIMEOUT_HTTP_CONTENT,
- AWAITING_TIMEOUT);
-
- if (wsi->protocol->callback)
- n = wsi->protocol->callback(context, wsi,
- LWS_CALLBACK_HTTP,
- wsi->user_space, uri_ptr, uri_len);
- }
-
-cleanup:
- /* now drop the header info we kept a pointer to */
- if (ah)
- free(ah);
- /* not possible to continue to use past here */
- wsi->u.http.ah = NULL;
-
- if (n) {
- lwsl_info("LWS_CALLBACK_HTTP closing\n");
- goto bail; /* struct ah ptr already nuked */
- }
-
- /*
- * (if callback didn't start sending a file)
- * deal with anything else as body, whether
- * there was a content-length or not
- */
-
- if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
- wsi->state = WSI_STATE_HTTP_BODY;
- goto http_postbody;
- }
-
- if (!wsi->protocol)
- lwsl_err("NULL protocol at libwebsocket_read\n");
-
- /*
- * It's websocket
- *
- * Make sure user side is happy about protocol
- */
-
- while (wsi->protocol->callback) {
-
- if (!lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
- if (wsi->protocol->name == NULL)
- break;
- } else
- if (wsi->protocol->name && strcmp(
- lws_hdr_simple_ptr(wsi,
- WSI_TOKEN_PROTOCOL),
- wsi->protocol->name) == 0)
- break;
-
- wsi->protocol++;
- }
-
- /* we didn't find a protocol he wanted? */
-
- if (wsi->protocol->callback == NULL) {
- if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) ==
- NULL) {
- lwsl_info("no protocol -> prot 0 handler\n");
- wsi->protocol = &context->protocols[0];
- } else {
- lwsl_err("Req protocol %s not supported\n",
- lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL));
- goto bail_nuke_ah;
- }
- }
-
- /* allocate wsi->user storage */
- if (libwebsocket_ensure_user_space(wsi))
- goto bail_nuke_ah;
-
- /*
- * Give the user code a chance to study the request and
- * have the opportunity to deny it
- */
-
- if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
- LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
- wsi->user_space,
- lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
- lwsl_warn("User code denied connection\n");
- goto bail_nuke_ah;
- }
-
-
- /*
- * Perform the handshake according to the protocol version the
- * client announced
- */
-
- switch (wsi->ietf_spec_revision) {
- case 13:
- lwsl_parser("lws_parse calling handshake_04\n");
- if (handshake_0405(context, wsi)) {
- lwsl_info("hs0405 has failed the connection\n");
- goto bail_nuke_ah;
- }
- break;
-
- default:
- lwsl_warn("Unknown client spec version %d\n",
- wsi->ietf_spec_revision);
- goto bail_nuke_ah;
- }
-
- /* drop the header info -- no bail_nuke_ah after this */
-
- if (wsi->u.hdr.ah)
- free(wsi->u.hdr.ah);
-
- wsi->mode = LWS_CONNMODE_WS_SERVING;
-
- /* union transition */
- memset(&wsi->u, 0, sizeof(wsi->u));
- wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
-
- /*
- * create the frame buffer for this connection according to the
- * size mentioned in the protocol definition. If 0 there, use
- * a big default for compatibility
- */
-
- n = wsi->protocol->rx_buffer_size;
- if (!n)
- n = LWS_MAX_SOCKET_IO_BUF;
- n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
- wsi->u.ws.rx_user_buffer = malloc(n);
- if (!wsi->u.ws.rx_user_buffer) {
- lwsl_err("Out of Mem allocating rx buffer %d\n", n);
- goto bail;
- }
- lwsl_info("Allocating RX buffer %d\n", n);
-
- if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
- lwsl_warn("Failed to set SNDBUF to %d", n);
- goto bail;
- }
+ if (lws_handshake_client(wsi, &buf, len))
+ goto bail;
- lwsl_parser("accepted v%02d connection\n",
- wsi->ietf_spec_revision);
- } /* while all chars are handled */
+ switch (lws_handshake_server(context, wsi, &buf, len)) {
+ case 1:
+ goto bail;
+ case 2:
+ goto http_postbody;
+ }
break;
-#endif
case WSI_STATE_AWAITING_CLOSE_ACK:
case WSI_STATE_ESTABLISHED:
return 0;
-#ifndef LWS_NO_SERVER
-bail_nuke_ah:
- /* drop the header info */
- if (wsi->u.hdr.ah)
- free(wsi->u.hdr.ah);
-#endif
-
bail:
lwsl_debug("closing connection at libwebsocket_read bail:\n");
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
LWS_EXTERN int lws_context_init_client(struct lws_context_creation_info *info,
struct libwebsocket_context *context);
+ LWS_EXTERN int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len);
#else
#define lws_context_init_client(_a, _b) (0)
+#define lws_handshake_client(_a, _b, _c) (0)
#endif
#ifndef LWS_NO_SERVER
LWS_EXTERN int lws_server_socket_service(
struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
LWS_EXTERN int _libwebsocket_rx_flow_control(struct libwebsocket *wsi);
+ LWS_EXTERN int lws_handshake_server(struct libwebsocket_context *context,
+ struct libwebsocket *wsi, unsigned char **buf, size_t len);
#else
#define _libwebsocket_rx_flow_control(_a) (0)
+#define lws_handshake_server(_a, _b, _c, _d) (0)
#endif
/*
return 1;
}
+
+int lws_handshake_server(struct libwebsocket_context *context,
+ struct libwebsocket *wsi, unsigned char **buf, size_t len)
+{
+ struct allocated_headers *ah;
+ char *uri_ptr = NULL;
+ int uri_len = 0;
+ char content_length_str[32];
+ int n;
+
+ /* LWS_CONNMODE_WS_SERVING */
+
+ while (len--) {
+ if (libwebsocket_parse(wsi, *(*buf)++)) {
+ lwsl_info("libwebsocket_parse failed\n");
+ goto bail_nuke_ah;
+ }
+
+ if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
+ continue;
+
+ lwsl_parser("libwebsocket_parse sees parsing complete\n");
+
+ wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT;
+ libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+ /* is this websocket protocol or normal http 1.0? */
+
+ if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) ||
+ !lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
+
+ /* it's not websocket.... shall we accept it as http? */
+
+ if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
+ !lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
+ lwsl_warn("Missing URI in HTTP request\n");
+ goto bail_nuke_ah;
+ }
+
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
+ lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
+ lwsl_warn("GET and POST methods?\n");
+ goto bail_nuke_ah;
+ }
+
+ if (libwebsocket_ensure_user_space(wsi))
+ goto bail_nuke_ah;
+
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
+ uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
+ uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
+ lwsl_info("HTTP GET request for '%s'\n",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
+
+ }
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
+ lwsl_info("HTTP POST request for '%s'\n",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI));
+ uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI);
+ uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
+ }
+
+ /*
+ * Hm we still need the headers so the
+ * callback can look at leaders like the URI, but we
+ * need to transition to http union state.... hold a
+ * copy of u.hdr.ah and deallocate afterwards
+ */
+ ah = wsi->u.hdr.ah;
+
+ /* union transition */
+ memset(&wsi->u, 0, sizeof(wsi->u));
+ wsi->mode = LWS_CONNMODE_HTTP_SERVING_ACCEPTED;
+ wsi->state = WSI_STATE_HTTP;
+ wsi->u.http.fd = LWS_INVALID_FILE;
+
+ /* expose it at the same offset as u.hdr */
+ wsi->u.http.ah = ah;
+
+ /* HTTP header had a content length? */
+
+ wsi->u.http.content_length = 0;
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
+ wsi->u.http.content_length = 100 * 1024 * 1024;
+
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
+ lws_hdr_copy(wsi, content_length_str,
+ sizeof(content_length_str) - 1,
+ WSI_TOKEN_HTTP_CONTENT_LENGTH);
+ wsi->u.http.content_length = atoi(content_length_str);
+ }
+
+ if (wsi->u.http.content_length > 0) {
+ wsi->u.http.body_index = 0;
+ n = wsi->protocol->rx_buffer_size;
+ if (!n)
+ n = LWS_MAX_SOCKET_IO_BUF;
+ wsi->u.http.post_buffer = malloc(n);
+ if (!wsi->u.http.post_buffer) {
+ lwsl_err("Unable to allocate post buffer\n");
+ n = -1;
+ goto cleanup;
+ }
+ }
+
+ n = 0;
+ if (wsi->protocol->callback)
+ n = wsi->protocol->callback(context, wsi,
+ LWS_CALLBACK_FILTER_HTTP_CONNECTION,
+ wsi->user_space, uri_ptr, uri_len);
+
+ if (!n) {
+ /*
+ * if there is content supposed to be coming,
+ * put a timeout on it having arrived
+ */
+ libwebsocket_set_timeout(wsi,
+ PENDING_TIMEOUT_HTTP_CONTENT,
+ AWAITING_TIMEOUT);
+
+ if (wsi->protocol->callback)
+ n = wsi->protocol->callback(context, wsi,
+ LWS_CALLBACK_HTTP,
+ wsi->user_space, uri_ptr, uri_len);
+ }
+
+cleanup:
+ /* now drop the header info we kept a pointer to */
+ if (ah)
+ free(ah);
+ /* not possible to continue to use past here */
+ wsi->u.http.ah = NULL;
+
+ if (n) {
+ lwsl_info("LWS_CALLBACK_HTTP closing\n");
+ return 1; /* struct ah ptr already nuked */
+ }
+
+ /*
+ * (if callback didn't start sending a file)
+ * deal with anything else as body, whether
+ * there was a content-length or not
+ */
+
+ if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
+ wsi->state = WSI_STATE_HTTP_BODY;
+ return 2; /* goto http_postbody; */
+ }
+
+ if (!wsi->protocol)
+ lwsl_err("NULL protocol at libwebsocket_read\n");
+
+ /*
+ * It's websocket
+ *
+ * Make sure user side is happy about protocol
+ */
+
+ while (wsi->protocol->callback) {
+
+ if (!lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
+ if (wsi->protocol->name == NULL)
+ break;
+ } else
+ if (wsi->protocol->name && strcmp(
+ lws_hdr_simple_ptr(wsi,
+ WSI_TOKEN_PROTOCOL),
+ wsi->protocol->name) == 0)
+ break;
+
+ wsi->protocol++;
+ }
+
+ /* we didn't find a protocol he wanted? */
+
+ if (wsi->protocol->callback == NULL) {
+ if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) ==
+ NULL) {
+ lwsl_info("no protocol -> prot 0 handler\n");
+ wsi->protocol = &context->protocols[0];
+ } else {
+ lwsl_err("Req protocol %s not supported\n",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL));
+ goto bail_nuke_ah;
+ }
+ }
+
+ /* allocate wsi->user storage */
+ if (libwebsocket_ensure_user_space(wsi))
+ goto bail_nuke_ah;
+
+ /*
+ * Give the user code a chance to study the request and
+ * have the opportunity to deny it
+ */
+
+ if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
+ LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
+ wsi->user_space,
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
+ lwsl_warn("User code denied connection\n");
+ goto bail_nuke_ah;
+ }
+
+
+ /*
+ * Perform the handshake according to the protocol version the
+ * client announced
+ */
+
+ switch (wsi->ietf_spec_revision) {
+ case 13:
+ lwsl_parser("lws_parse calling handshake_04\n");
+ if (handshake_0405(context, wsi)) {
+ lwsl_info("hs0405 has failed the connection\n");
+ goto bail_nuke_ah;
+ }
+ break;
+
+ default:
+ lwsl_warn("Unknown client spec version %d\n",
+ wsi->ietf_spec_revision);
+ goto bail_nuke_ah;
+ }
+
+ /* drop the header info -- no bail_nuke_ah after this */
+
+ if (wsi->u.hdr.ah)
+ free(wsi->u.hdr.ah);
+
+ wsi->mode = LWS_CONNMODE_WS_SERVING;
+
+ /* union transition */
+ memset(&wsi->u, 0, sizeof(wsi->u));
+ wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
+
+ /*
+ * create the frame buffer for this connection according to the
+ * size mentioned in the protocol definition. If 0 there, use
+ * a big default for compatibility
+ */
+
+ n = wsi->protocol->rx_buffer_size;
+ if (!n)
+ n = LWS_MAX_SOCKET_IO_BUF;
+ n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
+ wsi->u.ws.rx_user_buffer = malloc(n);
+ if (!wsi->u.ws.rx_user_buffer) {
+ lwsl_err("Out of Mem allocating rx buffer %d\n", n);
+ return 1;
+ }
+ lwsl_info("Allocating RX buffer %d\n", n);
+
+ if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
+ lwsl_warn("Failed to set SNDBUF to %d", n);
+ return 1;
+ }
+
+ lwsl_parser("accepted v%02d connection\n",
+ wsi->ietf_spec_revision);
+ } /* while all chars are handled */
+
+ return 0;
+
+bail_nuke_ah:
+ /* drop the header info */
+ if (wsi->u.hdr.ah)
+ free(wsi->u.hdr.ah);
+ return 1;
+}
+
+
#ifdef LWS_OPENSSL_SUPPORT
static void