int lws_interpret_incoming_packet(struct lws *wsi, unsigned char *buf, size_t len) { size_t n = 0; int m; #if 0 lwsl_parser("received %d byte packet\n", (int)len); lwsl_hexdump(buf, len); #endif /* let the rx protocol state machine have as much as it needs */ while (n < len) { /* * we were accepting input but now we stopped doing so */ if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { lws_rxflow_cache(wsi, buf, n, len); return 1; } /* account for what we're using in rxflow buffer */ if (wsi->rxflow_buffer) wsi->rxflow_pos++; /* process the byte */ m = lws_rx_sm(wsi, buf[n++]); if (m < 0) return -1; } return 0; }
int lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len) { int m; lwsl_parser("%s: received %d byte packet\n", __func__, (int)len); #if 0 lwsl_hexdump(*buf, len); #endif /* let the rx protocol state machine have as much as it needs */ while (len) { /* * we were accepting input but now we stopped doing so */ if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { lws_rxflow_cache(wsi, *buf, 0, len); lwsl_parser("%s: cached %d\n", __func__, len); return 1; } if (wsi->u.ws.rx_draining_ext) { m = lws_rx_sm(wsi, 0); if (m < 0) return -1; continue; } /* account for what we're using in rxflow buffer */ if (wsi->rxflow_buffer) wsi->rxflow_pos++; /* consume payload bytes efficiently */ if (wsi->lws_rx_parse_state == LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) lws_payload_until_length_exhausted(wsi, buf, &len); /* process the byte */ m = lws_rx_sm(wsi, *(*buf)++); if (m < 0) return -1; len--; } lwsl_parser("%s: exit with %d unused\n", __func__, (int)len); return 0; }
int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, unsigned char *buf, size_t len) { size_t n = 0; int m; #if 0 lwsl_parser("received %d byte packet\n", (int)len); lwsl_hexdump(buf, len); #endif /* let the rx protocol state machine have as much as it needs */ while (n < len) { /* * we were accepting input but now we stopped doing so */ if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) { /* his RX is flowcontrolled, don't send remaining now */ if (!wsi->u.ws.rxflow_buffer) { /* a new rxflow, buffer it and warn caller */ lwsl_info("new rxflow input buffer len %d\n", len - n); wsi->u.ws.rxflow_buffer = (unsigned char *)malloc(len - n); wsi->u.ws.rxflow_len = len - n; wsi->u.ws.rxflow_pos = 0; memcpy(wsi->u.ws.rxflow_buffer, buf + n, len - n); } else /* rxflow while we were spilling prev rxflow */ lwsl_info("stalling in existing rxflow buf\n"); return 1; } /* account for what we're using in rxflow buffer */ if (wsi->u.ws.rxflow_buffer) wsi->u.ws.rxflow_pos++; /* process the byte */ m = libwebsocket_rx_sm(wsi, buf[n++]); if (m < 0) return -1; } return 0; }
LWS_VISIBLE int lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) { unsigned char *last_char, *oldbuf = buf; lws_filepos_t body_chunk_len; size_t n; switch (wsi->state) { #ifdef LWS_WITH_HTTP2 case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS: case LWSS_HTTP2_ESTABLISHED: n = 0; //lwsl_debug("%s: starting new block of %d\n", __func__, (int)len); /* * wsi here is always the network connection wsi, not a stream * wsi. */ while (n < len) { /* * we were accepting input but now we stopped doing so */ if (lws_is_flowcontrolled(wsi)) { lws_rxflow_cache(wsi, buf, n, len); return 1; } /* account for what we're using in rxflow buffer */ if (wsi->rxflow_buffer) { wsi->rxflow_pos++; assert(wsi->rxflow_pos <= wsi->rxflow_len); } if (lws_h2_parser(wsi, buf[n++])) { lwsl_debug("%s: http2_parser bailed\n", __func__); goto bail; } } lwsl_debug("%s: used up block of %d\n", __func__, (int)len); break; #endif case LWSS_HTTP_ISSUING_FILE: return 0; case LWSS_CLIENT_HTTP_ESTABLISHED: break; case LWSS_HTTP: wsi->hdr_parsing_completed = 0; /* fallthru */ case LWSS_HTTP_HEADERS: if (!wsi->u.hdr.ah) { lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__); assert(0); } lwsl_parser("issuing %d bytes to parser\n", (int)len); lwsl_hexdump(buf, (size_t)len); if (lws_handshake_client(wsi, &buf, (size_t)len)) goto bail; last_char = buf; if (lws_handshake_server(wsi, &buf, (size_t)len)) /* Handshake indicates this session is done. */ goto bail; /* we might have transitioned to RAW */ if (wsi->mode == LWSCM_RAW) /* we gave the read buffer to RAW handler already */ goto read_ok; /* * It's possible that we've exhausted our data already, or * rx flow control has stopped us dealing with this early, * but lws_handshake_server doesn't update len for us. * Figure out how much was read, so that we can proceed * appropriately: */ len -= (buf - last_char); lwsl_debug("%s: thinks we have used %ld\n", __func__, (long)len); if (!wsi->hdr_parsing_completed) /* More header content on the way */ goto read_ok; switch (wsi->state) { case LWSS_HTTP: case LWSS_HTTP_HEADERS: goto read_ok; case LWSS_HTTP_ISSUING_FILE: goto read_ok; case LWSS_HTTP_BODY: wsi->u.http.rx_content_remain = wsi->u.http.rx_content_length; if (wsi->u.http.rx_content_remain) goto http_postbody; /* there is no POST content */ goto postbody_completion; default: break; } break; case LWSS_HTTP_BODY: http_postbody: //lwsl_notice("http post body\n"); while (len && wsi->u.http.rx_content_remain) { /* Copy as much as possible, up to the limit of: * what we have in the read buffer (len) * remaining portion of the POST body (content_remain) */ body_chunk_len = min(wsi->u.http.rx_content_remain, len); wsi->u.http.rx_content_remain -= body_chunk_len; len -= body_chunk_len; #ifdef LWS_WITH_CGI if (wsi->cgi) { struct lws_cgi_args args; args.ch = LWS_STDIN; args.stdwsi = &wsi->cgi->stdwsi[0]; args.data = buf; args.len = body_chunk_len; /* returns how much used */ n = user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_CGI_STDIN_DATA, wsi->user_space, (void *)&args, 0); if ((int)n < 0) goto bail; } else { #endif n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY, wsi->user_space, buf, (size_t)body_chunk_len); if (n) goto bail; n = (size_t)body_chunk_len; #ifdef LWS_WITH_CGI } #endif buf += n; if (wsi->u.http.rx_content_remain) { lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, wsi->context->timeout_secs); break; } /* he sent all the content in time */ postbody_completion: #ifdef LWS_WITH_CGI /* * If we're running a cgi, we can't let him off the * hook just because he sent his POST data */ if (wsi->cgi) lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, wsi->context->timeout_secs); else #endif lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); #ifdef LWS_WITH_CGI if (!wsi->cgi) #endif { lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION, wsi->user_space, NULL, 0); if (n) goto bail; if (wsi->http2_substream) wsi->state = LWSS_HTTP2_ESTABLISHED; } break; } break; case LWSS_ESTABLISHED: case LWSS_AWAITING_CLOSE_ACK: case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION: case LWSS_SHUTDOWN: if (lws_handshake_client(wsi, &buf, (size_t)len)) goto bail; switch (wsi->mode) { case LWSCM_WS_SERVING: if (lws_interpret_incoming_packet(wsi, &buf, (size_t)len) < 0) { lwsl_info("interpret_incoming_packet has bailed\n"); goto bail; } break; } break; default: lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state); break; } read_ok: /* Nothing more to do for now */ lwsl_info("%s: read_ok, used %ld\n", __func__, (long)(buf - oldbuf)); return buf - oldbuf; bail: lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return -1; }