Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}"
67 changes: 51 additions & 16 deletions .sai.json
Original file line number Diff line number Diff line change
@@ -1,40 +1,75 @@
{
"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 --repeat until-pass:3",
"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 --repeat until-pass:3",
"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 --repeat until-pass:3",
"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 --repeat until-pass:3",
"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 --repeat until-pass:3",
"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 --repeat until-pass:3"
]
},
"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 --repeat until-pass:3",
"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} ; rm -flibwebsockets ; ln -sf ../.. libwebsockets",
"cp libwebsockets/minimal-examples/embedded/esp32/${cpack}/sdkconfig . && cp sdkconfig.h build",
". /opt/esp/esp-idf/export.sh ; idf.py set-target esp32 && 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": "",
Expand Down
20 changes: 7 additions & 13 deletions READMEs/README.ctest.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.
10 changes: 10 additions & 0 deletions include/libwebsockets/lws-context-vhost.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,16 @@
* Diffie-Hellman (DH) key exchange ciphers
* (e.g. TLS_DHE_RSA_WITH_AES_256_GCM_SHA384). It's not recommended. */

#define LWS_SERVER_OPTION_MBEDTLS_VERIFY_CLIENT_CERT_POST_HANDSHAKE ((1ll << 41) | \
(1ll << 12))
/**< (VH) An option to be used with mbedtls only, forces server to load
* and store the client cert (without CA dependent check)
* to be able to verify it later (after the handshake);
* provides LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT.
* Note: LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT and
* LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED are ignored if
* LWS_SERVER_OPTION_MBEDTLS_VERIFY_CLIENT_CERT_POST_HANDSHAKE is set */

/****** add new things just above ---^ ******/


Expand Down
31 changes: 29 additions & 2 deletions include/libwebsockets/lws-misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ lws_buflist_linear_use(struct lws_buflist **head, uint8_t *buf, size_t len);
* lws_buflist_fragment_use(): copy and consume <= 1 frag from buflist head
*
* \param head: list head
* \param buf: buffer to copy linearly into
* \param buf: NULL, buffer to copy linearly into
* \param len: length of buffer available
* \param frag_first: pointer to char written on exit to if this is start of frag
* \param frag_fin: pointer to char written on exit to if this is end of frag
Expand All @@ -148,6 +148,10 @@ lws_buflist_linear_use(struct lws_buflist **head, uint8_t *buf, size_t len);
* Since it was consumed, calling again will resume copying out and consuming
* from as far as it got the first time.
*
* It's legal for buf to be NULL and / or len = 0. In this case nothing is
* "used" and the effect is to set `frag_first` according to if we are at the
* start of the fragment and 0 is returned.
*
* Returns the number of bytes written into \p buf.
*/
LWS_VISIBLE LWS_EXTERN int
Expand Down Expand Up @@ -178,6 +182,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
Expand Down Expand Up @@ -1016,13 +1036,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);

Expand Down
13 changes: 11 additions & 2 deletions include/libwebsockets/lws-ws-state.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,30 @@ 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
*/
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
Expand Down
2 changes: 1 addition & 1 deletion lib/core-net/client/connect3.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
const char *cce = "Unable to connect", *iface, *local_port;
const struct sockaddr *psa = NULL;
uint16_t port = wsi->conn_port;
char dcce[48], t16[16];
char dcce[128], t16[16];
lws_dns_sort_t *curr;
ssize_t plen = 0;
lws_dll2_t *d;
Expand Down
2 changes: 2 additions & 0 deletions lib/core-net/private-lib-core-net.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
14 changes: 14 additions & 0 deletions lib/core/buflist.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ lws_buflist_fragment_use(struct lws_buflist **head, uint8_t *buf,
if (frag_fin)
*frag_fin = (*head)->pos + s == (*head)->len;

if (!buf || !len)
return 0;

memcpy(buf, ((uint8_t *)((*head) + 1)) + LWS_PRE + (*head)->pos, s);
len -= s;
buf += s;
Expand Down Expand Up @@ -276,6 +279,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)
{
Expand Down
51 changes: 45 additions & 6 deletions lib/core/libwebsockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
Expand All @@ -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
Expand Down
Loading