diff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml index 1eb1c10b3..4dd1dd74e 100644 --- a/.github/workflows/abi.yml +++ b/.github/workflows/abi.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v3 with: - ref: 'v3.5.0' + ref: 'v3.6.0' path: old - uses: actions/checkout@v3 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 42a61f732..efe333be7 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -48,7 +48,7 @@ jobs: - name: coverage check run: | - min_cov="63.9" + min_cov="63.8" cov=$(~/.local/bin/gcovr -r . -s | grep lines | awk '{ print $2 }' | sed 's/%//') echo "Coverage: ${cov}% (min $min_cov%)" exit $(echo "$cov < $min_cov" | bc -l) diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index e75862bd6..8735a267c 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -11,6 +11,7 @@ on: jobs: build: runs-on: macos-12 + timeout-minutes: 20 env: CMAKE_GENERATOR: Ninja diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 50502aa72..fa3865bbc 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -11,5 +11,5 @@ jobs: - name: build run: | - cmake -B build -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 -DCMAKE_DISABLE_FIND_PACKAGE_OpenSSL=ON -DUSE_OPENSSL=OFF -DCMAKE_C_FLAGS="-DDARWIN -Werror" + cmake -B build -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 -DCMAKE_DISABLE_FIND_PACKAGE_OpenSSL=ON -DUSE_OPENSSL=OFF -DCMAKE_C_FLAGS="-Werror" cmake --build build -- CODE_SIGNING_ALLOWED=NO diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e762c031..35ca7a7f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,54 @@ All notable changes to libre will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v3.6.2] - 2023-11-06 + +## What's Changed +sip/transp: add win32 local transport addr fallback (fixes TCP/TLS register) + + +## [v3.6.1] - 2023-11-03 + +## What's Changed +ice: AI_V4MAPPED doesn't exist on OpenBSD #989 +dialog: REVERT fix rtags of forking INVITE with 100rel (#947) #986 +debian: fix version number + + +## [v3.6.0] - 2023-10-17 + +## What's Changed +* ci/coverage: increase min. coverage by @sreimers in https://github.com/baresip/re/pull/958 +* Implement aufile_set_position by @larsimmisch in https://github.com/baresip/re/pull/943 +* dialog: fix rtags of forking INVITE with 100rel by @maximilianfridrich in https://github.com/baresip/re/pull/947 +* tls/alloc: set default min proto TLS 1.2 by @sreimers in https://github.com/baresip/re/pull/948 +* test: init err to 0 in sdp test (cppcheck) by @alfredh in https://github.com/baresip/re/pull/959 +* main: fd_listen fhs alloc rewrite by @sreimers in https://github.com/baresip/re/pull/805 +* Expand RE_BREAKPOINT macro on ARM64 by @larsimmisch in https://github.com/baresip/re/pull/961 +* jbuf: trace data for plot by @cspiel1 in https://github.com/baresip/re/pull/964 +* trace: use global trace log by @sreimers in https://github.com/baresip/re/pull/965 +* main: use ifdef for RE_TRACE_ENABLED by @sreimers in https://github.com/baresip/re/pull/966 +* test/hexdump: hide output by @sreimers in https://github.com/baresip/re/pull/968 +* trace: remove global default trace json by @sreimers in https://github.com/baresip/re/pull/969 +* ci/ssl: use tools repo and new assets by @sreimers in https://github.com/baresip/re/pull/972 +* fmt: doxygen correction in print.c by @cspiel1 in https://github.com/baresip/re/pull/973 +* trace: use only explicit RE_TRACE_ENABLED by cmake by @sreimers in https://github.com/baresip/re/pull/974 +* cmake: enable C11 for Windows (not MINGW) by @alfredh in https://github.com/baresip/re/pull/970 +* ci/coverage: lower min. coverage by @sreimers in https://github.com/baresip/re/pull/975 +* jbuf: move jbuf to baresip by @cspiel1 in https://github.com/baresip/re/pull/971 +* ci/coverage: improve coverage (enable trace) by @sreimers in https://github.com/baresip/re/pull/976 +* ci: bump pr-dependency-action@v0.6 by @sreimers in https://github.com/baresip/re/pull/977 +* ice: mDNS refactoring by @sreimers in https://github.com/baresip/re/pull/934 +* trace: add flush worker and optimize memory usage by @sreimers in https://github.com/baresip/re/pull/967 +* rtp: fix video jitter calculation and add arrival time rtp header by @sreimers in https://github.com/baresip/re/pull/978 +* ci: remove DARWIN compile flag from iOS build by @alfredh in https://github.com/baresip/re/pull/979 +* thread: add trace thread name logging by @sreimers in https://github.com/baresip/re/pull/980 +* ci/coverage: reduce min. coverage by @sreimers in https://github.com/baresip/re/pull/982 + + +**Full Changelog**: https://github.com/baresip/re/compare/v3.5.1...v3.6.0 + ## [v3.5.1] - 2023-09-12 ## What's Changed diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f10699dc..ebd9036db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,13 +14,13 @@ cmake_minimum_required(VERSION 3.13) project(re - VERSION 3.5.1 + VERSION 3.6.2 LANGUAGES C HOMEPAGE_URL https://github.com/baresip/re DESCRIPTION "Generic library for real-time communications" ) -set(PROJECT_SOVERSION 17) # bump if ABI breaks +set(PROJECT_SOVERSION 18) # bump if ABI breaks # Pre-release identifier, comment out on a release # Increment for breaking changes (dev2, dev3...) diff --git a/README.md b/README.md index e992a7a4b..4801cd922 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ $ sudo ldconfig ### Examples Coding examples are available from the -[redemo](http://creytiv.com/pub/redemo-0.5.0.tar.gz) project +[redemo](https://github.com/creytiv/redemo "creytiv/redemo: Demo example applications using libre") project. ## License @@ -218,6 +218,7 @@ legend: * [RFC 6455](https://tools.ietf.org/html/rfc6455) - The WebSocket Protocol * [RFC 7159](https://tools.ietf.org/html/rfc7159) - JavaScript Object Notation (JSON) * [RFC 7350](https://tools.ietf.org/html/rfc7350) - DTLS as Transport for STUN +* [RFC 7616](https://tools.ietf.org/html/rfc7616) - HTTP Digest Access Authentication * [RFC 7714](https://tools.ietf.org/html/rfc7714) - AES-GCM Authenticated Encryption in SRTP diff --git a/cmake/re-config.cmake b/cmake/re-config.cmake index 7a5983b14..6dc0ad8b6 100644 --- a/cmake/re-config.cmake +++ b/cmake/re-config.cmake @@ -1,6 +1,7 @@ include(CheckIncludeFile) include(CheckFunctionExists) include(CheckSymbolExists) +include(CheckTypeSize) option(USE_MBEDTLS "Enable MbedTLS" OFF) @@ -66,7 +67,11 @@ else() set(Backtrace_LIBRARIES) endif() -check_function_exists(thrd_create HAVE_THREADS) +check_function_exists(thrd_create HAVE_THREADS_FUN) +check_include_file(threads.h HAVE_THREADS_H) +if(HAVE_THREADS_FUN AND HAVE_THREADS_H) + set(HAVE_THREADS CACHE BOOL true) +endif() if(HAVE_THREADS) list(APPEND RE_DEFINITIONS HAVE_THREADS) endif() @@ -135,6 +140,20 @@ if(WIN32) WIN32 _WIN32_WINNT=0x0600 ) + + unset(CMAKE_EXTRA_INCLUDE_FILES) + set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;qos2.h") + check_type_size("QOS_FLOWID" HAVE_QOS_FLOWID BUILTIN_TYPES_ONLY) + check_type_size("PQOS_FLOWID" HAVE_PQOS_FLOWID BUILTIN_TYPES_ONLY) + unset(CMAKE_EXTRA_INCLUDE_FILES) + + if(HAVE_QOS_FLOWID) + list(APPEND RE_DEFINITIONS HAVE_QOS_FLOWID) + endif() + + if(HAVE_PQOS_FLOWID) + list(APPEND RE_DEFINITIONS HAVE_PQOS_FLOWID) + endif() endif() if(USE_OPENSSL) @@ -173,6 +192,8 @@ endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(APPEND RE_DEFINITIONS DARWIN) include_directories(/opt/local/include) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "iOS") + list(APPEND RE_DEFINITIONS DARWIN) elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") list(APPEND RE_DEFINITIONS FREEBSD) elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") diff --git a/debian/changelog b/debian/changelog index 17decc6f4..2cce21097 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +libre (3.6.2) unstable; urgency=medium + + * version 3.6.2 + + -- Sebastian Reimers Mon, 6 Nov 2023 14:00:00 +0200 + +libre (3.6.1) unstable; urgency=medium + + * version 3.6.1 + + -- Sebastian Reimers Fri, 3 Nov 2023 14:00:00 +0200 + libre (3.5.1) unstable; urgency=medium * version 3.5.1 diff --git a/include/re_fmt.h b/include/re_fmt.h index 13d0783ba..af4cd1841 100644 --- a/include/re_fmt.h +++ b/include/re_fmt.h @@ -29,6 +29,7 @@ struct pl { extern const struct pl pl_null; +struct pl *pl_alloc_str(const char *str); void pl_set_str(struct pl *pl, const char *str); void pl_set_mbuf(struct pl *pl, const struct mbuf *mb); int32_t pl_i32(const struct pl *pl); diff --git a/include/re_httpauth.h b/include/re_httpauth.h index 0fce26dbd..758a90862 100644 --- a/include/re_httpauth.h +++ b/include/re_httpauth.h @@ -35,6 +35,28 @@ struct httpauth_digest_chall { struct pl userhash; }; +struct httpauth_digest_enc_resp { + char *realm; + char *nonce; + char *opaque; + char *algorithm; + char *qop; + + /* response specific */ + char *response; + char *username; + char *username_star; + char *uri; + uint32_t cnonce; + uint32_t nc; + + /* optional */ + char *charset; + bool userhash; + void (*hashh)(const uint8_t *, size_t, uint8_t *); + size_t hash_length; +}; + /** HTTP Digest response */ struct httpauth_digest_resp { struct pl realm; @@ -81,6 +103,21 @@ int httpauth_digest_response_encode(const struct httpauth_digest_resp *resp, struct mbuf *mb); +int httpauth_digest_response_print(struct re_printf *pf, + const struct httpauth_digest_enc_resp *resp); +int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *user, const char *passwd, const char *entitybody, + const uint32_t cnonce, const uint32_t nc_); +int httpauth_digest_response(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody); +int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody, const char *charset, const bool userhash); + int httpauth_digest_chall_req_print(struct re_printf *pf, const struct httpauth_digest_chall_req *req); int httpauth_digest_chall_request(struct httpauth_digest_chall_req **preq, diff --git a/include/re_sipsess.h b/include/re_sipsess.h index 28cc2b6cc..87006197b 100644 --- a/include/re_sipsess.h +++ b/include/re_sipsess.h @@ -73,3 +73,4 @@ bool sipsess_refresh_allowed(const struct sipsess *sess); void sipsess_close_all(struct sipsess_sock *sock); struct sip_dialog *sipsess_dialog(const struct sipsess *sess); void sipsess_abort(struct sipsess *sess); +bool sipsess_ack_pending(const struct sipsess *sess); diff --git a/include/re_trace.h b/include/re_trace.h index e3e9710e2..96fe48702 100644 --- a/include/re_trace.h +++ b/include/re_trace.h @@ -3,6 +3,8 @@ * JSON traces (chrome://tracing) */ +struct pl; + typedef enum { RE_TRACE_ARG_NONE, RE_TRACE_ARG_INT, @@ -14,37 +16,46 @@ typedef enum { int re_trace_init(const char *json_file); int re_trace_close(void); int re_trace_flush(void); -void re_trace_event(const char *cat, const char *name, char ph, void *id, - int32_t async_id, re_trace_arg_type arg_type, - const char *arg_name, void *arg_value); +void re_trace_event(const char *cat, const char *name, char ph, struct pl *id, + re_trace_arg_type arg_type, const char *arg_name, + void *arg_value); #ifdef RE_TRACE_ENABLED #define RE_TRACE_BEGIN(c, n) \ - re_trace_event(c, n, 'B', 0, 0, RE_TRACE_ARG_NONE, NULL, NULL) + re_trace_event(c, n, 'B', NULL, RE_TRACE_ARG_NONE, NULL, NULL) #define RE_TRACE_END(c, n) \ - re_trace_event(c, n, 'E', 0, 0, RE_TRACE_ARG_NONE, NULL, NULL) + re_trace_event(c, n, 'E', NULL, RE_TRACE_ARG_NONE, NULL, NULL) #define RE_TRACE_ID_BEGIN(c, n, id) \ - re_trace_event(c, n, 'B', 0, id, RE_TRACE_ARG_NONE, NULL, NULL) + re_trace_event(c, n, 'B', id, RE_TRACE_ARG_NONE, NULL, NULL) #define RE_TRACE_ID_END(c, n, id) \ - re_trace_event(c, n, 'E', 0, id, RE_TRACE_ARG_NONE, NULL, NULL) + re_trace_event(c, n, 'E', id, RE_TRACE_ARG_NONE, NULL, NULL) #define RE_TRACE_INSTANT(c, n) \ - re_trace_event(c, n, 'I', 0, 0, RE_TRACE_ARG_NONE, NULL, NULL) + re_trace_event(c, n, 'I', NULL, RE_TRACE_ARG_NONE, NULL, NULL) #define RE_TRACE_INSTANT_C(c, n, vname, str) \ - re_trace_event(c, n, 'I', 0, 0, RE_TRACE_ARG_STRING_CONST, \ + re_trace_event(c, n, 'I', NULL, RE_TRACE_ARG_STRING_CONST, \ vname, (void *)(str)) #define RE_TRACE_INSTANT_I(c, n, i) \ - re_trace_event(c, n, 'I', 0, 0, RE_TRACE_ARG_INT, \ + re_trace_event(c, n, 'I', NULL, RE_TRACE_ARG_INT, \ + n, (void *)(intptr_t)i) + +#define RE_TRACE_ID_INSTANT(c, n, id) \ + re_trace_event(c, n, 'I', id, RE_TRACE_ARG_NONE, NULL, NULL) +#define RE_TRACE_ID_INSTANT_C(c, n, vname, str, id) \ + re_trace_event(c, n, 'I', id, RE_TRACE_ARG_STRING_CONST, \ + vname, (void *)(str)) +#define RE_TRACE_ID_INSTANT_I(c, n, i, id) \ + re_trace_event(c, n, 'I', id, RE_TRACE_ARG_INT, \ n, (void *)(intptr_t)i) #define RE_TRACE_PROCESS_NAME(n) \ - re_trace_event("", "process_name", 'M', 0, 0, \ + re_trace_event("", "process_name", 'M', NULL, \ RE_TRACE_ARG_STRING_COPY, \ "name", (void *)(n)) #define RE_TRACE_THREAD_NAME(n) \ - re_trace_event("", "thread_name", 'M', 0, 0, \ + re_trace_event("", "thread_name", 'M', NULL, \ RE_TRACE_ARG_STRING_COPY, \ "name", (void *)(n)) @@ -57,6 +68,9 @@ void re_trace_event(const char *cat, const char *name, char ph, void *id, #define RE_TRACE_INSTANT(c, n) #define RE_TRACE_INSTANT_C(c, n, str) #define RE_TRACE_INSTANT_I(c, n, i) +#define RE_TRACE_ID_INSTANT(c, n, id) +#define RE_TRACE_ID_INSTANT_C(c, n, str, id) +#define RE_TRACE_ID_INSTANT_I(c, n, i, id) #define RE_TRACE_PROCESS_NAME(n) #define RE_TRACE_THREAD_NAME(n) diff --git a/include/re_types.h b/include/re_types.h index 35d9d5992..c56ab2ed1 100644 --- a/include/re_types.h +++ b/include/re_types.h @@ -346,12 +346,31 @@ typedef int re_sock_t; #define RE_ARG_14(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_13(__VA_ARGS__) #define RE_ARG_15(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_14(__VA_ARGS__) #define RE_ARG_16(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_15(__VA_ARGS__) - -#define RE_ARG_VA_NUM_2(X, X16, X15, X14, X13, X12, X11, X10, X9, X8, X7, X6, \ - X5, X4, X3, X2, X1, N, ...) \ +#define RE_ARG_17(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_16(__VA_ARGS__) +#define RE_ARG_18(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_17(__VA_ARGS__) +#define RE_ARG_19(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_18(__VA_ARGS__) +#define RE_ARG_20(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_19(__VA_ARGS__) +#define RE_ARG_21(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_20(__VA_ARGS__) +#define RE_ARG_22(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_21(__VA_ARGS__) +#define RE_ARG_23(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_22(__VA_ARGS__) +#define RE_ARG_24(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_23(__VA_ARGS__) +#define RE_ARG_25(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_24(__VA_ARGS__) +#define RE_ARG_26(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_25(__VA_ARGS__) +#define RE_ARG_27(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_26(__VA_ARGS__) +#define RE_ARG_28(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_27(__VA_ARGS__) +#define RE_ARG_29(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_28(__VA_ARGS__) +#define RE_ARG_30(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_29(__VA_ARGS__) +#define RE_ARG_31(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_30(__VA_ARGS__) +#define RE_ARG_32(expr, ...) RE_ARG_SIZE(expr), (expr), RE_ARG_31(__VA_ARGS__) + +#define RE_ARG_VA_NUM_2(X, X32, X31, X30, X29, X28, X27, X26, X25, X24, X23, \ + X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, \ + X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, N, \ + ...) \ N #define RE_ARG_VA_NUM(...) \ - RE_ARG_VA_NUM_2(0, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, \ + RE_ARG_VA_NUM_2(0, ##__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, \ + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define RE_ARG_N3(N, ...) RE_ARG_##N(__VA_ARGS__) diff --git a/mk/Doxyfile b/mk/Doxyfile index dde38601b..cd59dc60a 100644 --- a/mk/Doxyfile +++ b/mk/Doxyfile @@ -4,7 +4,7 @@ # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = libre -PROJECT_NUMBER = 3.5.1 +PROJECT_NUMBER = 3.6.2 OUTPUT_DIRECTORY = ../re-dox CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/src/async/async.c b/src/async/async.c index 7d37ac7f8..9d1787647 100644 --- a/src/async/async.c +++ b/src/async/async.c @@ -68,8 +68,10 @@ static int worker_thread(void *arg) work = le->data; mtx_lock(work->mtx); - if (work->workh) + if (work->workh) { work->err = work->workh(work->arg); + work->workh = NULL; + } mtx_unlock(work->mtx); mtx_lock(&a->mtx); @@ -101,14 +103,18 @@ static void async_destructor(void *data) LIST_FOREACH(&async->workl, le) { struct async_work *work = le->data; - if (work->cb) + if (work->cb) { work->cb(ECANCELED, work->arg); + work->cb = NULL; + } } LIST_FOREACH(&async->curl, le) { struct async_work *work = le->data; - if (work->cb) + if (work->cb) { work->cb(ECANCELED, work->arg); + work->cb = NULL; + } } list_flush(&async->workl); @@ -146,8 +152,10 @@ static void queueh(int id, void *data, void *arg) (void)id; mtx_lock(work->mtx); - if (work->cb) + if (work->cb) { work->cb(work->err, work->arg); + work->cb =NULL; + } mtx_unlock(work->mtx); mtx_lock(&async->mtx); @@ -351,7 +359,8 @@ void re_async_cancel(struct re_async *async, intptr_t id) w->workh = NULL; w->cb = NULL; w->arg = mem_deref(w->arg); - list_move(&w->le, &async->freel); + /* No move to free list since queueh must always handled if + * mqueue_push is called */ mtx_unlock(w->mtx); } diff --git a/src/fmt/pl.c b/src/fmt/pl.c index 32edd193b..72ebfa4e8 100644 --- a/src/fmt/pl.c +++ b/src/fmt/pl.c @@ -21,6 +21,48 @@ const struct pl pl_null = {NULL, 0}; +static void pl_alloc_destruct(void *arg) +{ + struct pl *pl = arg; + + mem_deref((void *)pl->p); +} + + +/** + * Allocate a pointer-length object from a NULL-terminated string + * + * @param str NULL-terminated string + * + * @return Allocated Pointer-length object or NULL + */ +struct pl *pl_alloc_str(const char *str) +{ + struct pl *pl; + + if (!str) + return NULL; + + size_t sz = strlen(str); + + pl = mem_zalloc(sizeof(struct pl), pl_alloc_destruct); + if (!pl) + return NULL; + + pl->p = mem_alloc(sz, NULL); + if (!pl->p) { + mem_deref(pl); + return NULL; + } + + memcpy((void *)pl->p, str, sz); + + pl->l = sz; + + return pl; +} + + /** * Initialise a pointer-length object from a NULL-terminated string * diff --git a/src/httpauth/digest.c b/src/httpauth/digest.c index 1358fd450..5bd6c3a25 100644 --- a/src/httpauth/digest.c +++ b/src/httpauth/digest.c @@ -20,17 +20,28 @@ typedef void (digest_decode_h)(const struct pl *name, const struct pl *val, void *arg); -static const struct pl param_algorithm = PL("algorithm"); -static const struct pl param_cnonce = PL("cnonce"); -static const struct pl param_nc = PL("nc"); +/* General fields */ +static const struct pl param_realm = PL("realm"); static const struct pl param_nonce = PL("nonce"); static const struct pl param_opaque = PL("opaque"); +static const struct pl param_algorithm = PL("algorithm"); static const struct pl param_qop = PL("qop"); -static const struct pl param_realm = PL("realm"); +static const struct pl param_stale = PL("stale"); + +/* Challenge fields */ +static const struct pl param_domain = PL("domain"); + +/* Response fields */ static const struct pl param_response = PL("response"); static const struct pl param_uri = PL("uri"); static const struct pl param_username = PL("username"); -static const struct pl param_stale = PL("stale"); +/* static const struct pl param_userstar = PL("username*"); future use */ +static const struct pl param_cnonce = PL("cnonce"); +static const struct pl param_nc = PL("nc"); + +/* Optional fields */ +static const struct pl param_charset = PL("charset"); +static const struct pl param_userhash = PL("userhash"); static void challenge_decode(const struct pl *name, const struct pl *val, @@ -40,6 +51,8 @@ static void challenge_decode(const struct pl *name, const struct pl *val, if (!pl_casecmp(name, ¶m_realm)) chall->realm = *val; + else if (!pl_casecmp(name, ¶m_domain)) + chall->domain = *val; else if (!pl_casecmp(name, ¶m_nonce)) chall->nonce = *val; else if (!pl_casecmp(name, ¶m_opaque)) @@ -50,6 +63,10 @@ static void challenge_decode(const struct pl *name, const struct pl *val, chall->algorithm = *val; else if (!pl_casecmp(name, ¶m_qop)) chall->qop = *val; + else if (!pl_casecmp(name, ¶m_charset)) + chall->charset = *val; + else if (!pl_casecmp(name, ¶m_userhash)) + chall->userhash = *val; } @@ -591,3 +608,366 @@ int httpauth_digest_chall_request_full(struct httpauth_digest_chall_req **preq, return err; } + + +static void httpauth_digest_response_destructor(void *arg) +{ + struct httpauth_digest_enc_resp *resp = arg; + + mem_deref(resp->realm); + mem_deref(resp->nonce); + mem_deref(resp->opaque); + mem_deref(resp->algorithm); + mem_deref(resp->qop); + mem_deref(resp->response); + mem_deref(resp->username); + mem_deref(resp->username_star); + mem_deref(resp->uri); + mem_deref(resp->charset); +} + + +static int digest_response(struct httpauth_digest_enc_resp *resp, + const struct httpauth_digest_chall *chall, + const struct pl *method, const char *user, + const char *passwd, const char *entitybody) +{ + uint8_t *hash1 = NULL; + uint8_t *hash2 = NULL; + struct mbuf *mb = NULL; + size_t hashstringl = (resp->hash_length * 2) + 1; + int err = 0, n = 0; + + if (!resp || !resp->hashh) + return EINVAL; + + mb = mbuf_alloc(str_len(user) + str_len(passwd) + chall->realm.l + 2); + if (!mb) + return ENOMEM; + + hash1 = mem_zalloc(resp->hash_length, NULL); + hash2 = mem_zalloc(resp->hash_length, NULL); + if (!resp->response) + resp->response = mem_zalloc(hashstringl, NULL); + + if (!resp->response || !hash1 || !hash2) { + err = ENOMEM; + goto out; + } + + /* HASH A2 */ + if (str_isset(resp->qop) && str_str(resp->qop, "auth-int")) { + if (!entitybody || str_casecmp(entitybody, "") == 0) { + resp->hashh((uint8_t *)"", 0, hash1); + } + else { + resp->hashh((uint8_t *)entitybody, + str_len(entitybody), hash1); + } + + err = mbuf_printf(mb, "%r:%s:%w", + method, resp->uri, hash1, resp->hash_length); + } + else { + err = mbuf_printf(mb, "%r:%s", method, resp->uri); + } + + if (err) + goto out; + + resp->hashh(mb->buf, mb->end, hash2); + mbuf_rewind(mb); + + /* HASH A1 */ + if (resp->userhash) { + if (!resp->username) + resp->username = mem_zalloc(hashstringl, NULL); + + if (!resp->username) { + err = ENOMEM; + goto out; + } + + err = mbuf_printf(mb, "%s:%s", user, resp->realm); + if (err) + goto out; + + resp->hashh(mb->buf, mb->end, hash1); + n = re_snprintf(resp->username, hashstringl, "%w", + hash1, hashstringl); + if (n == -1 || n != (int)hashstringl -1) { + err = ERANGE; + goto out; + } + + mbuf_rewind(mb); + err = mbuf_printf(mb, "%w:%s:%s", + hash1, resp->hash_length, resp->realm, passwd); + } + else { + err = mbuf_printf(mb, "%s:%s:%s", user, resp->realm, passwd); + resp->username = mem_deref(resp->username); + err |= str_dup(&resp->username, user); + } + + if (err) + goto out; + + resp->hashh(mb->buf, mb->end, hash1); + mbuf_rewind(mb); + + if (str_str(resp->algorithm, "-sess")) { + err = mbuf_printf(mb, "%w:%s:%08x", + hash1, resp->hash_length, resp->nonce, resp->cnonce); + if (err) + goto out; + + resp->hashh(mb->buf, mb->end, hash1); + mbuf_rewind(mb); + } + + /* DIGEST */ + if (str_isset(resp->qop)) { + err = mbuf_printf(mb, "%w:%s:%08x:%08x:%s:%w", + hash1, resp->hash_length, resp->nonce, resp->nc, + resp->cnonce, resp->qop, hash2, resp->hash_length); + } + else { + err = mbuf_printf(mb, "%w:%s:%w", hash1, resp->hash_length, + resp->nonce, hash2, resp->hash_length); + } + + if (err) + goto out; + + resp->hashh(mb->buf, mb->end, hash1); + n = re_snprintf(resp->response, hashstringl, "%w", + hash1, resp->hash_length); + if (n == -1 || n != (int)hashstringl - 1) + err = ERANGE; + +out: + mem_deref(mb); + mem_deref(hash1); + mem_deref(hash2); + + return err; +} + + +/** + * Prints / encodes an HTTP digest response + * + * @param pf Re_printf object + * @param resp Response to print + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response_print(struct re_printf *pf, + const struct httpauth_digest_enc_resp *resp) +{ + int err = 0; + + if (!resp) + return EINVAL; + + /* historical reason quoted strings: */ + /* username, realm, nonce, uri, */ + /* response, cnonce, opaque */ + /* historical reason unquoted strings: */ + /* qop, algorithm, nc */ + err = re_hprintf(pf, "Digest realm=\"%s\"," + " nonce=\"%s\", username=\"%s\", uri=\"%s\"," + " response=\"%s\"", + resp->realm, resp->nonce, resp->username, + resp->uri, resp->response); + + if (str_isset(resp->opaque)) + err |= re_hprintf(pf, ", opaque=\"%s\"", resp->opaque); + if (str_isset(resp->algorithm)) + err |= re_hprintf(pf, ", algorithm=%s", resp->algorithm); + if (str_isset(resp->qop)) + err |= re_hprintf(pf, ", qop=%s, cnonce=\"%08x\", nc=\"%08x\"", + resp->qop, resp->cnonce, resp->nc); + + if (resp->userhash) + err |= re_hprintf(pf, ", userhash=true"); + if (str_isset(resp->charset)) + err |= re_hprintf(pf, ", charset=\"%s\"", resp->charset); + + return err; +} + + +/** + * Set cnonce and nc and recalculate the response value. + * This function should be used only for unit tests + * + * @param resp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param user Username + * @param passwd User password + * @param entitybody Entitybody if qop=auth-int + * @param cnonce Cnonce + * @param nonce_counter Nonce counter + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *user, const char *passwd, const char *entitybody, + uint32_t cnonce, uint32_t nonce_counter) +{ + if (!resp || !chall || !method || !passwd) + return EINVAL; + + resp->cnonce = cnonce; + resp->nc = nonce_counter; + + return digest_response(resp, chall, method, + user, passwd, entitybody); +} + + +/** + * Create a digest authentication response + * + * @param presp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param uri Accessed uri + * @param user Username + * @param passwd User password + * @param qop Quality of protection + * @param entitybody Entitybody if qop=auth-int + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody) +{ + return httpauth_digest_response_full(presp, chall, method, uri, + user, passwd, qop, entitybody, NULL, false); +} + + +/** + * Create a full configurable digest authentication response + * + * @param presp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param uri Accessed uri + * @param user Username + * @param passwd User password + * @param qop Quality of protection + * @param entitybody Entitybody if qop=auth-int + * @param charset Used character set (only UTF-8 or NULL allowed) + * @param userhash Enable hashed usernames + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody, const char *charset, const bool userhash) +{ + struct httpauth_digest_enc_resp *resp = NULL; + int err = 0; + + if (!presp || !chall || !method || !uri || !user || !passwd) + return EINVAL; + + resp = mem_zalloc(sizeof(*resp), httpauth_digest_response_destructor); + if (!resp) { + return ENOMEM; + } + + /* create cnonce & nonce count */ + resp->cnonce = rand_u32(); + resp->nc = nc++; + + /* copy fields */ + err = pl_strdup(&resp->realm, &chall->realm); + err |= pl_strdup(&resp->nonce, &chall->nonce); + err |= pl_strdup(&resp->opaque, &chall->opaque); + if (err) { + goto out; + } + + /* userhash supported by server */ + if (userhash && (pl_strcasecmp(&chall->userhash, "true") == 0)) + resp->userhash = true; + + /* only allowed qop Nothing, "auth" or "auth-int" */ + if (str_isset(qop) && (str_casecmp(qop, "auth")) && + (str_casecmp(qop, "auth-int"))) { + err = EPROTONOSUPPORT; + goto out; + } + + /* qop supported by server */ + if (pl_isset(&chall->qop) && str_isset(qop) && + pl_strstr(&chall->qop, qop)) { + err = str_dup(&resp->qop, qop); + if (err) + goto out; + } + + /* only allowed charset Nothing or "UTF-8" */ + if (str_isset(charset) && str_casecmp(charset, "UTF-8")) { + err = EPROTONOSUPPORT; + goto out; + } + + /* charset supported by server */ + if (pl_isset(&chall->charset) && str_isset(charset) && + pl_strstr(&chall->charset, charset) == 0) { + err = str_dup(&resp->charset, charset); + if (err) + goto out; + } + + err = str_dup(&resp->uri, uri); + if (err) + goto out; + + if (pl_strstr(&chall->algorithm, "SHA-256-sess")) { + resp->hashh = &sha256; + resp->hash_length = SHA256_DIGEST_LENGTH; + err = str_dup(&resp->algorithm, "SHA-256-sess"); + } + else if (pl_strstr(&chall->algorithm, "SHA-256")) { + resp->hashh = &sha256; + resp->hash_length = SHA256_DIGEST_LENGTH; + err = str_dup(&resp->algorithm, "SHA-256"); + } + else if (pl_strstr(&chall->algorithm, "MD5-sess")) { + resp->hashh = &md5; + resp->hash_length = MD5_SIZE; + err = str_dup(&resp->algorithm, "MD5-sess"); + } + else if (!pl_isset(&chall->algorithm) || + pl_strstr(&chall->algorithm, "MD5")) { + resp->hashh = &md5; + resp->hash_length = MD5_SIZE; + err = str_dup(&resp->algorithm, "MD5"); + } + else { + err = EPROTONOSUPPORT; + goto out; + } + + err = digest_response(resp, chall, method, user, passwd, entitybody); + +out: + if (err) + mem_deref(resp); + else + *presp = resp; + + return err; +} diff --git a/src/ice/icesdp.c b/src/ice/icesdp.c index 41a8b113f..1917ff327 100644 --- a/src/ice/icesdp.c +++ b/src/ice/icesdp.c @@ -209,7 +209,11 @@ static int getaddr_rcand(void *arg) { struct rcand *rcand = arg; struct addrinfo *res, *res0 = NULL; +#ifndef OPENBSD struct addrinfo hints = {.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG, +#else + struct addrinfo hints = {.ai_flags = AI_ADDRCONFIG, +#endif .ai_family = rcand->ai_family}; int err; diff --git a/src/rtp/rtp.c b/src/rtp/rtp.c index 9f5205d46..76d73cf5f 100644 --- a/src/rtp/rtp.c +++ b/src/rtp/rtp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "rtcp.h" @@ -38,7 +39,7 @@ struct rtp_sock { rtcp_recv_h *rtcph; /**< RTCP Receive handler */ void *arg; /**< Handler argument */ struct rtcp_sess *rtcp; /**< RTCP Session */ - bool rtcp_mux; /**< RTP/RTCP multiplexing */ + RE_ATOMIC bool rtcp_mux; /**< RTP/RTCP multiplexing */ }; @@ -187,7 +188,7 @@ static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg) int err; /* Handle RTCP multiplexed on RTP-port */ - if (rs->rtcp_mux) { + if (re_atomic_rlx(&rs->rtcp_mux)) { uint8_t pt; if (mbuf_get_left(mb) < 2) @@ -681,7 +682,7 @@ void rtcp_enable_mux(struct rtp_sock *rs, bool enabled) if (!rs) return; - rs->rtcp_mux = enabled; + re_atomic_rlx_set(&rs->rtcp_mux, enabled); } @@ -699,7 +700,7 @@ int rtcp_send(struct rtp_sock *rs, struct mbuf *mb) if (!rs) return EINVAL; - sock = rs->rtcp_mux ? rs->sock_rtp : rs->sock_rtcp; + sock = re_atomic_rlx(&rs->rtcp_mux) ? rs->sock_rtp : rs->sock_rtcp; if (!sock || !sa_isset(&rs->rtcp_peer, SA_ALL)) return EINVAL; diff --git a/src/sip/dialog.c b/src/sip/dialog.c index aef4b7449..4585e22b6 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -35,7 +35,6 @@ struct sip_dialog { uint32_t lseq; uint32_t rseq; size_t cpos; - size_t rpos; enum sip_transp tp; uint32_t srcport; }; @@ -120,7 +119,7 @@ int sip_dialog_alloc(struct sip_dialog **dlgp, rend = dlg->mb->pos - 2; } err |= mbuf_printf(dlg->mb, "To: <%s>\r\n", to_uri); - dlg->cpos = dlg->rpos = dlg->mb->pos; + dlg->cpos = dlg->mb->pos; err |= mbuf_printf(dlg->mb, "From: %s%s%s<%s>;tag=%016llx\r\n", from_name ? "\"" : "", from_name, from_name ? "\" " : "", @@ -309,7 +308,6 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) msg->req ? &msg->from.val : &msg->to.val); dlg->mb->pos = dlg->cpos; - dlg->rpos = renc.mb->pos; err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb), mbuf_get_left(dlg->mb)); dlg->mb->pos = 0; @@ -464,8 +462,6 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_addr addr; - struct route_enc renc; - struct pl pl; char *uri; int err; @@ -479,43 +475,14 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; - renc.mb = mbuf_alloc(512); - if (!renc.mb) - return ENOMEM; - err = pl_strdup(&uri, &addr.auri); if (err) return err; - renc.end = 0; - - err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, - record_route_handler, &renc) ? EINVAL : 0; - err |= mbuf_printf(renc.mb, "To: %r\r\n", - msg->req ? &msg->from.val : &msg->to.val); - - dlg->mb->pos = dlg->rpos; - dlg->rpos = renc.mb->pos; - err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb), - mbuf_get_left(dlg->mb)); - dlg->mb->pos = 0; - - if (err) - goto out; - - renc.mb->pos = 0; + if (dlg->route.scheme.p == dlg->uri) { - if (renc.end) { - pl.p = (const char *)mbuf_buf(renc.mb) + ROUTE_OFFSET; - pl.l = renc.end - ROUTE_OFFSET; - err = sip_addr_decode(&addr, &pl); - if (err) - goto out; - - dlg->route = addr.uri; - } - else { struct uri tmp; + struct pl pl; pl_set_str(&pl, uri); err = uri_decode(&tmp, &pl); @@ -525,14 +492,10 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) dlg->route = tmp; } - mem_deref(dlg->mb); mem_deref(dlg->uri); - - dlg->mb = mem_ref(renc.mb); dlg->uri = mem_ref(uri); out: - mem_deref(renc.mb); mem_deref(uri); return err; diff --git a/src/sip/transp.c b/src/sip/transp.c index eb7717b3e..ada515522 100644 --- a/src/sip/transp.c +++ b/src/sip/transp.c @@ -792,8 +792,22 @@ static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure, if (err) goto out; - if (connh) + /* Fallback check for any address win32 */ + if (!sa_isset(&conn->laddr, SA_ALL)) { + uint16_t port = sa_port(&conn->laddr); + err = sip_transp_laddr(sip, &conn->laddr, conn->tp, dst); + if (err) + goto out; + + if (port) + sa_set_port(&conn->laddr, port); + } + + if (connh) { err = connh(&conn->laddr, dst, mb, arg); + if (err) + goto out; + } (void)tcp_conn_settos(conn->tc, sip->tos); #ifdef USE_TLS diff --git a/src/sipsess/sess.c b/src/sipsess/sess.c index e919e0d65..bb62db33c 100644 --- a/src/sipsess/sess.c +++ b/src/sipsess/sess.c @@ -352,3 +352,17 @@ bool sipsess_refresh_allowed(const struct sipsess *sess) return ((sess->established || sess->refresh_allowed) && !sess->terminated && !sess->awaiting_answer); } + + +/** + * Return true if there is an open SIP Session Reply for which an ACK is + * expected + * + * @param sess SIP Session + * + * @return True if ACK is pending, otherwise false + */ +bool sipsess_ack_pending(const struct sipsess *sess) +{ + return sess && sess->replyl.head ? true : false; +} diff --git a/src/thread/thread.c b/src/thread/thread.c index 559df5f07..c3e16af8e 100644 --- a/src/thread/thread.c +++ b/src/thread/thread.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef HAVE_PRCTL #include #endif @@ -97,6 +98,7 @@ static int handler(void *p) (void)pthread_setname_np(*th.thr, th.name); #endif #endif + RE_TRACE_THREAD_NAME(th.name); return th.func(th.arg); } diff --git a/src/trace/trace.c b/src/trace/trace.c index d927953d7..980d41860 100644 --- a/src/trace/trace.c +++ b/src/trace/trace.c @@ -49,7 +49,7 @@ struct trace_event { const char *name; const char *cat; - void *id; + struct pl *id; uint64_t ts; int pid; unsigned long tid; @@ -243,8 +243,9 @@ int re_trace_flush(void) int i, flush_count; struct trace_event *event_tmp; struct trace_event *e; - char json_arg[256]; - char name[128]; + char json_arg[256] = {0}; + char name[128] = {0}; + char id_str[128] = {0}; #ifndef RE_TRACE_ENABLED return 0; @@ -291,12 +292,20 @@ int re_trace_flush(void) re_snprintf(name, sizeof(name), "\"name\":\"%s\"", e->name); + if (e->id) { + re_snprintf(id_str, sizeof(id_str), ", \"id\":\"%r\"", + e->id); + mem_deref(e->id); + } + (void)re_fprintf(trace.f, - "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%lu,\"ts\":%llu," - "\"ph\":\"%c\",%s%s}", + "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%lu,\"ts\":%Lu," + "\"ph\":\"%c\",%s%s%s}", trace.new ? "" : ",\n", e->cat, e->pid, e->tid, e->ts - trace.start_time, - e->ph, name, str_isset(json_arg) ? json_arg : ""); + e->ph, name, + e->id ? id_str : "", + str_isset(json_arg) ? json_arg : ""); trace.new = false; } @@ -305,9 +314,9 @@ int re_trace_flush(void) } -void re_trace_event(const char *cat, const char *name, char ph, void *id, - int32_t custom_id, re_trace_arg_type arg_type, - const char *arg_name, void *arg_value) +void re_trace_event(const char *cat, const char *name, char ph, struct pl *id, + re_trace_arg_type arg_type, const char *arg_name, + void *arg_value) { struct trace_event *e; @@ -329,17 +338,12 @@ void re_trace_event(const char *cat, const char *name, char ph, void *id, mtx_unlock(&trace.lock); e->ts = tmr_jiffies_usec(); - e->id = id; + e->id = mem_ref(id); e->ph = ph; e->cat = cat; e->name = name; e->pid = get_process_id(); - if (custom_id) { - e->tid = custom_id; - } - else { - e->tid = get_thread_id(); - } + e->tid = get_thread_id(); e->arg_type = arg_type; e->arg_name = arg_name; diff --git a/src/udp/udp.c b/src/udp/udp.c index 496e7581d..18b58d8f3 100644 --- a/src/udp/udp.c +++ b/src/udp/udp.c @@ -28,13 +28,19 @@ #include #include #ifdef WIN32 -#if !defined(_MSC_VER) -typedef UINT32 QOS_FLOWID, *PQOS_FLOWID; +#ifndef HAVE_QOS_FLOWID +typedef UINT32 QOS_FLOWID; +#endif + +#ifndef HAVE_PQOS_FLOWID +typedef UINT32 *PQOS_FLOWID; +#endif + +#include + #ifndef QOS_NON_ADAPTIVE_FLOW #define QOS_NON_ADAPTIVE_FLOW 0x00000002 #endif -#endif /*!_MSC_VER*/ -#include #endif /*WIN32*/ #define DEBUG_MODULE "udp" diff --git a/test/fmt.c b/test/fmt.c index 79a93aecc..6eb9ef807 100644 --- a/test/fmt.c +++ b/test/fmt.c @@ -138,6 +138,24 @@ int test_fmt_pl(void) } +int test_fmt_pl_alloc_str(void) +{ + int err = 0; + char test_str[] = "Test String"; + + struct pl *pl = pl_alloc_str(test_str); + if (!pl) + return ENOMEM; + + TEST_MEMCMP(test_str, str_len(test_str), pl->p, pl->l); + +out: + mem_deref(pl); + + return err; +} + + int test_fmt_pl_i32(void) { const struct { diff --git a/test/httpauth.c b/test/httpauth.c index 4c01a981a..cc0c91ec4 100644 --- a/test/httpauth.c +++ b/test/httpauth.c @@ -45,6 +45,9 @@ static bool chall_equal(const struct httpauth_digest_chall *a, err |= pl_equal("stale", &a->stale, &b->stale); err |= pl_equal("algorithm", &a->algorithm, &b->algorithm); err |= pl_equal("qop", &a->qop, &b->qop); + err |= pl_equal("domain", &a->domain, &b->domain); + err |= pl_equal("charset", &a->charset, &b->charset); + err |= pl_equal("userhash", &a->userhash, &b->userhash); return err == 0; } @@ -371,38 +374,23 @@ int test_httpauth_digest_request(void) }, { "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA256", + " nonce=\"%s\", algorithm=SHA-256", "/my/home", NULL, "localhost:5060", NULL, false, - "SHA256", "auth", NULL, false, 0 + "SHA-256", "auth", NULL, false, 0 }, { "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA256-sess, stale=true", + " nonce=\"%s\", algorithm=SHA-256-sess, stale=true", "/my/home", NULL, "localhost:5060", NULL, true, - "SHA256-sess", "auth", NULL, false, 0 + "SHA-256-sess", "auth", NULL, false, 0 }, { "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA1," - " stale=true, userhash=true", - "/my/home", NULL, "localhost:5060", NULL, true, - "SHA1", "auth", NULL, true, 0 - }, - { - "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA1-sess," + " nonce=\"%s\", algorithm=SHA-256," " domain=\"example.com\", stale=true," " charset=\"UTF-8\", userhash=true", "/my/home", "example.com", "localhost:5060", NULL, - true, "SHA1-sess", "auth", "UTF-8", true, 0 - }, - { - "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA256," - " domain=\"example.com\", stale=true," - " charset=\"UTF-8\", userhash=true", - "/my/home", "example.com", "localhost:5060", NULL, - true, "SHA256", "auth", "UTF-8", true, 0 + true, "SHA-256", "auth", "UTF-8", true, 0 }, { "Digest realm=\"/my/home\", qop=\"auth-int\"," @@ -412,14 +400,6 @@ int test_httpauth_digest_request(void) "/my/home", "example.com", "localhost:5060", NULL, true, "MD5-sess", "auth-int", "UTF-8", true, 0 }, - { - "Digest realm=\"/my/home\", qop=\"auth-int\"," - " nonce=\"%s\", algorithm=SHA1-sess," - " domain=\"example.com\", stale=true," - " charset=\"UTF-8\", userhash=true", - "/my/home", "example.com", "213579023", NULL, - true, "SHA1-sess", "auth-int", "UTF-8", true, 0 - }, { "Digest realm=\"/my/home\", qop=\"auth-int\"," " nonce=\"%s\", algorithm=MD5," @@ -431,7 +411,7 @@ int test_httpauth_digest_request(void) }; int err = 0; - for (unsigned int i = 0; i < RE_ARRAY_SIZE(testv); i++) { + for (size_t i = 0; i < RE_ARRAY_SIZE(testv); i++) { struct httpauth_digest_chall_req *req = NULL; struct mbuf *mb_refval = NULL; struct mbuf *mb_printed = NULL; @@ -504,3 +484,181 @@ int test_httpauth_digest_request(void) return err; } + + +int test_httpauth_digest_response(void) +{ + static const struct { + const struct httpauth_digest_chall chall; + const char *user; + const char *passwd; + const char *qop; + const struct pl method; + const char *uri; + const char *entitybody; + const char *precalc_digest; + const char *resp_hval; + } testv [] = { + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("MD5"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "88f41f7227700e07d0d65256714a5a1a", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e" + "9a7e4e7563155f1f9556414dd4615\"," + " username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"88f41f7227700e07d0d65256714a5a1a\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=MD5," + " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("SHA-256"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "c22b56ce81bbb59570f0fbbc0ba27210dbbfcb2b23fe" + "a371d214722f319dc41c", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e" + "9a7e4e7563155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"c22b56ce81bbb59570f0fbbc0ba27210dbbfcb2b2" + "3fea371d214722f319dc41c\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=SHA-256," + " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("MD5-sess"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "1e79ac7105a4fdf416aaacfc50349110", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a7e4e756" + "3155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"1e79ac7105a4fdf416aaacfc50349110\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=MD5-sess," + " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("SHA-256"), PL("auth-int"), PL_INIT, + PL_INIT, PL_INIT + }, + "retest", "sec_pwd_retest", "auth-int", PL("GET"), + "example.com/my/home/something", "", + "2c0746b7174441314164d8d9a980d8920732de32e163" + "03f0e6a82970230e79e4", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a7e4e756" + "3155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"2c0746b7174441314164d8d9a980d8920732de32e" + "16303f0e6a82970230e79e4\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=SHA-256," + " qop=auth-int, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + }; + + int err; + + for (size_t i = 0; i < RE_ARRAY_SIZE(testv); i++) { + struct httpauth_digest_enc_resp *resp = NULL; + struct mbuf *mb_printed = NULL; + + mb_printed = mbuf_alloc(512); + if (!mb_printed) { + err = ENOMEM; + goto for_out; + } + + err = httpauth_digest_response_full(&resp, &testv[i].chall, + &testv[i].method, testv[i].uri, testv[i].user, + testv[i].passwd, testv[i].qop, testv[i].entitybody, + NULL, false); + if (err == ENOMEM) { + goto for_out; + } + else if (err) { + DEBUG_WARNING("[%d]" + " Could not generate response %m\n", i, err); + goto for_out; + } + + err = httpauth_digest_response_set_cnonce(resp, + &testv[i].chall, &testv[i].method, testv[i].user, + testv[i].passwd, testv[i].entitybody, + 0xdeadbeef, 0x00000001); + if (err) { + DEBUG_WARNING("[%d]" + " Response recalculation failed %m\n", i, err); + goto for_out; + } + + err = mbuf_printf(mb_printed, "%H", + httpauth_digest_response_print, resp); + if (err) + goto for_out; + + if (str_casecmp(resp->response, + testv[i].precalc_digest) != 0) { + err = EINVAL; + DEBUG_WARNING("[%d]" + " Expected response %s, got %w\n", i, + testv[i].precalc_digest, + resp->response, resp->hash_length); + goto for_out; + } + + if (memcmp(testv[i].resp_hval, + mb_printed->buf, mb_printed->end)) { + err = EINVAL; + DEBUG_WARNING("[%d]" + " Expected header %s, got %b\n", + i, testv[i].resp_hval, + mb_printed->buf, mb_printed->end); + goto for_out; + } + + mb_printed = mem_deref (mb_printed); + resp = mem_deref(resp); + continue; + +for_out: + mb_printed = mem_deref (mb_printed); + resp = mem_deref(resp); + break; + } + + return err; +} diff --git a/test/test.c b/test/test.c index 86a3a278d..039dd6894 100644 --- a/test/test.c +++ b/test/test.c @@ -79,6 +79,7 @@ static const struct test tests[] = { TEST(test_fmt_human_time), TEST(test_fmt_param), TEST(test_fmt_pl), + TEST(test_fmt_pl_alloc_str), TEST(test_fmt_pl_float), TEST(test_fmt_pl_i32), TEST(test_fmt_pl_i64), @@ -121,6 +122,7 @@ static const struct test tests[] = { TEST(test_httpauth_resp), TEST(test_httpauth_basic_request), TEST(test_httpauth_digest_request), + TEST(test_httpauth_digest_response), TEST(test_ice_cand), TEST(test_ice_loop), TEST(test_json), diff --git a/test/test.h b/test/test.h index a11cfdc5a..ee386b5e9 100644 --- a/test/test.h +++ b/test/test.h @@ -181,6 +181,7 @@ int test_fmt_hexdump(void); int test_fmt_human_time(void); int test_fmt_param(void); int test_fmt_pl(void); +int test_fmt_pl_alloc_str(void); int test_fmt_pl_float(void); int test_fmt_pl_i32(void); int test_fmt_pl_i64(void); @@ -225,6 +226,7 @@ int test_httpauth_chall(void); int test_httpauth_resp(void); int test_httpauth_basic_request(void); int test_httpauth_digest_request(void); +int test_httpauth_digest_response(void); int test_ice_loop(void); int test_ice_cand(void); int test_json(void);