diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index aa6fa72f40..f1b9ee82d0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,17 +27,17 @@ jobs: uses: actions/checkout@v3 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql.yml queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 if: ${{ matrix.language == 'javascript' || matrix.language == 'cpp' }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" diff --git a/.sai.json b/.sai.json index 38420d5d91..5cec255c98 100644 --- a/.sai.json +++ b/.sai.json @@ -1,40 +1,73 @@ { "schema": "sai-1", - # We're doing separate install into destdir so that the test server - # has somewhere to go to find its /usr/share content like certs - "platforms": { "rocky9/aarch64-a72a55-rk3588/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j6 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": [ + "mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib cmake .. ${cmake}", + "cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install", + "cd build && ctest -j$SAI_PARALLEL --output-on-failure", + "cd build && SAI_CPACK=\"-G RPM\" ${cpack}" + ] }, "netbsd-OSX-bigsur/x86_64-intel-i3/llvm": { - "build": "mkdir build destdir; cd build; export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=12.5 ; cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": [ + "mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib MACOSX_DEPLOYMENT_TARGET=12.5 cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make ${cmake}", + "cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install", + "cd build && ctest -j$SAI_PARALLEL --output-on-failure", + "cd build && SAI_CPACK=\"-G ZIP\" ${cpack}" + ] }, "ubuntu-noble/riscv64/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": [ + "mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib cmake .. ${cmake}", + "cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install", + "cd build && ctest -j$SAI_PARALLEL --output-on-failure", + "cd build && SAI_CPACK=\"-G DEB\" ${cpack}" + ] }, "rocky9/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j6 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": [ + "mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib cmake .. ${cmake}", + "cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install", + "cd build && ctest -j$SAI_PARALLEL --output-on-failure", + "cd build && SAI_CPACK=\"-G RPM\" ${cpack}" + ] }, "linux-ubuntu-2404/aarch64-a72-bcm2711-rpi4/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": [ + "mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib cmake .. ${cmake}", + "cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install", + "cd build && ctest -j$SAI_PARALLEL --output-on-failure", + "cd build && SAI_CPACK=\"-G DEB\" ${cpack}" + ] }, "netbsd/aarch64BE-bcm2837-a53/gcc": { - "build": "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;cmake .. ${cmake};make -j6 && rm -rf ../destdir && make -j6 DESTDIR=../destdir install && /usr/pkg/bin/ctest -j4 --output-on-failure", - "default": false + "default": false, + "build": [ + "mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib cmake .. ${cmake}", + "cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install", + "cd build && /usr/pkg/bin/ctest -j$SAI_PARALLEL --output-on-failure" + ] }, "w11/x86_64-amd/msvc": { - "build": "mkdir build && cd build && set SAI_CPACK=\"-G ZIP\" && cmake .. -DOPENSSL_ROOT_DIR=\"C:\\Users\\andy\\vcpkg\\packages\\openssl_x64-windows\" -DLWS_EXT_PTHREAD_INCLUDE_DIR=\"C:\\Program Files (x86)\\pthreads\\include\" -DLWS_EXT_PTHREAD_LIBRARIES=\"C:\\Program Files (x86)\\pthreads\\lib\\x64\\libpthreadGC2.a\" ${cmake} && cmake --build . --config DEBUG && set CTEST_OUTPUT_ON_FAILURE=1 && ctest . -C DEBUG -j1 --output-on-failure", - "default": false + "default": false, + "build": [ + "mkdir -p build; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib cmake .. -DOPENSSL_ROOT_DIR=\"C:\\Users\\andy\\vcpkg\\packages\\openssl_x64-windows\" -DLWS_EXT_PTHREAD_INCLUDE_DIR=\"C:\\Program Files (x86)\\pthreads\\include\" -DLWS_EXT_PTHREAD_LIBRARIES=\"C:\\Program Files (x86)\\pthreads\\lib\\x64\\libpthreadGC2.a\" ${cmake}", + "cd build && cmake --build . --config DEBUG", + "cd build && /usr/pkg/bin/ctest -j$SAI_PARALLEL --output-on-failure", + "cd build && SAI_CPACK=\"-G ZIP\" ${cpack}" + ] }, "freertos-espidf/xl6-esp32/gcc": { - # official way to get sdkconfig.h is idf.py menuconfig, but - # no obvious way to do that in CI - "build": "rm -rf ebuild ; mkdir ebuild; cd ebuild; cp -rp ../minimal-examples/embedded/esp32/${cpack} . ; cd ${cpack} ; . /opt/esp/esp-idf/export.sh ; rm -f libwebsockets ; ln -sf ../.. libwebsockets ; idf.py set-target esp32 && cp libwebsockets/minimal-examples/embedded/esp32/${cpack}/sdkconfig . && cp sdkconfig.h build && idf.py ${cmake} build size size-components size-files && cd build && /usr/local/bin/sai-device ${cpack} ESPPORT=0 ctest --output-on-failure", - "default": false + "default": false, + "build": [ + "rm -rf ebuild ; mkdir ebuild; cd ebuild; cp -rp ../minimal-examples/embedded/esp32/${cpack} . ; cd ${cpack} ; . /opt/esp/esp-idf/export.sh ; rm -f libwebsockets ; ln -sf ../.. libwebsockets ; idf.py set-target esp32 && cp libwebsockets/minimal-examples/embedded/esp32/${cpack}/sdkconfig . && cp sdkconfig.h build && idf.py ${cmake} build size size-components size-files", + "cd build && /usr/local/bin/sai-device ${cpack} ESPPORT=0 ctest --output-on-failure" + ] } }, + "configurations": { "default": { "cmake": "", diff --git a/READMEs/README.ctest.md b/READMEs/README.ctest.md index 9fdb1ee7b6..2b905a07c8 100644 --- a/READMEs/README.ctest.md +++ b/READMEs/README.ctest.md @@ -309,14 +309,14 @@ For tests with local buddies using tcp sockets inside the same VM or systemd- nspawn networking context, you cannot just use a well-known port like 7681. ctest itself is usually executed concurrently, and Sai is typically building -multiple different instances concurrently as well (typically 3), so it may be +multiple different instances concurrently as well (perhaps dozens), so it may be running different ctests inside the same VM simultaneously. Different tests can have their own convention for port ranges, to solve the problem about Sai running different tests concurrently inside one ctest. For the case there are multiple ctests running, we can use the env var -`$ENV{SAI_INSTANCE_IDX}`, which is an ordinal like 0 or 1, to further ensure +`$ENV{SAI_INSTANCE_IDX}`, which is an ordinal like 0 or 1 or 33, to further ensure that port selections won't conflict. If not using Sai, you can just set this in the evironment yourself to reflect your build instance index. @@ -326,20 +326,14 @@ in the evironment yourself to reflect your build instance index. # machine context in parallel so they can tread on each other otherwise # set(PORT_HCM_SRV "7670") - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0") - set(PORT_HCM_SRV 7671) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1") - set(PORT_HCM_SRV 7672) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2") - set(PORT_HCM_SRV 7673) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3") - set(PORT_HCM_SRV 7674) + if ("$ENV{SAI_INSTANCE_IDX}") + math(EXPR PORT_HCM_SRV "7671 + $ENV{SAI_INSTANCE_IDX}") endif() ``` +The default value is for the case you are running the test manually, and not +under Sai. + This is complicated enough that the best approach is copy an existing simple case like the CMakeLists.txt for minimal-http-client and change the names and ports to be unique. diff --git a/include/libwebsockets/lws-misc.h b/include/libwebsockets/lws-misc.h index 1118165bd8..4050c03bbb 100644 --- a/include/libwebsockets/lws-misc.h +++ b/include/libwebsockets/lws-misc.h @@ -178,6 +178,22 @@ lws_buflist_destroy_all_segments(struct lws_buflist **head); LWS_VISIBLE LWS_EXTERN void lws_buflist_describe(struct lws_buflist **head, void *id, const char *reason); +/** + * lws_buflist_get_frag_start_or_NULL(): get pointer to start of fragment + * + * \param head: list head + * + * This gets you a pointer to the start of the fragment payload, no matter + * how much of it you may have 'used' already. This is useful for schemes + * where you prepend something to the payload and need to reference it no + * matter how much of it you have consumed or the fragmentation details. + * + * If the buflist is empty, it will return NULL. + */ +LWS_VISIBLE LWS_EXTERN void * +lws_buflist_get_frag_start_or_NULL(struct lws_buflist **head); + + /* * Optional helpers for closely-managed stream flow control. These are useful @@ -1016,13 +1032,20 @@ lws_assert_fourcc(uint32_t fourcc, uint32_t expected); * which represents a count of us as a human-readable time like " 14.350min", * or " 1.500d". * - * You can produce your own schema. + * You can produce your own schema tables. + * + * lws_humanize_pad() is the same but pads the lhs so that it + * always produces the same length. */ LWS_VISIBLE LWS_EXTERN int lws_humanize(char *buf, size_t len, uint64_t value, const lws_humanize_unit_t *schema); +LWS_VISIBLE LWS_EXTERN int +lws_humanize_pad(char *p, size_t len, uint64_t v, + const lws_humanize_unit_t *schema); + LWS_VISIBLE LWS_EXTERN void lws_ser_wu16be(uint8_t *b, uint16_t u); diff --git a/include/libwebsockets/lws-ws-state.h b/include/libwebsockets/lws-ws-state.h index b1cc54633f..e5b7cc9474 100644 --- a/include/libwebsockets/lws-ws-state.h +++ b/include/libwebsockets/lws-ws-state.h @@ -38,7 +38,7 @@ LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_send_pipe_choked(struct lws *wsi); /** - * lws_is_final_fragment() - tests if last part of ws message + * lws_is_final_fragment() - tests if received fragment is last part of ws message * * \param wsi: lws connection */ @@ -46,13 +46,22 @@ LWS_VISIBLE LWS_EXTERN int lws_is_final_fragment(struct lws *wsi); /** - * lws_is_first_fragment() - tests if first part of ws message + * lws_is_first_fragment() - tests if received fragment is first part of ws message * * \param wsi: lws connection */ LWS_VISIBLE LWS_EXTERN int lws_is_first_fragment(struct lws *wsi); +/** + * lws_ws_sending_multifragment() - return 1 if we are in the middle of sending a multi-fragment message + * + * \param wsi: lws connection + */ + +LWS_VISIBLE LWS_EXTERN int +lws_ws_sending_multifragment(struct lws *wsi); + /** * lws_get_reserved_bits() - access reserved bits of ws frame * \param wsi: lws connection diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 9351aa8e5c..7948380239 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -946,6 +946,8 @@ struct lws_spawn_piped { #if defined(WIN32) HANDLE child_pid; lws_sorted_usec_list_t sul_poll; + FILETIME ft_create; + FILETIME ft_exit; #else pid_t child_pid; diff --git a/lib/core/buflist.c b/lib/core/buflist.c index 511330ca34..8a6acaee39 100644 --- a/lib/core/buflist.c +++ b/lib/core/buflist.c @@ -276,6 +276,17 @@ lws_buflist_describe(struct lws_buflist **head, void *id, const char *reason) } #endif +LWS_VISIBLE LWS_EXTERN void * +lws_buflist_get_frag_start_or_NULL(struct lws_buflist **head) +{ + struct lws_buflist *b = (*head); + + if (!b) + return NULL; /* there is no segment to work on */ + + return ((uint8_t *)b) + sizeof(*b) + LWS_PRE; +} + lws_stateful_ret_t lws_flow_feed(lws_flow_t *flow) { diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index 7ae41f7584..c57c9bd6e5 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -1762,23 +1762,37 @@ int lws_humanize(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema) { char *obuf = p, *end = p + len; + const lws_humanize_unit_t *s = NULL; do { if (v >= schema->factor || schema->factor == 1) { + if (schema[1].name) + s = &schema[1]; + if (schema->factor == 1) { p += decim(p, v, 4, 0); p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), - "%s", schema->name); + "%s", schema->name); return lws_ptr_diff(p, obuf); } p += decim(p, v / schema->factor, 4, 0); - *p++ = '.'; - p += decim(p, (v % schema->factor) / - (schema->factor / 1000), 3, 1); - + if (s) { + uint64_t iif = schema->factor / s->factor; + + if (s->factor * 1000 == schema->factor || + s->factor * 1024 == schema->factor) { /* decimal */ + *p++ = '.'; + p += decim(p, (v % schema->factor) / + (schema->factor / 1000), 3, 1); + } else { /* imperial fraction, eg, h:m */ + *p++ = ':'; + p += decim(p, (v % schema->factor) / s->factor, + iif >= 100 ? 3 : (iif >= 10 ? 2 : 1), 1); + } + } p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), - "%s", schema->name); + "%s", schema->name); return lws_ptr_diff(p, obuf); } schema++; @@ -1790,6 +1804,31 @@ lws_humanize(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema) return 0; } +int +lws_humanize_pad(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema) +{ + size_t m, w = 0, n = (size_t)lws_humanize(p, len, v, schema); + const lws_humanize_unit_t *s = schema; + int t; + + while (s->name) { + if (strlen(s->name) > w) + w = strlen(s->name); + s++; + } + + m = (3 + 1 + 3 + w) - (size_t)n; + + for (t = (int)n - 1; t >= 0; t--) + p[(size_t)t + m] = p[t]; + p[m + n] = '\0'; + + for (t = 0; t < (int)m; t++) + p[t] = ' '; + + return (int)(n + m); +} + /* * -1 = fail * 0 = continue diff --git a/lib/misc/lws-struct-sqlite.c b/lib/misc/lws-struct-sqlite.c index f64192fb8c..e71403874e 100644 --- a/lib/misc/lws-struct-sqlite.c +++ b/lib/misc/lws-struct-sqlite.c @@ -662,7 +662,7 @@ lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema) p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), ");"); if (sqlite3_exec(pdb, s, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("%s: %s: fail\n", __func__, sqlite3_errmsg(pdb)); + lwsl_err("%s: %s: fail: %s\n", __func__, sqlite3_errmsg(pdb), s); return -1; } diff --git a/lib/plat/windows/private-lib-plat-windows.h b/lib/plat/windows/private-lib-plat-windows.h index ef9a8d1b89..bb8778af99 100644 --- a/lib/plat/windows/private-lib-plat-windows.h +++ b/lib/plat/windows/private-lib-plat-windows.h @@ -70,6 +70,12 @@ #if defined(LWS_WITH_TLS) #include +#if defined(LWS_WITH_BORINGSSL) + /* Undefine wincrypt.h symbols that conflict with BoringSSL */ + #undef X509_NAME + #undef X509_EXTENSIONS + #undef PKCS7_SIGNER_INFO +#endif #endif #if defined(LWS_HAVE_PTHREAD_H) diff --git a/lib/plat/windows/windows-spawn.c b/lib/plat/windows/windows-spawn.c index b6df4266f5..2519fb9706 100644 --- a/lib/plat/windows/windows-spawn.c +++ b/lib/plat/windows/windows-spawn.c @@ -27,6 +27,7 @@ #include #include #include +#include void lws_spawn_timeout(struct lws_sorted_usec_list *sul) @@ -153,7 +154,7 @@ lws_spawn_reap(struct lws_spawn_piped *lsp) lsp_cb_t cb = lsp->info.reap_cb; struct _lws_siginfo_t lsi; PROCESS_MEMORY_COUNTERS pmc; - IO_COUNTERS ic; + // IO_COUNTERS ic; ULARGE_INTEGER uli; FILETIME ftk, ftu; DWORD ex; @@ -624,3 +625,9 @@ lws_spawn_get_fd_stdxxx(struct lws_spawn_piped *lsp, int std_idx) return (int)(intptr_t)lsp->pipe_fds[std_idx][!!(std_idx == 0)]; } + +int +lws_spawn_prepare_self_cgroup(const char *user, const char *group) +{ + return 0; +} diff --git a/lib/roles/ws/ops-ws.c b/lib/roles/ws/ops-ws.c index af7fd27de2..80bc6d4461 100644 --- a/lib/roles/ws/ops-ws.c +++ b/lib/roles/ws/ops-ws.c @@ -915,6 +915,11 @@ lws_server_init_wsi_for_ws(struct lws *wsi) } +int +lws_ws_sending_multifragment(struct lws *wsi) +{ + return wsi->ws->last_valid && !wsi->ws->last_fin; +} int lws_is_final_fragment(struct lws *wsi) @@ -1830,12 +1835,37 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len, switch ((*wp) & 0xf) { case LWS_WRITE_TEXT: n = LWSWSOPC_TEXT_FRAME; + if (wsi->ws->last_valid && !wsi->ws->last_fin) { + lwsl_wsi_err(wsi, "Sending TEXT after previous frame that lacked FIN"); + assert(0); + } + wsi->ws->last_valid = 1; + wsi->ws->last_opcode = (uint8_t)n; + wsi->ws->last_fin = !((*wp) & LWS_WRITE_NO_FIN); break; case LWS_WRITE_BINARY: n = LWSWSOPC_BINARY_FRAME; + if (wsi->ws->last_valid && !wsi->ws->last_fin) { + lwsl_wsi_err(wsi, "Sending BINARY after previous frame that lacked FIN"); + assert(0); + } + wsi->ws->last_valid = 1; + wsi->ws->last_opcode = (uint8_t)n; + wsi->ws->last_fin = !((*wp) & LWS_WRITE_NO_FIN); break; case LWS_WRITE_CONTINUATION: n = LWSWSOPC_CONTINUATION; + if (wsi->ws->last_valid && wsi->ws->last_fin) { + lwsl_wsi_err(wsi, "Sending CONTINUATION after previous frame that had FIN"); + assert(0); + } + if (!wsi->ws->last_valid) { + lwsl_wsi_err(wsi, "Sending CONTINUATION as first frame"); + assert(0); + } + wsi->ws->last_valid = 1; + wsi->ws->last_opcode = (uint8_t)n; + wsi->ws->last_fin = !((*wp) & LWS_WRITE_NO_FIN); break; case LWS_WRITE_CLOSE: diff --git a/lib/roles/ws/private-lib-roles-ws.h b/lib/roles/ws/private-lib-roles-ws.h index 9bb8c840c0..573d1bb04e 100644 --- a/lib/roles/ws/private-lib-roles-ws.h +++ b/lib/roles/ws/private-lib-roles-ws.h @@ -137,6 +137,10 @@ struct _lws_websocket_related { uint32_t rx_ubuf_head; uint32_t rx_ubuf_alloc; + uint8_t last_valid; + uint8_t last_opcode; /* for outgoing state validation */ + uint8_t last_fin; /* for outgoing state validation */ + uint8_t pong_payload_len; uint8_t mask_idx; uint8_t opcode; diff --git a/lib/secure-streams/secure-streams.c b/lib/secure-streams/secure-streams.c index d973bf84fc..c8dd81a1b6 100644 --- a/lib/secure-streams/secure-streams.c +++ b/lib/secure-streams/secure-streams.c @@ -101,6 +101,7 @@ const uint32_t ss_state_txn_validity[] = { [LWSSSCS_UNREACHABLE] = (1 << LWSSSCS_ALL_RETRIES_FAILED) | (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_POLL) | + (1 << LWSSSCS_UNREACHABLE) | (1 << LWSSSCS_CONNECTING) | /* win conn failure > retry > succ */ (1 << LWSSSCS_CONNECTED) | diff --git a/minimal-examples-lowlevel/api-tests/api-test-lws_spawn/main.c b/minimal-examples-lowlevel/api-tests/api-test-lws_spawn/main.c index 3c5f0e27c6..0aa3f3fe35 100644 --- a/minimal-examples-lowlevel/api-tests/api-test-lws_spawn/main.c +++ b/minimal-examples-lowlevel/api-tests/api-test-lws_spawn/main.c @@ -166,8 +166,13 @@ reap_cb(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si, test_phase_t last_phase = ts->phase; if (si) { +#if defined(WIN32) + lwsl_user("%s: Reap callback for phase %d, exit code %d\n", + __func__, (int)last_phase, (int)si->retcode); +#else lwsl_user("%s: Reap callback for phase %d, exit code %d\n", __func__, (int)last_phase, si->si_status); +#endif lwsl_notice(" CPU us: user %llu, sys %llu\n", (unsigned long long)res->us_cpu_user, (unsigned long long)res->us_cpu_sys); @@ -179,10 +184,18 @@ reap_cb(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si, lwsl_err("%s: Spawned process was killed by timeout\n", __func__); ts->result = 1; - } else if (si->si_status != 0) { - lwsl_err("%s: Spawned process failed with exit code %d\n", + } else { +#if defined(WIN32) + if (si->retcode != 0) { + lwsl_err("%s: Spawned process failed with exit code %d\n", + __func__, (int)si->retcode); +#else + if (si->si_status != 0) { + lwsl_err("%s: Spawned process failed with exit code %d\n", __func__, si->si_status); - ts->result = 1; +#endif + ts->result = 1; + } } if (res->us_cpu_user == 0 && res->us_cpu_sys == 0) { diff --git a/minimal-examples-lowlevel/http-client/minimal-http-client-multi/CMakeLists.txt b/minimal-examples-lowlevel/http-client/minimal-http-client-multi/CMakeLists.txt index 871e1263be..8c51837c21 100644 --- a/minimal-examples-lowlevel/http-client/minimal-http-client-multi/CMakeLists.txt +++ b/minimal-examples-lowlevel/http-client/minimal-http-client-multi/CMakeLists.txt @@ -33,19 +33,9 @@ if (requirements) # machine context in parallel so they can tread on each other otherwise # set(PORT_HCM_SRV "7670") - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0") - set(PORT_HCM_SRV 7671) + if ("$ENV{SAI_INSTANCE_IDX}") + math(EXPR PORT_HCM_SRV "7671 + $ENV{SAI_INSTANCE_IDX}") endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1") - set(PORT_HCM_SRV 7672) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2") - set(PORT_HCM_SRV 7673) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3") - set(PORT_HCM_SRV 7674) - endif() - # hack if (NOT WIN32 AND LWS_WITH_SERVER) diff --git a/minimal-examples-lowlevel/http-client/minimal-http-client-post/CMakeLists.txt b/minimal-examples-lowlevel/http-client/minimal-http-client-post/CMakeLists.txt index 1efd356413..9d73823b35 100644 --- a/minimal-examples-lowlevel/http-client/minimal-http-client-post/CMakeLists.txt +++ b/minimal-examples-lowlevel/http-client/minimal-http-client-post/CMakeLists.txt @@ -29,19 +29,10 @@ if (requirements) # machine context in parallel so they can tread on each other otherwise # set(PORT_HCP_SRV "7640") - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0") - set(PORT_HCP_SRV 7641) + if ("$ENV{SAI_INSTANCE_IDX}") + math(EXPR PORT_HCP_SRV "7671 + $ENV{SAI_INSTANCE_IDX}") endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1") - set(PORT_HCP_SRV 7642) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2") - set(PORT_HCP_SRV 7643) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3") - set(PORT_HCP_SRV 7644) - endif() - + # hack if (NOT WIN32 AND LWS_WITH_SERVER) diff --git a/minimal-examples-lowlevel/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt b/minimal-examples-lowlevel/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt index 02b16f8f53..5f5110d020 100644 --- a/minimal-examples-lowlevel/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt +++ b/minimal-examples-lowlevel/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt @@ -111,17 +111,8 @@ if (requirements) # set(PORT_HSEF_SRV "961") - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0") - set(PORT_HSEF_SRV 962) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1") - set(PORT_HSEF_SRV 963) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2") - set(PORT_HSEF_SRV 964) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3") - set(PORT_HSEF_SRV 965) + if ("$ENV{SAI_INSTANCE_IDX}") + math(EXPR PORT_HSEF_SRV "962 + $ENV{SAI_INSTANCE_IDX}") endif() if (websockets_shared) diff --git a/minimal-examples-lowlevel/ws-client/minimal-ws-client-spam/CMakeLists.txt b/minimal-examples-lowlevel/ws-client/minimal-ws-client-spam/CMakeLists.txt index c39fcb322d..14132a2728 100644 --- a/minimal-examples-lowlevel/ws-client/minimal-ws-client-spam/CMakeLists.txt +++ b/minimal-examples-lowlevel/ws-client/minimal-ws-client-spam/CMakeLists.txt @@ -27,19 +27,10 @@ if (requirements) # instantiate the server per sai builder instance, they are running in the same # machine context in parallel so they can tread on each other otherwise # - set(PORT_WCS_SRV "7620") - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0") - set(PORT_WCS_SRV 7621) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1") - set(PORT_WCS_SRV 7622) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2") - set(PORT_WCS_SRV 7623) - endif() - if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3") - set(PORT_WCS_SRV 7624) - endif() + set(PORT_WCS_SRV "7620") + if ("$ENV{SAI_INSTANCE_IDX}") + math(EXPR PORT_WCS_SRV "7621 + $ENV{SAI_INSTANCE_IDX}") + endif() # hack if (WIN32) diff --git a/plugins/deaddrop/protocol_lws_deaddrop.c b/plugins/deaddrop/protocol_lws_deaddrop.c index 2a2cce4866..57c8e43c79 100644 --- a/plugins/deaddrop/protocol_lws_deaddrop.c +++ b/plugins/deaddrop/protocol_lws_deaddrop.c @@ -371,20 +371,13 @@ file_upload_cb(void *data, const char *name, const char *filename, static int format_result(struct pss_deaddrop *pss) { - unsigned char *p, *start, *end; - - p = (unsigned char *)pss->result + LWS_PRE; - start = p; - end = p + sizeof(pss->result) - LWS_PRE - 1; - - p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), - "" - "" - ""); - p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), ""); - - return (int)lws_ptr_diff(p, start); + /* + * We don't want to send any entity body back for the upload + * POST. The success / failure is indicated by the + * HTTP response code. The javascript on the client side that + * did the post is not expecting to navigate to a new page. + */ + return 0; } @@ -463,7 +456,7 @@ handler_server_protocol_destroy(struct vhd_deaddrop *vhd) #endif } -static void +static int handler_server_http(struct vhd_deaddrop *vhd, struct pss_deaddrop *pss, struct lws *wsi) { @@ -484,12 +477,14 @@ handler_server_http(struct vhd_deaddrop *vhd, struct pss_deaddrop *pss, meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len); if (meth != LWSHUMETH_POST || !uri_ptr) - return; + return 1; if (!strstr(uri_ptr, "/upload/")) - return; + return 1; pss->vhd = vhd; pss->wsi = wsi; + + return 0; } static int @@ -566,8 +561,8 @@ handler_server_http_writeable(struct vhd_deaddrop *vhd, /* first send the headers ... */ n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), - LWS_WRITE_HTTP_HEADERS | - LWS_WRITE_H2_STREAM_END); + LWS_WRITE_HTTP_HEADERS );//| + //LWS_WRITE_H2_STREAM_END); if (n < 0) return 1; @@ -863,7 +858,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_HTTP: - handler_server_http(vhd, pss, wsi); + if (!handler_server_http(vhd, pss, wsi)) + return 0; break; case LWS_CALLBACK_PROTOCOL_DESTROY: @@ -889,7 +885,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_SERVER_WRITEABLE: - return handler_server_ws_writeable(vhd, pss, wsi); + handler_server_ws_writeable(vhd, pss, wsi); + return 0; /* POST-related */ @@ -898,12 +895,12 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_BODY_COMPLETION: handler_server_http_body_completion(pss, wsi); - break; + return 0; case LWS_CALLBACK_HTTP_WRITEABLE: switch (handler_server_http_writeable(vhd, pss, wsi)) { case 0: - break; + return 0; case 1: goto bail; case 2: