static void esp8266_cb_sent(void *arg) { struct espconn *conn = arg; struct lws *wsi = conn->reverse; struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; // lwsl_err("%s: wsi %p (psc %d) wsi->position_in_fds_table=%d\n", __func__, wsi, wsi->pending_send_completion, wsi->position_in_fds_table); wsi->pending_send_completion--; if (wsi->close_is_pending_send_completion && !wsi->pending_send_completion && !lws_partial_buffered(wsi)) { lwsl_notice("doing delayed close\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); } if (pt->fds[wsi->position_in_fds_table].events & LWS_POLLOUT) { struct lws_pollfd pollfd; pollfd.fd = arg; pollfd.events = LWS_POLLOUT; pollfd.revents = LWS_POLLOUT; // lwsl_notice("informing POLLOUT\n"); lws_service_fd(lws_get_context(wsi), &pollfd); } }
static int callback_Play(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { HostStuff* phoststuff=(HostStuff*)libwebsocket_context_user(context); switch (reason) { case LWS_CALLBACK_ESTABLISHED: { ((PlayBackData*)user)->p_queue=0; break; } case LWS_CALLBACK_CLOSED: { queue<string> * _queue = ((PlayBackData*)user)->p_queue; delete _queue; ((PlayBackData*)user)->p_queue=0; WebSocketFeedBackSession* se=((PlayBackData*)user)->p_se; se->close(); delete se; break; } case LWS_CALLBACK_RECEIVE: { queue<string> * _queue = ((PlayBackData*)user)->p_queue; delete _queue; _queue = ((PlayBackData*)user)->p_queue=new queue<string>; WebSocketFeedBackSession* se=((PlayBackData*)user)->p_se=new WebSocketFeedBackSession(context, wsi, _queue); IncomingSession(phoststuff, (char*)in, se); break; } case LWS_CALLBACK_SERVER_WRITEABLE: { queue<string> * _queue = *((queue<string> **)user); unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 + LWS_SEND_BUFFER_POST_PADDING]; unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; if (!_queue->empty() && lws_partial_buffered (wsi)!=1) { string s=_queue->front(); _queue->pop(); int n = sprintf((char *)p, s.data()); libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT); } if (!_queue->empty()) libwebsocket_callback_on_writable (context, wsi); break; } } return 0; }
static int callback_lws_mirror(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { int n; struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; switch (reason) { case LWS_CALLBACK_ESTABLISHED: lwsl_info("callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n"); pss->ringbuffer_tail = ringbuffer_head; pss->wsi = wsi; break; case LWS_CALLBACK_PROTOCOL_DESTROY: lwsl_notice("mirror protocol cleaning up\n"); for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++) if (ringbuffer[n].payload) free(ringbuffer[n].payload); break; case LWS_CALLBACK_SERVER_WRITEABLE: if (close_testing) break; while (pss->ringbuffer_tail != ringbuffer_head) { n = libwebsocket_write(wsi, (unsigned char *) ringbuffer[pss->ringbuffer_tail].payload + LWS_SEND_BUFFER_PRE_PADDING, ringbuffer[pss->ringbuffer_tail].len, LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to mirror socket\n", n); return -1; } if (n < ringbuffer[pss->ringbuffer_tail].len) lwsl_err("mirror partial write %d vs %d\n", n, ringbuffer[pss->ringbuffer_tail].len); if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) pss->ringbuffer_tail = 0; else pss->ringbuffer_tail++; if (((ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15)) libwebsocket_rx_flow_allow_all_protocol( libwebsockets_get_protocol(wsi)); // lwsl_debug("tx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)); if (lws_partial_buffered(wsi) || lws_send_pipe_choked(wsi)) { libwebsocket_callback_on_writable(context, wsi); break; } /* * for tests with chrome on same machine as client and * server, this is needed to stop chrome choking */ #ifdef _WIN32 Sleep(1); #else usleep(1); #endif } break; case LWS_CALLBACK_RECEIVE: if (((ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) { lwsl_err("dropping!\n"); goto choke; } if (ringbuffer[ringbuffer_head].payload) free(ringbuffer[ringbuffer_head].payload); ringbuffer[ringbuffer_head].payload = malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); ringbuffer[ringbuffer_head].len = len; memcpy((char *)ringbuffer[ringbuffer_head].payload + LWS_SEND_BUFFER_PRE_PADDING, in, len); if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) ringbuffer_head = 0; else ringbuffer_head++; if (((ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2)) goto done; choke: lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi); libwebsocket_rx_flow_control(wsi, 0); // lwsl_debug("rx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)); done: libwebsocket_callback_on_writable_all_protocol( libwebsockets_get_protocol(wsi)); break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: dump_handshake_info(wsi); /* you could return non-zero here and kill the connection */ break; default: break; } return 0; }
static int callback_http(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { #if 0 char client_name[128]; char client_ip[128]; #endif char buf[256]; char leaf_path[1024]; char b64[64]; struct timeval tv; int n, m; unsigned char *p; char *other_headers; static unsigned char buffer[4096]; struct stat stat_buf; struct per_session_data__http *pss = (struct per_session_data__http *)user; const char *mimetype; #ifdef EXTERNAL_POLL struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *)in; #endif unsigned char *end; switch (reason) { case LWS_CALLBACK_HTTP: dump_handshake_info(wsi); if (len < 1) { libwebsockets_return_http_status(context, wsi, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } /* this example server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); goto try_to_reuse; } /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* check for the "send a big file by hand" example case */ if (!strcmp((const char *)in, "/leaf.jpg")) { if (strlen(resource_path) > sizeof(leaf_path) - 10) return -1; sprintf(leaf_path, "%s/leaf.jpg", resource_path); /* well, let's demonstrate how to send the hard way */ p = buffer + LWS_SEND_BUFFER_PRE_PADDING; end = p + sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING; #ifdef WIN32 pss->fd = open(leaf_path, O_RDONLY | _O_BINARY); #else pss->fd = open(leaf_path, O_RDONLY); #endif if (pss->fd < 0) return -1; fstat(pss->fd, &stat_buf); /* * we will send a big jpeg file, but it could be * anything. Set the Content-Type: appropriately * so the browser knows what to do with it. * * Notice we use the APIs to build the header, which * will do the right thing for HTTP 1/1.1 and HTTP2 * depending on what connection it happens to be working * on */ if (lws_add_http_header_status(context, wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"image/jpeg", 10, &p, end)) return 1; if (lws_add_http_header_content_length(context, wsi,stat_buf.st_size, &p, end)) return 1; if (lws_finalize_http_header(context, wsi, &p, end)) return 1; /* * send the http headers... * this won't block since it's the first payload sent * on the connection since it was established * (too small for partial) * * Notice they are sent using LWS_WRITE_HTTP_HEADERS * which also means you can't send body too in one step, * this is mandated by changes in HTTP2 */ n = libwebsocket_write(wsi, buffer + LWS_SEND_BUFFER_PRE_PADDING, p - (buffer + LWS_SEND_BUFFER_PRE_PADDING), LWS_WRITE_HTTP_HEADERS); if (n < 0) { close(pss->fd); return -1; } /* * book us a LWS_CALLBACK_HTTP_WRITEABLE callback */ libwebsocket_callback_on_writable(context, wsi); break; } /* if not, send a file the easy way */ strcpy(buf, resource_path); if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(resource_path)); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demostrates how to set a cookie on / */ other_headers = NULL; n = 0; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); p = (unsigned char *)leaf_path; if (lws_add_http_header_by_name(context, wsi, (unsigned char *)"set-cookie:", (unsigned char *)b64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; n = (char *)p - leaf_path; other_headers = leaf_path; } n = libwebsockets_serve_http_file(context, wsi, buf, mimetype, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: strncpy(buf, in, 20); buf[20] = '\0'; if (len < 20) buf[len] = '\0'; lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n", (const char *)buf, (int)len); break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* the whole of the sent body arrived, close or reuse the connection */ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_OK, NULL); goto try_to_reuse; case LWS_CALLBACK_HTTP_FILE_COMPLETION: // lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n"); /* kill the connection after we sent one file */ goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: /* * we can send more of whatever it is we were sending */ lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n"); do { lwsl_info("a\n"); n = read(pss->fd, buffer + LWS_SEND_BUFFER_PRE_PADDING, sizeof (buffer) - LWS_SEND_BUFFER_PRE_PADDING); /* problem reading, close conn */ if (n < 0) goto bail; /* sent it all, close conn */ if (n == 0) goto flush_bail; lwsl_info("b\n"); /* * To support HTTP2, must take care about preamble space * and identify when we send the last frame */ m = libwebsocket_write(wsi, buffer + LWS_SEND_BUFFER_PRE_PADDING, n, LWS_WRITE_HTTP); if (m < 0) /* write failed, close conn */ goto bail; lwsl_info("c\n"); /* * http2 won't do this */ if (m != n) /* partial write, adjust */ lseek(pss->fd, m - n, SEEK_CUR); lwsl_info("d\n"); if (m) /* while still active, extend timeout */ libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5); /* if he has indigestion, let him clear it before eating more */ if (lws_partial_buffered(wsi)) break; } while (!lws_send_pipe_choked(wsi)); lwsl_info("e\n"); libwebsocket_callback_on_writable(context, wsi); lwsl_info("f\n"); break; flush_bail: /* true if still partial pending */ if (lws_partial_buffered(wsi)) { libwebsocket_callback_on_writable(context, wsi); break; } close(pss->fd); goto try_to_reuse; bail: close(pss->fd); return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default uhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: #if 0 libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name, sizeof(client_name), client_ip, sizeof(client_ip)); fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip); #endif /* if we returned non-zero from here, we kill the connection */ break; #ifdef EXTERNAL_POLL /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback */ break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback */ break; case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "libwebsocket_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; default: break; } return 0; try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; }
int callback_jittertrap(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len __attribute__((unused))) { unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_JSON_MSG_LEN + LWS_SEND_BUFFER_POST_PADDING]; unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; struct per_session_data__jittertrap *pss = (struct per_session_data__jittertrap *)user; int err, cb_err; struct cb_data cbd = { wsi, p }; /* run jt init, stats producer, etc. */ jt_server_tick(); switch (reason) { case LWS_CALLBACK_CLOSED: err = jt_ws_mq_consumer_unsubscribe(pss->consumer_id); if (err) { lwsl_err("mq consumer unsubscribe failed.\n"); } break; case LWS_CALLBACK_ESTABLISHED: lwsl_info("callback_jt: " "LWS_CALLBACK_ESTABLISHED\n"); err = jt_ws_mq_consumer_subscribe(&(pss->consumer_id)); if (err) { lwsl_err("mq consumer subscription failed.\n"); } jt_srv_send_iface_list(); jt_srv_send_select_iface(); jt_srv_send_netem_params(); jt_srv_send_sample_period(); break; case LWS_CALLBACK_SERVER_WRITEABLE: do { err = jt_ws_mq_consume(pss->consumer_id, lws_writer, &cbd, &cb_err); if (lws_partial_buffered(wsi) || lws_send_pipe_choked(wsi)) { lws_callback_on_writable(wsi); break; } } while (!err); if (-JT_WS_MQ_EMPTY != err) { return err; } break; case LWS_CALLBACK_RECEIVE: jt_server_msg_receive(in); break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: dump_handshake_info(wsi); /* you could return non-zero here and kill the connection */ break; default: break; } return 0; }
int callback_http(struct lws *webSocketInstance, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__http *pss = (struct per_session_data__http *) user; struct timeval tv; unsigned long amount, file_len; const char *contentType; static unsigned char buffer4096[4096]; char buffer256[256]; char buffer64[64]; char leaf_path[1024]; char *other_headers; unsigned char *end; unsigned char *p; int n, m, headerIndex = 0; #ifdef EXTERNAL_POLL struct lws_pollargs *pa = (struct lws_pollargs *)in; #endif switch (reason) { case LWS_CALLBACK_HTTP: /* SS_Server_DumpHandShake(webSocketInstance); */ /* dump the individual URI Arg parameters */ while (lws_hdr_copy_fragment(webSocketInstance, buffer256, sizeof(buffer256), WSI_TOKEN_HTTP_URI_ARGS, headerIndex) > 0) { lwsl_info("URI Arg %d: %s\n", ++headerIndex, buffer256); } if (len < 1) { lws_return_http_status(webSocketInstance, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(webSocketInstance, WSI_TOKEN_POST_URI)) { return 0; } if(strchr((const char*)in + 1, '/')) { if (strcmp(in, "/")) { if (*((const char *)in) != '/') { strcat(buffer256, "/"); } strncat(buffer256, in, sizeof(buffer256) - strlen(RESOURCE_PATH)); } else { /* default file to serve */ strcat(buffer256, in); } buffer256[sizeof(buffer256) - 1] = '\0'; sprintf(leaf_path, "%s%s", RESOURCE_PATH, buffer256); p = buffer4096 + LWS_PRE; end = p + sizeof(buffer4096) - LWS_PRE; pss->fd = lws_plat_file_open(webSocketInstance, leaf_path, &file_len, LWS_O_RDONLY); contentType = get_mimetype(buffer256); if (!contentType) { lwsl_err("Unknown content-type for %s\n", buffer256); lws_return_http_status(webSocketInstance, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } if (pss->fd == LWS_INVALID_FILE) { return -1; } if (lws_add_http_header_status(webSocketInstance, 200, &p, end)) { return 1; } if (lws_add_http_header_by_token(webSocketInstance, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) { return 1; } if(strncmp(contentType, "*/*", 3) == 0) { if (lws_add_http_header_by_token(webSocketInstance, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)contentType, 4, &p, end)) { return 1; } } else { if(strncmp(contentType, "application/x-javascript", 24) == 0) { if (lws_add_http_header_by_token(webSocketInstance, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)contentType, 24, &p, end)) { return 1; } } else { if (lws_add_http_header_by_token(webSocketInstance, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)contentType, 9, &p, end)) { return 1; } } } if (lws_add_http_header_content_length(webSocketInstance, file_len, &p, end)) { return 1; } if (lws_finalize_http_header(webSocketInstance, &p, end)) { return 1; } n = lws_write(webSocketInstance, buffer4096 + LWS_PRE, p - (buffer4096 + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) { lws_plat_file_close(webSocketInstance, pss->fd); return -1; } lws_callback_on_writable(webSocketInstance); break; printf("%s",buffer256); other_headers = NULL; n = 0; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(webSocketInstance, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(buffer64, "test=SOUNDSHIELD_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); p = (unsigned char *)buffer256; if (lws_add_http_header_by_name(webSocketInstance, (unsigned char *)"set-cookie:", (unsigned char *)buffer64, n, &p, (unsigned char *)buffer256 + sizeof(buffer256))) { return 1; } n = (char *)p - buffer256; other_headers = buffer256; } n = lws_serve_http_file(webSocketInstance, buffer256, contentType, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(webSocketInstance))) { return -1; /* error or can't reuse connection: close the socket */ } break; } /* if not, send a file the easy way */ strcpy(buffer256, RESOURCE_PATH); if (strcmp(in, "/")) { if (*((const char *)in) != '/') { strcat(buffer256, "/"); } strncat(buffer256, in, sizeof(buffer256) - strlen(RESOURCE_PATH)); } else { /* default file to serve */ strcat(buffer256, "/index.html"); } buffer256[sizeof(buffer256) - 1] = '\0'; /* refuse to serve files we don't understand */ contentType = get_mimetype(buffer256); if (!contentType) { lwsl_err("Unknown content-type for %s\n", buffer256); lws_return_http_status(webSocketInstance, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demonstrates how to set a cookie on / */ other_headers = NULL; n = 0; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(webSocketInstance, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(buffer64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); p = (unsigned char *)leaf_path; if (lws_add_http_header_by_name(webSocketInstance, (unsigned char *)"set-cookie:", (unsigned char *)buffer64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) { return 1; } n = (char *)p - leaf_path; other_headers = leaf_path; } n = lws_serve_http_file(webSocketInstance, buffer256, contentType, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(webSocketInstance))) { return -1; /* error or can't reuse connection: close the socket */ } /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: strncpy(buffer256, in, 20); buffer256[20] = '\0'; if (len < 20) { buffer256[len] = '\0'; } lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n", (const char *)buffer256, (int)len); break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* the whole of the sent body arrived, close or reuse the connection */ lws_return_http_status(webSocketInstance, HTTP_STATUS_OK, NULL); goto try_to_reuse; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: /* * we can send more of whatever it is we were sending */ do { /* we'd like the send this much */ n = sizeof(buffer4096) - LWS_PRE; /* but if the peer told us he wants less, we can adapt */ m = lws_get_peer_write_allowance(webSocketInstance); /* -1 means not using a protocol that has this info */ if (m == 0) { /* right now, peer can't handle anything */ goto later; } if (m != -1 && m < n) { /* he couldn't handle that much */ n = m; } n = lws_plat_file_read(webSocketInstance, pss->fd, &amount, buffer4096 + LWS_PRE, n); /* problem reading, close conn */ if (n < 0) { goto bail; } n = (int)amount; /* sent it all, close conn */ if (n == 0) { goto flush_bail; } /* * To support HTTP2, must take care about preamble space * * identification of when we send the last payload frame * is handled by the library itself if you sent a * content-length header */ m = lws_write(webSocketInstance, buffer4096 + LWS_PRE, n, LWS_WRITE_HTTP); if (m < 0) { /* write failed, close conn */ goto bail; } /* * http2 won't do this */ if (m != n) { /* partial write, adjust */ if (lws_plat_file_seek_cur(webSocketInstance, pss->fd, m - n) == (unsigned long)-1) goto bail; } if (m) { /* while still active, extend timeout */ lws_set_timeout(webSocketInstance, PENDING_TIMEOUT_HTTP_CONTENT, 5); } /* if we have indigestion, let him clear it * before eating more */ if (lws_partial_buffered(webSocketInstance)) break; } while (!lws_send_pipe_choked(webSocketInstance)); later: lws_callback_on_writable(webSocketInstance); break; flush_bail: /* true if still partial pending */ if (lws_partial_buffered(webSocketInstance)) { lws_callback_on_writable(webSocketInstance); break; } lws_plat_file_close(webSocketInstance, pss->fd); goto try_to_reuse; bail: lws_plat_file_close(webSocketInstance, pss->fd); return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default uhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: /* if we returned non-zero from here, we kill the connection */ break; /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_lock(len); break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_unlock(len); break; #ifdef EXTERNAL_POLL case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) { break; } m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "lws_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; default: break; } return 0; /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */ try_to_reuse: if (lws_http_transaction_completed(webSocketInstance)) { return -1; } return 0; }