Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f8ad243

Browse files
authoredJan 17, 2023
Merge pull request #612 from mildsunrise/stream-list-api
Allow overriding stream list implementation
2 parents b1f3b8b + d1eb03a commit f8ad243

File tree

5 files changed

+846
-256
lines changed

5 files changed

+846
-256
lines changed
 

‎.github/workflows/stream_list.yml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Stream List CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build:
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
os: [ubuntu-latest, macos-latest, windows-latest]
15+
16+
runs-on: ${{ matrix.os }}
17+
18+
env:
19+
CTEST_OUTPUT_ON_FAILURE: 1
20+
21+
steps:
22+
23+
- uses: actions/checkout@v2
24+
25+
- name: Create Build Environment
26+
run: cmake -E make_directory ${{github.workspace}}/build
27+
28+
- name: Configure CMake
29+
working-directory: ${{github.workspace}}/build
30+
shell: bash
31+
run: cmake $GITHUB_WORKSPACE -DBUILD_WITH_SANITIZERS=TRUE -DCMAKE_C_FLAGS:STRING="-DSRTP_NO_STREAM_LIST -DSRTP_USE_TEST_STREAM_LIST"
32+
33+
- name: Build
34+
working-directory: ${{github.workspace}}/build
35+
shell: bash
36+
run: cmake --build . -t srtp_driver
37+
38+
- name: Test
39+
working-directory: ${{github.workspace}}/build
40+
shell: bash
41+
run: ctest -R srtp_driver

‎include/srtp_priv.h

+10-8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ extern "C" {
6666

6767
typedef struct srtp_stream_ctx_t_ srtp_stream_ctx_t;
6868
typedef srtp_stream_ctx_t *srtp_stream_t;
69+
typedef struct srtp_stream_list_ctx_t_ *srtp_stream_list_t;
6970

7071
/*
7172
* the following declarations are libSRTP internal functions
@@ -96,12 +97,6 @@ srtp_err_status_t srtp_steam_init_all_master_keys(
9697
srtp_master_key_t **keys,
9798
const unsigned int max_master_keys);
9899

99-
/*
100-
* srtp_stream_init(s, p) initializes the srtp_stream_t s to
101-
* use the policy at the location p
102-
*/
103-
srtp_err_status_t srtp_stream_init(srtp_stream_t srtp, const srtp_policy_t *p);
104-
105100
/*
106101
* libsrtp internal datatypes
107102
*/
@@ -149,14 +144,21 @@ typedef struct srtp_stream_ctx_t_ {
149144
int *enc_xtn_hdr;
150145
int enc_xtn_hdr_count;
151146
uint32_t pending_roc;
152-
struct srtp_stream_ctx_t_ *next; /* linked list of streams */
147+
/*
148+
The next and prev pointers are here to allow for a stream list to be
149+
implemented as an intrusive doubly-linked list (the former being the
150+
default). Other stream list implementations can ignore these fields or use
151+
them for some other purpose specific to the stream list implementation.
152+
*/
153+
struct srtp_stream_ctx_t_ *next;
154+
struct srtp_stream_ctx_t_ *prev;
153155
} strp_stream_ctx_t_;
154156

155157
/*
156158
* an srtp_ctx_t holds a stream list and a service description
157159
*/
158160
typedef struct srtp_ctx_t_ {
159-
struct srtp_stream_ctx_t_ *stream_list; /* linked list of streams */
161+
srtp_stream_list_t stream_list; /* linked list of streams */
160162
struct srtp_stream_ctx_t_ *stream_template; /* act as template for other */
161163
/* streams */
162164
void *user_data; /* user custom data */

‎include/stream_list_priv.h

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* stream_list_priv.h
3+
*
4+
* list of SRTP streams, keyed by SSRC
5+
*
6+
* Alba Mendez
7+
*/
8+
/*
9+
*
10+
* Copyright (c) 2001-2017, Cisco Systems, Inc.
11+
* Copyright (c) 2022, Dolby Laboratories, Inc.
12+
* All rights reserved.
13+
*
14+
* Redistribution and use in source and binary forms, with or without
15+
* modification, are permitted provided that the following conditions
16+
* are met:
17+
*
18+
* Redistributions of source code must retain the above copyright
19+
* notice, this list of conditions and the following disclaimer.
20+
*
21+
* Redistributions in binary form must reproduce the above
22+
* copyright notice, this list of conditions and the following
23+
* disclaimer in the documentation and/or other materials provided
24+
* with the distribution.
25+
*
26+
* Neither the name of the Cisco Systems, Inc. nor the names of its
27+
* contributors may be used to endorse or promote products derived
28+
* from this software without specific prior written permission.
29+
*
30+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34+
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
35+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39+
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41+
* OF THE POSSIBILITY OF SUCH DAMAGE.
42+
*
43+
*/
44+
45+
#ifndef SRTP_STREAM_LIST_PRIV_H
46+
#define SRTP_STREAM_LIST_PRIV_H
47+
48+
#include <srtp_priv.h>
49+
50+
#ifdef __cplusplus
51+
extern "C" {
52+
#endif
53+
54+
/**
55+
* srtp_stream_list_t holds a list of srtp_stream_t, each identified
56+
* by their SSRC.
57+
*
58+
* the API was extracted to allow downstreams to override its
59+
* implementation by defining the `SRTP_NO_STREAM_LIST` preprocessor
60+
* directive, which removes the default implementation of these
61+
* functions. if this is done, the `next` & `prev` fields are free for
62+
* the implementation to use.
63+
*
64+
* this is still an internal interface; there is no stability
65+
* guarantee--downstreams should watch this file for changes in
66+
* signatures or semantics.
67+
*/
68+
69+
/**
70+
* allocate and initialize a stream list instance
71+
*/
72+
srtp_err_status_t srtp_stream_list_alloc(srtp_stream_list_t *list_ptr);
73+
74+
/**
75+
* deallocate a stream list instance
76+
*
77+
* the list must be empty or else an error is returned.
78+
*/
79+
srtp_err_status_t srtp_stream_list_dealloc(srtp_stream_list_t list);
80+
81+
/**
82+
* insert a stream into the list
83+
*
84+
* returns srtp_err_status_alloc_fail if insertion failed due to unavailable
85+
* capacity in the list. if operation succeeds, srtp_err_status_ok is returned
86+
*
87+
* if another stream with the same SSRC already exists in the list,
88+
* behavior is undefined. if the SSRC field is mutated while the
89+
* stream is inserted, further operations have undefined behavior
90+
*/
91+
srtp_err_status_t srtp_stream_list_insert(srtp_stream_list_t list,
92+
srtp_stream_t stream);
93+
94+
/*
95+
* look up the stream corresponding to the specified SSRC and return it.
96+
* if no such SSRC is found, NULL is returned.
97+
*/
98+
srtp_stream_t srtp_stream_list_get(srtp_stream_list_t list, uint32_t ssrc);
99+
100+
/**
101+
* remove the stream from the list.
102+
*
103+
* The stream to be removed is referenced "by value", i.e., by the pointer to be
104+
* removed from the list. This pointer is obtained using `srtp_stream_list_get`
105+
* or as callback parameter in `srtp_stream_list_for_each`.
106+
*/
107+
void srtp_stream_list_remove(srtp_stream_list_t list, srtp_stream_t stream);
108+
109+
/**
110+
* iterate through all stored streams. while iterating, it is allowed to delete
111+
* the current element; any other mutation to the list is undefined behavior.
112+
* returning non-zero from callback aborts the iteration.
113+
*/
114+
void srtp_stream_list_for_each(srtp_stream_list_t list,
115+
int (*callback)(srtp_stream_t, void *),
116+
void *data);
117+
118+
#ifdef __cplusplus
119+
}
120+
#endif
121+
122+
#endif /* SRTP_STREAM_LIST_PRIV_H */

‎srtp/srtp.c

+332-156
Large diffs are not rendered by default.

‎test/srtp_driver.c

+341-92
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "getopt_s.h" /* for local getopt() */
5050

5151
#include "srtp_priv.h"
52+
#include "stream_list_priv.h"
5253
#include "util.h"
5354

5455
#ifdef HAVE_NETINET_IN_H
@@ -124,6 +125,8 @@ char *srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len);
124125

125126
double mips_estimate(int num_trials, int *ignore);
126127

128+
srtp_err_status_t srtp_stream_list_test(void);
129+
127130
#define TEST_MKI_ID_SIZE 4
128131

129132
extern uint8_t test_key[46];
@@ -153,15 +156,17 @@ srtp_master_key_t *test_keys[2] = {
153156

154157
void usage(char *prog_name)
155158
{
156-
printf("usage: %s [ -t ][ -c ][ -v ][ -o ][-d <debug_module> ]* [ -l ]\n"
157-
" -t run timing test\n"
158-
" -r run rejection timing test\n"
159-
" -c run codec timing test\n"
160-
" -v run validation tests\n"
161-
" -o output logging to stdout\n"
162-
" -d <mod> turn on debugging module <mod>\n"
163-
" -l list debugging modules\n",
164-
prog_name);
159+
printf(
160+
"usage: %s [ -t ][ -c ][ -v ][ -s ][ -o ][-d <debug_module> ]* [ -l ]\n"
161+
" -t run timing test\n"
162+
" -r run rejection timing test\n"
163+
" -c run codec timing test\n"
164+
" -v run validation tests\n"
165+
" -s run stream list tests only\n"
166+
" -o output logging to stdout\n"
167+
" -d <mod> turn on debugging module <mod>\n"
168+
" -l list debugging modules\n",
169+
prog_name);
165170
exit(1);
166171
}
167172

@@ -217,6 +222,7 @@ int main(int argc, char *argv[])
217222
unsigned do_rejection_test = 0;
218223
unsigned do_codec_timing = 0;
219224
unsigned do_validation = 0;
225+
unsigned do_stream_list = 0;
220226
unsigned do_list_mods = 0;
221227
unsigned do_log_stdout = 0;
222228
srtp_err_status_t status;
@@ -251,7 +257,7 @@ int main(int argc, char *argv[])
251257

252258
/* process input arguments */
253259
while (1) {
254-
q = getopt_s(argc, argv, "trcvold:");
260+
q = getopt_s(argc, argv, "trcvsold:");
255261
if (q == -1) {
256262
break;
257263
}
@@ -267,6 +273,10 @@ int main(int argc, char *argv[])
267273
break;
268274
case 'v':
269275
do_validation = 1;
276+
do_stream_list = 1;
277+
break;
278+
case 's':
279+
do_stream_list = 1;
270280
break;
271281
case 'o':
272282
do_log_stdout = 1;
@@ -287,7 +297,7 @@ int main(int argc, char *argv[])
287297
}
288298

289299
if (!do_validation && !do_timing_test && !do_codec_timing &&
290-
!do_list_mods && !do_rejection_test) {
300+
!do_list_mods && !do_rejection_test && !do_stream_list) {
291301
usage(argv[0]);
292302
}
293303

@@ -597,6 +607,16 @@ int main(int argc, char *argv[])
597607
}
598608
}
599609

