test_spi.c revision a74702c6
1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov#include <assert.h>
350aadb33SDmitri Tikhonov#include <errno.h>
450aadb33SDmitri Tikhonov#include <stdio.h>
550aadb33SDmitri Tikhonov#include <stdlib.h>
650aadb33SDmitri Tikhonov#include <string.h>
750aadb33SDmitri Tikhonov#include <sys/queue.h>
8461e84d8SAmol Deshpande#ifndef WIN32
950aadb33SDmitri Tikhonov#include <unistd.h>
10461e84d8SAmol Deshpande#endif
1150aadb33SDmitri Tikhonov
1250aadb33SDmitri Tikhonov#include "lsquic.h"
1350aadb33SDmitri Tikhonov
145392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
15bfc7bfd8SDmitri Tikhonov#include "lsquic_packet_common.h"
1650aadb33SDmitri Tikhonov#include "lsquic_packet_in.h"
1750aadb33SDmitri Tikhonov#include "lsquic_conn_flow.h"
1850aadb33SDmitri Tikhonov#include "lsquic_sfcw.h"
195392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
205392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
215392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
225392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
2350aadb33SDmitri Tikhonov#include "lsquic_stream.h"
2450aadb33SDmitri Tikhonov#include "lsquic_types.h"
25fbc6cc04SDmitri Tikhonov#include "lsquic_rtt.h"
26fbc6cc04SDmitri Tikhonov#include "lsquic_conn_public.h"
2750aadb33SDmitri Tikhonov#include "lsquic_spi.h"
2850aadb33SDmitri Tikhonov#include "lsquic_logger.h"
2950aadb33SDmitri Tikhonov
3050aadb33SDmitri Tikhonov
3150aadb33SDmitri Tikhonov/* Sharing the same SPI tests safety of reusing the same iterator object
3250aadb33SDmitri Tikhonov * (no need to deinitialize it).
3350aadb33SDmitri Tikhonov */
3450aadb33SDmitri Tikhonovstatic struct stream_prio_iter spi;
3550aadb33SDmitri Tikhonov
365392f7a3SLiteSpeed Techstatic struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
375392f7a3SLiteSpeed Tech
38fbc6cc04SDmitri Tikhonovstatic struct lsquic_conn_public conn_pub = { .lconn = &lconn, };
39fbc6cc04SDmitri Tikhonov
4050aadb33SDmitri Tikhonov
4150aadb33SDmitri Tikhonovstatic lsquic_stream_t *
4250aadb33SDmitri Tikhonovnew_stream (unsigned priority)
4350aadb33SDmitri Tikhonov{
4450aadb33SDmitri Tikhonov    lsquic_stream_t *stream = calloc(1, sizeof(*stream));
4550aadb33SDmitri Tikhonov    stream->sm_priority = priority;
4650aadb33SDmitri Tikhonov    return stream;
4750aadb33SDmitri Tikhonov}
4850aadb33SDmitri Tikhonov
4950aadb33SDmitri Tikhonov
5050aadb33SDmitri Tikhonovstatic void
5150aadb33SDmitri Tikhonovfree_streams (lsquic_stream_t **streams, size_t count)
5250aadb33SDmitri Tikhonov{
5350aadb33SDmitri Tikhonov    size_t n;
5450aadb33SDmitri Tikhonov    for (n = 0; n < count; ++n)
5550aadb33SDmitri Tikhonov        free(streams[n]);
5650aadb33SDmitri Tikhonov}
5750aadb33SDmitri Tikhonov
5850aadb33SDmitri Tikhonov
5950aadb33SDmitri Tikhonovstatic void
6050aadb33SDmitri Tikhonovtest_same_priority (unsigned priority)
6150aadb33SDmitri Tikhonov{
6250aadb33SDmitri Tikhonov    lsquic_stream_t *stream_arr[4] = {
6350aadb33SDmitri Tikhonov        new_stream(priority),
6450aadb33SDmitri Tikhonov        new_stream(priority),
6550aadb33SDmitri Tikhonov        new_stream(priority),
6650aadb33SDmitri Tikhonov        new_stream(priority),
6750aadb33SDmitri Tikhonov    };
6850aadb33SDmitri Tikhonov    struct lsquic_streams_tailq streams;
6950aadb33SDmitri Tikhonov    lsquic_stream_t *stream;
7050aadb33SDmitri Tikhonov
7150aadb33SDmitri Tikhonov    TAILQ_INIT(&streams);
72c51ce338SDmitri Tikhonov    TAILQ_INSERT_TAIL(&streams, stream_arr[0], next_write_stream);
73c51ce338SDmitri Tikhonov    TAILQ_INSERT_TAIL(&streams, stream_arr[1], next_write_stream);
74c51ce338SDmitri Tikhonov    TAILQ_INSERT_TAIL(&streams, stream_arr[2], next_write_stream);
75c51ce338SDmitri Tikhonov    TAILQ_INSERT_TAIL(&streams, stream_arr[3], next_write_stream);
7650aadb33SDmitri Tikhonov
77c51ce338SDmitri Tikhonov    lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
7850aadb33SDmitri Tikhonov        TAILQ_LAST(&streams, lsquic_streams_tailq),
79c51ce338SDmitri Tikhonov        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
80fbc6cc04SDmitri Tikhonov        &conn_pub, __func__, NULL, NULL);
8150aadb33SDmitri Tikhonov
8250aadb33SDmitri Tikhonov    stream = lsquic_spi_first(&spi);
8350aadb33SDmitri Tikhonov    assert(stream == stream_arr[0]);
8450aadb33SDmitri Tikhonov    stream = lsquic_spi_next(&spi);
8550aadb33SDmitri Tikhonov    assert(stream == stream_arr[1]);
8650aadb33SDmitri Tikhonov    stream = lsquic_spi_next(&spi);
8750aadb33SDmitri Tikhonov    assert(stream == stream_arr[2]);
8850aadb33SDmitri Tikhonov    stream = lsquic_spi_next(&spi);
8950aadb33SDmitri Tikhonov    assert(stream == stream_arr[3]);
9050aadb33SDmitri Tikhonov    stream = lsquic_spi_next(&spi);
9150aadb33SDmitri Tikhonov    assert(stream == NULL);
9250aadb33SDmitri Tikhonov
9350aadb33SDmitri Tikhonov    /* Test reinitialization: */
94c51ce338SDmitri Tikhonov    lsquic_spi_init(&spi, stream_arr[0], stream_arr[1],
95c51ce338SDmitri Tikhonov        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
96fbc6cc04SDmitri Tikhonov        &conn_pub, __func__, NULL, NULL);
9750aadb33SDmitri Tikhonov    stream = lsquic_spi_first(&spi);
9850aadb33SDmitri Tikhonov    assert(stream == stream_arr[0]);
9950aadb33SDmitri Tikhonov    stream = lsquic_spi_next(&spi);
10050aadb33SDmitri Tikhonov    assert(stream == stream_arr[1]);
10150aadb33SDmitri Tikhonov    stream = lsquic_spi_next(&spi);
10250aadb33SDmitri Tikhonov    assert(stream == NULL);
10350aadb33SDmitri Tikhonov
10450aadb33SDmitri Tikhonov    free_streams(stream_arr, sizeof(stream_arr) / sizeof(stream_arr[0]));
10550aadb33SDmitri Tikhonov}
10650aadb33SDmitri Tikhonov
10750aadb33SDmitri Tikhonov
10850aadb33SDmitri Tikhonovstatic void
10950aadb33SDmitri Tikhonovtest_different_priorities (int *priority)
11050aadb33SDmitri Tikhonov{
11150aadb33SDmitri Tikhonov    struct lsquic_streams_tailq streams;
11250aadb33SDmitri Tikhonov    lsquic_stream_t *stream;
11350aadb33SDmitri Tikhonov    int prio, prev_prio, count, n_streams = 0;
11450aadb33SDmitri Tikhonov
11550aadb33SDmitri Tikhonov    TAILQ_INIT(&streams);
11650aadb33SDmitri Tikhonov
11750aadb33SDmitri Tikhonov    for ( ; *priority >= 0; ++priority)
11850aadb33SDmitri Tikhonov    {
11950aadb33SDmitri Tikhonov        assert(*priority < 256);
12050aadb33SDmitri Tikhonov        stream = new_stream(*priority);
12150aadb33SDmitri Tikhonov        TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
12250aadb33SDmitri Tikhonov        ++n_streams;
12350aadb33SDmitri Tikhonov    }
12450aadb33SDmitri Tikhonov
125c51ce338SDmitri Tikhonov    lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
12650aadb33SDmitri Tikhonov        TAILQ_LAST(&streams, lsquic_streams_tailq),
12750aadb33SDmitri Tikhonov        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
128fbc6cc04SDmitri Tikhonov        &conn_pub, __func__, NULL, NULL);
12950aadb33SDmitri Tikhonov    for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
13050aadb33SDmitri Tikhonov                                        stream = lsquic_spi_next(&spi), ++count)
13150aadb33SDmitri Tikhonov    {
13250aadb33SDmitri Tikhonov        prio = stream->sm_priority;
13350aadb33SDmitri Tikhonov        assert(prio >= prev_prio);
13450aadb33SDmitri Tikhonov        if (prio > prev_prio)
13550aadb33SDmitri Tikhonov            prev_prio = prio;
13650aadb33SDmitri Tikhonov    }
13750aadb33SDmitri Tikhonov
13850aadb33SDmitri Tikhonov    assert(count == n_streams);
13950aadb33SDmitri Tikhonov
14050aadb33SDmitri Tikhonov    while ((stream = TAILQ_FIRST(&streams)))
14150aadb33SDmitri Tikhonov    {
14250aadb33SDmitri Tikhonov        TAILQ_REMOVE(&streams, stream, next_send_stream);
14350aadb33SDmitri Tikhonov        free(stream);
14450aadb33SDmitri Tikhonov    }
14550aadb33SDmitri Tikhonov}
14650aadb33SDmitri Tikhonov
14750aadb33SDmitri Tikhonov
148c51ce338SDmitri Tikhonovstruct stream_info
14950aadb33SDmitri Tikhonov{
150c51ce338SDmitri Tikhonov    uint32_t        stream_id;
151a0e1aeeeSDmitri Tikhonov    enum stream_b_flags bflags;
152c51ce338SDmitri Tikhonov    unsigned char   prio;
15350aadb33SDmitri Tikhonov};
15450aadb33SDmitri Tikhonov
15550aadb33SDmitri Tikhonov
156c51ce338SDmitri Tikhonovconst struct stream_info infos1[] = {
1577a8b2eceSDmitri Tikhonov    { 1,                                SMBF_CRITICAL, 0, },
1587a8b2eceSDmitri Tikhonov    { 3,                                SMBF_CRITICAL, 0, },
159a0e1aeeeSDmitri Tikhonov    { 5,                                0, 0, },
160a0e1aeeeSDmitri Tikhonov    { 7,                                0, 1, },
161a0e1aeeeSDmitri Tikhonov    { 127,                              0, 200, },
162c51ce338SDmitri Tikhonov};
16350aadb33SDmitri Tikhonov
16450aadb33SDmitri Tikhonov
165c51ce338SDmitri Tikhonovconst struct stream_info infos2[] = {
1667a8b2eceSDmitri Tikhonov    { 1,                                SMBF_CRITICAL, 0, },
1677a8b2eceSDmitri Tikhonov    { 3,                                SMBF_CRITICAL, 0, },
168a0e1aeeeSDmitri Tikhonov    { 5,                                0, 4, },
169a0e1aeeeSDmitri Tikhonov    { 7,                                0, 1, },
170a0e1aeeeSDmitri Tikhonov    { 127,                              0, 200, },
171a0e1aeeeSDmitri Tikhonov};
172a0e1aeeeSDmitri Tikhonov
173a0e1aeeeSDmitri Tikhonov
174a0e1aeeeSDmitri Tikhonovconst struct stream_info infos3[] = {
175a0e1aeeeSDmitri Tikhonov    { 0,    0,  0, },
176c51ce338SDmitri Tikhonov};
17750aadb33SDmitri Tikhonov
17850aadb33SDmitri Tikhonov
179c51ce338SDmitri Tikhonovstruct drop_test
180c51ce338SDmitri Tikhonov{
181c51ce338SDmitri Tikhonov    const struct stream_info    *infos;
182c51ce338SDmitri Tikhonov    unsigned                     n_infos;
183c51ce338SDmitri Tikhonov    unsigned                     high_streams;
184c51ce338SDmitri Tikhonov};
18550aadb33SDmitri Tikhonov
18650aadb33SDmitri Tikhonov
187c51ce338SDmitri Tikhonovstatic const struct drop_test drop_tests[] = {
188c51ce338SDmitri Tikhonov    { infos1, 5, 0x7, },
189c51ce338SDmitri Tikhonov    { infos2, 5, 0x3, },
190a0e1aeeeSDmitri Tikhonov    { infos3, 1, 0x0, },
191c51ce338SDmitri Tikhonov};
19250aadb33SDmitri Tikhonov
19350aadb33SDmitri Tikhonov
19450aadb33SDmitri Tikhonovstatic void
195c51ce338SDmitri Tikhonovtest_drop (const struct drop_test *test)
19650aadb33SDmitri Tikhonov{
197c51ce338SDmitri Tikhonov
198c51ce338SDmitri Tikhonov    struct lsquic_stream stream_arr[20];
199c51ce338SDmitri Tikhonov    unsigned seen_mask, n;
20050aadb33SDmitri Tikhonov    struct lsquic_streams_tailq streams;
201c51ce338SDmitri Tikhonov    lsquic_stream_t *stream;
202c51ce338SDmitri Tikhonov    int drop_high;
20350aadb33SDmitri Tikhonov
20450aadb33SDmitri Tikhonov    TAILQ_INIT(&streams);
205c51ce338SDmitri Tikhonov    for (n = 0; n < test->n_infos; ++n)
20650aadb33SDmitri Tikhonov    {
207c51ce338SDmitri Tikhonov        stream_arr[n].sm_priority = test->infos[n].prio;
208c51ce338SDmitri Tikhonov        stream_arr[n].id          = test->infos[n].stream_id;
209a0e1aeeeSDmitri Tikhonov        stream_arr[n].sm_bflags   = SMBF_USE_HEADERS | test->infos[n].bflags;
21050aadb33SDmitri Tikhonov    }
21150aadb33SDmitri Tikhonov
212c51ce338SDmitri Tikhonov    for (drop_high = 0; drop_high < 2; ++drop_high)
21350aadb33SDmitri Tikhonov    {
214c51ce338SDmitri Tikhonov        TAILQ_INIT(&streams);
215c51ce338SDmitri Tikhonov        for (n = 0; n < test->n_infos; ++n)
216c51ce338SDmitri Tikhonov            TAILQ_INSERT_TAIL(&streams, &stream_arr[n], next_write_stream);
217c51ce338SDmitri Tikhonov
218c51ce338SDmitri Tikhonov        lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
219c51ce338SDmitri Tikhonov            TAILQ_LAST(&streams, lsquic_streams_tailq),
220c51ce338SDmitri Tikhonov            (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
221fbc6cc04SDmitri Tikhonov            &conn_pub, __func__, NULL, NULL);
222c51ce338SDmitri Tikhonov
223c51ce338SDmitri Tikhonov        if (drop_high)
224c51ce338SDmitri Tikhonov            lsquic_spi_drop_high(&spi);
225c51ce338SDmitri Tikhonov        else
226c51ce338SDmitri Tikhonov            lsquic_spi_drop_non_high(&spi);
227c51ce338SDmitri Tikhonov
228c51ce338SDmitri Tikhonov        seen_mask = 0;
229c51ce338SDmitri Tikhonov        for (stream = lsquic_spi_first(&spi); stream;
230c51ce338SDmitri Tikhonov                                            stream = lsquic_spi_next(&spi))
231c51ce338SDmitri Tikhonov            seen_mask |= 1 << (stream - stream_arr);
232c51ce338SDmitri Tikhonov
233a0e1aeeeSDmitri Tikhonov        if (test->n_infos == 1)
234a0e1aeeeSDmitri Tikhonov            assert(seen_mask == (1u << test->infos[0].stream_id));
235a0e1aeeeSDmitri Tikhonov        else if (drop_high)
236c51ce338SDmitri Tikhonov            assert((((1 << test->n_infos) - 1) & ~test->high_streams) == seen_mask);
237c51ce338SDmitri Tikhonov        else
238c51ce338SDmitri Tikhonov            assert(test->high_streams == seen_mask);
23950aadb33SDmitri Tikhonov    }
24050aadb33SDmitri Tikhonov}
24150aadb33SDmitri Tikhonov
24250aadb33SDmitri Tikhonov
24319f667fbSDmitri Tikhonov#define MAGIC 0x12312312U
24419f667fbSDmitri Tikhonov
24519f667fbSDmitri Tikhonovstruct my_filter_ctx
24619f667fbSDmitri Tikhonov{
24719f667fbSDmitri Tikhonov    unsigned magic;
24819f667fbSDmitri Tikhonov};
24919f667fbSDmitri Tikhonov
25019f667fbSDmitri Tikhonov
25119f667fbSDmitri Tikhonovstatic int
25219f667fbSDmitri Tikhonovfilter_out_odd_priorities (void *ctx, lsquic_stream_t *stream)
25319f667fbSDmitri Tikhonov{
25419f667fbSDmitri Tikhonov    struct my_filter_ctx *fctx = ctx;
25519f667fbSDmitri Tikhonov    assert(fctx->magic == MAGIC);
25619f667fbSDmitri Tikhonov    return 0 == (stream->sm_priority & 1);
25719f667fbSDmitri Tikhonov}
25819f667fbSDmitri Tikhonov
25919f667fbSDmitri Tikhonov
26019f667fbSDmitri Tikhonovstatic void
26119f667fbSDmitri Tikhonovtest_different_priorities_filter_odd (int *priority)
26219f667fbSDmitri Tikhonov{
26319f667fbSDmitri Tikhonov    struct lsquic_streams_tailq streams;
26419f667fbSDmitri Tikhonov    lsquic_stream_t *stream;
26519f667fbSDmitri Tikhonov    int prio, prev_prio, count, n_streams = 0;
26619f667fbSDmitri Tikhonov
26719f667fbSDmitri Tikhonov    TAILQ_INIT(&streams);
26819f667fbSDmitri Tikhonov
26919f667fbSDmitri Tikhonov    for ( ; *priority >= 0; ++priority)
27019f667fbSDmitri Tikhonov    {
27119f667fbSDmitri Tikhonov        assert(*priority < 256);
27219f667fbSDmitri Tikhonov        stream = new_stream(*priority);
27319f667fbSDmitri Tikhonov        TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
27419f667fbSDmitri Tikhonov        ++n_streams;
27519f667fbSDmitri Tikhonov    }
27619f667fbSDmitri Tikhonov
27719f667fbSDmitri Tikhonov    struct my_filter_ctx my_filter_ctx = { MAGIC };
27819f667fbSDmitri Tikhonov
27919f667fbSDmitri Tikhonov    lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
28019f667fbSDmitri Tikhonov        TAILQ_LAST(&streams, lsquic_streams_tailq),
28119f667fbSDmitri Tikhonov        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
282fbc6cc04SDmitri Tikhonov        &conn_pub, __func__, filter_out_odd_priorities, &my_filter_ctx);
28319f667fbSDmitri Tikhonov
28419f667fbSDmitri Tikhonov    for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
28519f667fbSDmitri Tikhonov                                        stream = lsquic_spi_next(&spi), ++count)
28619f667fbSDmitri Tikhonov    {
28719f667fbSDmitri Tikhonov        prio = stream->sm_priority;
28819f667fbSDmitri Tikhonov        assert(0 == (prio & 1));
28919f667fbSDmitri Tikhonov        assert(prio >= prev_prio);
29019f667fbSDmitri Tikhonov        if (prio > prev_prio)
29119f667fbSDmitri Tikhonov            prev_prio = prio;
29219f667fbSDmitri Tikhonov    }
29319f667fbSDmitri Tikhonov
29419f667fbSDmitri Tikhonov    assert(count < n_streams);
29519f667fbSDmitri Tikhonov
29619f667fbSDmitri Tikhonov    while ((stream = TAILQ_FIRST(&streams)))
29719f667fbSDmitri Tikhonov    {
29819f667fbSDmitri Tikhonov        TAILQ_REMOVE(&streams, stream, next_send_stream);
29919f667fbSDmitri Tikhonov        free(stream);
30019f667fbSDmitri Tikhonov    }
30119f667fbSDmitri Tikhonov}
30219f667fbSDmitri Tikhonov
30319f667fbSDmitri Tikhonov
30450aadb33SDmitri Tikhonovint
30550aadb33SDmitri Tikhonovmain (int argc, char **argv)
30650aadb33SDmitri Tikhonov{
30750aadb33SDmitri Tikhonov    lsquic_log_to_fstream(stderr, LLTS_NONE);
30850aadb33SDmitri Tikhonov    lsq_log_levels[LSQLM_SPI] = LSQ_LOG_DEBUG;
30950aadb33SDmitri Tikhonov
31050aadb33SDmitri Tikhonov    test_same_priority(0);
31150aadb33SDmitri Tikhonov    test_same_priority(99);
31250aadb33SDmitri Tikhonov    test_same_priority(255);
31350aadb33SDmitri Tikhonov
31450aadb33SDmitri Tikhonov    {
31550aadb33SDmitri Tikhonov        int prio[] = { 1, 2, 3, 4, 5, 6, 7, -1 };
31650aadb33SDmitri Tikhonov        test_different_priorities(prio);
31750aadb33SDmitri Tikhonov    }
31850aadb33SDmitri Tikhonov
31950aadb33SDmitri Tikhonov    {
32050aadb33SDmitri Tikhonov        int prio[] = { 7, 6, 5, 4, 3, 2, 1, -1 };
32150aadb33SDmitri Tikhonov        test_different_priorities(prio);
32250aadb33SDmitri Tikhonov    }
32350aadb33SDmitri Tikhonov
32450aadb33SDmitri Tikhonov    {
32550aadb33SDmitri Tikhonov        int prio[] = { 7, 100, 80, 1, 0, 0, 20, 23, 255, 30, 2, 101, -1 };
32650aadb33SDmitri Tikhonov        test_different_priorities(prio);
32750aadb33SDmitri Tikhonov    }
32850aadb33SDmitri Tikhonov
32950aadb33SDmitri Tikhonov    {
33050aadb33SDmitri Tikhonov        int prio[] = { 200, 202, 240, 201, 200, 199, -1 };
33150aadb33SDmitri Tikhonov        test_different_priorities(prio);
33250aadb33SDmitri Tikhonov    }
33350aadb33SDmitri Tikhonov
33419f667fbSDmitri Tikhonov    {
33519f667fbSDmitri Tikhonov        int prio[] = { 200, 202, 240, 201, 200, 199, -1 };
33619f667fbSDmitri Tikhonov        test_different_priorities_filter_odd(prio);
33719f667fbSDmitri Tikhonov    }
33819f667fbSDmitri Tikhonov
339c51ce338SDmitri Tikhonov    unsigned n;
340c51ce338SDmitri Tikhonov    for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n)
341c51ce338SDmitri Tikhonov        test_drop(&drop_tests[n]);
34250aadb33SDmitri Tikhonov
34350aadb33SDmitri Tikhonov    return 0;
34450aadb33SDmitri Tikhonov}
345