From 9f662d309f8600aaa5973031f986c94306333ef0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 20 Jan 2023 18:13:11 +0100 Subject: [PATCH] Add libselect to use select instead of polling all file descriptors --- .gitignore | 1 + configure.ac | 1 + src/Makefile.am | 1 + src/amps/Makefile.am | 3 + src/anetz/Makefile.am | 1 + src/bnetz/Makefile.am | 1 + src/cnetz/Makefile.am | 1 + src/eurosignal/Makefile.am | 1 + src/fuenf/Makefile.am | 1 + src/fuvst/Makefile.am | 2 + src/golay/Makefile.am | 1 + src/imts/Makefile.am | 1 + src/jolly/Makefile.am | 1 + src/libmobile/call.c | 12 +-- src/libmobile/console.c | 4 +- src/libmobile/main_mobile.c | 13 ++- src/libosmocc/endpoint.c | 1 + src/libosmocc/helper.c | 1 + src/libosmocc/rtp.c | 134 ++++++++++++++++++---------- src/libosmocc/rtp.h | 1 - src/libosmocc/screen.c | 1 + src/libosmocc/sdp.c | 1 + src/libosmocc/session.c | 17 +--- src/libosmocc/session.h | 5 +- src/libosmocc/socket.c | 128 +++++++++++++++++---------- src/libosmocc/socket.h | 4 +- src/libselect/Makefile.am | 6 ++ src/libselect/select.c | 168 ++++++++++++++++++++++++++++++++++++ src/libselect/select.h | 20 +++++ src/mpt1327/Makefile.am | 1 + src/nmt/Makefile.am | 1 + src/pocsag/Makefile.am | 1 + src/r2000/Makefile.am | 1 + src/test/Makefile.am | 2 + src/zeitansage/Makefile.am | 1 + 35 files changed, 408 insertions(+), 131 deletions(-) create mode 100644 src/libselect/Makefile.am create mode 100644 src/libselect/select.c create mode 100644 src/libselect/select.h diff --git a/.gitignore b/.gitignore index ad59228..cbe0733 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ src/libsquelch/libsquelch.a src/libhagelbarger/libhagelbarger.a src/libdtmf/libdtmf.a src/libtimer/libtimer.a +src/libselect/libselect.a src/libsamplerate/libsamplerate.a src/libscrambler/libscrambler.a src/libemphasis/libemphasis.a diff --git a/configure.ac b/configure.ac index d11f741..0cab408 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,7 @@ AC_OUTPUT( src/libhagelbarger/Makefile src/libdtmf/Makefile src/libtimer/Makefile + src/libselect/Makefile src/libsamplerate/Makefile src/libscrambler/Makefile src/libemphasis/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index d81dbd7..3cf15bd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,7 @@ SUBDIRS = \ libhagelbarger \ libdtmf \ libtimer \ + libselect \ libsamplerate \ libscrambler \ libemphasis \ diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am index 2887466..5769341 100644 --- a/src/amps/Makefile.am +++ b/src/amps/Makefile.am @@ -38,6 +38,7 @@ amps_LDADD = \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ @@ -82,6 +83,7 @@ tacs_LDADD = \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ @@ -125,6 +127,7 @@ jtacs_LDADD = \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am index 66de260..a9a6503 100644 --- a/src/anetz/Makefile.am +++ b/src/anetz/Makefile.am @@ -27,6 +27,7 @@ anetz_LDADD = \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libsquelch/libsquelch.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am index a799256..7f98e09 100644 --- a/src/bnetz/Makefile.am +++ b/src/bnetz/Makefile.am @@ -23,6 +23,7 @@ bnetz_LDADD = \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libsquelch/libsquelch.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfsk/libfsk.a \ diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am index 3c521bd..7975c7c 100644 --- a/src/cnetz/Makefile.am +++ b/src/cnetz/Makefile.am @@ -31,6 +31,7 @@ cnetz_LDADD = \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libscrambler/libscrambler.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ diff --git a/src/eurosignal/Makefile.am b/src/eurosignal/Makefile.am index 9ec8837..ab7b654 100644 --- a/src/eurosignal/Makefile.am +++ b/src/eurosignal/Makefile.am @@ -22,6 +22,7 @@ eurosignal_LDADD = \ $(top_builddir)/src/libdisplay/libdisplay.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfsk/libfsk.a \ diff --git a/src/fuenf/Makefile.am b/src/fuenf/Makefile.am index 4c90762..9b123f5 100644 --- a/src/fuenf/Makefile.am +++ b/src/fuenf/Makefile.am @@ -19,6 +19,7 @@ bin_PROGRAMS = \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/fuvst/Makefile.am b/src/fuvst/Makefile.am index 090a433..f7c73f4 100644 --- a/src/fuvst/Makefile.am +++ b/src/fuvst/Makefile.am @@ -22,6 +22,7 @@ fuvst_LDADD = \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ @@ -48,6 +49,7 @@ fuvst_sniffer_LDADD = \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/golay/Makefile.am b/src/golay/Makefile.am index d7cc8fe..9375968 100644 --- a/src/golay/Makefile.am +++ b/src/golay/Makefile.am @@ -18,6 +18,7 @@ golay_LDADD = \ $(top_builddir)/src/libdisplay/libdisplay.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/imts/Makefile.am b/src/imts/Makefile.am index 9dd0cc1..9cfc677 100644 --- a/src/imts/Makefile.am +++ b/src/imts/Makefile.am @@ -20,6 +20,7 @@ imts_LDADD = \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libsquelch/libsquelch.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/jolly/Makefile.am b/src/jolly/Makefile.am index a968f89..f78fb49 100644 --- a/src/jolly/Makefile.am +++ b/src/jolly/Makefile.am @@ -20,6 +20,7 @@ jollycom_LDADD = \ $(top_builddir)/src/libsquelch/libsquelch.a \ $(top_builddir)/src/libdtmf/libdtmf.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfilter/libfilter.a \ diff --git a/src/libmobile/call.c b/src/libmobile/call.c index 6b0214e..15aa1df 100644 --- a/src/libmobile/call.c +++ b/src/libmobile/call.c @@ -28,6 +28,7 @@ #include "../libsample/sample.h" #include "../libdebug/debug.h" #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "../libosmocc/endpoint.h" #include "../libosmocc/helper.h" #include "../libg711/g711.h" @@ -929,14 +930,3 @@ int call_handle(void) return osmo_cc_handle(); } -void call_media_handle(void) -{ - process_t *process = process_head; - - while(process) { - if (process->session) - osmo_cc_session_handle(process->session, process); - process = process->next; - } -} - diff --git a/src/libmobile/console.c b/src/libmobile/console.c index d0ca5dc..9526e21 100755 --- a/src/libmobile/console.c +++ b/src/libmobile/console.c @@ -29,6 +29,7 @@ #include "../libjitter/jitter.h" #include "../libdebug/debug.h" #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "../libosmocc/endpoint.h" #include "../libosmocc/helper.h" #include "testton.h" @@ -568,9 +569,6 @@ void process_console(int c) if (!console.loopback && console.number_max_length) process_ui(c); - if (console.session) - osmo_cc_session_handle(console.session, &console); - if (!console.sound) return; diff --git a/src/libmobile/main_mobile.c b/src/libmobile/main_mobile.c index a6e7702..85eeace 100644 --- a/src/libmobile/main_mobile.c +++ b/src/libmobile/main_mobile.c @@ -32,6 +32,7 @@ #include "../libdebug/debug.h" #include "sender.h" #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "call.h" #include "../libosmocc/endpoint.h" #include "console.h" @@ -711,6 +712,7 @@ void main_mobile_loop(const char *name, int *quit, void (*myhandler)(void), cons *quit = 1; while(!(*quit)) { + int work; begin_time = get_time(); /* process sound of all transceivers */ @@ -803,9 +805,14 @@ next_char: #endif } - /* process call control */ - call_media_handle(); - while (call_handle()); + /* handle all handlers until no more events */ + do { + work = 0; + work |= osmo_cc_handle(); + work |= (process_timer() == 0.0); + work |= osmo_fd_select(0.0); + } while (work); + if (!use_osmocc_sock) process_console(c); diff --git a/src/libosmocc/endpoint.c b/src/libosmocc/endpoint.c index 2b6d759..7d9c57f 100644 --- a/src/libosmocc/endpoint.c +++ b/src/libosmocc/endpoint.c @@ -24,6 +24,7 @@ #include #include #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "../libdebug/debug.h" #include "endpoint.h" diff --git a/src/libosmocc/helper.c b/src/libosmocc/helper.c index 7700174..e75b47a 100644 --- a/src/libosmocc/helper.c +++ b/src/libosmocc/helper.c @@ -25,6 +25,7 @@ #include #include #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "../libdebug/debug.h" #include "endpoint.h" #include "helper.h" diff --git a/src/libosmocc/rtp.c b/src/libosmocc/rtp.c index fc70748..406d330 100644 --- a/src/libosmocc/rtp.c +++ b/src/libosmocc/rtp.c @@ -28,6 +28,7 @@ #include #include "../libdebug/debug.h" #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "endpoint.h" #define RTP_VERSION 2 @@ -132,6 +133,22 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_ return 0; } +static int rtcp_receive(int sock) +{ + static uint8_t data[2048]; + int len; + + len = read(sock, data, sizeof(data)); + if (len < 0) { + if (errno == EAGAIN) + return -EAGAIN; + PDEBUG(DCC, DEBUG_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno)); + return -EIO; + } + + return 0; +} + static void rtp_send(int sock, uint8_t *payload, int payload_len, uint8_t marker, uint8_t pt, uint16_t sequence, uint32_t timestamp, uint32_t ssrc) { struct rtp_hdr *rtph; @@ -157,6 +174,9 @@ static void rtp_send(int sock, uint8_t *payload, int payload_len, uint8_t marker PDEBUG(DCC, DEBUG_DEBUG, "Write errno = %d (%s)\n", errno, strerror(errno)); } +static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when); +static int rtcp_listen_cb(struct osmo_fd *ofd, unsigned int when); + /* open and bind RTP * set local port to what we bound */ @@ -221,15 +241,23 @@ socket_error: osmo_cc_rtp_close(media); return -EIO; } - media->rtp_socket = rc; + media->rtp_ofd.fd = rc; + media->rtp_ofd.cb = rtp_listen_cb; + media->rtp_ofd.data = media; + media->rtp_ofd.when = OSMO_FD_READ; + osmo_fd_register(&media->rtp_ofd); rc = socket(domain, SOCK_DGRAM, IPPROTO_UDP); if (rc < 0) goto socket_error; - media->rtcp_socket = rc; + media->rtcp_ofd.fd = rc; + media->rtcp_ofd.cb = rtcp_listen_cb; + media->rtcp_ofd.data = media; + media->rtcp_ofd.when = OSMO_FD_READ; + osmo_fd_register(&media->rtcp_ofd); /* bind sockets */ *sport = htons(conf->rtp_port_next); - rc = bind(media->rtp_socket, (struct sockaddr *)&sa, slen); + rc = bind(media->rtp_ofd.fd, (struct sockaddr *)&sa, slen); if (rc < 0) { bind_error: osmo_cc_rtp_close(media); @@ -241,18 +269,18 @@ bind_error: continue; } *sport = htons(conf->rtp_port_next + 1); - rc = bind(media->rtcp_socket, (struct sockaddr *)&sa, slen); + rc = bind(media->rtcp_ofd.fd, (struct sockaddr *)&sa, slen); if (rc < 0) goto bind_error; media->description.port_local = conf->rtp_port_next; conf->rtp_port_next = (conf->rtp_port_next + 2 > conf->rtp_port_to) ? conf->rtp_port_from : conf->rtp_port_next + 2; - /* set nonblocking io */ - flags = fcntl(media->rtp_socket, F_GETFL); + /* set nonblocking io, to prevent write to block */ + flags = fcntl(media->rtp_ofd.fd, F_GETFL); flags |= O_NONBLOCK; - fcntl(media->rtp_socket, F_SETFL, flags); - flags = fcntl(media->rtcp_socket, F_GETFL); + fcntl(media->rtp_ofd.fd, F_SETFL, flags); + flags = fcntl(media->rtcp_ofd.fd, F_GETFL); flags |= O_NONBLOCK; - fcntl(media->rtcp_socket, F_SETFL, flags); + fcntl(media->rtcp_ofd.fd, F_SETFL, flags); break; } @@ -305,7 +333,7 @@ pton_error: } *sport = htons(media->description.port_remote); - rc = connect(media->rtp_socket, (struct sockaddr *)&sa, slen); + rc = connect(media->rtp_ofd.fd, (struct sockaddr *)&sa, slen); if (rc < 0) { connect_error: PDEBUG(DCC, DEBUG_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address); @@ -313,7 +341,7 @@ connect_error: return -EIO; } *sport = htons(media->description.port_remote + 1); - rc = connect(media->rtcp_socket, (struct sockaddr *)&sa, slen); + rc = connect(media->rtcp_ofd.fd, (struct sockaddr *)&sa, slen); if (rc < 0) goto connect_error; @@ -326,7 +354,7 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui uint8_t *payload = NULL; int payload_len = 0; - if (!codec || !codec->media->rtp_socket) + if (!codec || !codec->media->rtp_ofd.fd) return; if (codec->encoder) @@ -336,7 +364,7 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui payload_len = len; } - rtp_send(codec->media->rtp_socket, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc); + rtp_send(codec->media->rtp_ofd.fd, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc); codec->media->tx_sequence += inc_sequence; codec->media->tx_timestamp += inc_timestamp; @@ -344,9 +372,9 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui free(payload); } -/* receive rtp data for given media, return < 0, if there is nothing this time */ -int osmo_cc_rtp_receive(osmo_cc_session_media_t *media, void *priv) +static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when) { + osmo_cc_session_media_t *media = ofd->data; int rc; uint8_t *payload = NULL; int payload_len = 0; @@ -356,49 +384,63 @@ int osmo_cc_rtp_receive(osmo_cc_session_media_t *media, void *priv) uint8_t *data; int len; - if (!media || media->rtp_socket <= 0) - return -EIO; + if (when & OSMO_FD_READ) { + rc = rtp_receive(media->rtp_ofd.fd, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc); + if (rc < 0) + return rc; - rc = rtp_receive(media->rtp_socket, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc); - if (rc < 0) - return rc; + /* search for codec */ + for (codec = media->codec_list; codec; codec = codec->next) { + if (codec->payload_type_local == payload_type) + break; + } + if (!codec) { + PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame for unknown codec (payload_type = %d).\n", payload_type); + return 0; + } - /* search for codec */ - for (codec = media->codec_list; codec; codec = codec->next) { - - if (codec->payload_type_local == payload_type) - break; - } - if (!codec) { - PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame for unknown codec (payload_type = %d).\n", payload_type); - return 0; + if (codec->decoder) + codec->decoder(payload, payload_len, &data, &len, media->session->priv); + else { + data = payload; + len = payload_len; + } + + if (codec->media->receive) + codec->media->receiver(codec, marker, media->rx_sequence, media->rx_timestamp, media->rx_ssrc, data, len); + + if (codec->decoder) + free(data); } - if (codec->decoder) - codec->decoder(payload, payload_len, &data, &len, priv); - else { - data = payload; - len = payload_len; + return 0; +} + +static int rtcp_listen_cb(struct osmo_fd *ofd, unsigned int when) +{ + osmo_cc_session_media_t *media = ofd->data; + int rc; + + if (when & OSMO_FD_READ) { + rc = rtcp_receive(media->rtp_ofd.fd); + if (rc < 0) + return rc; } - if (codec->media->receive) - codec->media->receiver(codec, marker, media->rx_sequence, media->rx_timestamp, media->rx_ssrc, data, len); - - if (codec->decoder) - free(data); - return 0; } void osmo_cc_rtp_close(osmo_cc_session_media_t *media) { - if (media->rtp_socket) { - close(media->rtp_socket); - media->rtp_socket = 0; + if (media->rtp_ofd.fd) { + osmo_fd_unregister(&media->rtp_ofd); + close(media->rtp_ofd.fd); + media->rtp_ofd.fd = 0; } - if (media->rtcp_socket) { - close(media->rtcp_socket); - media->rtcp_socket = 0; + if (media->rtcp_ofd.fd) { + osmo_fd_unregister(&media->rtcp_ofd); + close(media->rtcp_ofd.fd); + media->rtcp_ofd.fd = 0; } } diff --git a/src/libosmocc/rtp.h b/src/libosmocc/rtp.h index f6e5632..ea1b31f 100644 --- a/src/libosmocc/rtp.h +++ b/src/libosmocc/rtp.h @@ -3,6 +3,5 @@ void osmo_cc_set_rtp_ports(osmo_cc_session_config_t *conf, uint16_t from, uint16 int osmo_cc_rtp_open(osmo_cc_session_media_t *media); int osmo_cc_rtp_connect(osmo_cc_session_media_t *media); void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, uint8_t marker, int inc_sequence, int inc_timestamp, void *priv); -int osmo_cc_rtp_receive(osmo_cc_session_media_t *media, void *priv); void osmo_cc_rtp_close(osmo_cc_session_media_t *media); diff --git a/src/libosmocc/screen.c b/src/libosmocc/screen.c index 5558f42..a3b0797 100644 --- a/src/libosmocc/screen.c +++ b/src/libosmocc/screen.c @@ -24,6 +24,7 @@ #include #include #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "../libdebug/debug.h" #include "endpoint.h" #include "message.h" diff --git a/src/libosmocc/sdp.c b/src/libosmocc/sdp.c index 849bfb9..3498843 100644 --- a/src/libosmocc/sdp.c +++ b/src/libosmocc/sdp.c @@ -25,6 +25,7 @@ #include #include "../libdebug/debug.h" #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "endpoint.h" #include "sdp.h" diff --git a/src/libosmocc/session.c b/src/libosmocc/session.c index 427eca7..5e2447a 100644 --- a/src/libosmocc/session.c +++ b/src/libosmocc/session.c @@ -25,6 +25,7 @@ #include #include #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "../libdebug/debug.h" #include "../liboptions/options.h" #include "endpoint.h" @@ -622,19 +623,3 @@ int osmo_cc_session_if_codec(osmo_cc_session_codec_t *codec, const char *name, u && codec->payload_channels == channels); } -int osmo_cc_session_handle(osmo_cc_session_t *session, void *codec_priv) -{ - osmo_cc_session_media_t *media; - int w = 0, rc; - - osmo_cc_session_for_each_media(session->media_list, media) { - do { - rc = osmo_cc_rtp_receive(media, codec_priv); - if (rc >= 0) - w = 1; - } while (rc >= 0); - } - - return w; -} - diff --git a/src/libosmocc/session.h b/src/libosmocc/session.h index 0330f51..ddbed82 100644 --- a/src/libosmocc/session.h +++ b/src/libosmocc/session.h @@ -80,8 +80,8 @@ typedef struct osmo_cc_session_media { struct osmo_cc_session_codec *codec_list; int send, receive; void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len); - int rtp_socket; - int rtcp_socket; + struct osmo_fd rtp_ofd; + struct osmo_fd rtcp_ofd; uint32_t tx_ssrc, rx_ssrc; uint16_t tx_sequence, rx_sequence; uint32_t tx_timestamp, rx_timestamp; @@ -126,5 +126,4 @@ const char *osmo_cc_session_addrtype2string(enum osmo_cc_session_addrtype addrty const char *osmo_cc_session_media_type2string(enum osmo_cc_session_media_type media_type); const char *osmo_cc_session_media_proto2string(enum osmo_cc_session_media_proto media_proto); int osmo_cc_session_if_codec(osmo_cc_session_codec_t *codec, const char *name, uint32_t rate, int channels); -int osmo_cc_session_handle(osmo_cc_session_t *session, void *codec_priv); diff --git a/src/libosmocc/socket.c b/src/libosmocc/socket.c index e41e0fc..d489fcf 100644 --- a/src/libosmocc/socket.c +++ b/src/libosmocc/socket.c @@ -28,6 +28,7 @@ #include #include "../libdebug/debug.h" #include "../libtimer/timer.h" +#include "../libselect/select.h" #include "message.h" #include "cause.h" #include "socket.h" @@ -101,12 +102,14 @@ static void rx_keepalive_timeout(void *data) close_conn(conn, OSMO_CC_SOCKET_CAUSE_TIMEOUT); } +static int socket_listen_cb(struct osmo_fd *ofd, unsigned int when); + /* create socket process and bind socket */ int osmo_cc_open_socket(osmo_cc_socket_t *os, const char *host, uint16_t port, void *priv, void (*recv_msg_cb)(void *priv, uint32_t callref, osmo_cc_msg_t *msg), uint8_t location) { int try = 0, auto_port = 0; struct addrinfo *result, *rp; - int rc, sock, flags; + int rc, sock; memset(os, 0, sizeof(*os)); @@ -148,15 +151,16 @@ try_again: rc = listen(sock, 10); if (rc < 0) { PDEBUG(DCC, DEBUG_ERROR, "Failed to listen on socket.\n"); + close(sock); return rc; } - /* set nonblocking io */ - flags = fcntl(sock, F_GETFL); - flags |= O_NONBLOCK; - fcntl(sock, F_SETFL, flags); - - os->socket = sock; + /* register */ + os->ofd.fd = sock; + os->ofd.cb = socket_listen_cb; + os->ofd.data = os; + os->ofd.when = OSMO_FD_READ; + osmo_fd_register(&os->ofd); os->recv_msg_cb = recv_msg_cb; os->priv = priv; os->location = location; @@ -164,6 +168,8 @@ try_again: return port; } +static int socket_conn_cb(struct osmo_fd *ofd, unsigned int when); + /* create a connection */ static osmo_cc_conn_t *open_conn(osmo_cc_socket_t *os, int sock, uint32_t callref, int read_setup) { @@ -176,7 +182,11 @@ static osmo_cc_conn_t *open_conn(osmo_cc_socket_t *os, int sock, uint32_t callre abort(); } conn->os = os; - conn->socket = sock; + conn->ofd.fd = sock; + conn->ofd.cb = socket_conn_cb; + conn->ofd.data = conn; + conn->ofd.when = OSMO_FD_READ; + osmo_fd_register(&conn->ofd); conn->read_version = 1; conn->write_version = 1; conn->read_setup = read_setup; @@ -221,8 +231,10 @@ static void close_conn(osmo_cc_conn_t *conn, uint8_t socket_cause) PDEBUG(DCC, DEBUG_DEBUG, "Destroy socket connection (callref %d).\n", conn->callref); /* close socket */ - if (conn->socket) - close(conn->socket); + if (conn->ofd.fd) { + osmo_fd_unregister(&conn->ofd); + close(conn->ofd.fd); + } /* free partly received message */ if (conn->read_msg) osmo_cc_free_msg(conn->read_msg); @@ -250,9 +262,10 @@ void osmo_cc_close_socket(osmo_cc_socket_t *os) while (os->conn_list) close_conn(os->conn_list, 0); /* close socket */ - if (os->socket > 0) { - close(os->socket); - os->socket = 0; + if (os->ofd.fd > 0) { + osmo_fd_unregister(&os->ofd); + close(os->ofd.fd); + os->ofd.fd = 0; } /* free send queue */ while ((ml = os->write_list)) { @@ -293,7 +306,7 @@ static int receive_conn(osmo_cc_conn_t *conn) /* get version from remote */ if (conn->read_version) { - rc = recv(conn->socket, conn->read_version_string + conn->read_version_pos, strlen(version_string) - conn->read_version_pos, 0); + rc = recv(conn->ofd.fd, conn->read_version_string + conn->read_version_pos, strlen(version_string) - conn->read_version_pos, 0); if (rc < 0 && errno == EAGAIN) return work; work = 1; @@ -320,7 +333,7 @@ static int receive_conn(osmo_cc_conn_t *conn) try_next_message: /* read message header from remote */ if (!conn->read_msg) { - rc = recv(conn->socket, ((uint8_t *)&conn->read_hdr) + conn->read_pos, sizeof(conn->read_hdr) - conn->read_pos, 0); + rc = recv(conn->ofd.fd, ((uint8_t *)&conn->read_hdr) + conn->read_pos, sizeof(conn->read_hdr) - conn->read_pos, 0); if (rc < 0 && errno == EAGAIN) return work; work = 1; @@ -344,7 +357,7 @@ try_next_message: len = ntohs(msg->length_networkorder); if (len == 0) goto empty_message; - rc = recv(conn->socket, msg->data + conn->read_pos, len - conn->read_pos, 0); + rc = recv(conn->ofd.fd, msg->data + conn->read_pos, len - conn->read_pos, 0); if (rc < 0 && errno == EAGAIN) return work; work = 1; @@ -397,7 +410,7 @@ static int transmit_conn(osmo_cc_conn_t *conn) /* send socket version to remote */ if (conn->write_version) { - rc = write(conn->socket, version_string, strlen(version_string)); + rc = write(conn->ofd.fd, version_string, strlen(version_string)); if (rc < 0 && errno == EAGAIN) return work; work = 1; @@ -416,7 +429,7 @@ static int transmit_conn(osmo_cc_conn_t *conn) timer_stop(&conn->tx_keepalive_timer); msg = conn->write_list->msg; len = sizeof(*msg) + ntohs(msg->length_networkorder); - rc = write(conn->socket, msg, len); + rc = write(conn->ofd.fd, msg, len); if (rc < 0 && errno == EAGAIN) return work; work = 1; @@ -460,8 +473,6 @@ close: */ int osmo_cc_handle_socket(osmo_cc_socket_t *os) { - struct sockaddr_storage sa; - socklen_t slen = sizeof(sa); int sock; osmo_cc_conn_t *conn; osmo_cc_msg_list_t *ml, **mlp; @@ -487,6 +498,7 @@ int osmo_cc_handle_socket(osmo_cc_socket_t *os) while (*mlp) mlp = &((*mlp)->next); *mlp = ml; + conn->ofd.when |= OSMO_FD_WRITE; /* done with message */ continue; } @@ -526,7 +538,7 @@ int osmo_cc_handle_socket(osmo_cc_socket_t *os) sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sock < 0) continue; - /* set nonblocking io */ + /* set nonblocking io, to prevent connect() and subsequent reads from blocking */ flags = fcntl(sock, F_GETFL); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); @@ -550,34 +562,58 @@ int osmo_cc_handle_socket(osmo_cc_socket_t *os) conn = open_conn(os, sock, ml->callref, 0); /* attach to list */ conn->write_list = ml; + conn->ofd.when |= OSMO_FD_WRITE; /* done with (setup) message */ } - /* handle new socket connection */ - while ((sock = accept(os->socket, (struct sockaddr *)&sa, &slen)) > 0) { - work = 1; - /* set nonblocking io */ - flags = fcntl(sock, F_GETFL); - flags |= O_NONBLOCK; - fcntl(sock, F_SETFL, flags); - /* create connection */ - open_conn(os, sock, 0, 1); - } - - /* start with list after each read/write, because while handling (the message), one or more connections may be destroyed */ - for (conn = os->conn_list; conn; conn=conn->next) { - /* check for rx */ - work = receive_conn(conn); - /* if "change" is set, connection list might have changed, so we restart processing the list */ - if (work) - break; - /* check for tx */ - work = transmit_conn(conn); - /* if "change" is set, connection list might have changed, so we restart processing the list */ - if (work) - break; - } - return work; } +static int socket_listen_cb(struct osmo_fd *ofd, unsigned int when) +{ + osmo_cc_socket_t *os = ofd->data; + struct sockaddr_storage sa; + socklen_t slen = sizeof(sa); + int sock; + int flags; + + if (when & OSMO_FD_READ) { + /* handle new socket connection */ + if ((sock = accept(os->ofd.fd, (struct sockaddr *)&sa, &slen)) > 0) { + /* set nonblocking io, to prevent subsequent reads from blocking */ + flags = fcntl(sock, F_GETFL); + flags |= O_NONBLOCK; + fcntl(sock, F_SETFL, flags); + /* create connection */ + open_conn(os, sock, 0, 1); + } + } + + return 0; +} + +static int socket_conn_cb(struct osmo_fd *ofd, unsigned int when) +{ + osmo_cc_conn_t *conn = ofd->data; + int work; + + if (when & OSMO_FD_READ) { + /* check for rx */ + work = receive_conn(conn); + /* if "change" is set, connection list might have changed, so we restart processing the list */ + if (work) + return 0; + } + if (when & OSMO_FD_WRITE) { + /* check for tx */ + work = transmit_conn(conn); + /* if "change" is set, connection list might have changed, so we restart processing the list */ + if (work) + return 0; + else + conn->ofd.when &= ~OSMO_FD_WRITE; + } + + return 0; +} + diff --git a/src/libosmocc/socket.h b/src/libosmocc/socket.h index bcd8b7c..a3cc046 100644 --- a/src/libosmocc/socket.h +++ b/src/libosmocc/socket.h @@ -12,7 +12,7 @@ struct osmo_cc_socket; typedef struct osmo_cc_conn { struct osmo_cc_conn *next; struct osmo_cc_socket *os; - int socket; + struct osmo_fd ofd; uint32_t callref; int read_setup; int read_version; @@ -28,7 +28,7 @@ typedef struct osmo_cc_conn { } osmo_cc_conn_t; typedef struct osmo_cc_socket { - int socket; + struct osmo_fd ofd; osmo_cc_conn_t *conn_list; osmo_cc_msg_list_t *write_list; void (*recv_msg_cb)(void *priv, uint32_t callref, osmo_cc_msg_t *msg); diff --git a/src/libselect/Makefile.am b/src/libselect/Makefile.am new file mode 100644 index 0000000..76ff4d6 --- /dev/null +++ b/src/libselect/Makefile.am @@ -0,0 +1,6 @@ +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) + +noinst_LIBRARIES = libselect.a + +libselect_a_SOURCES = \ + select.c diff --git a/src/libselect/select.c b/src/libselect/select.c new file mode 100644 index 0000000..3a4c0b1 --- /dev/null +++ b/src/libselect/select.c @@ -0,0 +1,168 @@ +/* Timer handling + * + * (C) 2023 by Andreas Eversberg + * All Rights Reserved + * + * Inspired by libosmocore + * + * 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 3 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "select.h" + +//#define DEBUG + +#define MAX_OFD 1024 + +struct osmo_fd *ofd_list = NULL; +int ofd_changed = 0; + +int osmo_fd_register(struct osmo_fd *ofd) +{ + struct osmo_fd **ofdp; + + /* attach to list, if not already */ + ofdp = &ofd_list; + while (*ofdp) { + if (*ofdp == ofd) + break; + ofdp = &((*ofdp)->next); + } + if (!*ofdp) { +#ifdef DEBUG + fprintf(stderr, "%s: ofd=%p fd=%d registers.\n", __func__, ofd, ofd->fd); +#endif + ofd->next = NULL; + *ofdp = ofd; + ofd_changed = 1; + } + + return 0; +} + +void osmo_fd_unregister(struct osmo_fd *ofd) +{ + struct osmo_fd **ofdp; + + /* detach from list, if not already */ + ofdp = &ofd_list; + while (*ofdp) { + if (*ofdp == ofd) + break; + ofdp = &((*ofdp)->next); + } + if (*ofdp) { +#ifdef DEBUG + fprintf(stderr, "%s: ofd=%p fd=%d unregisters.\n", __func__, ofd, ofd->fd); +#endif + *ofdp = ofd->next; + ofd->next = NULL; + ofd_changed = 1; + } +} + +int osmo_fd_select(double timeout) +{ + fd_set readset; + fd_set writeset; + fd_set exceptset; + struct osmo_fd *ofd; + struct timeval tv; + int max_fd; + unsigned int what; + int work = 0; + int rc; + + /* init event sets */ + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&exceptset); + + /* populate event set with all file descriptios */ + ofd = ofd_list; + max_fd = 0; + while (ofd) { + if (ofd->fd > max_fd) + max_fd = ofd->fd; + if (ofd->when & OSMO_FD_READ) + FD_SET(ofd->fd, &readset); + if (ofd->when & OSMO_FD_WRITE) + FD_SET(ofd->fd, &writeset); + if (ofd->when & OSMO_FD_EXCEPT) + FD_SET(ofd->fd, &exceptset); + ofd = ofd->next; + } + + if (timeout >= 0) { + /* prepare timeout */ + tv.tv_sec = floor(timeout); + tv.tv_usec = (timeout - tv.tv_sec) * 1000000.0; + /* wait for event or timeout */ + rc = select(max_fd + 1, &readset, &writeset, &exceptset, &tv); + } else { + /* wait for event */ + rc = select(max_fd + 1, &readset, &writeset, &exceptset, NULL); + } + if (rc < 0) { + if (errno != EINTR) + fprintf(stderr, "%s: select() failed: '%d' with errno %d (%s) Please fix!\n", __func__, rc, errno, strerror(errno)); + return 0; + } + +again: + /* check the result and call handler */ + ofd_changed = 0; + ofd = ofd_list; + while (ofd) { + what = 0; + if (FD_ISSET(ofd->fd, &readset)) { +#ifdef DEBUG + fprintf(stderr, "%s: ofd=%p fd=%d get READ event.\n", __func__, ofd, ofd->fd); +#endif + what |= OSMO_FD_READ; + FD_CLR(ofd->fd, &readset); + } + if (FD_ISSET(ofd->fd, &writeset)) { +#ifdef DEBUG + fprintf(stderr, "%s: ofd=%p fd=%d get WRITE event.\n", __func__, ofd, ofd->fd); +#endif + what |= OSMO_FD_WRITE; + FD_CLR(ofd->fd, &writeset); + } + if (FD_ISSET(ofd->fd, &exceptset)) { +#ifdef DEBUG + fprintf(stderr, "%s: ofd=%p fd=%d get EXCEPTION event.\n", __func__, ofd, ofd->fd); +#endif + what |= OSMO_FD_EXCEPT; + FD_CLR(ofd->fd, &exceptset); + } + if (what) { + work = 1; + ofd->cb(ofd, what); + /* list has changed */ + if (ofd_changed) + goto again; + } + ofd = ofd->next; + } + + return work; +} + diff --git a/src/libselect/select.h b/src/libselect/select.h new file mode 100644 index 0000000..def1000 --- /dev/null +++ b/src/libselect/select.h @@ -0,0 +1,20 @@ + +#define OSMO_FD_READ 0x0001 +#define OSMO_FD_WRITE 0x0002 +#define OSMO_FD_EXCEPT 0x0004 +#define BSC_FD_READ 0x0001 +#define BSC_FD_WRITE 0x0002 +#define BSC_FD_EXCEPT 0x0004 + +struct osmo_fd { + struct osmo_fd *next; + int fd; + unsigned int when; + int (*cb)(struct osmo_fd *fd, unsigned int what); + void *data; +}; + +int osmo_fd_register(struct osmo_fd *ofd); +void osmo_fd_unregister(struct osmo_fd *ofd); +int osmo_fd_select(double timeout); + diff --git a/src/mpt1327/Makefile.am b/src/mpt1327/Makefile.am index 49ec2c6..cfc2b1a 100644 --- a/src/mpt1327/Makefile.am +++ b/src/mpt1327/Makefile.am @@ -20,6 +20,7 @@ mpt1327_LDADD = \ $(top_builddir)/src/libsquelch/libsquelch.a \ $(top_builddir)/src/libdtmf/libdtmf.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfsk/libfsk.a \ diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am index 5887455..17a733a 100644 --- a/src/nmt/Makefile.am +++ b/src/nmt/Makefile.am @@ -33,6 +33,7 @@ nmt_LDADD = \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ $(top_builddir)/src/libdtmf/libdtmf.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfsk/libfsk.a \ diff --git a/src/pocsag/Makefile.am b/src/pocsag/Makefile.am index 817a95b..f5c7a41 100644 --- a/src/pocsag/Makefile.am +++ b/src/pocsag/Makefile.am @@ -19,6 +19,7 @@ pocsag_LDADD = \ $(top_builddir)/src/libdisplay/libdisplay.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am index c3d7cfb..6b52ff1 100644 --- a/src/r2000/Makefile.am +++ b/src/r2000/Makefile.am @@ -21,6 +21,7 @@ radiocom2000_LDADD = \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfsk/libfsk.a \ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 4ae1e3e..b6d8349 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -67,6 +67,7 @@ test_dms_LDADD = \ $(top_builddir)/src/nmt/libdmssms.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfilter/libfilter.a \ @@ -104,6 +105,7 @@ test_sms_LDADD = \ $(top_builddir)/src/nmt/libdmssms.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfilter/libfilter.a \ diff --git a/src/zeitansage/Makefile.am b/src/zeitansage/Makefile.am index dbab2fb..79eaeec 100644 --- a/src/zeitansage/Makefile.am +++ b/src/zeitansage/Makefile.am @@ -17,6 +17,7 @@ zeitansage_LDADD = \ $(top_builddir)/src/libdisplay/libdisplay.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libselect/libselect.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ $(top_builddir)/src/libfsk/libfsk.a \