610+
if (do_stream_list) {
611+
printf("testing srtp_stream_list...");
612+
if (srtp_stream_list_test() == srtp_err_status_ok) {
613+
printf("passed\n");
614+
} else {
615+
printf("failed\n");
616+
exit(1);
617+
}
618+
}
619+
600620
if (do_timing_test) {
601621
const srtp_policy_t **policy = policy_array;
602622

@@ -1467,13 +1487,75 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, int mki_index)
14671487
return srtp_err_status_ok;
14681488
}
14691489

1490+
struct srtp_session_print_stream_data {
1491+
// set by callback to indicate failure
1492+
srtp_err_status_t status;
1493+
// indicates if it is the template stream or a regular stream
1494+
int is_template;
1495+
};
1496+
1497+
int srtp_session_print_stream(srtp_stream_t stream, void *raw_data)
1498+
{
1499+
static const char *serv_descr[4] = { "none", "confidentiality",
1500+
"authentication",
1501+
"confidentiality and authentication" };
1502+
static const char *direction[3] = { "unknown", "outbound", "inbound" };
1503+
1504+
struct srtp_session_print_stream_data *data =
1505+
(struct srtp_session_print_stream_data *)raw_data;
1506+
srtp_session_keys_t *session_keys = &stream->session_keys[0];
1507+
char ssrc_text[32];
1508+
1509+
if (!data->is_template && stream->rtp_services > sec_serv_conf_and_auth) {
1510+
data->status = srtp_err_status_bad_param;
1511+
return 1;
1512+
}
1513+
1514+
if (data->is_template) {
1515+
snprintf(ssrc_text, sizeof(ssrc_text), "any %s",
1516+
direction[stream->direction]);
1517+
} else {
1518+
snprintf(ssrc_text, sizeof(ssrc_text), "0x%08x", stream->ssrc);
1519+
}
1520+
1521+
printf("# SSRC: %s\r\n"
1522+
"# rtp cipher: %s\r\n"
1523+
"# rtp auth: %s\r\n"
1524+
"# rtp services: %s\r\n"
1525+
"# rtcp cipher: %s\r\n"
1526+
"# rtcp auth: %s\r\n"
1527+
"# rtcp services: %s\r\n"
1528+
"# window size: %lu\r\n"
1529+
"# tx rtx allowed:%s\r\n",
1530+
ssrc_text, session_keys->rtp_cipher->type->description,
1531+
session_keys->rtp_auth->type->description,
1532+
serv_descr[stream->rtp_services],
1533+
session_keys->rtcp_cipher->type->description,
1534+
session_keys->rtcp_auth->type->description,
1535+
serv_descr[stream->rtcp_services],
1536+
srtp_rdbx_get_window_size(&stream->rtp_rdbx),
1537+
stream->allow_repeat_tx ? "true" : "false");
1538+
1539+
printf("# Encrypted extension headers: ");
1540+
if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) {
1541+
int *enc_xtn_hdr = stream->enc_xtn_hdr;
1542+
int count = stream->enc_xtn_hdr_count;
1543+
while (count > 0) {
1544+
printf("%d ", *enc_xtn_hdr);
1545+
enc_xtn_hdr++;
1546+
count--;
1547+
}
1548+
printf("\n");
1549+
} else {
1550+
printf("none\n");
1551+
}
1552+
1553+
return 0;
1554+
}
1555+
14701556
srtp_err_status_t srtp_session_print_policy(srtp_t srtp)
14711557
{
1472-
char *serv_descr[4] = { "none", "confidentiality", "authentication",
1473-
"confidentiality and authentication" };
1474-
char *direction[3] = { "unknown", "outbound", "inbound" };
1475-
srtp_stream_t stream;
1476-
srtp_session_keys_t *session_keys = NULL;
1558+
struct srtp_session_print_stream_data data = { srtp_err_status_ok, 0 };
14771559

14781560
/* sanity checking */
14791561
if (srtp == NULL) {
@@ -1482,86 +1564,16 @@ srtp_err_status_t srtp_session_print_policy(srtp_t srtp)
14821564

14831565
/* if there's a template stream, print it out */
14841566
if (srtp->stream_template != NULL) {
1485-
stream = srtp->stream_template;
1486-
session_keys = &stream->session_keys[0];
1487-
printf("# SSRC: any %s\r\n"
1488-
"# rtp cipher: %s\r\n"
1489-
"# rtp auth: %s\r\n"
1490-
"# rtp services: %s\r\n"
1491-
"# rtcp cipher: %s\r\n"
1492-
"# rtcp auth: %s\r\n"
1493-
"# rtcp services: %s\r\n"
1494-
"# window size: %lu\r\n"
1495-
"# tx rtx allowed:%s\r\n",
1496-
direction[stream->direction],
1497-
session_keys->rtp_cipher->type->description,
1498-
session_keys->rtp_auth->type->description,
1499-
serv_descr[stream->rtp_services],
1500-
session_keys->rtcp_cipher->type->description,
1501-
session_keys->rtcp_auth->type->description,
1502-
serv_descr[stream->rtcp_services],
1503-
srtp_rdbx_get_window_size(&stream->rtp_rdbx),
1504-
stream->allow_repeat_tx ? "true" : "false");
1505-
1506-
printf("# Encrypted extension headers: ");
1507-
if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) {
1508-
int *enc_xtn_hdr = stream->enc_xtn_hdr;
1509-
int count = stream->enc_xtn_hdr_count;
1510-
while (count > 0) {
1511-
printf("%d ", *enc_xtn_hdr);
1512-
enc_xtn_hdr++;
1513-
count--;
1514-
}
1515-
printf("\n");
1516-
} else {
1517-
printf("none\n");
1518-
}
1567+
data.is_template = 1;
1568+
srtp_session_print_stream(srtp->stream_template, &data);
15191569
}
15201570

15211571
/* loop over streams in session, printing the policy of each */
1522-
stream = srtp->stream_list;
1523-
while (stream != NULL) {
1524-
if (stream->rtp_services > sec_serv_conf_and_auth) {
1525-
return srtp_err_status_bad_param;
1526-
}
1527-
session_keys = &stream->session_keys[0];
1528-
1529-
printf("# SSRC: 0x%08x\r\n"
1530-
"# rtp cipher: %s\r\n"
1531-
"# rtp auth: %s\r\n"
1532-
"# rtp services: %s\r\n"
1533-
"# rtcp cipher: %s\r\n"
1534-
"# rtcp auth: %s\r\n"
1535-
"# rtcp services: %s\r\n"
1536-
"# window size: %lu\r\n"
1537-
"# tx rtx allowed:%s\r\n",
1538-
stream->ssrc, session_keys->rtp_cipher->type->description,
1539-
session_keys->rtp_auth->type->description,
1540-
serv_descr[stream->rtp_services],
1541-
session_keys->rtcp_cipher->type->description,
1542-
session_keys->rtcp_auth->type->description,
1543-
serv_descr[stream->rtcp_services],
1544-
srtp_rdbx_get_window_size(&stream->rtp_rdbx),
1545-
stream->allow_repeat_tx ? "true" : "false");
1546-
1547-
printf("# Encrypted extension headers: ");
1548-
if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) {
1549-
int *enc_xtn_hdr = stream->enc_xtn_hdr;
1550-
int count = stream->enc_xtn_hdr_count;
1551-
while (count > 0) {
1552-
printf("%d ", *enc_xtn_hdr);
1553-
enc_xtn_hdr++;
1554-
count--;
1555-
}
1556-
printf("\n");
1557-
} else {
1558-
printf("none\n");
1559-
}
1572+
data.is_template = 0;
1573+
srtp_stream_list_for_each(srtp->stream_list, srtp_session_print_stream,
1574+
&data);
15601575

1561-
/* advance to next stream in the list */
1562-
stream = stream->next;
1563-
}
1564-
return srtp_err_status_ok;
1576+
return data.status;
15651577
}
15661578

