diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c3e456c1..1352009df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,30 @@ 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.14.0] - 2024-07-23 + +## What's Changed +* aumix: use mutex_alloc() by @alfredh in https://github.com/baresip/re/pull/1142 +* sipreg/reg.c: stop retrying registers early after 401/407 by @maximilianfridrich in https://github.com/baresip/re/pull/1143 +* aumix: add locking in aumix_source_count() by @alfredh in https://github.com/baresip/re/pull/1145 +* test: init err in test_sip_auth_encode() by @alfredh in https://github.com/baresip/re/pull/1146 +* sipreg: refactor response_handler else optimization by @sreimers in https://github.com/baresip/re/pull/1147 +* vidmix: improve mutex usage by @alfredh in https://github.com/baresip/re/pull/1148 +* udp/mcast: use group scopeid as interface for IPv6 by @maximilianfridrich in https://github.com/baresip/re/pull/1149 +* .clangd: suppress -Wgnu-zero-variadic-macro-arguments by @maximilianfridrich in https://github.com/baresip/re/pull/1150 +* ci/build: use only macos-latest by @sreimers in https://github.com/baresip/re/pull/1153 +* cmake: fix resolv on FreeBSD by @sreimers in https://github.com/baresip/re/pull/1152 +* test: use h264_stap_decode_annexb() by @alfredh in https://github.com/baresip/re/pull/1151 +* sipsess/reply: terminate session if no (PR)ACK received after 64*T1 by @maximilianfridrich in https://github.com/baresip/re/pull/1155 +* rtcp: send BYE manually by @alfredh in https://github.com/baresip/re/pull/1154 +* cmake: check accept4 only on linux by @sreimers in https://github.com/baresip/re/pull/1157 +* cmake: fix iOS HAVE_ROUTE_LIST and darwin dns by @sreimers in https://github.com/baresip/re/pull/1158 +* test: check if header and payload is set by @alfredh in https://github.com/baresip/re/pull/1161 + + +**Full Changelog**: https://github.com/baresip/re/compare/v3.13.0...v3.14.0 + + ## [v3.13.0] - 2024-06-19 ## What's Changed diff --git a/CMakeLists.txt b/CMakeLists.txt index 981052de0..7a547fb01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,13 +14,13 @@ cmake_minimum_required(VERSION 3.14) project(re - VERSION 3.13.0 + VERSION 3.14.0 LANGUAGES C HOMEPAGE_URL https://github.com/baresip/re DESCRIPTION "Generic library for real-time communications" ) -set(PROJECT_SOVERSION 25) # bump if ABI breaks +set(PROJECT_SOVERSION 26) # bump if ABI breaks # Pre-release identifier, comment out on a release # Increment for breaking changes (dev2, dev3...) @@ -132,6 +132,7 @@ set(HEADERS include/re_convert.h include/re_crc32.h include/re_dbg.h + include/re_dd.h include/re_dns.h include/re_fmt.h include/re_h264.h @@ -226,6 +227,10 @@ set(SRCS src/dbg/dbg.c + src/dd/dd.c + src/dd/dd_enc.c + src/dd/putbit.c + src/dns/client.c src/dns/cstr.c src/dns/dname.c diff --git a/cmake/re-config.cmake b/cmake/re-config.cmake index eb2bf42a2..09276385f 100644 --- a/cmake/re-config.cmake +++ b/cmake/re-config.cmake @@ -111,7 +111,6 @@ endif() list(APPEND RE_DEFINITIONS HAVE_ATOMIC - HAVE_INET6 HAVE_SELECT ) diff --git a/debian/changelog b/debian/changelog index a42e88786..22cba17d5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +libre (3.14.0) unstable; urgency=medium + + * version 3.14.0 + + -- Sebastian Reimers Tue, 23 Jul 2024 09:00:00 +0200 + libre (3.13.0) unstable; urgency=medium * version 3.13.0 diff --git a/include/re_dd.h b/include/re_dd.h new file mode 100644 index 000000000..9dfecd200 --- /dev/null +++ b/include/re_dd.h @@ -0,0 +1,109 @@ +/** + * @file re_dd.h Dependency Descriptor (DD) + * + * Copyright (C) 2010 - 2023 Alfred E. Heggestad + */ + + +/* + * Put bits wrapper (XXX: move to common place) + */ + +struct putbit { + struct mbuf *mb; + size_t bit_pos; +}; + +void putbit_init(struct putbit *pb, struct mbuf *mb); +int putbit_one(struct putbit *pb, unsigned bit); +int putbit_write(struct putbit *pb, unsigned count, unsigned val); +int putbit_write_ns(struct putbit *pb, unsigned n, unsigned v); + + +/* + * Dependency Descriptor (DD) + * + * DT: Decode Target + * DTI: Decode Target Indication + * SID: Spatial ID + * TID: Temporal ID + */ + +/* Constants. */ +enum { + DD_MAX_SPATIAL_IDS = 4u, + DD_MAX_TEMPORAL_IDS = 4u, + DD_MAX_TEMPLATES = 8u, + DD_MAX_FDIFFS = 16u, + DD_MAX_DECODE_TARGETS= 16u, + DD_MAX_CHAINS = 32u, +}; + + +/* Decode Target Indication (DTI) */ +enum dd_dti { + DD_DTI_NOT_PRESENT = 0, + DD_DTI_DISCARDABLE = 1, + DD_DTI_SWITCH = 2, + DD_DTI_REQUIRED = 3, +}; + +enum dd_next_layer_idc { + DD_SAME_LAYER = 0, + DD_NEXT_TEMPORAL_LAYER = 1, + DD_NEXT_SPATIAL_LAYER = 2, + DD_NO_MORE_TEMPLATES = 3, +}; + +/* + * https://aomediacodec.github.io/av1-rtp-spec/ + * #dependency-descriptor-rtp-header-extension + */ +struct dd { + + /* Mandatory Descriptor Fields */ + unsigned start_of_frame:1; + unsigned end_of_frame:1; + unsigned frame_dependency_template_id:6; + uint16_t frame_number; + + // TODO: needed? + bool ext; + + unsigned template_dependency_structure_present_flag:1; + unsigned active_decode_targets_present_flag:1; + unsigned custom_dtis_flag:1; + unsigned custom_fdiffs_flag:1; + unsigned custom_chains_flag:1; + + unsigned active_decode_targets_bitmask; + unsigned template_id_offset:6; + uint8_t dt_cnt; + uint8_t template_cnt; + uint8_t max_spatial_id; + + uint8_t template_spatial_id[DD_MAX_TEMPLATES]; + uint8_t template_temporal_id[DD_MAX_TEMPLATES]; + + /* render_resolutions */ + bool resolutions_present_flag; + uint16_t max_render_width_minus_1[DD_MAX_SPATIAL_IDS]; + uint16_t max_render_height_minus_1[DD_MAX_SPATIAL_IDS]; + uint8_t render_count; + + /* type: enum dd_dti */ + uint8_t template_dti[DD_MAX_TEMPLATES][DD_MAX_DECODE_TARGETS]; + + /* template fdiffs */ + uint8_t template_fdiff[DD_MAX_TEMPLATES][DD_MAX_FDIFFS]; + uint8_t template_fdiff_cnt[DD_MAX_TEMPLATES]; + + /* template chains */ + uint8_t decode_target_protected_by[DD_MAX_DECODE_TARGETS]; + uint8_t template_chain_fdiff[DD_MAX_TEMPLATES][DD_MAX_CHAINS]; + uint8_t chain_cnt; +}; + +int dd_encode(struct mbuf *mb, const struct dd *dd); +int dd_decode(struct dd *dd, const uint8_t *buf, size_t sz); +void dd_print(const struct dd *dd); diff --git a/include/re_h264.h b/include/re_h264.h index e5674ea8e..c1ffbfba6 100644 --- a/include/re_h264.h +++ b/include/re_h264.h @@ -105,3 +105,21 @@ int h264_stap_encode(struct mbuf *mb, const uint8_t *frame, size_t frame_sz); int h264_stap_decode_annexb(struct mbuf *mb_frame, struct mbuf *mb_pkt); int h264_stap_decode_annexb_long(struct mbuf *mb_frame, struct mbuf *mb_pkt); + + +/* + * Get bits wrapper + */ + +struct getbit { + const uint8_t *buf; + size_t pos; + size_t end; +}; + +void getbit_init(struct getbit *gb, const uint8_t *buf, size_t size); +size_t getbit_get_left(const struct getbit *gb); +unsigned get_bit(struct getbit *gb); +int get_ue_golomb(struct getbit *gb, unsigned *valp); +unsigned get_bits(struct getbit *gb, unsigned n); +unsigned getbit_read_ns(struct getbit *gb, unsigned n); diff --git a/include/re_sa.h b/include/re_sa.h index 9670bfbcd..1d26a0e5f 100644 --- a/include/re_sa.h +++ b/include/re_sa.h @@ -68,6 +68,7 @@ bool sa_cmp(const struct sa *l, const struct sa *r, int flag); bool sa_is_linklocal(const struct sa *sa); bool sa_is_loopback(const struct sa *sa); +bool sa_is_multicast(const struct sa *sa); bool sa_is_any(const struct sa *sa); void sa_set_scopeid(struct sa *sa, uint32_t scopeid); diff --git a/include/re_sip.h b/include/re_sip.h index c4c013c1d..acd2c7ced 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -311,6 +311,8 @@ void sip_set_trace_handler(struct sip *sip, sip_trace_h *traceh); /* transport */ int sip_transp_add(struct sip *sip, enum sip_transp tp, const struct sa *laddr, ...); +int sip_transp_add_sock(struct sip *sip, enum sip_transp tp, + bool listen, const struct sa *laddr, ...); int sip_transp_add_websock(struct sip *sip, enum sip_transp tp, const struct sa *laddr, bool server, const char *cert, struct tls *tls); diff --git a/mk/Doxyfile b/mk/Doxyfile index 6b15fbd76..6cb70eea3 100644 --- a/mk/Doxyfile +++ b/mk/Doxyfile @@ -4,7 +4,7 @@ # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = libre -PROJECT_NUMBER = 3.13.0 +PROJECT_NUMBER = 3.14.0 OUTPUT_DIRECTORY = ../re-dox CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/src/av1/getbit.c b/src/av1/getbit.c new file mode 100644 index 000000000..cda472201 --- /dev/null +++ b/src/av1/getbit.c @@ -0,0 +1,61 @@ +/** + * @file getbit.c Get bits helper + * + * Copyright (C) 2023 Alfred E. Heggestad + */ + +#include +#include + + +#define DEBUG_MODULE "av1" +#define DEBUG_LEVEL 5 +#include + + +void getbit_init(struct getbit *gb, const uint8_t *buf, size_t size_bits) +{ + if (!gb) + return; + + gb->buf = buf; + gb->pos = 0; + gb->end = size_bits; +} + + +size_t getbit_get_left(const struct getbit *gb) +{ + if (!gb) + return 0; + + if (gb->end > gb->pos) + return gb->end - gb->pos; + else + return 0; +} + + +unsigned get_bit(struct getbit *gb) +{ + register unsigned tmp; + + if (!gb) + return 0; + + if (gb->pos >= gb->end) { + DEBUG_WARNING("get_bit: read past end" + " (%zu >= %zu)\n", gb->pos, gb->end); + assert(0); + return 0; + } + + const uint8_t *p = gb->buf; + tmp = ((*(p + (gb->pos >> 0x3))) >> (0x7 - (gb->pos & 0x7))) & 0x1; + + ++gb->pos; + + return tmp; +} + + diff --git a/src/dd/dd.c b/src/dd/dd.c new file mode 100644 index 000000000..db708c09c --- /dev/null +++ b/src/dd/dd.c @@ -0,0 +1,432 @@ +/** + * @file dd.c Dependency Descriptor (DD) -- decoder + * + * Copyright (C) 2023 Alfred E. Heggestad + */ + +#include +#include +#include + + +#define dd_f(n) get_bits(gb, (n)) + + +static const char *dti_name(enum dd_dti dti) +{ + switch (dti) { + + case DD_DTI_NOT_PRESENT: return "NOT_PRESENT"; + case DD_DTI_DISCARDABLE: return "DISCARDABLE"; + case DD_DTI_SWITCH: return "SWITCH"; + case DD_DTI_REQUIRED: return "REQUIRED"; + } + + return "???"; +} + + +#if 0 +static const char *next_layer_name(enum dd_next_layer_idc idc) +{ + switch (idc) { + + case DD_SAME_LAYER: return "Same"; + case DD_NEXT_TEMPORAL_LAYER: return "Temporal"; + case DD_NEXT_SPATIAL_LAYER: return "Spatial"; + case DD_NO_MORE_TEMPLATES: return "None"; + } + + return "???"; +} +#endif + + +static int mandatory_descriptor_fields(struct dd *dd, struct getbit *gb) +{ + if (getbit_get_left(gb) < 24) + return EBADMSG; + + dd->start_of_frame = dd_f(1); + dd->end_of_frame = dd_f(1); + dd->frame_dependency_template_id = dd_f(6); + dd->frame_number = dd_f(16); + + return 0; +} + + +/* + * 0 next template has the same spatial ID and temporal ID as current template + * + * 1 next template has the same spatial ID and temporal ID plus 1 compared + * with the current Frame dependency template. + * + * 2 next Frame dependency template has temporal ID equal to 0 and + * spatial ID plus 1 compared with the current Frame dependency template. + * + * 3 No more Frame dependency templates are present in the + * Frame dependency structure. + */ +static int template_layers(struct dd *dd, struct getbit *gb) +{ + uint8_t temporalId = 0; + uint8_t spatialId = 0; + uint8_t TemplateCnt = 0; + uint8_t MaxTemporalId = 0; + uint8_t next_layer_idc = DD_SAME_LAYER; + + do { + if (TemplateCnt >= DD_MAX_TEMPLATES) + return EOVERFLOW; + + dd->template_spatial_id[TemplateCnt] = spatialId; + dd->template_temporal_id[TemplateCnt] = temporalId; + + ++TemplateCnt; + + if (getbit_get_left(gb) < 2) + return EBADMSG; + + next_layer_idc = dd_f(2); + + /* next_layer_idc == 0 - same sid and tid */ + if (next_layer_idc == DD_NEXT_TEMPORAL_LAYER) { + ++temporalId; + if (temporalId > MaxTemporalId) { + MaxTemporalId = temporalId; + } + } + else if (next_layer_idc == DD_NEXT_SPATIAL_LAYER) { + temporalId = 0; + ++spatialId; + } + } + while (next_layer_idc != DD_NO_MORE_TEMPLATES); + + dd->max_spatial_id = spatialId; + dd->template_cnt = TemplateCnt; + + return 0; +} + + +static int template_dtis(struct dd *dd, struct getbit *gb) +{ + for (uint8_t templateIndex = 0; + templateIndex < dd->template_cnt; + templateIndex++) { + + if (templateIndex >= DD_MAX_TEMPLATES) + return EOVERFLOW; + + for (uint8_t dtIndex = 0; dtIndex < dd->dt_cnt; dtIndex++) { + + if (getbit_get_left(gb) < 2) + return EBADMSG; + + /* See table A.1 below for meaning of DTI values. */ + dd->template_dti[templateIndex][dtIndex] = dd_f(2); + } + } + + return 0; +} + + +static int template_fdiffs(struct dd *dd, struct getbit *gb) +{ + for (uint8_t templateIndex = 0; + templateIndex < dd->template_cnt; + templateIndex++) { + + uint8_t fdiffCnt = 0; + + if (getbit_get_left(gb) < 1) + return EBADMSG; + + bool fdiff_follows_flag = dd_f(1); + + while (fdiff_follows_flag) { + + if (getbit_get_left(gb) < 5) + return EBADMSG; + + uint8_t fdiff_minus_one = dd_f(4); + + uint8_t fdiff = fdiff_minus_one + 1; + + dd->template_fdiff[templateIndex][fdiffCnt] = fdiff; + + ++fdiffCnt; + fdiff_follows_flag = dd_f(1); + } + + dd->template_fdiff_cnt[templateIndex] = fdiffCnt; + } + + return 0; +} + + +static int template_chains(struct dd *dd, struct getbit *gb) +{ + /* todo: check bits left */ + dd->chain_cnt = getbit_read_ns(gb, dd->dt_cnt + 1); + + if (dd->chain_cnt == 0) + return 0; + + for (uint8_t dtIndex = 0; dtIndex < dd->dt_cnt; dtIndex++) { + uint8_t v = getbit_read_ns(gb, dd->chain_cnt); + dd->decode_target_protected_by[dtIndex] = v; + } + + for (uint8_t templateIndex = 0; + templateIndex < dd->template_cnt; + templateIndex++) { + + for (uint8_t chainIndex = 0; + chainIndex < dd->chain_cnt; + chainIndex++) { + + if (getbit_get_left(gb) < 4) + return EBADMSG; + + dd->template_chain_fdiff[templateIndex][chainIndex] = + dd_f(4); + } + } + + return 0; +} + + +static int render_resolutions(struct dd *dd, struct getbit *gb) +{ + for (uint8_t spatial_id = 0; + spatial_id <= dd->max_spatial_id; + spatial_id++) { + + if (getbit_get_left(gb) < 32) + return EBADMSG; + + dd->max_render_width_minus_1[spatial_id] = dd_f(16); + dd->max_render_height_minus_1[spatial_id] = dd_f(16); + + ++dd->render_count; + } + + return 0; +} + + +static int template_dependency_structure(struct dd *dd, struct getbit *gb) +{ + if (getbit_get_left(gb) < 11) + return EBADMSG; + + dd->template_id_offset = dd_f(6); + uint8_t dt_cnt_minus_one = dd_f(5); + + dd->dt_cnt = dt_cnt_minus_one + 1; + + int err = template_layers(dd, gb); + if (err) + return err; + + err = template_dtis(dd, gb); + if (err) + return err; + + err = template_fdiffs(dd, gb); + if (err) + return err; + + template_chains(dd, gb); + + /* TODO decode_target_layers() */ + + if (getbit_get_left(gb) < 1) + return EBADMSG; + + dd->resolutions_present_flag = dd_f(1); + if (dd->resolutions_present_flag) { + err = render_resolutions(dd, gb); + if (err) + return err; + } + + return 0; +} + + +static int extended_descriptor_fields(struct dd *dd, struct getbit *gb) +{ + if (getbit_get_left(gb) < 5) + return EBADMSG; + + dd->template_dependency_structure_present_flag = dd_f(1); + dd->active_decode_targets_present_flag = dd_f(1); + dd->custom_dtis_flag = dd_f(1); + dd->custom_fdiffs_flag = dd_f(1); + dd->custom_chains_flag = dd_f(1); + + if (dd->template_dependency_structure_present_flag) { + + int err = template_dependency_structure(dd, gb); + if (err) + return err; + + dd->active_decode_targets_bitmask = (1u << dd->dt_cnt) - 1; + } + + if (dd->active_decode_targets_present_flag) { + + dd->active_decode_targets_bitmask = dd_f(dd->dt_cnt); + } + + return 0; +} + + +static void no_extended_descriptor_fields(struct dd *dd) +{ + dd->custom_dtis_flag = 0; + dd->custom_fdiffs_flag = 0; + dd->custom_chains_flag = 0; +} + + +int dd_decode(struct dd *dd, const uint8_t *buf, size_t sz) +{ + if (!dd || !buf) + return EINVAL; + + memset(dd, 0, sizeof(*dd)); + + struct getbit gb; + + getbit_init(&gb, buf, sz*8); + + int err = mandatory_descriptor_fields(dd, &gb); + if (err) + return err; + + if (sz > 3) { + err = extended_descriptor_fields(dd, &gb); + if (err) + return err; + + dd->ext = true; + } + else { + no_extended_descriptor_fields(dd); + } + + return 0; +} + + +void dd_print(const struct dd *dd) +{ + if (!dd) + return; + + re_printf("~~~~ DD: ~~~~\n"); + + re_printf(".... start=%d, end=%d," + " frame_dependency_template_id=%u, frame_number=%u\n", + dd->start_of_frame, + dd->end_of_frame, + dd->frame_dependency_template_id, + dd->frame_number); + re_printf(".... ext: %d\n", dd->ext); + + if (dd->ext) { + + re_printf(".... template_dependency_structure_present: %u\n", + dd->template_dependency_structure_present_flag); + re_printf(".... active_decode_targets_present_flag: %u\n", + dd->active_decode_targets_present_flag); + re_printf(".... custom_dtis_flag: %u\n", + dd->custom_dtis_flag); + re_printf(".... custom_fdiffs_flag: %u\n", + dd->custom_fdiffs_flag); + re_printf(".... custom_chains_flag: %u\n", + dd->custom_chains_flag); + re_printf("\n"); + + re_printf(".... active_decode_targets_bitmask: 0x%x\n", + dd->active_decode_targets_bitmask); + re_printf(".... template_id_offset: %u\n", + dd->template_id_offset); + re_printf(".... dt_cnt: %u\n", + dd->dt_cnt); + re_printf(".... template_cnt: %u\n", + dd->template_cnt); + re_printf(".... max_spatial_id: %u\n", + dd->max_spatial_id); + re_printf("\n"); + + re_printf(".... template spatial/temporal ids:\n"); + for (uint8_t i=0; itemplate_cnt; i++) { + + re_printf(".... [%u] spatial=%u temporal=%u\n", + i, + dd->template_spatial_id[i], + dd->template_temporal_id[i]); + } + re_printf("\n"); + + re_printf(".... resolutions_present_flag: %u\n", + dd->resolutions_present_flag); + re_printf(".... render_count: %u\n", dd->render_count); + for (uint8_t i = 0; i < dd->render_count; i++) { + + re_printf(".... max_render %u: %u x %u\n", + i, + dd->max_render_width_minus_1[i] + 1, + dd->max_render_height_minus_1[i] + 1); + } + re_printf("\n"); + + for (uint8_t i = 0; i < dd->template_cnt; i++) { + + uint8_t fdiffCnt = dd->template_fdiff_cnt[i]; + + re_printf(".... [%u] template_fdiff_cnt: %u", + i, fdiffCnt); + + for (uint8_t j = 0; j < fdiffCnt; j++) { + + uint8_t fdiff; + + fdiff = dd->template_fdiff[i][j]; + + re_printf(" ", fdiff); + } + + re_printf("\n"); + } + re_printf("\n"); + + re_printf(".... chain_cnt: %u\n", dd->chain_cnt); + re_printf("\n"); + + re_printf(".... template_dti: 2D\n"); + for (uint8_t tix = 0; tix < dd->template_cnt; tix++) { + + for (uint8_t dtix = 0; dtix < dd->dt_cnt; dtix++) { + + uint8_t val = dd->template_dti[tix][dtix]; + + re_printf(".... DTI: [%u][%u] %u %s\n", + tix, dtix, val, dti_name(val)); + } + } + } + + re_printf("~~~~~~~~~~~~\n"); + re_printf("\n"); +} diff --git a/src/dd/dd_enc.c b/src/dd/dd_enc.c new file mode 100644 index 000000000..d56a035bc --- /dev/null +++ b/src/dd/dd_enc.c @@ -0,0 +1,275 @@ +/** + * @file dd_enc.c Dependency Descriptor (DD) -- encoder + * + * Copyright (C) 2023 Alfred E. Heggestad + */ + +#include +#include +#include + + +#define DEBUG_MODULE "dd" +#define DEBUG_LEVEL 5 +#include + + +static int mandatory_descriptor_fields(struct putbit *pb, const struct dd *dd) +{ + int err = 0; + + err |= putbit_one(pb, dd->start_of_frame); + err |= putbit_one(pb, dd->end_of_frame); + err |= putbit_write(pb, 6, dd->frame_dependency_template_id); + err |= putbit_write(pb, 16, dd->frame_number); + + return err; +} + + +static uint8_t next_layer(const struct dd *dd, unsigned prev, unsigned next) +{ + if (dd->template_spatial_id[next] == dd->template_spatial_id[prev] && + dd->template_temporal_id[next] == dd->template_temporal_id[prev]) { + + return DD_SAME_LAYER; + } + else if (dd->template_spatial_id[next] == + dd->template_spatial_id[prev] && + dd->template_temporal_id[next] == + dd->template_temporal_id[prev] + 1) { + + return DD_NEXT_TEMPORAL_LAYER; + } + else if (dd->template_spatial_id[next] == + dd->template_spatial_id[prev] + 1 && + dd->template_temporal_id[next] == 0) { + + return DD_NEXT_SPATIAL_LAYER; + } + + return DD_NO_MORE_TEMPLATES; +} + + +static int template_layers(struct putbit *pb, const struct dd *dd) +{ + int err = 0; + + for (unsigned i = 1; i < dd->template_cnt; ++i) { + + uint8_t next_layer_idc = next_layer(dd, i - 1, i); + if (next_layer_idc == DD_NO_MORE_TEMPLATES) + return EBADMSG; + + err |= putbit_write(pb, 2, next_layer_idc); + } + + /* end of layers */ + err |= putbit_write(pb, 2, DD_NO_MORE_TEMPLATES); + + return err; +} + + +static int template_dtis(struct putbit *pb, const struct dd *dd) +{ + for (uint8_t templateIndex = 0; + templateIndex < dd->template_cnt; + templateIndex++) { + + for (uint8_t dtIndex = 0; dtIndex < dd->dt_cnt; dtIndex++) { + + /* See table A.1 below for meaning of DTI values. */ + + uint8_t v = dd->template_dti[templateIndex][dtIndex]; + + int err = putbit_write(pb, 2, v); + if (err) + return err; + } + } + + return 0; +} + + +static int template_fdiffs(struct putbit *pb, const struct dd *dd) +{ + int err; + + for (uint8_t templateIndex = 0; + templateIndex < dd->template_cnt; + templateIndex++) { + + uint8_t fdiffCnt = dd->template_fdiff_cnt[templateIndex]; + + for (uint8_t j = 0; j < fdiffCnt; j++) { + + uint8_t fdiff; + + fdiff = dd->template_fdiff[templateIndex][j]; + + /* fdiff_follows_flag */ + err = putbit_write(pb, 1, true); + if (err) + return err; + + err = putbit_write(pb, 4, fdiff - 1); + if (err) + return err; + } + + /* fdiff_follows_flag */ + err = putbit_write(pb, 1, false); + if (err) + return err; + } + + return 0; +} + + +static int template_chains(struct putbit *pb, const struct dd *dd) +{ + int err = putbit_write_ns(pb, dd->dt_cnt + 1, dd->chain_cnt); + if (err) + return err; + + if (dd->chain_cnt == 0) + return 0; + + for (uint8_t dtIndex = 0; dtIndex < dd->dt_cnt; dtIndex++) { + + uint8_t val = dd->decode_target_protected_by[dtIndex]; + + err = putbit_write_ns(pb, dd->chain_cnt, val); + if (err) + return err; + } + + for (uint8_t templateIndex = 0; + templateIndex < dd->template_cnt; + templateIndex++) { + + for (uint8_t chainIndex = 0; + chainIndex < dd->chain_cnt; + chainIndex++) { + + uint8_t val; + + val=dd->template_chain_fdiff[templateIndex][chainIndex]; + + err = putbit_write(pb, 4, val); + if (err) + return err; + } + } + + return 0; +} + + +static int render_resolutions(struct putbit *pb, const struct dd *dd) +{ + for (uint8_t i=0; irender_count; i++) { + + putbit_write(pb, 16, dd->max_render_width_minus_1[i]); + putbit_write(pb, 16, dd->max_render_height_minus_1[i]); + } + + return 0; +} + + +static int template_dependency_structure(struct putbit *pb, + const struct dd *dd) +{ + int err; + + uint8_t dt_cnt_minus_one = dd->dt_cnt - 1; + + err = putbit_write(pb, 6, dd->template_id_offset); + err |= putbit_write(pb, 5, dt_cnt_minus_one); + if (err) + return err; + + err = template_layers(pb, dd); + if (err) + return err; + + err = template_dtis(pb, dd); + if (err) + return err; + + err = template_fdiffs(pb, dd); + if (err) + return err; + + err = template_chains(pb, dd); + if (err) + return err; + + err = putbit_one(pb, dd->resolutions_present_flag); + if (err) + return err; + + if (dd->resolutions_present_flag) { + render_resolutions(pb, dd); + } + + /* XXX decode_target_layers() */ + + return 0; +} + + +static int extended_descriptor_fields(struct putbit *pb, const struct dd *dd) +{ + int err = 0; + + err |= putbit_one(pb, dd->template_dependency_structure_present_flag); + err |= putbit_one(pb, dd->active_decode_targets_present_flag); + err |= putbit_one(pb, dd->custom_dtis_flag); + err |= putbit_one(pb, dd->custom_fdiffs_flag); + err |= putbit_one(pb, dd->custom_chains_flag); + if (err) + return err; + + if (dd->template_dependency_structure_present_flag) { + + err = template_dependency_structure(pb, dd); + if (err) + return err; + } + + if (dd->active_decode_targets_present_flag) { + DEBUG_WARNING("no active_decode_targets_present_flag\n"); + return ENOTSUP; + } + + return 0; +} + + +int dd_encode(struct mbuf *mb, const struct dd *dd) +{ + struct putbit pb; + + if (!mb || !dd) + return EINVAL; + + putbit_init(&pb, mb); + + int err = mandatory_descriptor_fields(&pb, dd); + if (err) + return err; + + if (dd->ext) { + err = extended_descriptor_fields(&pb, dd); + if (err) + return err; + } + + return 0; +} diff --git a/src/dd/putbit.c b/src/dd/putbit.c new file mode 100644 index 000000000..82f734da1 --- /dev/null +++ b/src/dd/putbit.c @@ -0,0 +1,108 @@ +/** + * @file putbit.c Put bits helper + * + * Copyright (C) 2023 Alfred E. Heggestad + */ + +#include +#include +#include + + +void putbit_init(struct putbit *pb, struct mbuf *mb) +{ + if (!pb || !mb) + return; + + pb->mb = mb; + pb->bit_pos = 0; + + memset(pb->mb->buf, 0, pb->mb->size); +} + + +int putbit_one(struct putbit *pb, unsigned bit) +{ + if (!pb) + return EINVAL; + + size_t byte_pos = pb->bit_pos >> 0x3; + + /* resize mbuf */ + if (byte_pos >= pb->mb->size) { + + int err = mbuf_resize(pb->mb, pb->mb->size * 2); + if (err) + return err; + } + + uint8_t *p = pb->mb->buf; + size_t bit_pos = (size_t)(1u << (0x7 - (pb->bit_pos & 0x7))); + + if (bit) { + p[byte_pos] |= bit_pos; + } + else { + p[byte_pos] &= ~bit_pos; + } + + ++pb->bit_pos; + + /* NOTE: mb->pos not used */ + mbuf_set_end(pb->mb, (pb->bit_pos + 7) >> 0x3); + + return 0; +} + + +int putbit_write(struct putbit *pb, unsigned count, unsigned val) +{ + if (!pb) + return EINVAL; + + if (count > 32) + return EINVAL; + + for (unsigned i=0; i> shift) & 0x1; + + int err = putbit_one(pb, bit); + if (err) + return err; + } + + return 0; +} + + +int putbit_write_ns(struct putbit *pb, unsigned n, unsigned v) +{ + if (!pb) + return EINVAL; + + int err; + +#if 0 + /* TODO: check this */ + if (n == 1) + return EINVAL; +#endif + + unsigned w = 0; + unsigned x = n; + + while (x != 0) { + x = x >> 1; + ++w; + } + + unsigned m = (1 << w) - n; + if (v < m) + err = putbit_write(pb, w - 1, v); + else + err = putbit_write(pb, w, v + m); + + return err; +} diff --git a/src/dns/client.c b/src/dns/client.c index dfc542de3..716ca3302 100644 --- a/src/dns/client.c +++ b/src/dns/client.c @@ -1217,9 +1217,7 @@ int dnsc_alloc(struct dnsc **dcpp, const struct dnsc_conf *conf, { struct dnsc *dnsc; struct sa laddr; -#ifdef HAVE_INET6 struct sa laddr6; -#endif int err; if (!dcpp) @@ -1241,10 +1239,9 @@ int dnsc_alloc(struct dnsc **dcpp, const struct dnsc_conf *conf, sa_set_str(&laddr, "0.0.0.0", 0); err = udp_listen(&dnsc->us, &laddr, udp_recv_handler, dnsc); -#ifdef HAVE_INET6 sa_set_str(&laddr6, "::", 0); err &= udp_listen(&dnsc->us6, &laddr6, udp_recv_handler, dnsc); -#endif + if (err) goto out; diff --git a/src/dns/rr.c b/src/dns/rr.c index 513b30489..35fc1535c 100644 --- a/src/dns/rr.c +++ b/src/dns/rr.c @@ -615,8 +615,10 @@ int dns_rr_print(struct re_printf *pf, const struct dnsrr *rr) n = (w > l) ? w - l : 0; err = re_hprintf(pf, "%s.", rr->name); - while (n--) + while (n) { err |= pf->vph(" ", 1, pf->arg); + --n; + } err |= re_hprintf(pf, " %10lld %-4s %-7s ", rr->ttl, diff --git a/src/fmt/print.c b/src/fmt/print.c index 040dd3aac..cef34ba1f 100644 --- a/src/fmt/print.c +++ b/src/fmt/print.c @@ -441,20 +441,16 @@ static int vhprintf(const char *fmt, va_list ap, re_vprintf_h *vph, void *arg, break; } -#ifdef HAVE_INET6 if (AF_INET6 == sa_af(sa)) { ch = '['; err |= vph(&ch, 1, arg); } -#endif err |= write_padded(addr, strlen(addr), pad, ' ', plr, NULL, vph, arg); -#ifdef HAVE_INET6 if (AF_INET6 == sa_af(sa)) { ch = ']'; err |= vph(&ch, 1, arg); } -#endif ch = ':'; err |= vph(&ch, 1, arg); diff --git a/src/h264/getbit.c b/src/h264/getbit.c index f6f35318d..770533838 100644 --- a/src/h264/getbit.c +++ b/src/h264/getbit.c @@ -6,9 +6,15 @@ #include #include +#include #include "h264.h" +#define DEBUG_MODULE "getbit" +#define DEBUG_LEVEL 5 +#include + + void getbit_init(struct getbit *gb, const uint8_t *buf, size_t size) { if (!gb) @@ -90,3 +96,61 @@ int get_ue_golomb(struct getbit *gb, unsigned *valp) return 0; } + + +/* + x = 0 + for ( i = 0; i < n; i++ ) { + x = 2 * x + read_bit() + } + TotalConsumedBits += n + return x + */ +unsigned get_bits(struct getbit *gb, unsigned n) +{ + unsigned x = 0; + + if (getbit_get_left(gb) < n) { + DEBUG_WARNING("get_bits: read past end" + " (n=%zu, left=%zu)\n", n, getbit_get_left(gb)); + return 0; + } + + for (unsigned i=0; i> 1; + ++w; + } + + unsigned m = (1u << w) - n; + unsigned v = dd_f(w - 1); + + if (v < m) + return v; + + unsigned extra_bit = dd_f(1); + + return (v << 1) - m + extra_bit; +} diff --git a/src/h264/h264.h b/src/h264/h264.h index 105e3b57b..5ed49f883 100644 --- a/src/h264/h264.h +++ b/src/h264/h264.h @@ -5,14 +5,3 @@ */ -struct getbit { - const uint8_t *buf; - size_t pos; - size_t end; -}; - - -void getbit_init(struct getbit *gb, const uint8_t *buf, size_t size); -size_t getbit_get_left(const struct getbit *gb); -unsigned get_bit(struct getbit *gb); -int get_ue_golomb(struct getbit *gb, unsigned *valp); diff --git a/src/http/client.c b/src/http/client.c index 06186f269..456685b78 100644 --- a/src/http/client.c +++ b/src/http/client.c @@ -48,9 +48,7 @@ struct http_cli { struct mbuf *cert; struct mbuf *key; struct sa laddr; -#ifdef HAVE_INET6 struct sa laddr6; -#endif size_t bufsize_max; }; @@ -601,10 +599,8 @@ static int conn_connect(struct http_req *req) if (sa_af(&conn->addr) == AF_INET) laddr = &req->cli->laddr; -#ifdef HAVE_INET6 else if (sa_af(&conn->addr) == AF_INET6) laddr = &req->cli->laddr6; -#endif if (sa_isset(laddr, SA_ADDR)) { sa_set_scopeid(&conn->addr, sa_scopeid(laddr)); @@ -878,16 +874,13 @@ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met, goto out; } else { -#ifdef HAVE_INET6 struct sa tmp; -#endif err = dnsc_query(&req->dq, cli->dnsc, req->host, DNS_TYPE_A, DNS_CLASS_IN, true, query_handler, req); if (err) goto out; -#ifdef HAVE_INET6 if (0 == net_default_source_addr_get(AF_INET6, &tmp)) { err = dnsc_query(&req->dq6, cli->dnsc, req->host, @@ -896,7 +889,6 @@ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met, if (err) goto out; } -#endif } out: @@ -1338,13 +1330,8 @@ void http_client_set_laddr(struct http_cli *cli, const struct sa *addr) */ void http_client_set_laddr6(struct http_cli *cli, const struct sa *addr) { -#ifdef HAVE_INET6 if (cli && addr) sa_cpy(&cli->laddr6, addr); -#else - (void)cli; - (void)addr; -#endif } diff --git a/src/net/linux/rt.c b/src/net/linux/rt.c index 5e7f70ce1..8992b1f48 100644 --- a/src/net/linux/rt.c +++ b/src/net/linux/rt.c @@ -124,11 +124,9 @@ static int rt_parse(const struct nlmsghdr *nlhdr, struct net_rt *rt) = *(uint32_t *)RTA_DATA(rtattr); break; -#ifdef HAVE_INET6 case AF_INET6: sa_set_in6(&rt->gw, RTA_DATA(rtattr), 0); break; -#endif default: DEBUG_WARNING("RTA_GW: unknown family %d\n", @@ -146,11 +144,9 @@ static int rt_parse(const struct nlmsghdr *nlhdr, struct net_rt *rt) = *(uint32_t *)RTA_DATA(rtattr); break; -#ifdef HAVE_INET6 case AF_INET6: sa_set_in6(&rt->dst, RTA_DATA(rtattr), 0); break; -#endif default: DEBUG_WARNING("RTA_DST: unknown family %d\n", @@ -227,11 +223,9 @@ int net_rt_list(net_rt_h *rth, void *arg) if (0 != rt_parse(nlmsg, &rt)) continue; -#ifdef HAVE_INET6 if (AF_INET6 == sa_af(&rt.dst) && IN6_IS_ADDR_UNSPECIFIED(&rt.dst.u.in6.sin6_addr)) continue; -#endif if (rth(rt.ifname, &rt.dst, rt.dstlen, &rt.gw, arg)) break; diff --git a/src/net/netstr.c b/src/net/netstr.c index 3f356d34e..aa015c040 100644 --- a/src/net/netstr.c +++ b/src/net/netstr.c @@ -42,9 +42,7 @@ const char *net_af2name(int af) case AF_UNSPEC: return "AF_UNSPEC"; case AF_INET: return "AF_INET"; -#ifdef HAVE_INET6 case AF_INET6: return "AF_INET6"; -#endif default: return "???"; } } diff --git a/src/net/rt.c b/src/net/rt.c index d90249423..3513b080d 100644 --- a/src/net/rt.c +++ b/src/net/rt.c @@ -31,7 +31,6 @@ static bool rt_debug_handler(const char *ifname, const struct sa *dst, err |= re_hprintf(pf, "%-40j", gw); err |= re_hprintf(pf, " %-15s ", ifname); -#ifdef HAVE_INET6 if (AF_INET6 == sa_af(dst)) { const struct sockaddr_in6 *sin6 = &dst->u.in6; const struct in6_addr *in6 = &sin6->sin6_addr; @@ -43,7 +42,6 @@ static bool rt_debug_handler(const char *ifname, const struct sa *dst, if (IN6_IS_ADDR_SITELOCAL(in6)) err |= re_hprintf(pf, " SITELOCAL"); } -#endif err |= re_hprintf(pf, "\n"); @@ -98,7 +96,6 @@ static bool rt_default_get_handler(const char *_ifname, const struct sa *dst, } break; -#ifdef HAVE_INET6 case AF_INET6: if (IN6_IS_ADDR_MULTICAST(&dst->u.in6.sin6_addr)) return false; @@ -111,7 +108,6 @@ static bool rt_default_get_handler(const char *_ifname, const struct sa *dst, return false; } break; -#endif } return false; diff --git a/src/pcp/payload.c b/src/pcp/payload.c index b1a500c93..225da3a03 100644 --- a/src/pcp/payload.c +++ b/src/pcp/payload.c @@ -25,11 +25,9 @@ static int pcp_write_port(struct mbuf *mb, const struct sa *sa) port_be = sa->u.in.sin_port; break; -#ifdef HAVE_INET6 case AF_INET6: port_be = sa->u.in6.sin6_port; break; -#endif default: return EAFNOSUPPORT; diff --git a/src/pcp/pcp.c b/src/pcp/pcp.c index 099215f2d..61e58c164 100644 --- a/src/pcp/pcp.c +++ b/src/pcp/pcp.c @@ -30,11 +30,9 @@ int pcp_ipaddr_encode(struct mbuf *mb, const struct sa *sa) 4); break; -#ifdef HAVE_INET6 case AF_INET6: err |= mbuf_write_mem(mb, sa->u.in6.sin6_addr.s6_addr, 16); break; -#endif default: err = EAFNOSUPPORT; @@ -62,12 +60,10 @@ int pcp_ipaddr_decode(struct mbuf *mb, struct sa *sa) sa_init(sa, AF_INET); memcpy(&sa->u.in.sin_addr, p + 12, 4); } -#ifdef HAVE_INET6 else { sa_init(sa, AF_INET6); memcpy(sa->u.in6.sin6_addr.s6_addr, p, 16); } -#endif mb->pos += 16; diff --git a/src/rtmp/conn.c b/src/rtmp/conn.c index 50a822e80..4e3e123ca 100644 --- a/src/rtmp/conn.c +++ b/src/rtmp/conn.c @@ -869,9 +869,7 @@ int rtmp_connect(struct rtmp_conn **connp, struct dnsc *dnsc, const char *uri, goto out; } else { -#ifdef HAVE_INET6 struct sa tmp; -#endif if (!dnsc) { err = EINVAL; @@ -885,7 +883,6 @@ int rtmp_connect(struct rtmp_conn **connp, struct dnsc *dnsc, const char *uri, if (err) goto out; -#ifdef HAVE_INET6 if (0 == net_default_source_addr_get(AF_INET6, &tmp)) { err = dnsc_query(&conn->dnsq6, dnsc, conn->host, @@ -894,7 +891,6 @@ int rtmp_connect(struct rtmp_conn **connp, struct dnsc *dnsc, const char *uri, if (err) goto out; } -#endif } out: diff --git a/src/sa/printaddr.c b/src/sa/printaddr.c index b8b25c11a..ddcc2b01e 100644 --- a/src/sa/printaddr.c +++ b/src/sa/printaddr.c @@ -30,7 +30,6 @@ int sa_print_addr(struct re_printf *pf, const struct sa *sa) err = re_hprintf(pf, "%j", sa); -#ifdef HAVE_INET6 if (sa_af(sa) == AF_INET6 && sa_is_linklocal(sa)) { #ifdef HAVE_GETIFADDRS char ifname[IF_NAMESIZE]; @@ -44,7 +43,6 @@ int sa_print_addr(struct re_printf *pf, const struct sa *sa) err |= re_hprintf(pf, "%%%d", scope_id); #endif } -#endif return err; } diff --git a/src/sa/sa.c b/src/sa/sa.c index 4b5c6410f..8f6abb7f8 100644 --- a/src/sa/sa.c +++ b/src/sa/sa.c @@ -109,7 +109,6 @@ int sa_pton(const char *addr, struct sa *sa) sizeof(sa->u.un.sun_path)); } #endif -#ifdef HAVE_INET6 else if (!strncmp(addr, "fe80:", 5) && strrchr(addr, '%')) { err = sa_addrinfo(addr, sa); } @@ -124,7 +123,6 @@ int sa_pton(const char *addr, struct sa *sa) sa->u.in6.sin6_family = AF_INET6; } } -#endif else { return EINVAL; } @@ -166,12 +164,10 @@ int sa_set_str(struct sa *sa, const char *addr, uint16_t port) sa->len = sizeof(struct sockaddr_in); break; -#ifdef HAVE_INET6 case AF_INET6: sa->u.in6.sin6_port = htons(port); sa->len = sizeof(struct sockaddr_in6); break; -#endif default: return EAFNOSUPPORT; @@ -213,16 +209,11 @@ void sa_set_in6(struct sa *sa, const uint8_t *addr, uint16_t port) if (!sa) return; -#ifdef HAVE_INET6 memset(sa, 0, sizeof(*sa)); sa->u.in6.sin6_family = AF_INET6; memcpy(&sa->u.in6.sin6_addr, addr, 16); sa->u.in6.sin6_port = htons(port); sa->len = sizeof(struct sockaddr_in6); -#else - (void)addr; - (void)port; -#endif } @@ -247,12 +238,10 @@ int sa_set_sa(struct sa *sa, const struct sockaddr *s) sa->len = sizeof(struct sockaddr_in); break; -#ifdef HAVE_INET6 case AF_INET6: memcpy(&sa->u.in6, s, sizeof(struct sockaddr_in6)); sa->len = sizeof(struct sockaddr_in6); break; -#endif default: return EAFNOSUPPORT; @@ -281,11 +270,9 @@ void sa_set_port(struct sa *sa, uint16_t port) sa->u.in.sin_port = htons(port); break; -#ifdef HAVE_INET6 case AF_INET6: sa->u.in6.sin6_port = htons(port); break; -#endif default: DEBUG_WARNING("sa_set_port: no af %d (port %u)\n", @@ -387,9 +374,7 @@ void sa_in6(const struct sa *sa, uint8_t *addr) if (!sa || !addr) return; -#ifdef HAVE_INET6 memcpy(addr, &sa->u.in6.sin6_addr, 16); -#endif } @@ -421,11 +406,9 @@ int sa_ntop(const struct sa *sa, char *buf, int size) ret = inet_ntop(AF_INET, &sa->u.in.sin_addr, buf, size); break; -#ifdef HAVE_INET6 case AF_INET6: ret = inet_ntop(AF_INET6, &sa->u.in6.sin6_addr, buf, size); break; -#endif default: return EAFNOSUPPORT; @@ -455,10 +438,8 @@ uint16_t sa_port(const struct sa *sa) case AF_INET: return ntohs(sa->u.in.sin_port); -#ifdef HAVE_INET6 case AF_INET6: return ntohs(sa->u.in6.sin6_port); -#endif default: return 0; @@ -496,7 +477,6 @@ bool sa_isset(const struct sa *sa, int flag) return false; break; -#ifdef HAVE_INET6 case AF_INET6: if (flag & SA_ADDR) if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.in6.sin6_addr)) @@ -505,7 +485,6 @@ bool sa_isset(const struct sa *sa, int flag) if (0 == sa->u.in6.sin6_port) return false; break; -#endif default: return false; @@ -539,7 +518,6 @@ uint32_t sa_hash(const struct sa *sa, int flag) v += ntohs(sa->u.in.sin_port); break; -#ifdef HAVE_INET6 case AF_INET6: if (flag & SA_ADDR) { uint32_t *a = (uint32_t *)&sa->u.in6.sin6_addr; @@ -548,7 +526,6 @@ uint32_t sa_hash(const struct sa *sa, int flag) if (flag & SA_PORT) v += ntohs(sa->u.in6.sin6_port); break; -#endif default: DEBUG_WARNING("sa_hash: unknown af %d\n", sa->u.sa.sa_family); @@ -614,7 +591,6 @@ bool sa_cmp(const struct sa *l, const struct sa *r, int flag) return false; break; -#ifdef HAVE_INET6 case AF_INET6: if (flag & SA_ADDR) if (memcmp(&l->u.in6.sin6_addr, @@ -624,7 +600,6 @@ bool sa_cmp(const struct sa *l, const struct sa *r, int flag) if (l->u.in6.sin6_port != r->u.in6.sin6_port) return false; break; -#endif default: return false; @@ -656,10 +631,8 @@ bool sa_is_linklocal(const struct sa *sa) case AF_INET: return IN_IS_ADDR_LINKLOCAL(sa->u.in.sin_addr.s_addr); -#ifdef HAVE_INET6 case AF_INET6: return IN6_IS_ADDR_LINKLOCAL(&sa->u.in6.sin6_addr); -#endif default: return false; @@ -685,16 +658,38 @@ bool sa_is_loopback(const struct sa *sa) return (ntohl(sa->u.in.sin_addr.s_addr) & 0xff000000) == 0x7f000000; -#ifdef HAVE_INET6 case AF_INET6: return IN6_IS_ADDR_LOOPBACK(&sa->u.in6.sin6_addr); -#endif default: return false; } } +/** + * Check if socket address is a multicast address + * + * @param sa Socket address + * + * @return true if multicast address, otherwise false + */ +bool sa_is_multicast(const struct sa *sa) +{ + if (!sa) + return false; + + switch (sa_af(sa)) { + + case AF_INET: + return IN_MULTICAST(ntohl(sa->u.in.sin_addr.s_addr)); + + case AF_INET6: + return IN6_IS_ADDR_MULTICAST(&sa->u.in6.sin6_addr); + + default: + return false; + } +} /** * Check if socket address is any/unspecified address @@ -713,10 +708,8 @@ bool sa_is_any(const struct sa *sa) case AF_INET: return INADDR_ANY == ntohl(sa->u.in.sin_addr.s_addr); -#ifdef HAVE_INET6 case AF_INET6: return IN6_IS_ADDR_UNSPECIFIED(&sa->u.in6.sin6_addr); -#endif default: return false; @@ -729,14 +722,10 @@ void sa_set_scopeid(struct sa *sa, uint32_t scopeid) if (!sa) return; -#ifdef HAVE_INET6 if (sa_af(sa) != AF_INET6) return; sa->u.in6.sin6_scope_id = scopeid; -#else - (void)scopeid; -#endif } @@ -745,13 +734,10 @@ uint32_t sa_scopeid(const struct sa *sa) if (!sa) return 0; -#ifdef HAVE_INET6 if (sa_af(sa) != AF_INET6) return 0; return sa->u.in6.sin6_scope_id; -#endif - return 0; } diff --git a/src/sip/request.c b/src/sip/request.c index a7eec96e6..017db0e7c 100644 --- a/src/sip/request.c +++ b/src/sip/request.c @@ -406,7 +406,6 @@ static bool rr_cache_handler(struct dnsrr *rr, void *arg) list_append(&req->cachel, &rr->le_priv, rr); break; -#ifdef HAVE_INET6 case DNS_TYPE_AAAA: if (!sip_transp_supported(req->sip, req->tp, AF_INET6)) break; @@ -414,7 +413,6 @@ static bool rr_cache_handler(struct dnsrr *rr, void *arg) list_unlink(&rr->le_priv); list_append(&req->cachel, &rr->le_priv, rr); break; -#endif case DNS_TYPE_CNAME: list_unlink(&rr->le_priv); @@ -626,7 +624,6 @@ static int addr_lookup(struct sip_request *req, const char *name) return err; } -#ifdef HAVE_INET6 if (sip_transp_supported(req->sip, req->tp, AF_INET6)) { err = dnsc_query(&req->dnsq2, req->sip->dnsc, name, @@ -635,7 +632,6 @@ static int addr_lookup(struct sip_request *req, const char *name) if (err) return err; } -#endif if (!req->dnsq && !req->dnsq2) return EPROTONOSUPPORT; diff --git a/src/sip/transp.c b/src/sip/transp.c index ea9e9d43c..5a6506a96 100644 --- a/src/sip/transp.c +++ b/src/sip/transp.c @@ -1102,7 +1102,6 @@ static int ws_conn_send(struct sip_connqent **qentp, struct sip *sip, } -#if HAVE_INET6 static int dst_set_scopeid(struct sip *sip, struct sa *dst, enum sip_transp tp) { struct sa laddr; @@ -1118,7 +1117,6 @@ static int dst_set_scopeid(struct sip *sip, struct sa *dst, enum sip_transp tp) sa_set_scopeid(dst, sa_scopeid(&laddr)); return 0; } -#endif int sip_transp_init(struct sip *sip, uint32_t sz) @@ -1193,19 +1191,19 @@ static void http_req_handler(struct http_conn *hc, const struct http_msg *msg, /** * Add a SIP transport * - * @param sip SIP stack instance - * @param tp SIP Transport - * @param laddr Local network address - * @param ... Optional transport parameters such as TLS context + * @param sip SIP stack instance + * @param tp SIP Transport + * @param listen True to open listening socket (UDP socket always opened) + * @param laddr Local network address + * @param ap Optional transport parameters such as TLS context * * @return 0 if success, otherwise errorcode */ -int sip_transp_add(struct sip *sip, enum sip_transp tp, - const struct sa *laddr, ...) +static int add_transp(struct sip *sip, enum sip_transp tp, + bool listen, const struct sa *laddr, va_list ap) { struct sip_transport *transp; struct tls *tls; - va_list ap; int err = 0; if (!sip || !laddr || !sa_isset(laddr, SA_ADDR)) @@ -1227,8 +1225,6 @@ int sip_transp_add(struct sip *sip, enum sip_transp tp, transp->sip = sip; transp->tp = tp; - va_start(ap, laddr); - switch (tp) { case SIP_TRANSP_UDP: @@ -1252,6 +1248,13 @@ int sip_transp_add(struct sip *sip, enum sip_transp tp, /*@fallthrough@*/ case SIP_TRANSP_TCP: + + if (!listen) { + transp->laddr = *laddr; + sa_set_port(&transp->laddr, 0); + return err; + } + err = tcp_listen((struct tcp_sock **)&transp->sock, laddr, tcp_connect_handler, transp); if (err) @@ -1265,8 +1268,6 @@ int sip_transp_add(struct sip *sip, enum sip_transp tp, break; } - va_end(ap); - if (err) mem_deref(transp); @@ -1274,6 +1275,57 @@ int sip_transp_add(struct sip *sip, enum sip_transp tp, } +/** + * Add a SIP transport + * + * @param sip SIP stack instance + * @param tp SIP Transport + * @param laddr Local network address + * @param ... Optional transport parameters such as TLS context + * + * @return 0 if success, otherwise errorcode + */ +int sip_transp_add(struct sip *sip, enum sip_transp tp, + const struct sa *laddr, ...) +{ + int err; + va_list ap; + + va_start(ap, laddr); + err = add_transp(sip, tp, true, laddr, ap); + va_end(ap); + + return err; +} + + +/** + * Add a SIP transport and open listening socket if requested + * + * UDP socket will always be opened even if listen is false. + * + * @param sip SIP stack instance + * @param tp SIP Transport + * @param listen True to open listening socket + * @param laddr Local network address + * @param ... Optional transport parameters such as TLS context + * + * @return 0 if success, otherwise errorcode + */ +int sip_transp_add_sock(struct sip *sip, enum sip_transp tp, + bool listen, const struct sa *laddr, ...) +{ + int err; + va_list ap; + + va_start(ap, laddr); + err = add_transp(sip, tp, listen, laddr, ap); + va_end(ap); + + return err; +} + + /** * Add a SIP websocket transport * @@ -1446,11 +1498,9 @@ int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, return EINVAL; sa_cpy(&dsttmp, dst); -#if HAVE_INET6 err = dst_set_scopeid(sip, &dsttmp, tp); if (err) return err; -#endif switch (tp) { @@ -1768,11 +1818,30 @@ int sip_settos(struct sip *sip, uint8_t tos) } +static void sip_transports_print(struct re_printf *pf, const struct sip* sip) +{ + uint32_t mask = 0; + + for (struct le *le = sip->transpl.head; le; le = le->next) { + const struct sip_transport *transp = le->data; + mask |= (1 << transp->tp); + } + + for (uint8_t i = 0; i < SIP_TRANSPC; ++i) { + if (mask==0 || (0 != (mask & (1u << i)))) + (void)re_hprintf(pf, " %s\n", sip_transp_name(i)); + } +} + + static bool debug_handler(struct le *le, void *arg) { const struct sip_transport *transp = le->data; struct re_printf *pf = arg; + if (sa_port(&transp->laddr) == 0) + return false; + (void)re_hprintf(pf, " %J (%s)\n", &transp->laddr, sip_transp_name(transp->tp)); @@ -1813,6 +1882,9 @@ int sip_transp_debug(struct re_printf *pf, const struct sip *sip) int err; err = re_hprintf(pf, "transports:\n"); + sip_transports_print(pf, sip); + + err |= re_hprintf(pf, "transport sockets:\n"); list_apply(&sip->transpl, true, debug_handler, pf); err |= re_hprintf(pf, "connections:\n"); diff --git a/src/stun/addr.c b/src/stun/addr.c index 812942a4f..d34cbd245 100644 --- a/src/stun/addr.c +++ b/src/stun/addr.c @@ -29,9 +29,7 @@ static void in6_xor_tid(uint8_t *in6, const uint8_t *tid) int stun_addr_encode(struct mbuf *mb, const struct sa *addr, const uint8_t *tid) { -#ifdef HAVE_INET6 uint8_t addr6[16]; -#endif uint16_t port; uint32_t addr4; int err = 0; @@ -52,7 +50,6 @@ int stun_addr_encode(struct mbuf *mb, const struct sa *addr, err |= mbuf_write_u32(mb, htonl(addr4)); break; -#ifdef HAVE_INET6 case AF_INET6: sa_in6(addr, addr6); if (tid) @@ -63,7 +60,7 @@ int stun_addr_encode(struct mbuf *mb, const struct sa *addr, err |= mbuf_write_u16(mb, htons(port)); err |= mbuf_write_mem(mb, addr6, 16); break; -#endif + default: err = EAFNOSUPPORT; break; diff --git a/src/stun/dnsdisc.c b/src/stun/dnsdisc.c index c79b2c4ef..50b2adf2e 100644 --- a/src/stun/dnsdisc.c +++ b/src/stun/dnsdisc.c @@ -79,7 +79,6 @@ static void a_handler(int err, const struct dnshdr *hdr, struct list *ansl, } -#ifdef HAVE_INET6 static void aaaa_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { @@ -104,7 +103,6 @@ static void aaaa_handler(int err, const struct dnshdr *hdr, struct list *ansl, out: resolved(dns, err); } -#endif static int a_or_aaaa_query(struct stun_dns *dns, const char *name) @@ -117,11 +115,9 @@ static int a_or_aaaa_query(struct stun_dns *dns, const char *name) return dnsc_query(&dns->dq, dns->dnsc, name, DNS_TYPE_A, DNS_CLASS_IN, true, a_handler, dns); -#ifdef HAVE_INET6 case AF_INET6: return dnsc_query(&dns->dq, dns->dnsc, name, DNS_TYPE_AAAA, DNS_CLASS_IN, true, aaaa_handler, dns); -#endif default: return EAFNOSUPPORT; @@ -172,7 +168,6 @@ static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, } break; -#ifdef HAVE_INET6 case AF_INET6: arr = dns_rrlist_find(addl, rr->rdata.srv.target, DNS_TYPE_AAAA, DNS_CLASS_IN, true); @@ -183,7 +178,6 @@ static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, goto out; } break; -#endif } sa_set_in(&dns->srv, 0, rr->rdata.srv.port); diff --git a/src/tls/openssl/sni.c b/src/tls/openssl/sni.c index 8298e40fd..aee7605ce 100644 --- a/src/tls/openssl/sni.c +++ b/src/tls/openssl/sni.c @@ -135,41 +135,18 @@ struct tls_cert *tls_cert_for_sni(const struct tls *tls, const char *sni) } -static int ssl_set_verify_client(SSL *ssl, const char *host) -{ - struct sa sa; - - if (!ssl || !host) - return EINVAL; - - if (sa_set_str(&sa, host, 0)) { - SSL_set_hostflags(ssl, - X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); - - if (!SSL_set1_host(ssl, host)) { - DEBUG_WARNING("SSL_set1_host error\n"); - ERR_clear_error(); - return EPROTO; - } - } - - SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_handler); - - return 0; -} - - static int ssl_servername_handler(SSL *ssl, int *al, void *arg) { struct tls *tls = arg; struct tls_cert *uc = NULL; const char *sni; + if (!SSL_is_server(ssl)) + return SSL_TLSEXT_ERR_OK; + sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - if (!str_isset(sni)) { - *al = SSL_AD_UNRECOGNIZED_NAME; - return SSL_TLSEXT_ERR_ALERT_FATAL; - } + if (!str_isset(sni)) + return SSL_TLSEXT_ERR_OK; /* find and apply matching certificate */ uc = tls_cert_for_sni(tls, sni); @@ -184,8 +161,6 @@ static int ssl_servername_handler(SSL *ssl, int *al, void *arg) return SSL_TLSEXT_ERR_ALERT_FATAL; } - (void)ssl_set_verify_client(ssl, tls_cert_host(uc)); - return SSL_TLSEXT_ERR_OK; } diff --git a/src/turn/turnc.c b/src/turn/turnc.c index 25bfad6cd..659efa5de 100644 --- a/src/turn/turnc.c +++ b/src/turn/turnc.c @@ -252,11 +252,9 @@ static inline size_t stun_indlen(const struct sa *sa) len += STUN_ATTR_ADDR4_SIZE; break; -#ifdef HAVE_INET6 case AF_INET6: len += STUN_ATTR_ADDR6_SIZE; break; -#endif } return len; diff --git a/src/udp/mcast.c b/src/udp/mcast.c index 429479b8d..d0e9a985b 100644 --- a/src/udp/mcast.c +++ b/src/udp/mcast.c @@ -13,9 +13,7 @@ static int multicast_update(struct udp_sock *us, const struct sa *group, bool join) { struct ip_mreq mreq; -#ifdef HAVE_INET6 struct ipv6_mreq mreq6; -#endif int err; if (!us || !group) @@ -34,7 +32,6 @@ static int multicast_update(struct udp_sock *us, const struct sa *group, &mreq, sizeof(mreq)); break; -#ifdef HAVE_INET6 case AF_INET6: mreq6.ipv6mr_multiaddr = group->u.in6.sin6_addr; mreq6.ipv6mr_interface = sa_scopeid(group); @@ -45,7 +42,6 @@ static int multicast_update(struct udp_sock *us, const struct sa *group, : IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)); break; -#endif default: return EAFNOSUPPORT; diff --git a/src/udp/udp.c b/src/udp/udp.c index 18b58d8f3..7a7f9cb52 100644 --- a/src/udp/udp.c +++ b/src/udp/udp.c @@ -285,11 +285,7 @@ int udp_listen(struct udp_sock **usp, const struct sa *local, (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local)); } else { -#ifdef HAVE_INET6 af = AF_UNSPEC; -#else - af = AF_INET; -#endif } memset(&hints, 0, sizeof(hints)); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a1bbf043..213e5d4a3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,6 +80,7 @@ set(SRCS conf.c convert.c crc32.c + dd.c dns.c dsp.c dtmf.c diff --git a/test/async.c b/test/async.c index b0da51e91..c2f2c7a84 100644 --- a/test/async.c +++ b/test/async.c @@ -41,7 +41,7 @@ static int blocking_getaddr(void *arg) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; - hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; + hints.ai_flags = AI_V4MAPPED; /* Blocking */ diff --git a/test/dd.c b/test/dd.c new file mode 100644 index 000000000..a2fae38a5 --- /dev/null +++ b/test/dd.c @@ -0,0 +1,333 @@ +/** + * @file test/dd.c Dependency Descriptor (DD) testcode + * + * Copyright (C) 2010 - 2023 Alfred E. Heggestad + */ + +#include +#include +#include +#include "test.h" + + +#define DEBUG_MODULE "ddtest" +#define DEBUG_LEVEL 5 +#include + + +static int test_dd_mand(void) +{ + struct dd dd = { 0 }; + struct mbuf *mb = mbuf_alloc(512); + + if (!mb) + return ENOMEM; + + int err = dd_encode(mb, &dd); + TEST_ERR(err); + + /* Mandatory Descriptor Fields -- 3 bytes only */ + static const uint8_t buf_exp[] = { 0, 0, 0 }; + + TEST_MEMCMP(buf_exp, sizeof(buf_exp), mb->buf, mb->end); + + struct dd dd_dec; + + err = dd_decode(&dd_dec, mb->buf, mb->end); + TEST_ERR(err); + + ASSERT_EQ(0, dd_dec.start_of_frame); + ASSERT_EQ(0, dd_dec.end_of_frame); + ASSERT_EQ(0, dd_dec.frame_dependency_template_id); + ASSERT_EQ(0, dd_dec.frame_number); + + ASSERT_TRUE(!dd_dec.ext); + + out: + mem_deref(mb); + return err; +} + + +/* + +80012f800214eaa860414d1410208426 + + +"startOfFrame":true, +"endOfFrame":false, +"frameDependencyTemplateId":0, +"frameNumber":303, +"templateStructure":{ + "templateIdOffset":0, + "templateInfo":{ + "0":{ + "spatialId":0, + "temporalId":0, + "dti":[ + "SWITCH", + "SWITCH", + "SWITCH" + ], + "fdiff":[ + + ], + "chains":[ + 0 + ] + }, + "1":{ + "spatialId":0, + "temporalId":0, + "dti":[ + "SWITCH", + "SWITCH", + "SWITCH" + ], + "fdiff":[ + 4 + ], + "chains":[ + 4 + ] + }, + "2":{ + "spatialId":0, + "temporalId":1, + "dti":[ + "NOT_PRESENT", + "DISCARDABLE", + "SWITCH" + ], + "fdiff":[ + 2 + ], + "chains":[ + 2 + ] + }, + "3":{ + "spatialId":0, + "temporalId":2, + "dti":[ + "NOT_PRESENT", + "NOT_PRESENT", + "DISCARDABLE" + ], + "fdiff":[ + 1 + ], + "chains":[ + 1 + ] + }, + "4":{ + "spatialId":0, + "temporalId":2, + "dti":[ + "NOT_PRESENT", + "NOT_PRESENT", + "DISCARDABLE" + ], + "fdiff":[ + 1 + ], + "chains":[ + 3 + ] + } + }, + "decodeTargetInfo":{ + "0":{ + "protectedBy":0, + "spatialId":0, + "temporalId":0 + }, + "1":{ + "protectedBy":0, + "spatialId":0, + "temporalId":1 + }, + "2":{ + "protectedBy":0, + "spatialId":0, + "temporalId":2 + } + }, + "maxSpatialId":0, + "maxTemporalId":2 +} +} + + + */ +static int test_dd_decode(void) +{ + static const char *str = "80012f800214eaa860414d1410208426"; + struct mbuf *mb = mbuf_alloc(8); + uint8_t buf[16]; + int err; + + if (!mb) + return ENOMEM; + + err = str_hex(buf, sizeof(buf), str); + TEST_ERR(err); + + struct dd dd; + + err = dd_decode(&dd, buf, sizeof(buf)); + TEST_ERR(err); + +#if 0 + dd_print(&dd); +#endif + + ASSERT_EQ(1, dd.start_of_frame); + ASSERT_EQ(0, dd.end_of_frame); + ASSERT_EQ(0, dd.frame_dependency_template_id); + ASSERT_EQ(303, dd.frame_number); + + ASSERT_EQ(1, dd.template_dependency_structure_present_flag); + ASSERT_EQ(0, dd.active_decode_targets_present_flag); + ASSERT_EQ(0, dd.custom_dtis_flag); + ASSERT_EQ(0, dd.custom_fdiffs_flag); + ASSERT_EQ(0, dd.custom_chains_flag); + + ASSERT_EQ(7, dd.active_decode_targets_bitmask); + ASSERT_EQ(0, dd.template_id_offset); + ASSERT_EQ(3, dd.dt_cnt); + ASSERT_EQ(5, dd.template_cnt); + ASSERT_EQ(0, dd.max_spatial_id); + + ASSERT_EQ(0, dd.template_spatial_id[0]); + ASSERT_EQ(0, dd.template_spatial_id[1]); + ASSERT_EQ(0, dd.template_spatial_id[2]); + ASSERT_EQ(0, dd.template_spatial_id[3]); + ASSERT_EQ(0, dd.template_spatial_id[4]); + + ASSERT_EQ(0, dd.template_temporal_id[0]); + ASSERT_EQ(0, dd.template_temporal_id[1]); + ASSERT_EQ(1, dd.template_temporal_id[2]); + ASSERT_EQ(2, dd.template_temporal_id[3]); + ASSERT_EQ(2, dd.template_temporal_id[4]); + + ASSERT_TRUE(!dd.resolutions_present_flag); + ASSERT_EQ(0, dd.render_count); + + ASSERT_EQ(2, dd.template_dti[0][0]); + ASSERT_EQ(2, dd.template_dti[0][1]); + ASSERT_EQ(2, dd.template_dti[0][2]); + ASSERT_EQ(2, dd.template_dti[1][0]); + ASSERT_EQ(2, dd.template_dti[1][1]); + ASSERT_EQ(2, dd.template_dti[1][2]); + ASSERT_EQ(0, dd.template_dti[2][0]); + ASSERT_EQ(1, dd.template_dti[2][1]); + ASSERT_EQ(2, dd.template_dti[2][2]); + ASSERT_EQ(0, dd.template_dti[3][0]); + ASSERT_EQ(0, dd.template_dti[3][1]); + ASSERT_EQ(1, dd.template_dti[3][2]); + ASSERT_EQ(0, dd.template_dti[4][0]); + ASSERT_EQ(0, dd.template_dti[4][1]); + ASSERT_EQ(1, dd.template_dti[4][2]); + + ASSERT_EQ(1, dd.chain_cnt); + + err = dd_encode(mb, &dd); + TEST_ERR(err); + + TEST_MEMCMP(buf, sizeof(buf), mb->buf, mb->end); + + out: + mem_deref(mb); + return err; +} + + +/* + * Interop test with Chrome Version 118.0.5993.70 + */ +static int test_dd_chrome(void) +{ + static const char *str = "80000180003a40813f80ef80"; + struct mbuf *mb = mbuf_alloc(16); + uint8_t buf[12]; + int err; + + if (!mb) + return ENOMEM; + + err = str_hex(buf, sizeof(buf), str); + TEST_ERR(err); + + struct dd dd; + + err = dd_decode(&dd, buf, sizeof(buf)); + TEST_ERR(err); + +#if 0 + dd_print(&dd); +#endif + + ASSERT_EQ(1, dd.start_of_frame); + ASSERT_EQ(0, dd.end_of_frame); + ASSERT_EQ(0, dd.frame_dependency_template_id); + ASSERT_EQ(1, dd.frame_number); + + ASSERT_EQ(1, dd.template_dependency_structure_present_flag); + ASSERT_EQ(0, dd.active_decode_targets_present_flag); + ASSERT_EQ(0, dd.custom_dtis_flag); + ASSERT_EQ(0, dd.custom_fdiffs_flag); + ASSERT_EQ(0, dd.custom_chains_flag); + + ASSERT_EQ(1, dd.active_decode_targets_bitmask); + ASSERT_EQ(0, dd.template_id_offset); + ASSERT_EQ(1, dd.dt_cnt); + ASSERT_EQ(2, dd.template_cnt); + ASSERT_EQ(0, dd.max_spatial_id); + + ASSERT_EQ(0, dd.template_spatial_id[0]); + ASSERT_EQ(0, dd.template_spatial_id[1]); + + ASSERT_EQ(0, dd.template_temporal_id[0]); + ASSERT_EQ(0, dd.template_temporal_id[1]); + + ASSERT_TRUE(dd.resolutions_present_flag); + ASSERT_EQ(1, dd.render_count); + ASSERT_EQ(639, dd.max_render_width_minus_1[0]); + ASSERT_EQ(479, dd.max_render_height_minus_1[0]); + + ASSERT_EQ(2, dd.template_dti[0][0]); + ASSERT_EQ(2, dd.template_dti[1][0]); + + ASSERT_EQ(0, dd.chain_cnt); + + err = dd_encode(mb, &dd); + TEST_ERR(err); + + TEST_MEMCMP(buf, sizeof(buf), mb->buf, mb->end); + + out: + mem_deref(mb); + return err; +} + + +int test_dd(void) +{ + int err; + + err = test_dd_mand(); + if (err) + return err; + + err = test_dd_decode(); + if (err) + return err; + + err = test_dd_chrome(); + if (err) + return err; + + return 0; +} diff --git a/test/main.c b/test/main.c index 62ff47fa4..5b26f5320 100644 --- a/test/main.c +++ b/test/main.c @@ -32,8 +32,7 @@ static void signal_handler(int num) #ifdef HAVE_GETOPT static void usage(void) { - (void)re_fprintf(stderr, "Usage: retest [-rotalp] [-hmv]" - " \n"); + (void)re_fprintf(stderr, "Usage: retest [options] \n"); (void)re_fprintf(stderr, "\ntest group options:\n"); (void)re_fprintf(stderr, "\t-r Run regular tests\n"); diff --git a/test/test.c b/test/test.c index 967f5dca5..66d2d377e 100644 --- a/test/test.c +++ b/test/test.c @@ -59,6 +59,7 @@ static const struct test tests[] = { TEST(test_auresamp), TEST(test_async), TEST(test_av1), + TEST(test_dd), TEST(test_base64), TEST(test_bfcp), TEST(test_bfcp_bin), diff --git a/test/test.h b/test/test.h index 04b2639f2..aa04d92b3 100644 --- a/test/test.h +++ b/test/test.h @@ -164,6 +164,7 @@ int test_auposition(void); int test_auresamp(void); int test_async(void); int test_av1(void); +int test_dd(void); int test_base64(void); int test_bfcp(void); int test_bfcp_bin(void);