arehbein has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-netif/+/33197 )
Change subject: stream: Add server-side (segmentation) support for IPAC ......................................................................
stream: Add server-side (segmentation) support for IPAC
With this commit, IPAC segmentation is taken care of by setting the protocol being streamed
Depends on change I3a639e6896cc3b3fc8e9b2e1a58254710efa0d3f
Related: OS#5753, OS#5751 Change-Id: I6c91ff385cb5f36ab6b6c96d0e44997995d0d24c --- M include/osmocom/netif/stream.h M src/stream.c M tests/stream/stream_test.c M tests/stream/stream_test.ok 4 files changed, 334 insertions(+), 21 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-netif refs/changes/97/33197/1
diff --git a/include/osmocom/netif/stream.h b/include/osmocom/netif/stream.h index 0e983a4..c9b7a88 100644 --- a/include/osmocom/netif/stream.h +++ b/include/osmocom/netif/stream.h @@ -21,6 +21,18 @@ /*! \brief Osmocom Stream Server Link: A server socket listening/accepting */ struct osmo_stream_srv_link;
+/*! \brief Type of protocol transported by the data stream */ +enum osmo_stream_proto { + OSMO_STREAM_UNSPECIFIED = 0, + OSMO_STREAM_IPAC, + /* TODO: Add protocols for which libosmo-netif should be able to handle segmentation */ + _NUM_OSMO_STREAM_PROTOS +}; + +/*! \brief Shortcut for unsetting the stream protocol (gets rid of segmentation pertaining to stream protocol) */ +#define osmo_stream_srv_link_unset_stream_proto(struct_osmo_stream_srv_link_ptr)\ + osmo_stream_srv_link_set_stream_proto(struct_osmo_stream_srv_link_ptr, OSMO_STREAM_UNSPECIFIED) + struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx); void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link);
@@ -29,6 +41,7 @@ int osmo_stream_srv_link_set_addrs(struct osmo_stream_srv_link *link, const char **addr, size_t addrcnt); void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link, uint16_t port); void osmo_stream_srv_link_set_proto(struct osmo_stream_srv_link *link, uint16_t proto); +void osmo_stream_srv_link_set_stream_proto(struct osmo_stream_srv_link *link, enum osmo_stream_proto osp); int osmo_stream_srv_link_set_type(struct osmo_stream_srv_link *link, int type); int osmo_stream_srv_link_set_domain(struct osmo_stream_srv_link *link, int domain); void osmo_stream_srv_link_set_accept_cb(struct osmo_stream_srv_link *link, int (*accept_cb)(struct osmo_stream_srv_link *link, int fd)); diff --git a/src/stream.c b/src/stream.c index d6b16d3..a033455 100644 --- a/src/stream.c +++ b/src/stream.c @@ -36,6 +36,7 @@ #include <osmocom/core/select.h> #include <osmocom/core/utils.h> #include <osmocom/gsm/tlv.h> +#include <osmocom/gsm/ipa.h> #include <osmocom/core/msgb.h> #include <osmocom/core/osmo_io.h> #include <osmocom/core/panic.h> @@ -78,6 +79,11 @@ #define MSG_NOSIGNAL 0 #endif
+static int (*segmentation_cbs[_NUM_OSMO_STREAM_PROTOS])(struct msgb *) = { + [OSMO_STREAM_UNSPECIFIED] = NULL, + [OSMO_STREAM_IPAC] = ipa_segmentation_cb, +}; + /* is any of the bytes from offset .. u8_size in 'u8' non-zero? return offset or -1 if all zero */ static int byte_nonzero(const uint8_t *u8, unsigned int offset, unsigned int u8_size) { @@ -640,7 +646,7 @@ } }
-static void stream_cli_iofd_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg) +static void stream_cli_iofd_write_cb(struct osmo_io_fd *iofd, int res, const struct msgb *msg) { struct osmo_stream_cli *cli = osmo_iofd_get_data(iofd);
@@ -1189,6 +1195,7 @@ int sk_domain; int sk_type; uint16_t proto; + enum osmo_stream_proto stream_proto; int (*accept_cb)(struct osmo_stream_srv_link *srv, int fd); void *data; int flags; @@ -1279,22 +1286,7 @@ link->sk_domain = AF_UNSPEC; link->sk_type = SOCK_STREAM; link->proto = IPPROTO_TCP; - osmo_fd_setup(&link->ofd, -1, OSMO_FD_READ | OSMO_FD_WRITE, osmo_stream_srv_ofd_cb, link, 0); - - return link; -} - -struct osmo_stream_srv_link *osmo_stream_srv_link_create_iofd(void *ctx, const char *name) -{ - struct osmo_stream_srv_link *link; - - link = talloc_zero(ctx, struct osmo_stream_srv_link); - if (!link) - return NULL; - - link->sk_domain = AF_UNSPEC; - link->sk_type = SOCK_STREAM; - link->proto = IPPROTO_TCP; + link->stream_proto = OSMO_STREAM_UNSPECIFIED; osmo_fd_setup(&link->ofd, -1, OSMO_FD_READ | OSMO_FD_WRITE, osmo_stream_srv_ofd_cb, link, 0);
return link; @@ -1431,6 +1423,23 @@ .write_cb = stream_srv_iofd_write_cb, };
+/*! \brief Set the protocol transported by the stream for the stream server link + * \param[in] link Stream Server Link to modify + * \param[in] proto Protocol (like IPPROTO_TCP (default), IPPROTO_SCTP, ...). + */ +void osmo_stream_srv_link_set_stream_proto(struct osmo_stream_srv_link *link, + enum osmo_stream_proto osp) +{ + if (!(OSMO_STREAM_UNSPECIFIED <= osp && osp < _NUM_OSMO_STREAM_PROTOS)) { + LOGP(DLINP, LOGL_ERROR, "Unexpected value (%d) for variable of type " + "'enum osmo_stream_proto'\n", osp); + return; + } + link->stream_proto = osp; + srv_ioops.segmentation_cb = segmentation_cbs[osp]; + link->flags |= OSMO_STREAM_SRV_F_RECONF; +} + /*! \brief Set the socket type for the stream server link * \param[in] link Stream Server Link to modify * \param[in] type Socket Type (like SOCK_STREAM (default), SOCK_SEQPACKET, ...) @@ -1765,7 +1774,8 @@ } conn->mode = OSMO_STREAM_MODE_OSMO_IO; conn->srv = link; - conn->iofd = osmo_iofd_setup(conn, fd, name, OSMO_IO_FD_MODE_READ_WRITE, &srv_ioops, conn); + conn->iofd = osmo_iofd_setup(conn, fd, name, OSMO_IO_FD_MODE_READ_WRITE, + &srv_ioops, conn); conn->iofd_read_cb = read_cb; conn->closed_cb = closed_cb; conn->data = data; diff --git a/tests/stream/stream_test.c b/tests/stream/stream_test.c index 36a222e..b537d5e 100644 --- a/tests/stream/stream_test.c +++ b/tests/stream/stream_test.c @@ -8,18 +8,23 @@ * (at your option) any later version. */
+#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/socket.h> +#include <sys/un.h> #include <unistd.h> #include <errno.h>
+#include <osmocom/core/byteswap.h> #include <osmocom/core/select.h> #include <osmocom/core/talloc.h> #include <osmocom/core/msgb.h> #include <osmocom/core/logging.h> #include <osmocom/core/application.h> #include <osmocom/core/timer.h> +#include <osmocom/gsm/protocol/ipaccess.h>
#include <osmocom/netif/stream.h>
@@ -363,10 +368,233 @@ printf("{%lu.%06lu} %s test complete.\n\n", tv.tv_sec, tv.tv_usec, ASTR(autoreconnect)); }
+/* Segmentation test code (using IPA) */ +struct ipa_head { + uint16_t len; + uint8_t proto; + uint8_t data[0]; +} __attribute__ ((packed)); + +#define IPAC_MSG_PING_LEN 0x01 +static const uint8_t ipac_msg_ping[] = { + 0x00, IPAC_MSG_PING_LEN, + IPAC_PROTO_IPACCESS, + IPAC_MSGT_PING +}; +#define IPAC_MSG_PONG_LEN 0x01 +static const uint8_t ipac_msg_pong[] = { + 0x00, IPAC_MSG_PONG_LEN, + IPAC_PROTO_IPACCESS, + IPAC_MSGT_PONG +}; +#define IPAC_MSG_ID_REQ_LEN 0x03 +static const uint8_t ipac_msg_idreq[] = { + 0x00, IPAC_MSG_ID_REQ_LEN, + IPAC_PROTO_IPACCESS, + IPAC_MSGT_ID_GET, + 0x01, IPAC_IDTAG_UNITNAME +}; +#define ipac_msg_idreq_half (sizeof (ipac_msg_idreq)/2) +#define ipac_msg_idreq_other_half (sizeof (ipac_msg_idreq) - ipac_msg_idreq_half) +#define IPAC_MSG_ID_RESP_LEN 0x07 +static const uint8_t ipac_msg_idresp[] = { + 0x00, IPAC_MSG_ID_RESP_LEN, + IPAC_PROTO_IPACCESS, + IPAC_MSGT_ID_RESP, + 0x01, IPAC_IDTAG_UNITNAME, 0xde, 0xad, 0xbe, 0xef +}; + +#define put_ipa_msg(unsigned_char_ptr, struct_msgb_ptr, byte_array) do {\ + (unsigned_char_ptr) = msgb_put(struct_msgb_ptr, sizeof (byte_array));\ + memcpy(unsigned_char_ptr, byte_array, sizeof (byte_array));\ +} while (0) + +/* Array indices correspond to enum values stringified on the right */ +static const char * const IPAC_MSG_TYPES[] = { + [0] = "IPAC_MSGT_PING", + [1] = "IPAC_MSGT_PONG", + [2] = "UNEXPECTED VALUE", + [3] = "UNEXPECTED VALUE", + [4] = "IPAC_MSGT_ID_GET", + [5] = "IPAC_MSGT_ID_RESP", +}; + +#define IPAC_MSGT_OFFSET 3 +/* Append a message to UCHAR_PTR_DST. SRC_IPAC_MSG_BUF is expected to be a + * message buffer containing an * IPA message of type IPAC_PROTO_ACCESS that is + * syntactically correct up to offset 3 (IPAC_MSGT_OFFSET). + * Uses a counter so that appended messages can be distinguished easily in the logs */ +#define CLI_APPEND_MSG(OSMO_STREAM_CLI_PTR, UCHAR_PTR_DST, STRUCT_MSGB_PTR, SRC_IPAC_MSG_BUF) do {\ + LOGCLI(OSMO_STREAM_CLI_PTR, "[0%u-cli] Appending msg of type %s into buffer\n",\ + ++msglognum_cli, IPAC_MSG_TYPES[SRC_IPAC_MSG_BUF[IPAC_MSGT_OFFSET]]);\ + LOGCLI(OSMO_STREAM_CLI_PTR, "\t(msg dump: %s)\n", osmo_hexdump(SRC_IPAC_MSG_BUF,\ + sizeof(SRC_IPAC_MSG_BUF)));\ + put_ipa_msg(UCHAR_PTR_DST, STRUCT_MSGB_PTR, SRC_IPAC_MSG_BUF);\ +} while (0) + +static unsigned msglognum_cli = 0; +static int test_segm_cli_connect_cb(struct osmo_stream_cli *cli) +{ + printf("Connect callback triggered (segmentation test)\n"); + unsigned char *data; + struct msgb *m = msgb_alloc_headroom(128, 0, "IPA messages"); + if (m == NULL) { + fprintf(stderr, "Cannot allocate message\n"); + return -ENOMEM; + } + + /* Send 4 and 1/2 messages */ + CLI_APPEND_MSG(cli, data, m, ipac_msg_ping); + CLI_APPEND_MSG(cli, data, m, ipac_msg_pong); + CLI_APPEND_MSG(cli, data, m, ipac_msg_ping); + CLI_APPEND_MSG(cli, data, m, ipac_msg_idresp); + + LOGCLI(cli, "[0%u.5-cli] Appending *half* of msg of type %s into buffer\n", + msglognum_cli, IPAC_MSG_TYPES[ipac_msg_idreq[3]]); + LOGCLI(cli, "\t(dump: %s)\n", osmo_hexdump(ipac_msg_idreq, ipac_msg_idreq_half)); + data = msgb_put(m, ipac_msg_idreq_half); + memcpy(data, ipac_msg_idreq, ipac_msg_idreq_half); + + LOGCLI(cli, "Sending 4 1/2 messages as one:\n"); + LOGCLI(cli, "\t(msg dump: %s)\n\n", osmo_hexdump(m->data, m->len)); + osmo_stream_cli_send(cli, m); + return 0; +} + +static bool all_msgs_processed = false; + +static int test_segm_stream_cli_read_cb(struct osmo_stream_cli *osc, struct msgb *msg) +{ + unsigned char *data; + struct ipa_head *h = (struct ipa_head *) msg->data; + uint8_t ipa_msg_type = ((uint8_t *)h)[sizeof(struct ipa_head)]; + LOGCLI(osc, "Received message from stream (total len = %" PRIu16 ")\n", msgb_length(msg)); + if (ipa_msg_type < 0 || 5 < ipa_msg_type) { + fprintf(stderr, "Received unexpected IPAC message type %"PRIu8"\n", ipa_msg_type); + return -ENOMSG; + } + LOGCLI(osc, "\tType: %s\n", IPAC_MSG_TYPES[ipa_msg_type]); + if (ipa_msg_type == IPAC_MSGT_ID_GET) { + LOGCLI(osc, "Got IPAC_MSGT_ID_GET from server\n"); + LOGCLI(osc, "[%u-cli] Sending second half of IPAC_MSGT_ID_GET\n", ++msglognum_cli); + data = msgb_put(msg, ipac_msg_idreq_other_half); + memcpy(data, ipac_msg_idreq + ipac_msg_idreq_half, + ipac_msg_idreq_other_half); + LOGCLI(osc, "\t(msg dump: %s)\n", osmo_hexdump(data, ipac_msg_idreq_other_half)); + osmo_stream_cli_send(osc, msg); + } else if (ipa_msg_type == IPAC_MSGT_ID_RESP) { + LOGCLI(osc, "\tresult= %s\n", osmo_hexdump(msg->data, msg->len)); + LOGCLI(osc, "\texpected=%s\n", + osmo_hexdump(ipac_msg_idresp, sizeof(ipac_msg_idresp))); + } + printf("\n"); + return 0; +} + +static void *test_segm_run_client(void) +{ + struct osmo_stream_cli *osc; + void *ctx = talloc_named_const(NULL, 0, "test_segm_run_client"); + + (void) msgb_talloc_ctx_init(ctx, 0); + osc = osmo_stream_cli_create_iofd(ctx, "IPA test client"); + if (osc == NULL) { + fprintf(stderr, "osmo_stream_cli_create_iofd()\n"); + return NULL; + } + osmo_stream_cli_set_addr(osc, "127.0.0.11"); + osmo_stream_cli_set_port(osc, 1111); + osmo_stream_cli_set_connect_cb(osc, test_segm_cli_connect_cb); + osmo_stream_cli_set_data(osc, ctx); + osmo_stream_cli_set_iofd_read_cb(osc, test_segm_stream_cli_read_cb); + osmo_stream_cli_set_nodelay(osc, true); + if (osmo_stream_cli_open(osc) < 0) { + fprintf(stderr, "Cannot open stream client\n"); + return NULL; + } + + return NULL; +} + +static bool test_segm_ipa(void *ctx, const char *host, unsigned port, + struct osmo_stream_srv_link *srv) +{ + int rc; + const int max_test_duration = 2; + struct timespec start, now; + test_segm_run_client(); + + rc = clock_gettime(CLOCK_MONOTONIC, &start); + if (rc < 0) { + fprintf(stderr, "clock_gettime(): %s\n", strerror(errno)); + return EXIT_FAILURE; + } + while (!all_msgs_processed) { + osmo_gettimeofday_override_add(0, 1); /* small increment to easily spot iterations */ + osmo_select_main(1); + rc = clock_gettime(CLOCK_MONOTONIC, &now); + if (rc < 0) { + fprintf(stderr, "clock_gettime(): %s\n", strerror(errno)); + return EXIT_FAILURE; + } + if (now.tv_sec - start.tv_sec > max_test_duration) { + fprintf(stderr, "test_segm_ipa(): Timeout\n"); + osmo_stream_srv_link_unset_stream_proto(srv); + return EXIT_FAILURE; + } + } + + osmo_stream_srv_link_unset_stream_proto(srv); + return EXIT_SUCCESS; +} + +static unsigned msgnum_srv = 0; +int test_segm_stream_srv_read_cb(struct osmo_stream_srv *conn, struct msgb *msg) +{ + unsigned char *data; + struct msgb *m; + uint8_t *msgt = msg->data + sizeof(struct ipa_head); + LOGSRV(conn, "[%u-srv] Received message from stream (len = %" PRIu16 ")\n", + ++msgnum_srv, msgb_length(msg)); + msgb_pull(msg, sizeof(struct ipa_head)); + LOGSRV(conn, "\tIPA data: %s\n", osmo_hexdump(msg->data, msg->len)); + LOGSRV(conn, "\tType: %s\n", IPAC_MSG_TYPES[*msgt]); + LOGSRV(conn, "\t(msg dump: %s)\n", osmo_hexdump(msg->data - sizeof(struct ipa_head), + msg->len + sizeof(struct ipa_head))); + if (*msgt == IPAC_MSGT_ID_RESP) { /* */ + LOGSRV(conn, "Send IPAC_MSGT_ID_GET to trigger client to send 2nd half\n\n"); + m = msgb_alloc_headroom(128, 0, "IPA messages"); + if (m == NULL) { + fprintf(stderr, "Cannot allocate message\n"); + return -ENOMEM; + } + put_ipa_msg(data, m, ipac_msg_idreq); + osmo_stream_srv_send(conn, m); + } else if (*msgt == IPAC_MSGT_ID_GET) { + all_msgs_processed = true; + } + return 0; +} + +static int test_segm_stream_srv_accept_cb(struct osmo_stream_srv_link *srv, int fd) +{ + void *ctx = talloc_named_const(NULL, 0, "test_segm_stream_srv_accept_cb"); + struct osmo_stream_srv *oss = + osmo_stream_srv_create_iofd(ctx, "srv link", srv, fd, + test_segm_stream_srv_read_cb, + close_cb_srv, NULL); + if (oss == NULL) { + fprintf(stderr, "Error while creating connection\n"); + return -1; + } + + return 0; +}
int main(void) { struct osmo_stream_srv_link *srv; + bool rc; char *host = "127.0.0.11"; unsigned port = 1111; void *tall_test = talloc_named_const(NULL, 1, "osmo_stream_test"); @@ -402,8 +630,14 @@ test_recon(tall_test, host, port, 12, srv, true); test_recon(tall_test, host, port, 8, srv, false);
- osmo_stream_srv_link_destroy(srv); + osmo_stream_srv_link_set_accept_cb(srv, + test_segm_stream_srv_accept_cb); + osmo_stream_srv_link_set_stream_proto(srv, OSMO_STREAM_IPAC); + if (osmo_stream_srv_link_open(srv) < 0) { + printf("Unable to open server\n"); + return EXIT_FAILURE; + } + rc = test_segm_ipa(tall_test, host, port, srv); printf("Stream tests completed\n"); - - return EXIT_SUCCESS; + return rc; } diff --git a/tests/stream/stream_test.ok b/tests/stream/stream_test.ok index 2106295..7763212 100644 --- a/tests/stream/stream_test.ok +++ b/tests/stream/stream_test.ok @@ -48,4 +48,46 @@ {11.000019} [OK] Client's read_cb_cli(): 0-byte read, auto-reconnect will be triggered if enabled {20.000019} non-reconnecting test complete.
+Connect callback triggered (segmentation test) +{20.000020} [OK] Client's test_segm_cli_connect_cb(): [01-cli] Appending msg of type IPAC_MSGT_PING into buffer +{20.000020} [OK] Client's test_segm_cli_connect_cb(): (msg dump: 00 01 fe 00 ) +{20.000020} [OK] Client's test_segm_cli_connect_cb(): [02-cli] Appending msg of type IPAC_MSGT_PONG into buffer +{20.000020} [OK] Client's test_segm_cli_connect_cb(): (msg dump: 00 01 fe 01 ) +{20.000020} [OK] Client's test_segm_cli_connect_cb(): [03-cli] Appending msg of type IPAC_MSGT_PING into buffer +{20.000020} [OK] Client's test_segm_cli_connect_cb(): (msg dump: 00 01 fe 00 ) +{20.000020} [OK] Client's test_segm_cli_connect_cb(): [04-cli] Appending msg of type IPAC_MSGT_ID_RESP into buffer +{20.000020} [OK] Client's test_segm_cli_connect_cb(): (msg dump: 00 07 fe 05 01 01 de ad be ef ) +{20.000020} [OK] Client's test_segm_cli_connect_cb(): [04.5-cli] Appending *half* of msg of type IPAC_MSGT_ID_GET into buffer +{20.000020} [OK] Client's test_segm_cli_connect_cb(): (dump: 00 03 fe ) +{20.000020} [OK] Client's test_segm_cli_connect_cb(): Sending 4 1/2 messages as one: +{20.000020} [OK] Client's test_segm_cli_connect_cb(): (msg dump: 00 01 fe 00 00 01 fe 01 00 01 fe 00 00 07 fe 05 01 01 de ad be ef 00 03 fe ) + +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): [1-srv] Received message from stream (len = 4) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): IPA data: 00 +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): Type: IPAC_MSGT_PING +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): (msg dump: 00 01 fe 00 ) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): [2-srv] Received message from stream (len = 4) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): IPA data: 01 +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): Type: IPAC_MSGT_PONG +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): (msg dump: 00 01 fe 01 ) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): [3-srv] Received message from stream (len = 4) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): IPA data: 00 +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): Type: IPAC_MSGT_PING +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): (msg dump: 00 01 fe 00 ) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): [4-srv] Received message from stream (len = 10) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): IPA data: 05 01 01 de ad be ef +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): Type: IPAC_MSGT_ID_RESP +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): (msg dump: 00 07 fe 05 01 01 de ad be ef ) +{20.000022} [NA|OK] Server's test_segm_stream_srv_read_cb(): Send IPAC_MSGT_ID_GET to trigger client to send 2nd half + +{20.000024} [OK] Client's test_segm_stream_cli_read_cb(): Received message from stream (total len = 6) +{20.000024} [OK] Client's test_segm_stream_cli_read_cb(): Type: IPAC_MSGT_ID_GET +{20.000024} [OK] Client's test_segm_stream_cli_read_cb(): Got IPAC_MSGT_ID_GET from server +{20.000024} [OK] Client's test_segm_stream_cli_read_cb(): [5-cli] Sending second half of IPAC_MSGT_ID_GET +{20.000024} [OK] Client's test_segm_stream_cli_read_cb(): (msg dump: 04 01 01 ) + +{20.000026} [NA|OK] Server's test_segm_stream_srv_read_cb(): [5-srv] Received message from stream (len = 6) +{20.000026} [NA|OK] Server's test_segm_stream_srv_read_cb(): IPA data: 04 01 01 +{20.000026} [NA|OK] Server's test_segm_stream_srv_read_cb(): Type: IPAC_MSGT_ID_GET +{20.000026} [NA|OK] Server's test_segm_stream_srv_read_cb(): (msg dump: 00 03 fe 04 01 01 ) Stream tests completed