15671579
srtp_err_status_t srtp_print_policy(const srtp_policy_t *policy)
@@ -4287,3 +4299,240 @@ const srtp_policy_t wildcard_policy = {
42874299
0, /* list of encrypted extension headers is empty */
42884300
NULL
42894301
};
4302+
4303+
static srtp_stream_t stream_list_test_create_stream(uint32_t ssrc)
4304+
{
4305+
srtp_stream_t stream = malloc(sizeof(srtp_stream_ctx_t));
4306+
stream->ssrc = ssrc;
4307+
return stream;
4308+
}
4309+
4310+
static void stream_list_test_free_stream(srtp_stream_t stream)
4311+
{
4312+
free(stream);
4313+
}
4314+
4315+
int stream_list_test_count_cb(srtp_stream_t stream, void *data)
4316+
{
4317+
int *count = (int *)data;
4318+
(*count)++;
4319+
(void)stream;
4320+
return 0;
4321+
}
4322+
4323+
struct remove_one_data {
4324+
uint32_t ssrc;
4325+
srtp_stream_list_t list;
4326+
};
4327+
4328+
int stream_list_test_remove_one_cb(srtp_stream_t stream, void *data)
4329+
{
4330+
struct remove_one_data *d = (struct remove_one_data *)data;
4331+
if (stream->ssrc == d->ssrc) {
4332+
srtp_stream_list_remove(d->list, stream);
4333+
stream_list_test_free_stream(stream);
4334+
return 1;
4335+
}
4336+
return 0;
4337+
}
4338+
4339+
int stream_list_test_remove_all_cb(srtp_stream_t stream, void *data)
4340+
{
4341+
srtp_stream_list_t *list = (srtp_stream_list_t *)data;
4342+
srtp_stream_list_remove(*list, stream);
4343+
stream_list_test_free_stream(stream);
4344+
return 0;
4345+
}
4346+
4347+
srtp_err_status_t srtp_stream_list_test(void)
4348+
{
4349+
srtp_stream_list_t list;
4350+
4351+
if (srtp_stream_list_alloc(&list)) {
4352+
return srtp_err_status_fail;
4353+
}
4354+
4355+
/* add 4 streams*/
4356+
if (srtp_stream_list_insert(list, stream_list_test_create_stream(1))) {
4357+
return srtp_err_status_fail;
4358+
}
4359+
if (srtp_stream_list_insert(list, stream_list_test_create_stream(2))) {
4360+
return srtp_err_status_fail;
4361+
}
4362+
if (srtp_stream_list_insert(list, stream_list_test_create_stream(3))) {
4363+
return srtp_err_status_fail;
4364+
}
4365+
if (srtp_stream_list_insert(list, stream_list_test_create_stream(4))) {
4366+
return srtp_err_status_fail;
4367+
}
4368+
4369+
/* find */
4370+
if (srtp_stream_list_get(list, 3) == NULL) {
4371+
return srtp_err_status_fail;
4372+
}
4373+
if (srtp_stream_list_get(list, 1) == NULL) {
4374+
return srtp_err_status_fail;
4375+
}
4376+
if (srtp_stream_list_get(list, 2) == NULL) {
4377+
return srtp_err_status_fail;
4378+
}
4379+
if (srtp_stream_list_get(list, 4) == NULL) {
4380+
return srtp_err_status_fail;
4381+
}
4382+
4383+
/* find not in list */
4384+
if (srtp_stream_list_get(list, 5)) {
4385+
return srtp_err_status_fail;
4386+
}
4387+
4388+
/* for each */
4389+
int count = 0;
4390+
srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
4391+
if (count != 4) {
4392+
return srtp_err_status_fail;
4393+
}
4394+
4395+
/* remove */
4396+
srtp_stream_t stream = srtp_stream_list_get(list, 3);
4397+
if (stream == NULL) {
4398+
return srtp_err_status_fail;
4399+
}
4400+
srtp_stream_list_remove(list, stream);
4401+
stream_list_test_free_stream(stream);
4402+
4403+
/* find after remove */
4404+
if (srtp_stream_list_get(list, 3)) {
4405+
return srtp_err_status_fail;
4406+
}
4407+
4408+
/* recount */
4409+
count = 0;
4410+
srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
4411+
if (count != 3) {
4412+
return srtp_err_status_fail;
4413+
}
4414+
4415+
/* remove one in for each */
4416+
struct remove_one_data data = { 2, list };
4417+
srtp_stream_list_for_each(list, stream_list_test_remove_one_cb, &data);
4418+
4419+
/* find after remove */
4420+
if (srtp_stream_list_get(list, 2)) {
4421+
return srtp_err_status_fail;
4422+
}
4423+
4424+
/* recount */
4425+
count = 0;
4426+
srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
4427+
if (count != 2) {
4428+
return srtp_err_status_fail;
4429+
}
4430+
4431+
/* destroy non empty list */
4432+
if (srtp_stream_list_dealloc(list) == srtp_err_status_ok) {
4433+
return srtp_err_status_fail;
4434+
}
4435+
4436+
/* remove all in for each */
4437+
srtp_stream_list_for_each(list, stream_list_test_remove_all_cb, &list);
4438+
4439+
/* recount */
4440+
count = 0;
4441+
srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
4442+
if (count != 0) {
4443+
return srtp_err_status_fail;
4444+
}
4445+
4446+
/* destroy empty list */
4447+
if (srtp_stream_list_dealloc(list)) {
4448+
return srtp_err_status_fail;
4449+
}
4450+
4451+
return srtp_err_status_ok;
4452+
}
4453+
4454+
#ifdef SRTP_USE_TEST_STREAM_LIST
4455+
4456+
/*
4457+
* A srtp_stream_list_ctx_t implementation using a single linked list
4458+
* that does not use the internal next / prev fields.
4459+
*/
4460+
4461+
struct test_list_node {
4462+
srtp_stream_t stream;
4463+
struct test_list_node *next;
4464+
};
4465+
struct srtp_stream_list_ctx_t_ {
4466+
struct test_list_node *head;
4467+
};
4468+
4469+
srtp_err_status_t srtp_stream_list_alloc(srtp_stream_list_t *list_ptr)
4470+
{
4471+
struct srtp_stream_list_ctx_t_ *l =
4472+
malloc(sizeof(struct srtp_stream_list_ctx_t_));
4473+
l->head = NULL;
4474+
*list_ptr = l;
4475+
return srtp_err_status_ok;
4476+
}
4477+
4478+
srtp_err_status_t srtp_stream_list_dealloc(srtp_stream_list_t list)
4479+
{
4480+
struct test_list_node *node = list->head;
4481+
if (node) {
4482+
return srtp_err_status_fail;
4483+
}
4484+
free(list);
4485+
4486+
return srtp_err_status_ok;
4487+
}
4488+
4489+
srtp_err_status_t srtp_stream_list_insert(srtp_stream_list_t list,
4490+
srtp_stream_t stream)
4491+
{
4492+
struct test_list_node *node = malloc(sizeof(struct test_list_node));
4493+
node->stream = stream;
4494+
node->next = list->head;
4495+
list->head = node;
4496+
4497+
return srtp_err_status_ok;
4498+
}
4499+
4500+
srtp_stream_t srtp_stream_list_get(srtp_stream_list_t list, uint32_t ssrc)
4501+
{
4502+
struct test_list_node *node = list->head;
4503+
while (node != NULL) {
4504+
if (node->stream->ssrc == ssrc)
4505+
return node->stream;
4506+
node = node->next;
4507+
}
4508+
return NULL;
4509+
}
4510+
4511+
void srtp_stream_list_remove(srtp_stream_list_t list, srtp_stream_t stream)
4512+
{
4513+
struct test_list_node **node = &(list->head);
4514+
while ((*node) != NULL) {
4515+
if ((*node)->stream->ssrc == stream->ssrc) {
4516+
struct test_list_node *tmp = (*node);
4517+
(*node) = tmp->next;
4518+
free(tmp);
4519+
return;
4520+
}
4521+
node = &(*node)->next;
4522+
}
4523+
}
4524+
4525+
void srtp_stream_list_for_each(srtp_stream_list_t list,
4526+
int (*callback)(srtp_stream_t, void *),
4527+
void *data)
4528+
{
4529+
struct test_list_node *node = list->head;
4530+
while (node != NULL) {
4531+
struct test_list_node *tmp = node;
4532+
node = node->next;
4533+
if (callback(tmp->stream, data))
4534+
break;
4535+
}
4536+
}
4537+
4538+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.