Projects
osmocom:latest
libosmo-netif
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 8
View file
libosmo-netif.spec
Added
@@ -0,0 +1,88 @@ +# +# spec file for package libosmo-netif +# +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +Name: libosmo-netif +Requires: osmocom-latest +Version: 1.6.0 +Release: 0 +Summary: Osmocom library for muxed audio +License: GPL-2.0-or-later +Group: Productivity/Telephony/Utilities +URL: https://osmocom.org/projects/libosmo-netif +Source: libosmo-netif_1.6.0.tar.xz +Source1: rpmlintrc +BuildRequires: automake +BuildRequires: libtool >= 2 +BuildRequires: lksctp-tools-devel +BuildRequires: pkgconfig >= 0.20 +BuildRequires: pkgconfig(libosmocore) >= 1.11.0 +BuildRequires: pkgconfig(libosmogsm) >= 1.11.0 +BuildRequires: pkgconfig(libosmocodec) >= 1.11.0 + +%description +Network interface demuxer library for OsmoCom projects. + +%package -n libosmonetif11 +Requires: osmocom-latest +Summary: Osmocom library for muxed audio +License: AGPL-3.0-or-later +Group: System/Libraries + +%description -n libosmonetif11 +Network interface demuxer library for OsmoCom projects. + +%package -n libosmonetif-devel +Requires: osmocom-latest +Summary: Development files for the Osmocom muxed audio library +License: AGPL-3.0-or-later +Group: Development/Libraries/C and C++ +Requires: libosmonetif11 = %{version} + +%description -n libosmonetif-devel +Network interface demuxer library for OsmoCom projects. + +This subpackage contains libraries and header files for developing +applications that want to make use of libosmo-netif. + +%prep +%setup -n libosmo-netif -q + +%build +echo "%{version}" >.tarball-version +autoreconf -fiv +%configure --enable-shared --disable-static --includedir="%{_includedir}/%{name}" +make %{?_smp_mflags} + +%install +%make_install +find %{buildroot} -type f -name "*.la" -delete -print + +%check +make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +) + +%post -n libosmonetif11 -p /sbin/ldconfig +%postun -n libosmonetif11 -p /sbin/ldconfig + +%files -n libosmonetif11 +%{_libdir}/libosmonetif.so.11* + +%files -n libosmonetif-devel +%license COPYING +%dir %{_includedir}/%{name} +%dir %{_includedir}/%{name}/osmocom +%{_includedir}/%{name}/osmocom/netif/ +%{_libdir}/libosmonetif.so +%{_libdir}/pkgconfig/libosmo-netif.pc + +%changelog
View file
libosmo-netif_1.5.1.tar.xz/examples/lapd-over-datagram-network.c
Deleted
@@ -1,177 +0,0 @@ -/* LAPD over datagram network-mode example. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/logging.h> -#include <osmocom/core/application.h> -#include <osmocom/core/select.h> - -#include <osmocom/abis/lapd.h> - -#include <osmocom/netif/datagram.h> - -static void *tall_test; - -#define DLAPDTEST 0 - -struct log_info_cat lapd_test_cat = { - DLAPDTEST = { - .name = "DLAPDTEST", - .description = "LAPD-mode test", - .color = "\0331;35m", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, -}; - -const struct log_info lapd_test_log_info = { - .filter_fn = NULL, - .cat = lapd_test_cat, - .num_cat = ARRAY_SIZE(lapd_test_cat), -}; - -static struct osmo_dgram *conn; -static struct lapd_instance *lapd; -static int tei = 0; - -void sighandler(int foo) -{ - lapd_instance_free(lapd); - LOGP(DLAPDTEST, LOGL_NOTICE, "closing LAPD.\n"); - exit(EXIT_SUCCESS); -} - -int read_cb(struct osmo_dgram *conn) -{ - int error; - struct msgb *msg; - - LOGP(DLAPDTEST, LOGL_DEBUG, "received message from datagram\n"); - - msg = msgb_alloc(1200, "LAPD/test"); - if (msg == NULL) { - LOGP(DLAPDTEST, LOGL_ERROR, "cannot allocate message\n"); - return -1; - } - if (osmo_dgram_recv(conn, msg) < 0) { - LOGP(DLAPDTEST, LOGL_ERROR, "cannot receive message\n"); - return -1; - } - if (lapd_receive(lapd, msg, &error) < 0) { - LOGP(DLAPDTEST, LOGL_ERROR, "lapd_receive returned error!\n"); - return -1; - } - - return 0; -} - -void lapd_tx_cb(struct msgb *msg, void *cbdata) -{ - struct osmo_dgram *conn = cbdata; - - LOGP(DLAPDTEST, LOGL_DEBUG, "sending message over datagram\n"); - osmo_dgram_send(conn, msg); -} - -void lapd_rx_cb(struct osmo_dlsap_prim *dp, uint8_t tei, uint8_t sapi, - void *rx_cbdata) -{ - struct msgb *msg = dp->oph.msg; - - switch (dp->oph.primitive) { - case PRIM_DL_EST: - DEBUGP(DLAPDTEST, "DL_EST: sapi(%d) tei(%d)\n", sapi, tei); - break; - case PRIM_DL_REL: - DEBUGP(DLAPDTEST, "DL_REL: sapi(%d) tei(%d)\n", sapi, tei); - break; - case PRIM_DL_DATA: - case PRIM_DL_UNIT_DATA: - if (dp->oph.operation == PRIM_OP_INDICATION) { - struct msgb *nmsg; - char *ptr; - int x; - - msg->l2h = msg->l3h; - - DEBUGP(DLAPDTEST, "RX: %s sapi=%d tei=%d\n", - osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)), - sapi, tei); - - LOGP(DLAPDTEST, LOGL_DEBUG, "forwarding message\n"); - - nmsg = msgb_alloc(1024, "LAPD/test"); - if (nmsg == NULL) { - LOGP(DLAPDTEST, LOGL_ERROR, "cannot alloc msg\n"); - return; - } - ptr = (char *)msgb_put(nmsg, sizeof(int)); - - x = *((int *)msg->data); - memcpy(ptr, &x, sizeof(int)); - - /* send the message back to client over LAPD */ - lapd_transmit(lapd, tei, sapi, msg); - return; - } - break; - case PRIM_MDL_ERROR: - DEBUGP(DLMI, "MDL_EERROR: cause(%d)\n", dp->u.error_ind.cause); - break; - default: - printf("ERROR: unknown prim\n"); - break; - } -} - -int main(int argc, char *argv) -{ - struct lapd_tei *teip; - - tall_test = talloc_named_const(NULL, 1, "lapd_test"); - msgb_talloc_ctx_init(tall_test, 0); - osmo_init_logging2(tall_test, &lapd_test_log_info); - log_set_log_level(osmo_stderr_target, LOGL_NOTICE); - - /* - * initialize datagram server. - */ - - conn = osmo_dgram_create(tall_test); - if (conn == NULL) { - fprintf(stderr, "cannot create client\n"); - exit(EXIT_FAILURE); - } - osmo_dgram_set_local_addr(conn, "127.0.0.1"); - osmo_dgram_set_local_port(conn, 10001); - osmo_dgram_set_remote_addr(conn, "127.0.0.1"); - osmo_dgram_set_remote_port(conn, 10000); - osmo_dgram_set_read_cb(conn, read_cb); - - lapd = lapd_instance_alloc(1, lapd_tx_cb, conn, lapd_rx_cb, conn, - &lapd_profile_sat); - if (lapd == NULL) { - LOGP(DLAPDTEST, LOGL_ERROR, "cannot allocate instance\n"); - exit(EXIT_FAILURE); - } - - teip = lapd_tei_alloc(lapd, tei); - if (teip == NULL) { - LOGP(DLAPDTEST, LOGL_ERROR, "cannot assign TEI\n"); - exit(EXIT_FAILURE); - } - - if (osmo_dgram_open(conn) < 0) { - fprintf(stderr, "cannot open client\n"); - exit(EXIT_FAILURE); - } - - LOGP(DLAPDTEST, LOGL_NOTICE, "Entering main loop\n"); - - while(1) { - osmo_select_main(0); - } -}
View file
libosmo-netif_1.5.1.tar.xz/examples/lapd-over-datagram-user.c
Deleted
@@ -1,241 +0,0 @@ -/* LAPD over datagram user-mode example. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <unistd.h> -#include <arpa/inet.h> - -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/logging.h> -#include <osmocom/core/application.h> -#include <osmocom/core/select.h> - -#include <osmocom/abis/lapd.h> - -#include <osmocom/netif/datagram.h> - -static LLIST_HEAD(msg_sent_list); - -struct msg_sent { - struct llist_head head; - struct msgb *msg; - int num; - struct timeval tv; -}; - -#define DLAPDTEST 0 - -struct log_info_cat lapd_test_cat = { - DLAPDTEST = { - .name = "DLAPDTEST", - .description = "LAPD-mode test", - .color = "\0331;35m", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, -}; - -const struct log_info lapd_test_log_info = { - .filter_fn = NULL, - .cat = lapd_test_cat, - .num_cat = ARRAY_SIZE(lapd_test_cat), -}; - -static struct osmo_dgram *conn; -static struct lapd_instance *lapd; -static int sapi = 63, tei = 0; - -void sighandler(int foo) -{ - lapd_sap_stop(lapd, tei, sapi); - lapd_instance_free(lapd); - LOGP(DLINP, LOGL_NOTICE, "closing LAPD.\n"); - exit(EXIT_SUCCESS); -} - -static int read_cb(struct osmo_dgram *conn) -{ - int error; - struct msgb *msg; - - msg = msgb_alloc(1200, "LAPD/test"); - if (msg == NULL) { - LOGP(DLAPDTEST, LOGL_ERROR, "cannot allocate message\n"); - return -1; - } - if (osmo_dgram_recv(conn, msg) < 0) { - msgb_free(msg); - LOGP(DLAPDTEST, LOGL_ERROR, "cannot receive message\n"); - return -1; - } - if (lapd_receive(lapd, msg, &error) < 0) { - msgb_free(msg); - LOGP(DLINP, LOGL_ERROR, "lapd_receive returned error!\n"); - return -1; - } - return 0; -} - -static void *tall_test; - -void lapd_tx_cb(struct msgb *msg, void *cbdata) -{ - LOGP(DLINP, LOGL_DEBUG, "sending message over datagram\n"); - osmo_dgram_send(conn, msg); -} - -void lapd_rx_cb(struct osmo_dlsap_prim *dp, uint8_t tei, uint8_t sapi, - void *rx_cbdata) -{ - struct msgb *msg = dp->oph.msg; - int *__msgs = rx_cbdata; - int num_msgs = *__msgs; - - switch (dp->oph.primitive) { - case PRIM_DL_EST: - DEBUGP(DLAPDTEST, "DL_EST: sapi(%d) tei(%d)\n", sapi, tei); - - int i; - for (i=0; i<num_msgs; i++) { - struct msgb *msg; - struct msg_sent *msg_sent; - char *ptr; - int x; - - msg = msgb_alloc(1024, "LAPD/test"); - if (msg == NULL) { - LOGP(DLINP, LOGL_ERROR, "cannot alloc msg\n"); - return; - } - ptr = (char *)msgb_put(msg, sizeof(int)); - - x = htonl(i); - memcpy(ptr, &x, sizeof(int)); - - msg_sent = talloc_zero(NULL, struct msg_sent); - if (msg_sent == NULL) { - LOGP(DLINP, LOGL_ERROR, "can't alloc struct\n"); - return; - } - msg_sent->msg = msg; - gettimeofday(&msg_sent->tv, NULL); - msg_sent->num = i; - llist_add(&msg_sent->head, &msg_sent_list); - - lapd_transmit(lapd, tei, sapi, msg); - - LOGP(DLAPDTEST, LOGL_DEBUG, "enqueueing msg %d of " - "%d bytes to be sent over LAPD\n", i, msg->len); - } - break; - case PRIM_DL_REL: - DEBUGP(DLAPDTEST, "DL_REL: sapi(%d) tei(%d)\n", sapi, tei); - break; - case PRIM_DL_DATA: - case PRIM_DL_UNIT_DATA: - if (dp->oph.operation == PRIM_OP_INDICATION) { - msg->l2h = msg->l3h; - DEBUGP(DLAPDTEST, "RX: %s sapi=%d tei=%d\n", - osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)), - sapi, tei); - - int num; - struct msg_sent *cur, *tmp, *found = NULL; - - num = ntohl(*((int *)msg->data)); - LOGP(DLINP, LOGL_DEBUG, - "received msg number %d\n", num); - - llist_for_each_entry_safe(cur, tmp, - &msg_sent_list, head) { - if (cur->num == num) { - llist_del(&cur->head); - found = cur; - break; - } - } - if (found) { - struct timeval tv, diff; - - gettimeofday(&tv, NULL); - timersub(&tv, &found->tv, &diff); - - LOGP(DLINP, LOGL_NOTICE, "message %d replied " - "in %lu.%.6lu\n", - num, diff.tv_sec, diff.tv_usec); - talloc_free(found); - } else { - LOGP(DLINP, LOGL_ERROR, - "message %d not found!\n", num); - } - } - break; - case PRIM_MDL_ERROR: - DEBUGP(DLMI, "MDL_EERROR: cause(%d)\n", dp->u.error_ind.cause); - break; - default: - printf("ERROR: unknown prim\n"); - break; - } -} - -int main(int argc, char *argv) -{ - int num_msgs; - - signal(SIGINT, sighandler); - - if (argc != 2) { - printf("Usage: %s num_msgs\n", argv0); - exit(EXIT_FAILURE); - } - num_msgs = atoi(argv1); - - tall_test = talloc_named_const(NULL, 1, "lapd_test"); - msgb_talloc_ctx_init(tall_test, 0); - osmo_init_logging2(tall_test, &lapd_test_log_info); - log_set_log_level(osmo_stderr_target, LOGL_NOTICE); - /* - * initialize LAPD stuff. - */ - - lapd = lapd_instance_alloc(0, lapd_tx_cb, NULL, lapd_rx_cb, &num_msgs, - &lapd_profile_sat); - if (lapd == NULL) { - LOGP(DLINP, LOGL_ERROR, "cannot allocate instance\n"); - exit(EXIT_FAILURE); - } - - /* - * initialize datagram socket. - */ - - conn = osmo_dgram_create(tall_test); - if (conn == NULL) { - fprintf(stderr, "cannot create client\n"); - exit(EXIT_FAILURE); - } - osmo_dgram_set_local_addr(conn, "127.0.0.1"); - osmo_dgram_set_local_port(conn, 10000); - osmo_dgram_set_remote_addr(conn, "127.0.0.1"); - osmo_dgram_set_remote_port(conn, 10001); - osmo_dgram_set_read_cb(conn, read_cb); - - if (osmo_dgram_open(conn) < 0) { - fprintf(stderr, "cannot open client\n"); - exit(EXIT_FAILURE); - } - - if (lapd_sap_start(lapd, tei, sapi) < 0) { - LOGP(DLINP, LOGL_ERROR, "cannot start user-side LAPD\n"); - exit(EXIT_FAILURE); - } - - LOGP(DLINP, LOGL_NOTICE, "Entering main loop\n"); - - while(1) { - osmo_select_main(0); - } -}
View file
libosmo-netif_1.5.1.dsc -> libosmo-netif_1.6.0.dsc
Changed
@@ -2,21 +2,21 @@ Source: libosmo-netif Binary: libosmonetif11, libosmo-netif-dev, libosmo-netif-doc, libosmo-netif-dbg Architecture: any all -Version: 1.5.1 +Version: 1.6.0 Maintainer: Osmocom team <openbsc@lists.osmocom.org> Homepage: https://projects.osmocom.org/projects/libosmo-netif Standards-Version: 3.9.6 Vcs-Browser: https://gitea.osmocom.org/osmocom/libosmo-netif Vcs-Git: https://gitea.osmocom.org/osmocom/libosmo-netif -Build-Depends: debhelper (>= 10), autotools-dev, autoconf, automake, libtool, dh-autoreconf, libdpkg-perl, git, doxygen, libosmocore-dev (>= 1.10.0), pkg-config, libpcap0.8-dev, libsctp-dev +Build-Depends: debhelper (>= 10), autotools-dev, autoconf, automake, libtool, dh-autoreconf, libdpkg-perl, git, doxygen, libosmocore-dev (>= 1.11.0), pkg-config, libpcap0.8-dev, libsctp-dev Package-List: libosmo-netif-dbg deb debug extra arch=any libosmo-netif-dev deb libdevel optional arch=any libosmo-netif-doc deb doc optional arch=all libosmonetif11 deb libs optional arch=any Checksums-Sha1: - 0dc84bed056bfacd0fd34a906437c520108bf7b4 193920 libosmo-netif_1.5.1.tar.xz + cbca1e98841ef72f31496d14386a0da2e27f1350 199208 libosmo-netif_1.6.0.tar.xz Checksums-Sha256: - a8566de108b03450b119d71ac5c75e6883a486d1d4c559c79e10d360592396dd 193920 libosmo-netif_1.5.1.tar.xz + 76f2334acef97398995178dd94722c2a62412f4514a052268aa2ffc77df58ac7 199208 libosmo-netif_1.6.0.tar.xz Files: - 16608100282ac7ba4b342c9c6ff46b0c 193920 libosmo-netif_1.5.1.tar.xz + bed32e77acc2f045f94147a4cd375568 199208 libosmo-netif_1.6.0.tar.xz
View file
libosmo-netif_1.5.1.tar.xz/.tarball-version -> libosmo-netif_1.6.0.tar.xz/.tarball-version
Changed
@@ -1 +1 @@ -1.5.1 +1.6.0
View file
libosmo-netif_1.5.1.tar.xz/Makefile.am -> libosmo-netif_1.6.0.tar.xz/Makefile.am
Changed
@@ -9,6 +9,7 @@ EXTRA_DIST = \ .version \ README.md \ + contrib/libosmo-netif.spec.in \ debian \ git-version-gen \ $(NULL)
View file
libosmo-netif_1.5.1.tar.xz/configure.ac -> libosmo-netif_1.6.0.tar.xz/configure.ac
Changed
@@ -89,22 +89,9 @@ dnl Generate the output AM_CONFIG_HEADER(config.h) -PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0) -PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.10.0) -PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.10.0) - -AC_ARG_ENABLE(lapd_examples, - AS_HELP_STRING( - --enable-lapd-examples, - Build some lapd examples - ), - lapd_examples=$enableval, lapd_examples="no") -AS_IF(test "x$lapd_examples" = "xyes", - PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0) - AC_DEFINE(ENABLE_LAPD, 1, Enable LAPD examples) -) -AM_CONDITIONAL(ENABLE_LAPD, test "x$lapd_examples" = "xyes") -AC_SUBST(ENABLE_LAPD) +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.11.0) +PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0) +PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.11.0) AC_ARG_ENABLE(libsctp, AS_HELP_STRING(--disable-libsctp, Do not enable socket multiaddr APIs requiring libsctp), ENABLE_LIBSCTP=$enableval, ENABLE_LIBSCTP="yes") @@ -148,4 +135,5 @@ utils/Makefile tests/Makefile Doxyfile - Makefile) + Makefile + contrib/libosmo-netif.spec)
View file
libosmo-netif_1.5.1.tar.xz/contrib/jenkins.sh -> libosmo-netif_1.6.0.tar.xz/contrib/jenkins.sh
Changed
@@ -24,7 +24,6 @@ export LD_LIBRARY_PATH="$inst/lib" osmo-build-dep.sh libosmocore "" --disable-doxygen -osmo-build-dep.sh libosmo-abis set +x echo
View file
libosmo-netif_1.6.0.tar.xz/contrib/libosmo-netif.spec.in
Added
@@ -0,0 +1,87 @@ +# +# spec file for package libosmo-netif +# +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +Name: libosmo-netif +Requires: osmocom-latest +Version: @VERSION@ +Release: 0 +Summary: Osmocom library for muxed audio +License: GPL-2.0-or-later +Group: Productivity/Telephony/Utilities +URL: https://osmocom.org/projects/libosmo-netif +Source: %{name}-%{version}.tar.xz +BuildRequires: automake +BuildRequires: libtool >= 2 +BuildRequires: lksctp-tools-devel +BuildRequires: pkgconfig >= 0.20 +BuildRequires: pkgconfig(libosmocore) >= 1.11.0 +BuildRequires: pkgconfig(libosmogsm) >= 1.11.0 +BuildRequires: pkgconfig(libosmocodec) >= 1.11.0 + +%description +Network interface demuxer library for OsmoCom projects. + +%package -n libosmonetif11 +Requires: osmocom-latest +Summary: Osmocom library for muxed audio +License: AGPL-3.0-or-later +Group: System/Libraries + +%description -n libosmonetif11 +Network interface demuxer library for OsmoCom projects. + +%package -n libosmonetif-devel +Requires: osmocom-latest +Summary: Development files for the Osmocom muxed audio library +License: AGPL-3.0-or-later +Group: Development/Libraries/C and C++ +Requires: libosmonetif11 = %{version} + +%description -n libosmonetif-devel +Network interface demuxer library for OsmoCom projects. + +This subpackage contains libraries and header files for developing +applications that want to make use of libosmo-netif. + +%prep +%setup -q + +%build +echo "%{version}" >.tarball-version +autoreconf -fiv +%configure --enable-shared --disable-static --includedir="%{_includedir}/%{name}" +make %{?_smp_mflags} + +%install +%make_install +find %{buildroot} -type f -name "*.la" -delete -print + +%check +make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +) + +%post -n libosmonetif11 -p /sbin/ldconfig +%postun -n libosmonetif11 -p /sbin/ldconfig + +%files -n libosmonetif11 +%{_libdir}/libosmonetif.so.11* + +%files -n libosmonetif-devel +%license COPYING +%dir %{_includedir}/%{name} +%dir %{_includedir}/%{name}/osmocom +%{_includedir}/%{name}/osmocom/netif/ +%{_libdir}/libosmonetif.so +%{_libdir}/pkgconfig/libosmo-netif.pc + +%changelog
View file
libosmo-netif_1.5.1.tar.xz/debian/changelog -> libosmo-netif_1.6.0.tar.xz/debian/changelog
Changed
@@ -1,3 +1,51 @@ +libosmo-netif (1.6.0) unstable; urgency=medium + + Harald Welte + * stream_test: don't check if uint8_t is negative + * src/stream.c: Use sctp_assoc_id 'canary' to detect misisng sinfo + + Neels Hofmeyr + * osmo_rtp_get_payload(): fix bounds check for padding + * coverity CID#216829 + * api doc: stream.h: hint at how to select modern vs legacy mode + + Pau Espin Pedrol + * rtp: osmo_rtp_get_payload(): Fix return ptr if RTP pkt contains padding + * Drop libosmo-abis cond dep together with examples/lapd-over-datagram + * stream_cli: Allow setting nodelay sockopt after opening sock + * examples/ipa-stream-client: Fix wrong call to osmo_ipa_process_msg() + * stream: Explicitly document MSG_NOTIFICATION case in recv() API + * stream: Improve logging around recv() failure + * stream_cli: Log all code paths ending up in close/reconnect + * stream_cli: Announce failed connect() if reconnect is disabled + * stream_cli: Add osmo_stream_cli_set_{ip_dscp,priority}() APIs + * stream_srv: Add osmo_stream_srv_link_set_{ip_dscp,priority}() APIs + * stream_cli: Rename private functions + * stream_cli: Move osmo_stream_cli_close() before osmo_stream_cli_reconnect() + * stream_cli: Support destroy object within user callback + * stream_cli: Add API osmo_stream_cli_set_tx_queue_max_length() + * stream_srv: Add API osmo_stream_srv_link_set_tx_queue_max_length() + * stream: Allow null ptr in destroy() functions + * stream_cli: steal talloc ctx upon delaying free to avoid use after free + * stream_cli: Assert reentrant disconnect_cb() never happens + * stream_cli: Explicitly ignore return code of stream_cli_close + * stream_cli: Explicitly ignore return code of internal functions + * stream_cli: Fix discard 1st msg received quick after connect + * ipa: Add osmo_ipa_ka_fsm_inst APIs + * stream: Introduce osmo_stream_{cli,srv}_set_segmentation_cb2 + * stream: Add osmo_stream_srv_link_set_msgb_alloc_info() + * stream: Undeprecate osmo_stream_srv_set_segmentation_cb() + * stream: osmo_stream_{cli,srv}_set_segmentation_cb(2): documentation improvements + + Mychaela N. Falconia + * include/osmocom/netif/Makefile.am cosmetic: make it easier to extend + * src/Makefile.am cosmetic: make it easier to extend + + Oliver Smith + * Revert "contrib: remove rpm spec file" + + -- Oliver Smith <osmith@sysmocom.de> Wed, 12 Feb 2025 11:01:12 +0100 + libosmo-netif (1.5.1) unstable; urgency=medium Daniel Willmann
View file
libosmo-netif_1.5.1.tar.xz/debian/control -> libosmo-netif_1.6.0.tar.xz/debian/control
Changed
@@ -11,7 +11,7 @@ libdpkg-perl, git, doxygen, - libosmocore-dev (>= 1.10.0), + libosmocore-dev (>= 1.11.0), pkg-config, libpcap0.8-dev, libsctp-dev
View file
libosmo-netif_1.5.1.tar.xz/examples/Makefile.am -> libosmo-netif_1.6.0.tar.xz/examples/Makefile.am
Changed
@@ -1,5 +1,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) +AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) noinst_PROGRAMS = ipa-stream-client \ @@ -25,19 +25,6 @@ ipa_stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -if ENABLE_LAPD -noinst_PROGRAMS += lapd-over-datagram-user lapd-over-datagram-network -lapd_over_datagram_user_SOURCES = lapd-over-datagram-user.c -lapd_over_datagram_user_LDADD = $(top_builddir)/src/libosmonetif.la \ - $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) - -lapd_over_datagram_network_SOURCES = lapd-over-datagram-network.c -lapd_over_datagram_network_LDADD = $(top_builddir)/src/libosmonetif.la \ - $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) -endif - stream_client_SOURCES = stream-client.c stream_client_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
View file
libosmo-netif_1.5.1.tar.xz/examples/ipa-stream-client.c -> libosmo-netif_1.6.0.tar.xz/examples/ipa-stream-client.c
Changed
@@ -115,13 +115,7 @@ return 0; } - if (osmo_ipa_process_msg(msg) < 0) { - LOGP(DIPATEST, LOGL_ERROR, "bad IPA message\n"); - msgb_free(msg); - return 0; - } - - num = osmo_load32be(msg->data); + num = osmo_load32be(msgb_l2(msg)); LOGP(DLINP, LOGL_DEBUG, "received msg number %d\n", num); llist_for_each_entry_safe(cur, tmp, &msg_sent_list, head) {
View file
libosmo-netif_1.5.1.tar.xz/include/osmocom/netif/Makefile.am -> libosmo-netif_1.6.0.tar.xz/include/osmocom/netif/Makefile.am
Changed
@@ -4,14 +4,15 @@ osmonetif_HEADERS = amr.h \ datagram.h \ - jibuf.h \ - osmux.h \ ipa.h \ ipa_unit.h \ + jibuf.h \ + osmux.h \ prim.h \ rs232.h \ rtp.h \ - stream.h + stream.h \ + $(NULL) if ENABLE_LIBSCTP osmonetif_HEADERS += sctp.h
View file
libosmo-netif_1.5.1.tar.xz/include/osmocom/netif/ipa.h -> libosmo-netif_1.6.0.tar.xz/include/osmocom/netif/ipa.h
Changed
@@ -67,4 +67,28 @@ void osmo_ipa_msg_push_headers(struct msgb *msg, enum ipaccess_proto p, enum ipaccess_proto_ext pe); +/*********************************************************************** + * IPA Keep-Alive FSM + ***********************************************************************/ +struct osmo_ipa_ka_fsm_inst; +typedef int (*osmo_ipa_ka_fsm_timeout_cb_t)(struct osmo_ipa_ka_fsm_inst *ka_fi, void *data); + +typedef int (*osmo_ipa_ka_fsm_send_cb_t)(struct osmo_ipa_ka_fsm_inst *ka_fi, struct msgb *msg, void *data); + +struct osmo_ipa_ka_fsm_inst *osmo_ipa_ka_fsm_alloc(void *ctx, const char *id); +void osmo_ipa_ka_fsm_free(struct osmo_ipa_ka_fsm_inst *ka_fi); + +int osmo_ipa_ka_fsm_set_id(struct osmo_ipa_ka_fsm_inst *ka_fi, const char *id); +int osmo_ipa_ka_fsm_set_ping_interval(struct osmo_ipa_ka_fsm_inst *ka_fi, unsigned int interval); +int osmo_ipa_ka_fsm_set_pong_timeout(struct osmo_ipa_ka_fsm_inst *ka_fi, unsigned int timeout); +void osmo_ipa_ka_fsm_set_data(struct osmo_ipa_ka_fsm_inst *ka_fi, void *cb_data); +void *osmo_ipa_ka_fsm_get_data(const struct osmo_ipa_ka_fsm_inst *ka_fi); + +void osmo_ipa_ka_fsm_set_send_cb(struct osmo_ipa_ka_fsm_inst *ka_fi, osmo_ipa_ka_fsm_send_cb_t send_cb); +void osmo_ipa_ka_fsm_set_timeout_cb(struct osmo_ipa_ka_fsm_inst *ka_fi, osmo_ipa_ka_fsm_timeout_cb_t timeout_cb); + +void osmo_ipa_ka_fsm_start(struct osmo_ipa_ka_fsm_inst *ka_fi); +void osmo_ipa_ka_fsm_pong_received(struct osmo_ipa_ka_fsm_inst *ka_fi); +void osmo_ipa_ka_fsm_stop(struct osmo_ipa_ka_fsm_inst *ka_fi); + #endif
View file
libosmo-netif_1.5.1.tar.xz/include/osmocom/netif/stream.h -> libosmo-netif_1.6.0.tar.xz/include/osmocom/netif/stream.h
Changed
@@ -32,6 +32,9 @@ * For any new applications, you definitely should use the modern mode, as it provides you with a higher * layer of abstraction and allows you to perform efficient I/O using the io_uring backend of osmo_io. * + * The modern mode is chosen by invoking osmo_stream_srv_create2(). + * The legacy mode is chosen by invoking the older osmo_stream_srv_create(). + * * The two main objects are osmo_stream_srv_link (main server accept()ing incoming connections) and * osmo_stream_srv (a single given connection from a remote client). * @@ -70,6 +73,8 @@ void osmo_stream_srv_link_set_name(struct osmo_stream_srv_link *link, const char *name); const char *osmo_stream_srv_link_get_name(const struct osmo_stream_srv_link *link); void osmo_stream_srv_link_set_nodelay(struct osmo_stream_srv_link *link, bool nodelay); +int osmo_stream_srv_link_set_priority(struct osmo_stream_srv_link *link, int sk_prio); +int osmo_stream_srv_link_set_ip_dscp(struct osmo_stream_srv_link *link, uint8_t ip_dscp); void osmo_stream_srv_link_set_addr(struct osmo_stream_srv_link *link, const char *addr); 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); @@ -79,9 +84,11 @@ void osmo_stream_srv_link_set_accept_cb(struct osmo_stream_srv_link *link, osmo_stream_srv_link_accept_cb_t accept_cb); void osmo_stream_srv_link_set_data(struct osmo_stream_srv_link *link, void *data); void *osmo_stream_srv_link_get_data(struct osmo_stream_srv_link *link); +int osmo_stream_srv_link_set_tx_queue_max_length(struct osmo_stream_srv_link *link, unsigned int size); char *osmo_stream_srv_link_get_sockname(const struct osmo_stream_srv_link *link); struct osmo_fd *osmo_stream_srv_link_get_ofd(struct osmo_stream_srv_link *link); int osmo_stream_srv_link_get_fd(const struct osmo_stream_srv_link *link); +int osmo_stream_srv_link_set_msgb_alloc_info(struct osmo_stream_srv_link *link, unsigned int size, unsigned int headroom); bool osmo_stream_srv_link_is_opened(const struct osmo_stream_srv_link *link); int osmo_stream_srv_link_open(struct osmo_stream_srv_link *link); void osmo_stream_srv_link_close(struct osmo_stream_srv_link *link); @@ -111,6 +118,7 @@ typedef int (*osmo_stream_srv_read_cb2_t)(struct osmo_stream_srv *conn, int res, struct msgb *msg); typedef int (*osmo_stream_srv_segmentation_cb_t)(struct msgb *msg); +typedef int (*osmo_stream_srv_segmentation_cb2_t)(struct osmo_stream_srv *conn, struct msgb *msg); struct osmo_stream_srv *osmo_stream_srv_create(void *ctx, struct osmo_stream_srv_link *link, int fd, osmo_stream_srv_read_cb_t read_cb, @@ -133,6 +141,7 @@ void osmo_stream_srv_set_data(struct osmo_stream_srv *conn, void *data); void osmo_stream_srv_set_segmentation_cb(struct osmo_stream_srv *conn, osmo_stream_srv_segmentation_cb_t segmentation_cb); +void osmo_stream_srv_set_segmentation_cb2(struct osmo_stream_srv *conn, osmo_stream_srv_segmentation_cb2_t segmentation_cb2); void osmo_stream_srv_send(struct osmo_stream_srv *conn, struct msgb *msg); int osmo_stream_srv_recv(struct osmo_stream_srv *conn, struct msgb *msg); @@ -157,6 +166,9 @@ * For any new applications, you definitely should use the modern mode, as it provides you with a higher * layer of abstraction and allows you to perform efficient I/O using the io_uring backend of osmo_io. * + * The modern mode is chosen by invoking osmo_stream_cli_set_read_cb2(). + * The legacy mode is chosen by invoking the older osmo_stream_cli_set_read_cb(). + * * A typical usage of osmo_stream_cli would look as follows: * * * call osmo_stream_cli_create() to create a new osmo_stream_cli @@ -188,10 +200,13 @@ typedef int (*osmo_stream_cli_read_cb2_t)(struct osmo_stream_cli *cli, int res, struct msgb *msg); typedef int (*osmo_stream_cli_segmentation_cb_t)(struct msgb *msg); +typedef int (*osmo_stream_cli_segmentation_cb2_t)(struct osmo_stream_cli *cli, struct msgb *msg); void osmo_stream_cli_set_name(struct osmo_stream_cli *cli, const char *name); const char *osmo_stream_cli_get_name(const struct osmo_stream_cli *cli); void osmo_stream_cli_set_nodelay(struct osmo_stream_cli *cli, bool nodelay); +int osmo_stream_cli_set_priority(struct osmo_stream_cli *cli, int sk_prio); +int osmo_stream_cli_set_ip_dscp(struct osmo_stream_cli *cli, uint8_t ip_dscp); void osmo_stream_cli_set_addr(struct osmo_stream_cli *cli, const char *addr); int osmo_stream_cli_set_addrs(struct osmo_stream_cli *cli, const char **addr, size_t addrcnt); void osmo_stream_cli_set_port(struct osmo_stream_cli *cli, uint16_t port); @@ -204,6 +219,7 @@ void osmo_stream_cli_set_data(struct osmo_stream_cli *cli, void *data); void osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout); void *osmo_stream_cli_get_data(struct osmo_stream_cli *cli); +int osmo_stream_cli_set_tx_queue_max_length(struct osmo_stream_cli *cli, unsigned int size); char *osmo_stream_cli_get_sockname(const struct osmo_stream_cli *cli); struct osmo_fd *osmo_stream_cli_get_ofd(struct osmo_stream_cli *cli); int osmo_stream_cli_get_fd(const struct osmo_stream_cli *cli); @@ -213,6 +229,7 @@ void osmo_stream_cli_set_read_cb(struct osmo_stream_cli *cli, osmo_stream_cli_read_cb_t read_cb); void osmo_stream_cli_set_read_cb2(struct osmo_stream_cli *cli, osmo_stream_cli_read_cb2_t read_cb); void osmo_stream_cli_set_segmentation_cb(struct osmo_stream_cli *cli, osmo_stream_cli_segmentation_cb_t segmentation_cb); +void osmo_stream_cli_set_segmentation_cb2(struct osmo_stream_cli *cli, osmo_stream_cli_segmentation_cb2_t segmentation_cb2); void osmo_stream_cli_reconnect(struct osmo_stream_cli *cli); bool osmo_stream_cli_is_connected(struct osmo_stream_cli *cli);
View file
libosmo-netif_1.5.1.tar.xz/src/Makefile.am -> libosmo-netif_1.6.0.tar.xz/src/Makefile.am
Changed
@@ -1,9 +1,9 @@ # This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification -LIBVERSION=13:1:2 +LIBVERSION=14:0:3 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS= -fPIC -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBSCTP_CFLAGS) +AM_CFLAGS= -fPIC -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(COVERAGE_CFLAGS) $(LIBSCTP_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) lib_LTLIBRARIES = libosmonetif.la @@ -14,6 +14,7 @@ libosmonetif_la_SOURCES = amr.c \ datagram.c \ ipa.c \ + ipa_keepalive.c \ ipa_unit.c \ jibuf.c \ osmux.c \ @@ -22,9 +23,10 @@ prim.c \ rs232.c \ rtp.c \ + stream.c \ stream_cli.c \ stream_srv.c \ - stream.c + $(NULL) if ENABLE_LIBSCTP libosmonetif_la_SOURCES += sctp.c
View file
libosmo-netif_1.6.0.tar.xz/src/ipa_keepalive.c
Added
@@ -0,0 +1,353 @@ +/* IPA keep-alive FSM; Periodically transmit IPA_PING and expect IPA_PONG in return. + * + * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de + * (C) 2019 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <osmocom/core/fsm.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> + +#include <osmocom/gsm/protocol/ipaccess.h> + +#include <osmocom/netif/ipa.h> + +#define KA_FI_DEFAULT_PING_INTERVAL 30 /* seconds */ +#define KA_FI_DEFAULT_PONG_TIMEOUT 10 /* seconds */ + +enum osmo_ipa_keepalive_event { + OSMO_IPA_KA_E_START, + OSMO_IPA_KA_E_STOP, + OSMO_IPA_KA_E_PONG, +}; + +static const struct value_string ipa_keepalive_event_names = { + OSMO_VALUE_STRING(OSMO_IPA_KA_E_START), + OSMO_VALUE_STRING(OSMO_IPA_KA_E_STOP), + OSMO_VALUE_STRING(OSMO_IPA_KA_E_PONG), + { 0, NULL } +}; + +struct osmo_ipa_ka_fsm_inst { + struct osmo_fsm_inst *fi; + /*! interval in which to send IPA CCM PING requests to the peer. */ + unsigned int ping_interval; + /*! time to wait for an IPA CCM PONG in response to a IPA CCM PING before giving up. */ + unsigned int pong_timeout; + osmo_ipa_ka_fsm_send_cb_t send_cb; + osmo_ipa_ka_fsm_timeout_cb_t timeout_cb; + void *cb_data; +}; + +/* generate a msgb containing an IPA CCM PING message */ +static struct msgb *gen_ipa_ping(void) +{ + struct msgb *msg = msgb_alloc_headroom(64, 32, "IPA PING"); + if (!msg) + return NULL; + + msgb_put_u8(msg, IPAC_MSGT_PING); + ipa_prepend_header(msg, IPAC_PROTO_IPACCESS); + + return msg; +} + +/******** + * FSM: + *******/ + +#define S(x) (1 << (x)) + +enum osmo_ipa_keepalive_state { + OSMO_IPA_KA_S_INIT, + OSMO_IPA_KA_S_IDLE, /* waiting for next interval */ + OSMO_IPA_KA_S_WAIT_RESP, /* waiting for response to keepalive */ +}; + +enum ipa_fsm_timer { + T_SEND_NEXT_PING = 1, + T_PONG_NOT_RECEIVED = 2, +}; + +static void ipa_ka_init(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct osmo_ipa_ka_fsm_inst *ka_fi = fi->priv; + + switch (event) { + case OSMO_IPA_KA_E_START: + osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_WAIT_RESP, + ka_fi->pong_timeout, T_PONG_NOT_RECEIVED); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +static void ipa_ka_wait_resp_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + struct osmo_ipa_ka_fsm_inst *ka_fi = fi->priv; + struct msgb *msg; + + if (!ka_fi->send_cb) + osmo_panic("osmo_ipa_ka_fsm_inst running without send_cb, fix your code!"); + + /* Send an IPA PING to the peer */ + msg = gen_ipa_ping(); + OSMO_ASSERT(msg); + + ka_fi->send_cb(ka_fi, msg, ka_fi->cb_data); +} + +static void ipa_ka_wait_resp(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct osmo_ipa_ka_fsm_inst *ka_fi = fi->priv; + + switch (event) { + case OSMO_IPA_KA_E_PONG: + osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_IDLE, + ka_fi->ping_interval, T_SEND_NEXT_PING); + break; + default: + OSMO_ASSERT(0); + } +} + +static int ipa_ka_fsm_timer_cb(struct osmo_fsm_inst *fi) +{ + struct osmo_ipa_ka_fsm_inst *ka_fi = fi->priv; + + switch (fi->T) { + case T_SEND_NEXT_PING: + /* send another PING */ + osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_WAIT_RESP, + ka_fi->pong_timeout, T_PONG_NOT_RECEIVED); + return 0; + case T_PONG_NOT_RECEIVED: + /* PONG not received within time */ + LOGPFSML(fi, LOGL_NOTICE, "IPA keep-alive FSM timed out: PONG not received\n"); + /* Keep FSM alive, move to INIT state */ + osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_INIT, 0, 0); + if (ka_fi->timeout_cb) + ka_fi->timeout_cb(ka_fi, ka_fi->cb_data); + return 0; + default: + OSMO_ASSERT(0); + } +} + +static void ipa_ka_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case OSMO_IPA_KA_E_STOP: + osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_INIT, 0, 0); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +static const struct osmo_fsm_state ipa_keepalive_states = { + OSMO_IPA_KA_S_INIT = { + .name = "INIT", + .in_event_mask = S(OSMO_IPA_KA_E_START), + .out_state_mask = S(OSMO_IPA_KA_S_WAIT_RESP) | S(OSMO_IPA_KA_S_INIT), + .action = ipa_ka_init, + }, + OSMO_IPA_KA_S_IDLE = { + .name = "IDLE", + .out_state_mask = S(OSMO_IPA_KA_S_WAIT_RESP) | S(OSMO_IPA_KA_S_INIT), + /* no permitted events aside from E_STOP, which is handled in allstate_events */ + }, + OSMO_IPA_KA_S_WAIT_RESP = { + .name = "WAIT_RESP", + .in_event_mask = S(OSMO_IPA_KA_E_PONG), + .out_state_mask = S(OSMO_IPA_KA_S_IDLE) | S(OSMO_IPA_KA_S_INIT), + .action = ipa_ka_wait_resp, + .onenter = ipa_ka_wait_resp_onenter, + }, +}; + +static struct osmo_fsm ipa_keepalive_fsm = { + .name = "IPA-KA", + .states = ipa_keepalive_states, + .num_states = ARRAY_SIZE(ipa_keepalive_states), + .log_subsys = DLINP, + .allstate_event_mask = S(OSMO_IPA_KA_E_STOP), + .allstate_action = ipa_ka_allstate_action, + .event_names = ipa_keepalive_event_names, + .timer_cb = ipa_ka_fsm_timer_cb, +}; + +static __attribute__((constructor)) void on_dso_load(void) +{ + OSMO_ASSERT(osmo_fsm_register(&ipa_keepalive_fsm) == 0); +} + + +/***************************** + * osmo_ipa_ka_fsm_inst APIS +******************************/ + +/*! Create a new instance of an IPA keepalive FSM: Periodically transmit PING and expect PONG. + * \paramin ctx Talloc context. + * \paramin id String used as identifier for the FSM. + * \returns pointer to the newly-created FSM instance; NULL in case of error. + * + * Must be freed with \ref osmo_ipa_ka_fsm_free() + */ +struct osmo_ipa_ka_fsm_inst *osmo_ipa_ka_fsm_alloc(void *ctx, const char *id) +{ + struct osmo_ipa_ka_fsm_inst *ka_fi; + + ka_fi = talloc_zero(ctx, struct osmo_ipa_ka_fsm_inst); + if (!ka_fi) + goto ret_free; + + ka_fi->fi = osmo_fsm_inst_alloc(&ipa_keepalive_fsm, ka_fi, NULL, LOGL_DEBUG, id); + if (!ka_fi->fi) + goto ret_free; + ka_fi->fi->priv = ka_fi; + + ka_fi->ping_interval = KA_FI_DEFAULT_PING_INTERVAL; + ka_fi->pong_timeout = KA_FI_DEFAULT_PONG_TIMEOUT; + + return ka_fi; + +ret_free: + talloc_free(ka_fi); + return NULL; +} + +/*! Free object allocated through \ref osmo_ipa_ka_fsm_alloc(). + * \paramin ka_fi IPA keepalive FSM instance. + * + * Does nothing if NULL is passed. + */ +void osmo_ipa_ka_fsm_free(struct osmo_ipa_ka_fsm_inst *ka_fi) +{ + if (!ka_fi) + return; + + osmo_fsm_inst_free(ka_fi->fi); + ka_fi->fi = NULL; + + talloc_free(ka_fi); +} + +/*! Set name id of the IPA keepalive FSM instance. + * \paramin ka_fi IPA keepalive FSM instance. + * \paramin id Name used during logging. + * \returns zero on success, negative on error. + */ +int osmo_ipa_ka_fsm_set_id(struct osmo_ipa_ka_fsm_inst *ka_fi, const char *id) +{ + return osmo_fsm_inst_update_id(ka_fi->fi, id); +} + +/*! Set PING interval value. + * \paramin ka_fi IPA keepalive FSM instance. + * \paramin interval PING interval value, in seconds. + * \returns zero on success, negative on error. + */ +int osmo_ipa_ka_fsm_set_ping_interval(struct osmo_ipa_ka_fsm_inst *ka_fi, unsigned int interval) +{ + ka_fi->ping_interval = interval; + return 0; +} + +/*! Set PONG timeout value. + * \paramin ka_fi IPA keepalive FSM instance. + * \paramin timeout PONG timeout value, in seconds. + * \returns zero on success, negative on error. + */ +int osmo_ipa_ka_fsm_set_pong_timeout(struct osmo_ipa_ka_fsm_inst *ka_fi, unsigned int timeout) +{ + ka_fi->pong_timeout = timeout; + return 0; +} + +/*! Set user private data which can be used by user of osmo_ipa_ka_fsm. + * \paramin ka_fi IPA keepalive FSM instance. + * \paramin cb_data User private data pointer. + */ +void osmo_ipa_ka_fsm_set_data(struct osmo_ipa_ka_fsm_inst *ka_fi, void *cb_data) +{ + ka_fi->cb_data = cb_data; +} + +/*! Get user private data set previously throuhg \ref osmo_ipa_ka_fsm_set_data. + * \paramin ka_fi IPA keepalive FSM instance. + */ +void *osmo_ipa_ka_fsm_get_data(const struct osmo_ipa_ka_fsm_inst *ka_fi) +{ + return ka_fi->cb_data; +} + +/*! Set a custom send callback for sending pings + * \paramin ka_fi IPA keepalive FSM instance. + * \paramin send_cb Function to call whenever a PING needs to be sent (present in msgb param). + */ +void osmo_ipa_ka_fsm_set_send_cb(struct osmo_ipa_ka_fsm_inst *ka_fi, osmo_ipa_ka_fsm_send_cb_t send_cb) +{ + ka_fi->send_cb = send_cb; +} + +/*! Set a timeout call-back which is to be called once the peer doesn't respond anymore. + * \paramin ka_fi IPA keepalive FSM instance. + * \paramin timeout_cb Function to call whenever PONG timeout occurs. + * + * When the PONG timeout occurs, the FSM will stop and transition to INITIAL + * state prior to triggering the timeout_cb(). This lets the user either destroy + * the FSM (|ref osmo_ipa_ka_fsm_free()) or restart it (\ref osmo_ipa_ka_fsm_start()). + */ +void osmo_ipa_ka_fsm_set_timeout_cb(struct osmo_ipa_ka_fsm_inst *ka_fi, osmo_ipa_ka_fsm_timeout_cb_t timeout_cb) +{ + ka_fi->timeout_cb = timeout_cb; +} + +/*! Start the ping/pong procedure of the IPA Keepalive FSM. + * \paramin ka_fi IPA keepalive FSM instance. + */ +void osmo_ipa_ka_fsm_start(struct osmo_ipa_ka_fsm_inst *ka_fi) +{ + struct osmo_fsm_inst *fi = ka_fi->fi; + LOGPFSML(fi, LOGL_INFO, "Starting IPA keep-alive FSM (interval=%us wait=%us)\n", + ka_fi->ping_interval, ka_fi->pong_timeout); + osmo_fsm_inst_dispatch(fi, OSMO_IPA_KA_E_START, NULL); +} + +/*! Inform IPA Keepalive FSM that a PONG has been received. + * \paramin ka_fi IPA keepalive FSM instance. + */ +void osmo_ipa_ka_fsm_pong_received(struct osmo_ipa_ka_fsm_inst *ka_fi) +{ + osmo_fsm_inst_dispatch(ka_fi->fi, OSMO_IPA_KA_E_PONG, NULL); +} + +/*! Stop the ping/pong procedure of the IPA Keepalive FSM. + * \paramin ka_fi IPA keepalive FSM instance. + */ +void osmo_ipa_ka_fsm_stop(struct osmo_ipa_ka_fsm_inst *ka_fi) +{ + struct osmo_fsm_inst *fi = ka_fi->fi; + LOGPFSML(fi, LOGL_INFO, "Stopping IPA keep-alive FSM\n"); + osmo_fsm_inst_dispatch(fi, OSMO_IPA_KA_E_STOP, NULL); +}
View file
libosmo-netif_1.5.1.tar.xz/src/rtp.c -> libosmo-netif_1.6.0.tar.xz/src/rtp.c
Changed
@@ -115,14 +115,21 @@ int x_len; int csrc_len; - csrc_len = rtph->csrc_count << 2; - payload = msg->data + sizeof(struct rtp_hdr) + csrc_len; - payload_len = msg->len - sizeof(struct rtp_hdr) - csrc_len; - if (payload_len < 0) { - DEBUGPC(DLMUX, "received RTP frame too short (len = %d, " - "csrc count = %d)\n", msg->len, rtph->csrc_count); + if (msg->len < sizeof(struct rtp_hdr)) { + DEBUGPC(DLMUX, "received RTP frame too short for an RTP header (%d < %zu)\n", + msg->len, sizeof(*rtph)); return NULL; } + + csrc_len = sizeof(struct rtp_hdr) + (rtph->csrc_count << 2); + if (msg->len < csrc_len) { + DEBUGPC(DLMUX, "received RTP frame too short for its csrc (%u < %d, csrc_count = %d)\n", + msg->len, csrc_len, rtph->csrc_count); + return NULL; + } + payload = msg->data + csrc_len; + payload_len = msg->len - csrc_len; + if (rtph->extension) { if (payload_len < sizeof(struct rtp_x_hdr)) { DEBUGPC(DLMUX, "received RTP frame too short for " @@ -131,30 +138,31 @@ } rtpxh = (struct rtp_x_hdr *)payload; x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr); - payload += x_len; - payload_len -= x_len; - if (payload_len < 0) { + if (x_len > payload_len) { DEBUGPC(DLMUX, "received RTP frame too short, " "extension header exceeds frame length\n"); return NULL; } + payload += x_len; + payload_len -= x_len; } if (rtph->padding) { - if (payload_len < 0) { + uint8_t padding_len; + if (payload_len < 1) { DEBUGPC(DLMUX, "received RTP frame too short for " "padding length\n"); return NULL; } - payload_len -= payloadpayload_len - 1; - if (payload_len < 0) { - DEBUGPC(DLMUX, "received RTP frame with padding " - "greater than payload\n"); + padding_len = payloadpayload_len - 1; + if (payload_len < padding_len) { + DEBUGPC(DLMUX, "received RTP frame with padding greater than payload\n"); return NULL; } + payload_len -= padding_len; } *plen = payload_len; - return (uint8_t *)msg->data + msg->len - payload_len; + return payload; } struct msgb *
View file
libosmo-netif_1.5.1.tar.xz/src/stream.c -> libosmo-netif_1.6.0.tar.xz/src/stream.c
Changed
@@ -279,8 +279,14 @@ int flags = 0; int ret; + /* Canary to detect if kernel returns sinfo; see https://github.com/sctp/lksctp-tools/issues/37 */ + sinfo.sinfo_assoc_id = 0; + ret = sctp_recvmsg(fd, msg->tail, msgb_tailroom(msg), NULL, NULL, &sinfo, &flags); - return stream_sctp_recvmsg_trailer(log_pfx, msg, ret, &sinfo, flags); + if (sinfo.sinfo_assoc_id) + return stream_sctp_recvmsg_trailer(log_pfx, msg, ret, &sinfo, flags); + else + return stream_sctp_recvmsg_trailer(log_pfx, msg, ret, NULL, flags); } /*! wrapper for osmo_io asynchronous recvmsg response */
View file
libosmo-netif_1.5.1.tar.xz/src/stream_cli.c -> libosmo-netif_1.6.0.tar.xz/src/stream_cli.c
Changed
@@ -83,6 +83,11 @@ #define OSMO_STREAM_CLI_F_RECONF (1 << 0) #define OSMO_STREAM_CLI_F_NODELAY (1 << 1) +/* Mark whether the object is currently in a user callback. */ +#define IN_CB_MASK_CONNECT_CB (1 << 0) +#define IN_CB_MASK_DISCONNECT_CB (1 << 1) +#define IN_CB_MASK_READ_CB (1 << 2) + struct osmo_stream_cli { char *name; char socknameOSMO_SOCK_NAME_MAXLEN; @@ -91,7 +96,9 @@ struct osmo_fd ofd; struct osmo_io_fd *iofd; }; - struct llist_head tx_queue; + struct llist_head tx_queue; /* osmo_ofd mode (only): Queue of msgbs */ + unsigned int tx_queue_count; /* osmo_ofd mode (only): Current amount of msgbs queued */ + unsigned int tx_queue_max_length; /* Max amount of msgbs which can be enqueued */ struct osmo_timer_list timer; enum osmo_stream_cli_state state; char *addrOSMO_STREAM_MAX_ADDRS; @@ -102,53 +109,47 @@ uint16_t local_port; int sk_domain; int sk_type; + int sk_prio; /* socket priority, SO_PRIORITY, default=0=unset */ uint16_t proto; + uint8_t ip_dscp; /* IP Differentiated services, 0..63, default=0=unset */ osmo_stream_cli_connect_cb_t connect_cb; osmo_stream_cli_disconnect_cb_t disconnect_cb; osmo_stream_cli_read_cb_t read_cb; osmo_stream_cli_read_cb2_t iofd_read_cb; osmo_stream_cli_segmentation_cb_t segmentation_cb; + osmo_stream_cli_segmentation_cb2_t segmentation_cb2; void *data; int flags; int reconnect_timeout; struct osmo_sock_init2_multiaddr_pars ma_pars; + uint8_t in_cb_mask; /* IN_CB_MASK_* */ + bool delay_free; }; -void osmo_stream_cli_close(struct osmo_stream_cli *cli); - /*! \addtogroup stream_cli * @{ */ -/*! Re-connect an Osmocom Stream Client. - * If re-connection is enabled for this client - * (which is the case unless negative timeout was explicitly set via osmo_stream_cli_set_reconnect_timeout() call), - * we close any existing connection (if any) and schedule a re-connect timer */ -void osmo_stream_cli_reconnect(struct osmo_stream_cli *cli) +/* return true if freed */ +static inline bool free_delayed_if_needed(struct osmo_stream_cli *cli) { - osmo_stream_cli_close(cli); + /* Nobody requested delayed free, skip */ + if (!cli->delay_free) + return false; + /* Check for other callbacks active in case we were e.g. in: + * read_cb() -> user -> osmo_steam_client_close() -> disconnect_cb() --> user --> osmo_stream_client_destroy() + * or: + * connect_cb() -> user -> osmo_steam_client_close() -> disconnect_cb() --> user --> osmo_stream_client_destroy() + */ + if (cli->in_cb_mask != 0) + return false; - if (cli->reconnect_timeout < 0) { - LOGSCLI(cli, LOGL_INFO, "not reconnecting, disabled\n"); - return; - } - - cli->state = STREAM_CLI_STATE_WAIT_RECONNECT; - LOGSCLI(cli, LOGL_INFO, "retrying reconnect in %d seconds...\n", - cli->reconnect_timeout); - osmo_timer_schedule(&cli->timer, cli->reconnect_timeout, 0); -} - -/*! Check if Osmocom Stream Client is in connected state. - * \paramin cli Osmocom Stream Client - * \return true if connected, false otherwise - */ -bool osmo_stream_cli_is_connected(struct osmo_stream_cli *cli) -{ - return cli->state == STREAM_CLI_STATE_CONNECTED; + LOGSCLI(cli, LOGL_DEBUG, "free(delayed)\n"); + talloc_free(cli); + return true; } -static void osmo_stream_cli_close_iofd(struct osmo_stream_cli *cli) +static void stream_cli_close_iofd(struct osmo_stream_cli *cli) { if (!cli->iofd) return; @@ -157,7 +158,7 @@ cli->iofd = NULL; } -static void osmo_stream_cli_close_ofd(struct osmo_stream_cli *cli) +static void stream_cli_close_ofd(struct osmo_stream_cli *cli) { if (cli->ofd.fd == -1) return; @@ -168,27 +169,30 @@ /*! Close an Osmocom Stream Client. * \paramin cli Osmocom Stream Client to be closed + * \return true if stream was freed due to disconnect_cb, false otherwise * We unregister the socket fd from the osmocom select() loop * abstraction and close the socket */ -void osmo_stream_cli_close(struct osmo_stream_cli *cli) +static bool stream_cli_close(struct osmo_stream_cli *cli) { int old_state = cli->state; + LOGSCLI(cli, LOGL_DEBUG, "close()\n"); + /* This guards against reentrant close through disconnect_cb(): */ if (cli->state == STREAM_CLI_STATE_CLOSED) - return; + return false; if (cli->state == STREAM_CLI_STATE_WAIT_RECONNECT) { osmo_timer_del(&cli->timer); cli->state = STREAM_CLI_STATE_CLOSED; - return; + return false; } switch (cli->mode) { case OSMO_STREAM_MODE_OSMO_FD: - osmo_stream_cli_close_ofd(cli); + stream_cli_close_ofd(cli); break; case OSMO_STREAM_MODE_OSMO_IO: - osmo_stream_cli_close_iofd(cli); + stream_cli_close_iofd(cli); break; default: OSMO_ASSERT(false); @@ -196,11 +200,79 @@ cli->state = STREAM_CLI_STATE_CLOSED; - if (old_state == STREAM_CLI_STATE_CONNECTED) { - LOGSCLI(cli, LOGL_DEBUG, "connection closed\n"); + /* If conn was established, notify the disconnection to the user: + * Also, if reconnect is disabled by user, notify the user that connect() failed: */ + if (old_state == STREAM_CLI_STATE_CONNECTED || + (old_state == STREAM_CLI_STATE_CONNECTING && cli->reconnect_timeout < 0)) { + OSMO_ASSERT(!(cli->in_cb_mask & IN_CB_MASK_DISCONNECT_CB)); + cli->in_cb_mask |= IN_CB_MASK_DISCONNECT_CB; if (cli->disconnect_cb) cli->disconnect_cb(cli); + cli->in_cb_mask &= ~IN_CB_MASK_DISCONNECT_CB; + return free_delayed_if_needed(cli); + } + return false; +} + +/*! Close an Osmocom Stream Client. + * \paramin cli Osmocom Stream Client to be closed + * We unregister the socket fd from the osmocom select() loop + * abstraction and close the socket */ +void osmo_stream_cli_close(struct osmo_stream_cli *cli) +{ + (void)stream_cli_close(cli); +} + +/*! Re-connect an Osmocom Stream Client. + * If re-connection is enabled for this client + * (which is the case unless negative timeout was explicitly set via osmo_stream_cli_set_reconnect_timeout() call), + * we close any existing connection (if any) and schedule a re-connect timer */ +static bool stream_cli_reconnect(struct osmo_stream_cli *cli) +{ + bool freed = stream_cli_close(cli); + + if (freed) + return true; + + if (cli->reconnect_timeout < 0) { + LOGSCLI(cli, LOGL_INFO, "not reconnecting, disabled\n"); + return false; } + + cli->state = STREAM_CLI_STATE_WAIT_RECONNECT; + LOGSCLI(cli, LOGL_INFO, "retrying reconnect in %d seconds...\n", + cli->reconnect_timeout); + osmo_timer_schedule(&cli->timer, cli->reconnect_timeout, 0); + return false; +} + +/*! Re-connect an Osmocom Stream Client. + * If re-connection is enabled for this client + * (which is the case unless negative timeout was explicitly set via osmo_stream_cli_set_reconnect_timeout() call), + * we close any existing connection (if any) and schedule a re-connect timer */ +void osmo_stream_cli_reconnect(struct osmo_stream_cli *cli) +{ + (void)stream_cli_reconnect(cli); +} + +/*! Check if Osmocom Stream Client is in connected state. + * \paramin cli Osmocom Stream Client + * \return true if connected, false otherwise + */ +bool osmo_stream_cli_is_connected(struct osmo_stream_cli *cli) +{ + return cli->state == STREAM_CLI_STATE_CONNECTED; +} + +/*! Check if Osmocom Stream Client is opened (has an FD available) according to + * its current state. + * \paramin cli Osmocom Stream Client + * \return true if fd is available (osmo_stream_cli_get_fd()), false otherwise + */ +static bool stream_cli_is_opened(const struct osmo_stream_cli *cli) +{ + return cli->state == STREAM_CLI_STATE_CONNECTING || + cli->state == STREAM_CLI_STATE_CONNECTED; } /*! Retrieve file descriptor of the stream client socket. @@ -233,15 +305,19 @@ return cli->iofd; } -static void osmo_stream_cli_read(struct osmo_stream_cli *cli) +/* Return true if read_cb caused a delayed_free, hence cli not available anymore. */ +static bool stream_cli_read(struct osmo_stream_cli *cli) { LOGSCLI(cli, LOGL_DEBUG, "message received\n"); + cli->in_cb_mask |= IN_CB_MASK_READ_CB; if (cli->read_cb) cli->read_cb(cli); + cli->in_cb_mask &= ~IN_CB_MASK_READ_CB; + return free_delayed_if_needed(cli); } -static int osmo_stream_cli_write(struct osmo_stream_cli *cli) +static int stream_cli_write(struct osmo_stream_cli *cli) { #ifdef HAVE_LIBSCTP struct sctp_sndrcvinfo sinfo; @@ -249,12 +325,11 @@ struct msgb *msg; int ret; - if (llist_empty(&cli->tx_queue)) { + msg = msgb_dequeue_count(&cli->tx_queue, &cli->tx_queue_count); + if (!msg) { /* done, tx_queue empty */ osmo_fd_write_disable(&cli->ofd); return 0; } - msg = llist_first_entry(&cli->tx_queue, struct msgb, list); - llist_del(&msg->list); if (!osmo_stream_cli_is_connected(cli)) { LOGSCLI(cli, LOGL_ERROR, "send: not connected, dropping data!\n"); @@ -295,6 +370,7 @@ /* Update msgb and re-add it at the start of the queue: */ msgb_pull(msg, ret); llist_add(&msg->list, &cli->tx_queue); + cli->tx_queue_count++; return 0; } @@ -304,10 +380,11 @@ if (err == EAGAIN) { /* Re-add at the start of the queue to re-attempt: */ llist_add(&msg->list, &cli->tx_queue); + cli->tx_queue_count++; return 0; } msgb_free(msg); - osmo_stream_cli_reconnect(cli); + (void)stream_cli_reconnect(cli); return 0; } @@ -333,7 +410,8 @@ #endif } -static void stream_cli_handle_connecting(struct osmo_stream_cli *cli, int res) +/* returns true if cli is freed */ +static bool stream_cli_handle_connecting(struct osmo_stream_cli *cli, int res) { int error, ret = res; socklen_t len = sizeof(error); @@ -342,13 +420,13 @@ OSMO_ASSERT(fd >= 0); if (ret < 0) { - osmo_stream_cli_reconnect(cli); - return; + LOGSCLI(cli, LOGL_ERROR, "connect failed (%d)\n", res); + return stream_cli_reconnect(cli); } ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len); if (ret >= 0 && error > 0) { - osmo_stream_cli_reconnect(cli); - return; + LOGSCLI(cli, LOGL_ERROR, "connect so_error (%d)\n", error); + return stream_cli_reconnect(cli); } /* If messages got enqueued while 'connecting', keep WRITE flag @@ -376,8 +454,11 @@ default: break; } + cli->in_cb_mask |= IN_CB_MASK_CONNECT_CB; if (cli->connect_cb) cli->connect_cb(cli); + cli->in_cb_mask &= ~IN_CB_MASK_CONNECT_CB; + return free_delayed_if_needed(cli); } static int osmo_stream_cli_fd_cb(struct osmo_fd *ofd, unsigned int what) @@ -386,16 +467,17 @@ switch (cli->state) { case STREAM_CLI_STATE_CONNECTING: - stream_cli_handle_connecting(cli, 0); + (void)stream_cli_handle_connecting(cli, 0); break; case STREAM_CLI_STATE_CONNECTED: if (what & OSMO_FD_READ) { LOGSCLI(cli, LOGL_DEBUG, "connected read\n"); - osmo_stream_cli_read(cli); + if (stream_cli_read(cli) == true) + break; /* cli (and hence ofd) freed, done. */ } if (what & OSMO_FD_WRITE) { LOGSCLI(cli, LOGL_DEBUG, "connected write\n"); - osmo_stream_cli_write(cli); + stream_cli_write(cli); } break; default: @@ -430,8 +512,8 @@ cli->state = STREAM_CLI_STATE_CLOSED; osmo_timer_setup(&cli->timer, cli_timer_cb, cli); cli->reconnect_timeout = 5; /* default is 5 seconds. */ - cli->segmentation_cb = NULL; INIT_LLIST_HEAD(&cli->tx_queue); + cli->tx_queue_max_length = 1024; /* Default tx queue size, msgbs. */ cli->ma_pars.sctp.version = 0; @@ -441,51 +523,72 @@ static void stream_cli_iofd_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg) { struct osmo_stream_cli *cli = osmo_iofd_get_data(iofd); + bool freed; switch (cli->state) { case STREAM_CLI_STATE_CONNECTING: - msgb_free(msg); - stream_cli_handle_connecting(cli, res); + freed = stream_cli_handle_connecting(cli, res); + if (freed) + return; /* msg was also freed as part of the talloc tree. */ + if (cli->state != STREAM_CLI_STATE_CONNECTED) { + msgb_free(msg); + return; + } + /* Follow below common path submitting read_cb(msg) to user. */ break; case STREAM_CLI_STATE_CONNECTED: switch (res) { case -EPIPE: case -ECONNRESET: LOGSCLI(cli, LOGL_ERROR, "lost connection with srv (%d)\n", res); - osmo_stream_cli_reconnect(cli); + freed = stream_cli_reconnect(cli); break; case 0: LOGSCLI(cli, LOGL_NOTICE, "connection closed with srv\n"); - osmo_stream_cli_reconnect(cli); + freed = stream_cli_reconnect(cli); break; default: LOGSCLI(cli, LOGL_DEBUG, "received %d bytes from srv\n", res); + freed = false; break; } - /* Notify user of new data or error: */ - if (cli->iofd_read_cb) - cli->iofd_read_cb(cli, res, msg); - else - msgb_free(msg); + if (freed) + return; /* msg was also freed as part of the talloc tree. */ + /* Follow below common path submitting read_cb(msg) to user. */ break; default: osmo_panic("%s() called with unexpected state %d\n", __func__, cli->state); } + + /* Notify user of new data or error: */ + if (!cli->iofd_read_cb) { + msgb_free(msg); + return; + } + cli->in_cb_mask |= IN_CB_MASK_READ_CB; + cli->iofd_read_cb(cli, res, msg); + cli->in_cb_mask &= ~IN_CB_MASK_READ_CB; + OSMO_ASSERT(cli->in_cb_mask == 0); + (void)free_delayed_if_needed(cli); } static void stream_cli_iofd_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg) { struct osmo_stream_cli *cli = osmo_iofd_get_data(iofd); + /* msgb is not owned by us here, no need to free it. */ switch (cli->state) { case STREAM_CLI_STATE_CONNECTING: - stream_cli_handle_connecting(cli, res); + (void)stream_cli_handle_connecting(cli, res); break; case STREAM_CLI_STATE_CONNECTED: if (msg && res <= 0) { - osmo_stream_cli_reconnect(cli); LOGSCLI(cli, LOGL_ERROR, "received error %d in response to send\n", res); + (void)stream_cli_reconnect(cli); } + /* res=0 && msgb=NULL: "connected notify", but we already received before a read_cb + * which moved us to CONNECTED state. Do nothing. + */ break; default: osmo_panic("%s() called with unexpected state %d\n", __func__, cli->state); @@ -495,52 +598,65 @@ static const struct osmo_io_ops osmo_stream_cli_ioops = { .read_cb = stream_cli_iofd_read_cb, .write_cb = stream_cli_iofd_write_cb, - - .segmentation_cb = NULL, }; #ifdef HAVE_LIBSCTP static void stream_cli_iofd_recvmsg_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct msghdr *msgh) { struct osmo_stream_cli *cli = osmo_iofd_get_data(iofd); + bool freed; res = stream_iofd_sctp_recvmsg_trailer(iofd, msg, res, msgh); switch (cli->state) { case STREAM_CLI_STATE_CONNECTING: - msgb_free(msg); - stream_cli_handle_connecting(cli, res); + freed = stream_cli_handle_connecting(cli, res); + if (freed) + return; /* msg was also freed as part of the talloc tree. */ + if (cli->state != STREAM_CLI_STATE_CONNECTED) { + msgb_free(msg); + return; + } + /* Follow below common path submitting read_cb(msg) to user. */ break; case STREAM_CLI_STATE_CONNECTED: switch (res) { case -EPIPE: case -ECONNRESET: LOGSCLI(cli, LOGL_ERROR, "lost connection with srv (%d)\n", res); - osmo_stream_cli_reconnect(cli); + freed = stream_cli_reconnect(cli); break; case 0: LOGSCLI(cli, LOGL_NOTICE, "connection closed with srv\n"); - osmo_stream_cli_reconnect(cli); + freed = stream_cli_reconnect(cli); break; default: + freed = false; break; } - /* Notify user of new data or error: */ - if (cli->iofd_read_cb) - cli->iofd_read_cb(cli, res, msg); - else - msgb_free(msg); + if (freed) + return; /* msg was also freed as part of the talloc tree. */ + /* Follow below common path submitting read_cb(msg) to user. */ break; default: osmo_panic("%s() called with unexpected state %d\n", __func__, cli->state); } + + /* Notify user of new data or error: */ + if (!cli->iofd_read_cb) { + msgb_free(msg); + return; + } + cli->in_cb_mask |= IN_CB_MASK_READ_CB; + cli->iofd_read_cb(cli, res, msg); + cli->in_cb_mask &= ~IN_CB_MASK_READ_CB; + OSMO_ASSERT(cli->in_cb_mask == 0); + (void)free_delayed_if_needed(cli); } static const struct osmo_io_ops osmo_stream_cli_ioops_sctp = { .recvmsg_cb = stream_cli_iofd_recvmsg_cb, .sendmsg_cb = stream_cli_iofd_write_cb, - - .segmentation_cb = NULL, }; #endif @@ -675,28 +791,66 @@ cli->flags |= OSMO_STREAM_CLI_F_RECONF; } +/* Callback from iofd, forward to stream_cli user: */ +static int stream_cli_iofd_segmentation_cb2(struct osmo_io_fd *iofd, struct msgb *msg) +{ + struct osmo_stream_cli *cli = osmo_iofd_get_data(iofd); + if (cli->segmentation_cb2) + return cli->segmentation_cb2(cli, msg); + if (cli->segmentation_cb) + return cli->segmentation_cb(msg); + OSMO_ASSERT(0); + return 0; +} + /* Configure client side segmentation for the iofd */ -static void configure_cli_segmentation_cb(struct osmo_stream_cli *cli, - osmo_stream_cli_segmentation_cb_t segmentation_cb) +static void configure_cli_segmentation_cb(struct osmo_stream_cli *cli) { /* Copy default settings */ struct osmo_io_ops client_ops; osmo_iofd_get_ioops(cli->iofd, &client_ops); /* Set segmentation cb for this client */ - client_ops.segmentation_cb = segmentation_cb; + if (cli->segmentation_cb || cli->segmentation_cb2) + client_ops.segmentation_cb2 = stream_cli_iofd_segmentation_cb2; + else + client_ops.segmentation_cb2 = NULL; osmo_iofd_set_ioops(cli->iofd, &client_ops); } /*! Set the segmentation callback for the client. * \paramin,out cli Stream Client to modify * \paramin segmentation_cb Target segmentation callback + * + * A segmentation call-back can optionally be used when a packet based protocol + * (like TCP) is used within a STREAM style socket that does not preserve + * message boundaries within the stream. If a segmentation call-back is given, + * the osmo_stream_srv library code will makes sure that the read_cb called + * only for complete single messages, and not arbitrary segments of the stream. */ void osmo_stream_cli_set_segmentation_cb(struct osmo_stream_cli *cli, osmo_stream_cli_segmentation_cb_t segmentation_cb) { cli->segmentation_cb = segmentation_cb; + cli->segmentation_cb2 = NULL; + if (cli->iofd) /* Otherwise, this will be done in osmo_stream_cli_open() */ + configure_cli_segmentation_cb(cli); +} + +/*! Set the segmentation callback for the client. + * \paramin,out cli Stream Client to modify + * \paramin segmentation_cb2 Target segmentation callback + * + * Same as osmo_stream_cli_set_segmentation_cb(), but a + * osmo_stream_cli_segmentation_cb2_t is called instead which allows access to + * the related cli object. + */ +void osmo_stream_cli_set_segmentation_cb2(struct osmo_stream_cli *cli, + osmo_stream_cli_segmentation_cb2_t segmentation_cb2) +{ + cli->segmentation_cb = NULL; + cli->segmentation_cb2 = segmentation_cb2; if (cli->iofd) /* Otherwise, this will be done in osmo_stream_cli_open() */ - configure_cli_segmentation_cb(cli, segmentation_cb); + configure_cli_segmentation_cb(cli); } /*! Set the socket type for the stream server link. @@ -767,6 +921,24 @@ return cli->data; } +/*! Set the maximum length queue of the stream client. + * \paramin cli Stream Client to modify + * \paramin size maximum amount of msgbs which can be queued in the internal tx queue. + * \returns 0 on success, negative on error. + * + * The maximum length queue default value is 1024 msgbs. */ +int osmo_stream_cli_set_tx_queue_max_length(struct osmo_stream_cli *cli, unsigned int size) +{ + cli->tx_queue_max_length = size; + + if (cli->iofd) /* Otherwise, this will be done in osmo_stream_cli_open() */ + osmo_iofd_set_txqueue_max_length(cli->iofd, cli->tx_queue_max_length); + + /* XXX: Here, in OSMO_STREAM_MODE_OSMO_FD mode we could check current + * size of cli->tx_queue and shrink it from the front or back... */ + return 0; +} + /*! Retrieve the stream client socket description. * Calling this function will build a string that describes the socket in terms of its local/remote * address/port. The returned name is stored in a static buffer; it is hence not re-entrant or thread-safe. @@ -844,10 +1016,27 @@ * \paramin cli Stream Client to destroy */ void osmo_stream_cli_destroy(struct osmo_stream_cli *cli) { - osmo_stream_cli_close(cli); + if (!cli) + return; + + LOGSCLI(cli, LOGL_DEBUG, "destroy()\n"); + OSMO_ASSERT(stream_cli_close(cli) == false); osmo_timer_del(&cli->timer); msgb_queue_free(&cli->tx_queue); - talloc_free(cli); + cli->tx_queue_count = 0; + /* if we are in a user callback, delay freeing. */ + if (cli->in_cb_mask != 0) { + LOGSCLI(cli, LOGL_DEBUG, "delay free() in_cb_mask=0x%02x\n", cli->in_cb_mask); + cli->delay_free = true; + /* Move ptr to avoid double free if parent ctx of cli is freed + * meanwhile (eg. during user callback after calling + * osmo_stream_client_destroy() and before returning from user + * callback. */ + talloc_steal(OTC_GLOBAL, cli); + } else { + LOGSCLI(cli, LOGL_DEBUG, "free(destroy)\n"); + talloc_free(cli); + } } /*! DEPRECATED: use osmo_stream_cli_set_reconnect_timeout() or osmo_stream_cli_reconnect() instead! @@ -861,8 +1050,10 @@ int ret; /* we are reconfiguring this socket, close existing first. */ - if ((cli->flags & OSMO_STREAM_CLI_F_RECONF) && cli->ofd.fd >= 0) - osmo_stream_cli_close(cli); + if ((cli->flags & OSMO_STREAM_CLI_F_RECONF) && cli->ofd.fd >= 0) { + if (stream_cli_close(cli) == true) + return -ENAVAIL; /* freed */ + } cli->flags &= ~OSMO_STREAM_CLI_F_RECONF; @@ -872,7 +1063,8 @@ ret = osmo_sock_init2_multiaddr2(AF_UNSPEC, SOCK_STREAM, cli->proto, (const char **)cli->local_addr, cli->local_addrcnt, cli->local_port, (const char **)cli->addr, cli->addrcnt, cli->port, - OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_BIND|OSMO_SOCK_F_NONBLOCK, + OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK | + OSMO_SOCK_F_DSCP(cli->ip_dscp) | OSMO_SOCK_F_PRIO(cli->sk_prio), &cli->ma_pars); break; #endif @@ -880,12 +1072,14 @@ ret = osmo_sock_init2(AF_UNSPEC, SOCK_STREAM, cli->proto, cli->local_addr0, cli->local_port, cli->addr0, cli->port, - OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_BIND|OSMO_SOCK_F_NONBLOCK); + OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK | + OSMO_SOCK_F_DSCP(cli->ip_dscp) | OSMO_SOCK_F_PRIO(cli->sk_prio)); } if (ret < 0) { + LOGSCLI(cli, LOGL_ERROR, "connect: socket creation error (%d)\n", ret); if (reconnect) - osmo_stream_cli_reconnect(cli); + (void)stream_cli_reconnect(cli); return ret; } osmo_fd_setup(&cli->ofd, ret, OSMO_FD_READ | OSMO_FD_WRITE, osmo_stream_cli_fd_cb, cli, 0); @@ -911,17 +1105,92 @@ /*! Set the NODELAY socket option to avoid Nagle-like behavior. * Setting this to nodelay=true will automatically set the NODELAY * socket option on any socket established via \ref osmo_stream_cli_open - * or any re-connect. You have to set this _before_ opening the + * or any re-connect. This can be set either before or after opening the * socket. * \paramin cli Stream client whose sockets are to be configured * \paramin nodelay whether to set (true) NODELAY before connect() */ void osmo_stream_cli_set_nodelay(struct osmo_stream_cli *cli, bool nodelay) { + int fd; if (nodelay) cli->flags |= OSMO_STREAM_CLI_F_NODELAY; else cli->flags &= ~OSMO_STREAM_CLI_F_NODELAY; + + if (!stream_cli_is_opened(cli)) + return; /* Config will be applied upon open() time */ + + if ((fd = osmo_stream_cli_get_fd(cli)) < 0) { + LOGSCLI(cli, LOGL_ERROR, "set_nodelay(%u): failed obtaining socket\n", nodelay); + return; + } + if (stream_setsockopt_nodelay(fd, cli->proto, nodelay ? 1 : 0) < 0) + LOGSCLI(cli, LOGL_ERROR, "set_nodelay(%u): failed setsockopt err=%d\n", + nodelay, errno); +} + +/*! Set the priority value of the stream socket. + * Setting this will automatically set the socket priority + * option on any socket established via \ref osmo_stream_cli_open + * or any re-connect. This can be set either before or after opening the + * socket. + * \paramin cli Stream client whose sockets are to be configured + * \paramin sk_prio priority value. Values outside 0..6 require CAP_NET_ADMIN. + * \return negative on error, 0 on success + */ +int osmo_stream_cli_set_priority(struct osmo_stream_cli *cli, int sk_prio) +{ + int rc; + int fd; + + if (cli->sk_prio == sk_prio) + return 0; /* No change needed */ + + cli->sk_prio = sk_prio; + + if (!stream_cli_is_opened(cli)) + return 0; /* Config will be applied upon open() time */ + + if ((fd = osmo_stream_cli_get_fd(cli)) < 0) { /* Shouldn't happen... */ + LOGSCLI(cli, LOGL_ERROR, "set_priority(%d): failed obtaining socket\n", cli->sk_prio); + return -EBADFD; + } + if ((rc = osmo_sock_set_priority(fd, cli->sk_prio)) < 0) + LOGSCLI(cli, LOGL_ERROR, "set_priority(%d): failed setsockopt err=%d\n", + cli->sk_prio, errno); + return rc; +} + +/*! Set the DSCP (differentiated services code point) of the stream socket. + * Setting this will automatically set the IP DSCP option on any socket established + * via \ref osmo_stream_cli_open or any re-connect. This can be set either before or + * after opening the socket. + * \paramin cli Stream client whose sockets are to be configured + * \paramin ip_dscp DSCP value. Value range 0..63. + * \return negative on error, 0 on success + */ +int osmo_stream_cli_set_ip_dscp(struct osmo_stream_cli *cli, uint8_t ip_dscp) +{ + int rc; + int fd; + + if (cli->ip_dscp == ip_dscp) + return 0; /* No change needed */ + + cli->ip_dscp = ip_dscp; + + if (!stream_cli_is_opened(cli)) + return 0; /* Config will be applied upon open() time */ + + if ((fd = osmo_stream_cli_get_fd(cli)) < 0) { /* Shouldn't happen... */ + LOGSCLI(cli, LOGL_ERROR, "set_ip_dscp(%u): failed obtaining socket\n", cli->ip_dscp); + return -EBADFD; + } + if ((rc = osmo_sock_set_dscp(fd, cli->ip_dscp)) < 0) + LOGSCLI(cli, LOGL_ERROR, "set_ip_dscp(%u): failed setsockopt err=%d\n", + cli->ip_dscp, errno); + return rc; } /*! Open connection of an Osmocom stream client. @@ -937,8 +1206,10 @@ unsigned int local_addrcnt; /* we are reconfiguring this socket, close existing first. */ - if ((cli->flags & OSMO_STREAM_CLI_F_RECONF) && osmo_stream_cli_get_fd(cli) >= 0) - osmo_stream_cli_close(cli); + if ((cli->flags & OSMO_STREAM_CLI_F_RECONF) && osmo_stream_cli_get_fd(cli) >= 0) { + if (stream_cli_close(cli) == true) + return -ENAVAIL; /* freed */ + } cli->flags &= ~OSMO_STREAM_CLI_F_RECONF; @@ -953,7 +1224,8 @@ #ifdef HAVE_LIBSCTP case IPPROTO_SCTP: local_addrcnt = cli->local_addrcnt; - flags = OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK; + flags = OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_NONBLOCK | + OSMO_SOCK_F_DSCP(cli->ip_dscp) | OSMO_SOCK_F_PRIO(cli->sk_prio); if (cli->local_addrcnt > 0 || cli->local_port > 0) { /* explicit bind required? */ flags |= OSMO_SOCK_F_BIND; /* If no local addr configured, use local_addr0=NULL by default when creating the socket. */ @@ -970,7 +1242,8 @@ ret = osmo_sock_init2(cli->sk_domain, cli->sk_type, cli->proto, cli->local_addr0, cli->local_port, cli->addr0, cli->port, - OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_BIND|OSMO_SOCK_F_NONBLOCK); + OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK | + OSMO_SOCK_F_DSCP(cli->ip_dscp) | OSMO_SOCK_F_PRIO(cli->sk_prio)); } break; default: @@ -978,7 +1251,8 @@ } if (ret < 0) { - osmo_stream_cli_reconnect(cli); + LOGSCLI(cli, LOGL_ERROR, "connect: socket creation error (%d)\n", ret); + (void)stream_cli_reconnect(cli); return ret; } @@ -998,7 +1272,7 @@ break; case OSMO_STREAM_MODE_OSMO_IO: /* Be sure that previous osmo_io instance is freed before creating a new one. */ - osmo_stream_cli_close_iofd(cli); + stream_cli_close_iofd(cli); #ifdef HAVE_LIBSCTP if (cli->proto == IPPROTO_SCTP) { cli->iofd = osmo_iofd_setup(cli, fd, cli->name, OSMO_IO_FD_MODE_RECVMSG_SENDMSG, @@ -1015,9 +1289,9 @@ if (!cli->iofd) goto error_close_socket; + osmo_iofd_set_txqueue_max_length(cli->iofd, cli->tx_queue_max_length); osmo_iofd_notify_connected(cli->iofd); - - configure_cli_segmentation_cb(cli, cli->segmentation_cb); + configure_cli_segmentation_cb(cli); if (osmo_iofd_register(cli->iofd, fd) < 0) goto error_close_socket; @@ -1064,7 +1338,12 @@ switch (cli->mode) { case OSMO_STREAM_MODE_OSMO_FD: - msgb_enqueue(&cli->tx_queue, msg); + if (cli->tx_queue_count >= cli->tx_queue_max_length) { + LOGSCLI(cli, LOGL_ERROR, "send: tx queue full, dropping msg!\n"); + msgb_free(msg); + return; + } + msgb_enqueue_count(&cli->tx_queue, msg, &cli->tx_queue_count); osmo_fd_write_enable(&cli->ofd); break; case OSMO_STREAM_MODE_OSMO_IO: @@ -1136,15 +1415,17 @@ } if (ret < 0) { - if (ret == -EAGAIN) + if (ret == -EAGAIN) /* Received MSG_NOTIFICATION from stream_sctp_recvmsg_wrapper() */ return ret; if (errno == EPIPE || errno == ECONNRESET) - LOGSCLI(cli, LOGL_ERROR, "lost connection with srv\n"); - osmo_stream_cli_reconnect(cli); + LOGSCLI(cli, LOGL_ERROR, "lost connection with srv (%d)\n", errno); + else + LOGSCLI(cli, LOGL_ERROR, "recv failed (%d)\n", errno); + (void)stream_cli_reconnect(cli); return ret; } else if (ret == 0) { LOGSCLI(cli, LOGL_ERROR, "connection closed with srv\n"); - osmo_stream_cli_reconnect(cli); + (void)stream_cli_reconnect(cli); return ret; } msgb_put(msg, ret); @@ -1159,6 +1440,7 @@ switch (cli->mode) { case OSMO_STREAM_MODE_OSMO_FD: msgb_queue_free(&cli->tx_queue); + cli->tx_queue_count = 0; /* If in state 'connecting', keep WRITE flag up to receive * socket connection signal and then transition to STATE_CONNECTED: */ if (cli->state == STREAM_CLI_STATE_CONNECTED)
View file
libosmo-netif_1.5.1.tar.xz/src/stream_srv.c -> libosmo-netif_1.6.0.tar.xz/src/stream_srv.c
Changed
@@ -69,6 +69,15 @@ * Server side. */ +struct msgb_alloc_info { + /*! Whether it was set by user or we use iofd defaults */ + bool set_by_user; + /*! size of msgb to allocate (excluding headroom) */ + unsigned int size; + /*! headroom to allocate when allocating msgb's */ + unsigned int headroom; +}; + #define OSMO_STREAM_SRV_F_RECONF (1 << 0) #define OSMO_STREAM_SRV_F_NODELAY (1 << 1) @@ -81,10 +90,14 @@ uint16_t port; int sk_domain; int sk_type; + int sk_prio; /* socket priority, SO_PRIORITY, default=0=unset */ uint16_t proto; + uint8_t ip_dscp; /* IP Differentiated services, 0..63, default=0=unset */ osmo_stream_srv_link_accept_cb_t accept_cb; void *data; int flags; + unsigned int tx_queue_max_length; /* Max amount of msgbs which can be enqueued */ + struct msgb_alloc_info msgb_alloc; struct osmo_sock_init2_multiaddr_pars ma_pars; }; @@ -148,6 +161,24 @@ goto error_close_socket; } + if (link->ip_dscp > 0) { + ret = osmo_sock_set_dscp(sock_fd, link->ip_dscp); + if (ret < 0) { + LOGSLNK(link, LOGL_ERROR, "set_ip_dscp(%u): failed setsockopt err=%d\n", + link->ip_dscp, errno); + goto error_close_socket; + } + } + + if (link->sk_prio > 0) { + ret = osmo_sock_set_priority(sock_fd, link->sk_prio); + if (ret < 0) { + LOGSLNK(link, LOGL_ERROR, "set_priority(%d): failed setsockopt err=%d\n", + link->sk_prio, errno); + goto error_close_socket; + } + } + if (!link->accept_cb) { ret = -ENOTSUP; goto error_close_socket; @@ -183,6 +214,7 @@ link->sk_domain = AF_UNSPEC; link->sk_type = SOCK_STREAM; link->proto = IPPROTO_TCP; + link->tx_queue_max_length = 1024; /* Default tx queue size, msgbs. */ osmo_fd_setup(&link->ofd, -1, OSMO_FD_READ | OSMO_FD_WRITE, osmo_stream_srv_link_ofd_cb, link, 0); link->ma_pars.sctp.version = 0; @@ -224,6 +256,33 @@ link->flags &= ~OSMO_STREAM_SRV_F_NODELAY; } +/*! Set the priority value of the stream socket. + * Setting this will automatically set the socket priority + * option on any socket established via this server link, before + * calling the accept_cb(). + * \paramin link server link whose sockets are to be configured + * \paramin sk_prio priority value. Values outside 0..6 require CAP_NET_ADMIN. + * \return negative on error, 0 on success + */ +int osmo_stream_srv_link_set_priority(struct osmo_stream_srv_link *link, int sk_prio) +{ + link->sk_prio = sk_prio; + return 0; +} + +/*! Set the DSCP (differentiated services code point) of the stream socket. + * Setting this will automatically set the IP DSCP option on any socket on any + * socket established via this server link, before calling the accept_cb(). + * \paramin link server link whose sockets are to be configured + * \paramin ip_dscp DSCP value. Value range 0..63. + * \return negative on error, 0 on success + */ +int osmo_stream_srv_link_set_ip_dscp(struct osmo_stream_srv_link *link, uint8_t ip_dscp) +{ + link->ip_dscp = ip_dscp; + return 0; +} + /*! Set the local address to which we bind. * Any changes to this setting will only become active upon next (re)connect. * \paramin link Stream Server Link to modify @@ -347,6 +406,18 @@ return link->data; } +/*! Set the maximum length queue of the stream servers accepted and allocated from this server link. + * \paramin link Stream Server Link to modify + * \paramin size maximum amount of msgbs which can be queued in the internal tx queue. + * \returns 0 on success, negative on error. + * + * The maximum length queue default value is 1024 msgbs. */ +int osmo_stream_srv_link_set_tx_queue_max_length(struct osmo_stream_srv_link *link, unsigned int size) +{ + link->tx_queue_max_length = size; + return 0; +} + /* Similar to osmo_sock_multiaddr_get_name_buf(), but aimed at listening sockets (only local part): */ static char *get_local_sockname_buf(char *buf, size_t buf_len, const struct osmo_stream_srv_link *link) { @@ -445,10 +516,32 @@ link->accept_cb = accept_cb; } +/*! Set the msgb allocation parameters on child osmo_stream_srv objects + * \paramin link Stream Server Link + * \paramin size Size of msgb to allocate (excluding headroom) + * \paramin headroom Headroom to allocate when allocating msgb's + * + * The parameters are applied to osmo_stream_srv objects upon creation. + * Setting both to 0 leaves it as implementation default. + **/ +int osmo_stream_srv_link_set_msgb_alloc_info(struct osmo_stream_srv_link *link, unsigned int size, unsigned int headroom) +{ + if (size == 0 && headroom == 0) { + link->msgb_alloc.set_by_user = false; + } else { + link->msgb_alloc.set_by_user = true; + link->msgb_alloc.headroom = headroom; + link->msgb_alloc.size = size; + } + return 0; +} + /*! Destroy the stream server link. Closes + Releases Memory. * \paramin link Stream Server Link */ void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link) { + if (!link) + return; osmo_stream_srv_link_close(link); talloc_free(link); } @@ -596,10 +689,13 @@ struct osmo_fd ofd; struct osmo_io_fd *iofd; }; - struct llist_head tx_queue; + struct llist_head tx_queue; /* osmo_ofd mode (only): Queue of msgbs */ + unsigned int tx_queue_count; /* osmo_ofd mode (only): Current amount of msgbs queued */ osmo_stream_srv_closed_cb_t closed_cb; osmo_stream_srv_read_cb_t read_cb; osmo_stream_srv_read_cb2_t iofd_read_cb; + osmo_stream_srv_segmentation_cb_t segmentation_cb; + osmo_stream_srv_segmentation_cb2_t segmentation_cb2; void *data; int flags; }; @@ -722,12 +818,11 @@ struct msgb *msg; int ret; - if (llist_empty(&conn->tx_queue)) { + msg = msgb_dequeue_count(&conn->tx_queue, &conn->tx_queue_count); + if (!msg) { /* done, tx_queue empty */ osmo_fd_write_disable(&conn->ofd); return; } - msg = llist_first_entry(&conn->tx_queue, struct msgb, list); - llist_del(&msg->list); LOGSSRV(conn, LOGL_DEBUG, "sending %u bytes of data\n", msg->len); @@ -764,6 +859,7 @@ /* Update msgb and re-add it at the start of the queue: */ msgb_pull(msg, ret); llist_add(&msg->list, &conn->tx_queue); + conn->tx_queue_count++; return; } @@ -773,6 +869,7 @@ if (err == EAGAIN) { /* Re-add at the start of the queue to re-attempt: */ llist_add(&msg->list, &conn->tx_queue); + conn->tx_queue_count++; return; } msgb_free(msg); @@ -876,6 +973,7 @@ conn->mode = OSMO_STREAM_MODE_OSMO_IO; conn->srv = link; + conn->data = data; osmo_sock_get_name_buf(conn->sockname, sizeof(conn->sockname), fd); @@ -892,7 +990,10 @@ talloc_free(conn); return NULL; } - conn->data = data; + + osmo_iofd_set_txqueue_max_length(conn->iofd, conn->srv->tx_queue_max_length); + if (conn->srv->msgb_alloc.set_by_user) + osmo_iofd_set_alloc_info(conn->iofd, conn->srv->msgb_alloc.size, conn->srv->msgb_alloc.headroom); if (osmo_iofd_register(conn->iofd, fd) < 0) { LOGSSRV(conn, LOGL_ERROR, "could not register FD %d\n", fd); @@ -973,30 +1074,75 @@ conn->data = data; } +/* Callback from iofd, forward to stream_srv user: */ +static int stream_srv_iofd_segmentation_cb2(struct osmo_io_fd *iofd, struct msgb *msg) +{ + struct osmo_stream_srv *conn = osmo_iofd_get_data(iofd); + if (conn->segmentation_cb2) + return conn->segmentation_cb2(conn, msg); + if (conn->segmentation_cb) + return conn->segmentation_cb(msg); + OSMO_ASSERT(0); + return 0; +} + +/* Configure server side segmentation for the iofd */ +static void configure_srv_segmentation_cb(struct osmo_stream_srv *conn) +{ + /* Copy default settings */ + struct osmo_io_ops client_ops; + osmo_iofd_get_ioops(conn->iofd, &client_ops); + /* Set segmentation cb for this client */ + if (conn->segmentation_cb || conn->segmentation_cb2) + client_ops.segmentation_cb2 = stream_srv_iofd_segmentation_cb2; + else + client_ops.segmentation_cb2 = NULL; + osmo_iofd_set_ioops(conn->iofd, &client_ops); +} + /*! Set the segmentation callback for target osmo_stream_srv structure. + * \paramin,out conn Target Stream Server to modify + * \paramin segmentation_cb Segmentation callback to be set * - * A segmentation call-back can optionally be used when a packet based protocol (like TCP) is used within a - * STREAM style socket that does not preserve message boundaries within the stream. If a segmentation - * call-back is given, the osmo_stream_srv library code will makes sure that the read_cb called only for - * complete single messages, and not arbitrary segments of the stream. + * A segmentation call-back can optionally be used when a packet based protocol + * (like TCP) is used within a STREAM style socket that does not preserve + * message boundaries within the stream. If a segmentation call-back is given, + * the osmo_stream_srv library code will makes sure that the read_cb called + * only for complete single messages, and not arbitrary segments of the stream. * - * This function only works with osmo_stream_srv in osmo_io mode, created by osmo_stream_srv_create2()! - * The connection has to have been established prior to calling this function. - * - * \paramin,out conn Target Stream Server to modify - * \paramin segmentation_cb Segmentation callback to be set */ + * This function only works with osmo_stream_srv in osmo_io mode, created by + * osmo_stream_srv_create2()! The connection has to have been established prior + * to calling this function. + * + */ void osmo_stream_srv_set_segmentation_cb(struct osmo_stream_srv *conn, osmo_stream_srv_segmentation_cb_t segmentation_cb) { /* Note that the following implies that iofd != NULL, since * osmo_stream_srv_create2() creates the iofd member, too */ OSMO_ASSERT(conn->mode == OSMO_STREAM_MODE_OSMO_IO); - /* Copy default settings */ - struct osmo_io_ops conn_ops; - osmo_iofd_get_ioops(conn->iofd, &conn_ops); - /* Set segmentation cb for this connection */ - conn_ops.segmentation_cb = segmentation_cb; - osmo_iofd_set_ioops(conn->iofd, &conn_ops); + conn->segmentation_cb = segmentation_cb; + conn->segmentation_cb2 = NULL; + configure_srv_segmentation_cb(conn); +} + +/*! Set the segmentation callback for target osmo_stream_srv structure. + * \paramin,out conn Target Stream Server to modify + * \paramin segmentation_cb2 Segmentation callback to be set + * + * Same as osmo_stream_srv_set_segmentation_cb(), but a + * osmo_stream_srv_segmentation_cb2_t is called instead which allows access to + * the related conn object. + */ +void osmo_stream_srv_set_segmentation_cb2(struct osmo_stream_srv *conn, + osmo_stream_srv_segmentation_cb2_t segmentation_cb2) +{ + /* Note that the following implies that iofd != NULL, since + * osmo_stream_srv_create2() creates the iofd member, too */ + OSMO_ASSERT(conn->mode == OSMO_STREAM_MODE_OSMO_IO); + conn->segmentation_cb = NULL; + conn->segmentation_cb2 = segmentation_cb2; + configure_srv_segmentation_cb(conn); } /*! Retrieve application private data of the stream server @@ -1075,11 +1221,15 @@ * \paramin conn Stream Server to be destroyed */ void osmo_stream_srv_destroy(struct osmo_stream_srv *conn) { + if (!conn) + return; + switch (conn->mode) { case OSMO_STREAM_MODE_OSMO_FD: osmo_fd_unregister(&conn->ofd); close(conn->ofd.fd); msgb_queue_free(&conn->tx_queue); + conn->tx_queue_count = 0; conn->ofd.fd = -1; break; case OSMO_STREAM_MODE_OSMO_IO: @@ -1111,7 +1261,12 @@ switch (conn->mode) { case OSMO_STREAM_MODE_OSMO_FD: - msgb_enqueue(&conn->tx_queue, msg); + if (conn->tx_queue_count >= conn->srv->tx_queue_max_length) { + LOGSSRV(conn, LOGL_ERROR, "send: tx queue full, dropping msg!\n"); + msgb_free(msg); + return; + } + msgb_enqueue_count(&conn->tx_queue, msg, &conn->tx_queue_count); osmo_fd_write_enable(&conn->ofd); break; case OSMO_STREAM_MODE_OSMO_IO: @@ -1181,8 +1336,12 @@ } if (ret < 0) { + if (ret == -EAGAIN) /* Received MSG_NOTIFICATION from stream_sctp_recvmsg_wrapper() */ + return ret; if (errno == EPIPE || errno == ECONNRESET) - LOGSSRV(conn, LOGL_ERROR, "lost connection with client\n"); + LOGSSRV(conn, LOGL_ERROR, "lost connection with client (%d)\n", errno); + else + LOGSSRV(conn, LOGL_ERROR, "recv failed (%d)\n", errno); return ret; } else if (ret == 0) { LOGSSRV(conn, LOGL_ERROR, "connection closed with client\n"); @@ -1198,6 +1357,7 @@ switch (conn->mode) { case OSMO_STREAM_MODE_OSMO_FD: msgb_queue_free(&conn->tx_queue); + conn->tx_queue_count = 0; osmo_fd_write_disable(&conn->ofd); break; case OSMO_STREAM_MODE_OSMO_IO:
View file
libosmo-netif_1.5.1.tar.xz/tests/stream/stream_test.c -> libosmo-netif_1.6.0.tar.xz/tests/stream/stream_test.c
Changed
@@ -516,7 +516,7 @@ } LOGCLI(osc, "Received message from stream (payload len = %" PRIu16 ")\n", msgb_length(msg)); - if (ipac_msg_type < 0 || 5 < ipac_msg_type) { + if (5 < ipac_msg_type) { fprintf(stderr, "Received unexpected IPAC message type %"PRIu8"\n", ipac_msg_type); msgb_free(msg); return -ENOMSG;
View file
libosmo-netif_1.5.1.tar.xz/tests/stream/stream_test.err -> libosmo-netif_1.6.0.tar.xz/tests/stream/stream_test.err
Changed
@@ -1,3 +1,4 @@ +CLICONN(cli_test,){CLOSED} close() SRV(srv_link_test,127.0.0.11:1111) accept()ed new link from 127.0.0.1:8976 CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTING} connection established @@ -32,7 +33,7 @@ CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} connected read CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} message received CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} connection closed with srv -CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} connection closed +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} close() CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){WAIT_RECONNECT} retrying reconnect in 9 seconds... {11.000008} autoreconnecting test step 4 client OK, server OK, FD reg 0 @@ -41,7 +42,7 @@ {11.000009} autoreconnecting test step 3 client OK, server OK, FD reg 1 SRV(srv_link_test,127.0.0.11:1111) accept()ed new link from 127.0.0.1:8976 CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTING} connection established -CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} connection closed +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} close() {11.000010} autoreconnecting test step 2 client OK, server OK, FD reg 0 SRVCONN(srv_test,r=127.0.0.1:8976<->l=127.0.0.11:1111) connected read/write (what=0x1) @@ -49,6 +50,10 @@ SRVCONN(srv_test,r=127.0.0.1:8976<->l=127.0.0.11:1111) connection closed with client {11.000011} autoreconnecting test step 1 client OK, server NA, FD reg 0 +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} destroy() +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} close() +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} free(destroy) +CLICONN(cli_test,){CLOSED} close() SRV(srv_link_test,127.0.0.11:1111) accept()ed new link from 127.0.0.1:8976 CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTING} connection established @@ -83,10 +88,13 @@ CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} connected read CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} message received CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} connection closed with srv -CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} connection closed +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CONNECTED} close() CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} not reconnecting, disabled {20.000019} non-reconnecting test step 0 client OK, server OK, FD reg 0 +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} destroy() +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} close() +CLICONN(cli_test,r=127.0.0.11:1111<->l=127.0.0.1:8976){CLOSED} free(destroy) SRV(srv_link_test,127.0.0.11:1111) accept()ed new link from 127.0.0.1:8977 CLICONN(,r=127.0.0.11:1111<->l=127.0.0.1:8977){CONNECTING} connection established SRVCONN(,r=127.0.0.1:8977<->l=127.0.0.11:1111) received 24 bytes from client @@ -98,7 +106,9 @@ SRVCONN(,r=127.0.0.1:8977<->l=127.0.0.11:1111) received 10 bytes from client SRVCONN(,r=127.0.0.1:8977<->l=127.0.0.11:1111) received 10 bytes from client SRVCONN(,r=127.0.0.1:8977<->l=127.0.0.11:1111) received 10 bytes from client -CLICONN(,r=127.0.0.11:1111<->l=127.0.0.1:8977){CLOSED} connection closed +CLICONN(,r=127.0.0.11:1111<->l=127.0.0.1:8977){CONNECTED} destroy() +CLICONN(,r=127.0.0.11:1111<->l=127.0.0.1:8977){CONNECTED} close() +CLICONN(,r=127.0.0.11:1111<->l=127.0.0.1:8977){CLOSED} free(destroy) SRV(srv_link_test,127.0.0.11:1112) accept()ed new link from 127.0.0.1:8977 CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CONNECTING} connection established SRVCONN(,r=127.0.0.1:8977<->l=127.0.0.11:1112) connected write @@ -112,4 +122,6 @@ CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CONNECTED} received 10 bytes from srv CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CONNECTED} received 10 bytes from srv CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CONNECTED} received 10 bytes from srv -CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CLOSED} connection closed +CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CONNECTED} destroy() +CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CONNECTED} close() +CLICONN(,r=127.0.0.11:1112<->l=127.0.0.1:8977){CLOSED} free(destroy)
View file
rpmlintrc
Added
@@ -0,0 +1,5 @@ +# Don't abort the build when finding a library that depends on a package with +# a specific version. This is intentional for nightly builds, we don't want +# libraries from different build dates to be mixed as they might have ABI +# incompatibilities. +setBadness('shlib-fixed-dependency', 0)
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.