Change in mncc-python[master]: initial checkin of 'osmo-rtpsource' program

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Fri Mar 6 22:20:49 UTC 2020


laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/mncc-python/+/17402 )


Change subject: initial checkin of 'osmo-rtpsource' program
......................................................................

initial checkin of 'osmo-rtpsource' program

osmo-rtpsource is a small utility program which is generating
RTP flows at a constant rate of 20ms, as required in most IP based
telphony.  The payload currently is hard-coded.

Change-Id: Id4e292ddfd5aa58754382b2380558993b2ddf07a
---
A rtpsource/Makefile
A rtpsource/ctrl_if.c
A rtpsource/internal.h
A rtpsource/rtpsource.c
4 files changed, 438 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/mncc-python refs/changes/02/17402/1

diff --git a/rtpsource/Makefile b/rtpsource/Makefile
new file mode 100644
index 0000000..9972325
--- /dev/null
+++ b/rtpsource/Makefile
@@ -0,0 +1,15 @@
+OSMO_CFLAGS:=$(shell pkg-config --cflags libosmocore libosmoctrl libosmotrau)
+OSMO_LIBS:=$(shell pkg-config --libs libosmocore libosmoctrl libosmotrau)
+
+CFLAGS:= -g -Wall $(OSMO_CFLAGS)
+LIBS:= $(OSMO_LIBS)
+
+rtpsource: rtpsource.o ctrl_if.o
+	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+
+%.o: %.c
+	$(CC) $(CFLAGS) -o $@ -c $^
+
+clean:
+	@rm -f rtpsource *.o
diff --git a/rtpsource/ctrl_if.c b/rtpsource/ctrl_if.c
new file mode 100644
index 0000000..708fb02
--- /dev/null
+++ b/rtpsource/ctrl_if.c
@@ -0,0 +1,131 @@
+/* CTRL interface of rtpsource program
+ *
+ * (C) 2020 by Harald Welte <laforge at gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <osmocom/ctrl/control_cmd.h>
+
+#include "internal.h"
+
+CTRL_CMD_DEFINE_WO_NOVRF(rtp_create, "rtp_create");
+static int set_rtp_create(struct ctrl_cmd *cmd, void *data)
+{
+	struct rtp_connection *conn;
+	const char *cname = cmd->value;
+
+	if (find_connection_by_cname(g_rss, cname)) {
+		cmd->reply = "Connection already exists for cname";
+		return CTRL_CMD_ERROR;
+	}
+
+	conn = create_connection(g_rss, cname);
+	if (!conn) {
+		cmd->reply = "Error creating RTP connection";
+		return CTRL_CMD_ERROR;
+	}
+
+	/* Respond */
+	cmd->reply = talloc_asprintf(cmd, "%s,%s,%d", conn->cname, conn->local_host, conn->local_port);
+	return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_WO_NOVRF(rtp_connect, "rtp_connect");
+static int set_rtp_connect(struct ctrl_cmd *cmd, void *data)
+{
+	struct rtp_connection *conn;
+	const char *cname, *remote_host, *remote_port, *pt;
+	char *tmp, *saveptr;
+	int rc;
+
+	tmp = talloc_strdup(cmd, cmd->value);
+	OSMO_ASSERT(tmp);
+
+	/* FIXME: parse command */
+	cname = strtok_r(tmp, ",", &saveptr);
+	remote_host = strtok_r(NULL, ",", &saveptr);
+	remote_port = strtok_r(NULL, ",", &saveptr);
+	pt = strtok_r(NULL, ",", &saveptr);
+
+	if (!cname || !remote_host || !remote_port || !pt) {
+		cmd->reply = "Format is cname,remote_host,remote_port,pt";
+		talloc_free(tmp);
+		return CTRL_CMD_ERROR;
+	}
+
+	conn = find_connection_by_cname(g_rss, cname);
+	if (!conn) {
+		cmd->reply = "Error finding RTP connection for connect";
+		talloc_free(tmp);
+		return CTRL_CMD_ERROR;
+	}
+
+	rc = connect_connection(conn, remote_host, atoi(remote_port), atoi(pt));
+	if (rc < 0) {
+		cmd->reply = "Error binding RTP connection";
+		talloc_free(tmp);
+		return CTRL_CMD_ERROR;
+	}
+
+	/* Respond */
+	talloc_free(tmp);
+	cmd->reply = talloc_asprintf(cmd, "%s,%s,%d,%d", conn->cname, conn->remote_host,
+					conn->remote_port, conn->rtp_pt);
+	return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_WO_NOVRF(rtp_delete, "rtp_delete");
+static int set_rtp_delete(struct ctrl_cmd *cmd, void *data)
+{
+	struct rtp_connection *conn;
+	const char *cname = cmd->value;
+
+	conn = find_connection_by_cname(g_rss, cname);
+	if (!conn) {
+		cmd->reply = "Error finding RTP connection for delete";
+		return CTRL_CMD_ERROR;
+	}
+	cmd->reply = talloc_asprintf(cmd, "%s", conn->cname);
+
+	delete_connection(conn);
+
+	/* Respond */
+	return CTRL_CMD_REPLY;
+}
+
+
+
+
+
+int rtpsource_ctrl_cmds_install(void)
+{
+	int rc;
+
+	rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_create);
+	if (rc)
+		goto end;
+
+	rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_connect);
+	if (rc)
+		goto end;
+
+	rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_delete);
+	if (rc)
+		goto end;
+end:
+	return rc;
+}
diff --git a/rtpsource/internal.h b/rtpsource/internal.h
new file mode 100644
index 0000000..788b695
--- /dev/null
+++ b/rtpsource/internal.h
@@ -0,0 +1,46 @@
+#pragma once
+#include <stdint.h>
+#include <stdlib.h>
+#include <osmocom/trau/osmo_ortp.h>
+#include <osmocom/ctrl/control_if.h>
+
+enum {
+	DMAIN,
+};
+
+struct rtp_connection {
+	struct llist_head list;
+
+	struct osmo_rtp_socket *rtp_sock;
+	char *cname;
+
+	char *local_host;
+	uint16_t local_port;
+
+	char *remote_host;
+	uint16_t remote_port;
+
+	uint8_t rtp_pt;
+};
+
+struct rtpsource_state {
+	struct llist_head connections;
+	struct osmo_fd timer_ofd;
+	struct ctrl_handle *ctrl;
+};
+extern struct rtpsource_state *g_rss;
+
+struct rtp_connection *find_connection_by_cname(struct rtpsource_state *rss, const char *cname);
+
+struct rtp_connection *create_connection(struct rtpsource_state *rss, const char *cname);
+
+int connect_connection(struct rtp_connection *conn, const char *remote_host,
+			uint16_t remote_port, uint8_t pt);
+
+void delete_connection(struct rtp_connection *conn);
+
+
+int rtpsource_ctrl_cmds_install(void);
+
+#define CLOGP(conn, subsys, lvl, fmt, args ...) \
+	LOGP(subsys, lvl, "[%s]: " fmt, (conn)->cname, ## args)
diff --git a/rtpsource/rtpsource.c b/rtpsource/rtpsource.c
new file mode 100644
index 0000000..7eb39ad
--- /dev/null
+++ b/rtpsource/rtpsource.c
@@ -0,0 +1,246 @@
+/* rtpsource program: RTP load generator
+ *
+ * This program binds a CTRL interface to 127.0.0.1:11111 and waits for
+ * an external entity to issue CTRL commands, such as rtp_create, rtp_connect
+ * and rtp_delete.  Those commands are used to create+bind, connect and destroy
+ * local RTP connections.
+ *
+ * Each connection will send a RTP frame with dummy payload every 20ms.
+ *
+ * This is useful for load testing scenarios
+ *
+ * (C) 2020 by Harald Welte <laforge at gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/signal.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/stats.h>
+#include <osmocom/core/fsm.h>
+
+#include <osmocom/ctrl/control_if.h>
+
+#include <osmocom/trau/osmo_ortp.h>
+
+#include "internal.h"
+
+
+/* find a connection based on its CNAME */
+struct rtp_connection *find_connection_by_cname(struct rtpsource_state *rss, const char *cname)
+{
+	struct rtp_connection *conn;
+	llist_for_each_entry(conn, &rss->connections, list) {
+		if (!strcmp(cname, conn->cname))
+			return conn;
+	}
+	return NULL;
+}
+
+/* create a new RTP connection for given CNAME; includes binding of local RTP port */
+struct rtp_connection *create_connection(struct rtpsource_state *rss, const char *cname)
+{
+	struct rtp_connection *conn;
+	const char *host;
+	int port;
+	int rc;
+
+	OSMO_ASSERT(!find_connection_by_cname(rss, cname));
+
+	conn = talloc_zero(rss, struct rtp_connection);
+	OSMO_ASSERT(conn);
+	conn->cname = talloc_strdup(conn, cname);
+
+	conn->rtp_sock = osmo_rtp_socket_create(conn, OSMO_RTP_F_POLL);
+	OSMO_ASSERT(conn->rtp_sock);
+
+	rc = osmo_rtp_socket_bind(conn->rtp_sock, "127.23.23.23", -1);
+	OSMO_ASSERT(rc == 0);
+
+	rc = osmo_rtp_get_bound_addr(conn->rtp_sock, &host, &port);
+	OSMO_ASSERT(rc == 0);
+	OSMO_ASSERT(port >= 0 && port <= 0xffff);
+	conn->local_port = port;
+	conn->local_host = talloc_strdup(conn, host);
+
+	osmo_rtp_set_source_desc(conn->rtp_sock, conn->cname, "rtpsource", NULL, NULL,
+				 NULL, "osmo-rtpsource", NULL);
+
+	llist_add_tail(&conn->list, &rss->connections);
+
+	CLOGP(conn, DMAIN, LOGL_INFO, "Created RTP connection; local=%s:%u\n",
+		conn->local_host, conn->local_port);
+
+
+	return conn;
+}
+
+/* connect a RTP connection to a given remote peer */
+int connect_connection(struct rtp_connection *conn, const char *remote_host,
+			uint16_t remote_port, uint8_t pt)
+{
+	int rc;
+
+	conn->remote_host = talloc_strdup(conn, remote_host);
+	conn->remote_port = remote_port;
+	conn->rtp_pt = pt;
+
+	rc = osmo_rtp_socket_connect(conn->rtp_sock, conn->remote_host, conn->remote_port);
+	OSMO_ASSERT(rc == 0);
+	rc = osmo_rtp_socket_set_pt(conn->rtp_sock, conn->rtp_pt);
+	OSMO_ASSERT(rc == 0);
+
+	CLOGP(conn, DMAIN, LOGL_INFO, "Connected RTP connection; remote=%s:%u\n",
+		conn->remote_host, conn->remote_port);
+
+	return 0;
+}
+
+/* delete a RTP connection */
+void delete_connection(struct rtp_connection *conn)
+{
+	char *prefix = talloc_asprintf(conn, "[%s]: STATS: ", conn->cname);
+	osmo_rtp_socket_log_stats(conn->rtp_sock, DMAIN, LOGL_INFO, prefix);
+	talloc_free(prefix);
+	osmo_rtp_socket_free(conn->rtp_sock);
+	conn->rtp_sock = NULL;
+
+	CLOGP(conn, DMAIN, LOGL_INFO, "Deleted RTP connection\n");
+
+	llist_del(&conn->list);
+	talloc_free(conn);
+}
+
+
+
+
+/* called every 20ms at timerfd expiration */
+static int timerfd_cb(struct osmo_fd *ofd, unsigned int priv_nr)
+{
+	struct rtpsource_state *rss = ofd->data;
+	struct rtp_connection *conn;
+	uint64_t expire_count;
+	int rc;
+
+	/* read from timerfd: number of expirations of periodic timer */
+	rc = read(ofd->fd, (void *) &expire_count, sizeof(expire_count));
+	if (rc < 0 && errno == EAGAIN)
+		return 0;
+
+	if (expire_count > 1)
+		LOGP(DMAIN, LOGL_ERROR, "Timer expire_count=%"PRIu64" != 1\n", expire_count);
+
+	/* iterate over all RTP connections and send one frame each */
+	llist_for_each_entry(conn, &rss->connections, list) {
+		int i;
+		/* TODO: have different sources (file+name, ...) */
+		const uint8_t payload[33];
+		osmo_rtp_send_frame_ext(conn->rtp_sock, payload, sizeof(payload), 160, false);
+		/* make sure RTP clock advances correctly, even if we missed transmit of some */
+		for (i = 1; i < expire_count; i++)
+			osmo_rtp_skipped_frame(conn->rtp_sock, 160);
+	}
+	return 0;
+}
+
+static const struct log_info_cat rtpsource_cat[] = {
+	[DMAIN] = {
+		.name = "DMAIN",
+		.description ="Main Program",
+		.enabled = 1,
+		.loglevel = LOGL_INFO,
+	},
+};
+
+const struct log_info rtpsource_log_info = {
+	.filter_fn = NULL,
+	.cat = rtpsource_cat,
+	.num_cat = ARRAY_SIZE(rtpsource_cat),
+};
+
+struct rtpsource_state *g_rss;
+static void *g_tall_ctx;
+
+static void signal_handler(int signal)
+{
+	switch (signal) {
+	case SIGABRT:
+		/* in case of abort, we want to obtain a talloc report
+		 * and then return to the caller, who will abort the process */
+	case SIGUSR1:
+		talloc_report_full(g_tall_ctx, stderr);
+		break;
+	default:
+		break;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	struct timespec interval = {
+		.tv_sec = 0,
+		.tv_nsec = 20*1000*1000, /* every 20ms */
+	};
+	int rc;
+
+	signal(SIGUSR1, &signal_handler);
+	signal(SIGABRT, &signal_handler);
+
+	talloc_enable_null_tracking();
+	g_tall_ctx = talloc_named_const(NULL, 1, "rtpsource");
+	OSMO_ASSERT(g_tall_ctx);
+
+	msgb_talloc_ctx_init(g_tall_ctx, 0);
+	//osmo_signal_talloc_ctx_init(g_tall_ctx);
+	osmo_init_logging2(g_tall_ctx, &rtpsource_log_info);
+	osmo_fsm_log_timeouts(true);
+	osmo_fsm_log_addr(true);
+	osmo_stats_init(g_tall_ctx);
+	osmo_rtp_init(g_tall_ctx);
+
+	g_rss = talloc_zero(g_tall_ctx, struct rtpsource_state);
+	OSMO_ASSERT(g_rss);
+	INIT_LLIST_HEAD(&g_rss->connections);
+
+	/* Create CTRL interface */
+	//g_rss->ctrl = ctrl_interface_setup_dynip(g_rss, ctrl_vty_get_bind_addr(), 11111, NULL);
+	g_rss->ctrl = ctrl_interface_setup_dynip(g_rss, "127.0.0.1", 11111, NULL);
+	OSMO_ASSERT(g_rss->ctrl);
+	rc = rtpsource_ctrl_cmds_install();
+	OSMO_ASSERT(rc == 0);
+
+	/* create + register timerfd to expire every 20ms */
+	g_rss->timer_ofd.fd = -1;
+	rc = osmo_timerfd_setup(&g_rss->timer_ofd, timerfd_cb, g_rss);
+	OSMO_ASSERT(rc == 0);
+
+	rc = osmo_timerfd_schedule(&g_rss->timer_ofd, NULL, &interval);
+	OSMO_ASSERT(rc == 0);
+
+	while (1) {
+		osmo_select_main(0);
+	}
+}

-- 
To view, visit https://gerrit.osmocom.org/c/mncc-python/+/17402
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: mncc-python
Gerrit-Branch: master
Gerrit-Change-Id: Id4e292ddfd5aa58754382b2380558993b2ddf07a
Gerrit-Change-Number: 17402
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge at osmocom.org>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200306/5a036de4/attachment.htm>


More information about the gerrit-log mailing list