[EVL] Client UDP not receiving data

Hannes Diethelm <[email protected]>
Newsgroups dev.linux.lists.xenomai
Message-ID <[email protected]>
Hello

I have issue porting an application that runs as an UDP client to OOB networking.

The standard client pattern:
-connect
-oob_sendmsg
-oob_recvmsg
does not work.

In Wireshark, i see the packages going out and returning with the correct ip/port
but oob_recvmsg() doesn't return.

To debug, I modified the oob-net-udp example, attached. Additionally, I ported it back
to posix networking where it works as expected.

Send only mode / receive with bind works well.

Config:
Debian Trixie
linux-evl v6.12.y-cip-evl-rebase 569beef0
libevl r57 877d5ca

Regards
Hannes
oob-net-udp.c (text/x-csrc, 7.4 KB)
/*
 * SPDX-License-Identifier: MIT
 *
 * This tidbit demonstrates out-of-band networking, by
 * sending[-S]/receiving[-R] UDP packets to/from a particular IP
 * address[-a] and port[-p].
 *
 * See https://v4.xenomai.org/core/net/ for details.
 */

#include <pthread.h>
#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <getopt.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <evl/thread.h>
#include <evl/clock.h>
#include <evl/proxy.h>
#include <evl/net/net.h>

static int verbosity = 1;

static void usage(void)
{
	fprintf(stderr, "oob-net-udp -a <IP-address> [-p <port>]"
		"[-m <text>][-n <msgcount>][-I <iterations>][-i <interface>]"
		"[-d][-s][-R|-S][-b]\n");
}

static void print_addr(char* desc, struct sockaddr_in *addr){
    char ip_str[INET_ADDRSTRLEN+1]; // Puffer für die IP-Adresse
    inet_ntop(AF_INET, &(addr->sin_addr), ip_str, sizeof(ip_str));
    evl_printf("--------%s--------\n", desc);
    evl_printf("IP-Adresse: %s\n", ip_str);
    evl_printf("Port:       %d\n", ntohs(addr->sin_port));
    evl_printf("Family:     %d\n", ntohs(addr->sin_family));
}

static void sender(int s, const char *text, int mcount,
		struct sockaddr_in *addr, int iter)
{
	struct oob_msghdr msghdr;
	struct iovec iov;
	int n, tlen;
	ssize_t ret;
	char *tbuf;

	tlen = (strlen(text) + 1) * mcount;
	tbuf = malloc(tlen);
	if (!tbuf)
		error(1, ENOMEM, "cannot create message");

	*tbuf = '\0';
	for (n = 0; n < mcount; n++)
		strcat(tbuf, text); /* yep, lazy.. */

	for (n = 0; !iter || n < iter; n++) {
		iov.iov_base = tbuf;
		iov.iov_len = tlen;
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = addr;
		msghdr.msg_namelen = sizeof(*addr);
		msghdr.msg_flags = 0;
		ret = oob_sendmsg(s, &msghdr, NULL, 0);
		if (ret < 0)
			error(1, errno, "oob_sendmsg() failed");

		evl_usleep(1000000);
	}
}

static void client(int s, const char *text, int mcount,
		struct sockaddr_in *addr, int iter)
{
	struct sockaddr_in _addr;
	socklen_t len = sizeof(_addr);
	struct oob_msghdr msghdr;
	struct iovec iov;
	int n, tlen;
	ssize_t ret;
	char *tbuf;
	char rbuf[16384];

	tlen = (strlen(text) + 1) * mcount;
	tbuf = malloc(tlen);
	if (!tbuf)
		error(1, ENOMEM, "cannot create message");

	*tbuf = '\0';
	for (n = 0; n < mcount; n++)
		strcat(tbuf, text); /* yep, lazy.. */

	ret = connect(s, (struct sockaddr *)addr, sizeof(*addr));
	if (ret < 0)
		error(1, errno, "connect() failed");

	print_addr("tx", addr);

	ret = getsockname(s, (struct sockaddr *)&_addr, &len);
	if (ret < 0)
		error(1, errno, "getsockname() failed");

	print_addr("rx", &_addr);

	for (n = 0; !iter || n < iter; n++) {
		iov.iov_base = tbuf;
		iov.iov_len = tlen;
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = addr;
		msghdr.msg_namelen = sizeof(*addr);
		msghdr.msg_flags = 0;
		ret = oob_sendmsg(s, &msghdr, NULL, 0);
		if (ret < 0)
			error(1, errno, "oob_sendmsg() failed");

		memset(rbuf, 0, sizeof(rbuf));
		iov.iov_base = rbuf;
		iov.iov_len = sizeof(rbuf);
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = &_addr;
		msghdr.msg_namelen = sizeof(_addr);
		msghdr.msg_flags = 0;
		ret = oob_recvmsg(s, &msghdr, NULL, 0);
		if (ret < 0)
			error(1, errno, "oob_recvmsg() failed");
		evl_printf("= %zd bytes received", ret);
		if (msghdr.msg_flags & MSG_TRUNC)
			evl_printf(" (TRUNCATED)");
		evl_printf(": %.*s\n", (int)ret, rbuf);
	}
}

static void receiver(int s, struct sockaddr_in *addr, int iter)
{
	struct sockaddr_in _addr;
	socklen_t len = sizeof(_addr);
	struct oob_msghdr msghdr;
	struct iovec iov;
	char rbuf[16384];
	ssize_t ret;
	int n;

	ret = bind(s, (struct sockaddr *)addr, sizeof(*addr));
	if (ret < 0)
		error(1, errno, "bind() failed");

	ret = getsockname(s, (struct sockaddr *)&_addr, &len);
	if (ret < 0)
		error(1, errno, "getsockname() failed");

	if (verbosity)
		printf("== bound to port %d\n", ntohs(_addr.sin_port));

	for (n = 0; !iter || n < iter; n++) {
		memset(rbuf, 0, sizeof(rbuf));
		iov.iov_base = rbuf;
		iov.iov_len = sizeof(rbuf);
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = &_addr;
		msghdr.msg_namelen = sizeof(_addr);
		msghdr.msg_flags = 0;
		ret = oob_recvmsg(s, &msghdr, NULL, 0);
		if (ret < 0)
			error(1, errno, "oob_recvmsg() failed");
		evl_printf("= %zd bytes received", ret);
		if (msghdr.msg_flags & MSG_TRUNC)
			evl_printf(" (TRUNCATED)");
		evl_printf(": %.*s\n", (int)ret, rbuf);
	}
}

int main(int argc, char *argv[])
{
	int tfd, s, c, mcount = 1, iter = 0, port = 42042, on = 1;
	const char *text = "Mellow sword!\n", *iface = NULL;
	bool send = false, bcast = false;
	struct sched_param param;
	struct sockaddr_in addr;
	const char *ip = NULL;
	ssize_t ret;

	while ((c = getopt(argc, argv, "a:m:n:i:I:p:dsRSb")) != EOF) {
		switch (c) {
		case 'a':
			ip = optarg;
			break;
		case 'd':
			verbosity = 2;
			break;
		case 's':
			verbosity = 0;
			break;
		case 'm':
			text = optarg;
			break;
		case 'n':
			mcount = atoi(optarg);
			break;
		case 'i':
			iface = optarg;
			break;
		case 'I':
			iter = atoi(optarg);
			break;
		case 'p':
			port = atoi(optarg);
			break;
		case 'b':
			bcast = true; /* Force mode, e.g. for directed broadcast */
			break;
		case 'R':
			send = false;
			break;
		case 'S':
			send = true;
			break;
		default:
			usage();
			exit(1);
		}
	}

	if (ip == NULL) {
		usage();
		exit(2);
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	if (!strcmp(ip, "broadcast")) {
		addr.sin_addr.s_addr = INADDR_BROADCAST;
		bcast = true;
	} else if (!inet_pton(AF_INET, ip, &addr.sin_addr)) {
		error(1, EINVAL, "invalid IP address");
	} else if (addr.sin_addr.s_addr == INADDR_BROADCAST) {
		bcast = true;
	}

	param.sched_priority = 1;
	ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
	if (ret)
		error(1, ret, "pthread_setschedparam()");

	tfd = evl_attach_self("oob-net-udp:%d", getpid());
	if (tfd < 0)
		error(1, -tfd, "cannot attach to the EVL core");

	/*
	 * Get an UDP socket with out-of-band capabilities.
	 */
	s = socket(AF_INET, SOCK_DGRAM | SOCK_OOB, 0);
	if (s < 0)
		error(1, errno, "cannot create out-of-band UDP socket");

	if (iface) {
		if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface)))
			error(1, errno, "setsockopt(SO_BINDTODEVICE)");
		if (verbosity)
			printf("== bound to %s\n", iface);
	}

	if (send) {
		if (bcast) {
			ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
			if (ret)
				error(1, errno, "cannot enable broadcast for UDP socket");
		}

		/*
		 * Guarantee a mere oob path from the first packet
		 * onward by pre-caching the route and link-layer
		 * address via an explicit neighbour solicitation
		 * before we start sending data.
		 */
		ret = evl_net_solicit(s, (const struct sockaddr *)&addr,
				EVL_NEIGH_PERMANENT);
		if (ret)
			error(1, -ret, "evl_net_solicit()");

		if (verbosity)
			printf("== sender mode (=> %s:%d)\n", bcast ? "[broadcast]" : ip, port);

		//sender(s, text, mcount, &addr, iter);
		client(s, text, mcount, &addr, iter);
	} else {
		if (verbosity)
			printf("== receiver mode (<= %s:%d)\n", ip, port);

		receiver(s, &addr, iter);
	}

	return 0;
}
net-udp.c (text/x-csrc, 7.6 KB)
/*
 * SPDX-License-Identifier: MIT
 *
 * This tidbit demonstrates out-of-band networking, by
 * sending[-S]/receiving[-R] UDP packets to/from a particular IP
 * address[-a] and port[-p].
 *
 * See https://v4.xenomai.org/core/net/ for details.
 */

#include <pthread.h>
#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <getopt.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <evl/thread.h>
#include <evl/clock.h>
#include <evl/proxy.h>
#include <evl/net/net.h>

static int verbosity = 1;

static void usage(void)
{
	fprintf(stderr, "oob-net-udp -a <IP-address> [-p <port>]"
		"[-m <text>][-n <msgcount>][-I <iterations>][-i <interface>]"
		"[-d][-s][-R|-S][-b]\n");
}

static void print_addr(char* desc, struct sockaddr_in *addr){
    char ip_str[INET_ADDRSTRLEN+1]; // Puffer für die IP-Adresse
    inet_ntop(AF_INET, &(addr->sin_addr), ip_str, sizeof(ip_str));
    printf("--------%s--------\n", desc);
    printf("IP-Adresse: %s\n", ip_str);
    printf("Port:       %d\n", ntohs(addr->sin_port));
    printf("Family:     %d\n", ntohs(addr->sin_family));
}

static void sender(int s, const char *text, int mcount,
		struct sockaddr_in *addr, int iter)
{
	struct msghdr msghdr;
	struct iovec iov;
	int n, tlen;
	ssize_t ret;
	char *tbuf;

	tlen = (strlen(text) + 1) * mcount;
	tbuf = malloc(tlen);
	if (!tbuf)
		error(1, ENOMEM, "cannot create message");

	*tbuf = '\0';
	for (n = 0; n < mcount; n++)
		strcat(tbuf, text); /* yep, lazy.. */

	for (n = 0; !iter || n < iter; n++) {
		iov.iov_base = tbuf;
		iov.iov_len = tlen;
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = addr;
		msghdr.msg_namelen = sizeof(*addr);
		msghdr.msg_flags = 0;
		ret = sendmsg(s, &msghdr, 0);
		if (ret < 0)
			error(1, errno, "sendmsg() failed");

		usleep(1000000);
	}
}

static void client_msg(int s, const char *text, int mcount,
		struct sockaddr_in *addr, int iter)
{
	struct sockaddr_in _addr;
	socklen_t len = sizeof(_addr);
	struct msghdr msghdr;
	struct iovec iov;
	int n, tlen;
	ssize_t ret;
	char *tbuf;
	char rbuf[16384];

	tlen = (strlen(text) + 1) * mcount;
	tbuf = malloc(tlen);
	if (!tbuf)
		error(1, ENOMEM, "cannot create message");

	*tbuf = '\0';
	for (n = 0; n < mcount; n++)
		strcat(tbuf, text); /* yep, lazy.. */

	ret = connect(s, (struct sockaddr *)addr, sizeof(*addr));
	if (ret < 0)
		error(1, errno, "connect() failed");

	print_addr("tx", addr);

	ret = getsockname(s, (struct sockaddr *)&_addr, &len);
	if (ret < 0)
		error(1, errno, "getsockname() failed");

	print_addr("rx", &_addr);

	for (n = 0; !iter || n < iter; n++) {
		iov.iov_base = tbuf;
		iov.iov_len = tlen;
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = addr;
		msghdr.msg_namelen = sizeof(*addr);
		msghdr.msg_flags = 0;
		ret = sendmsg(s, &msghdr, 0);
		if (ret < 0)
			error(1, errno, "sendmsg() failed");

		memset(rbuf, 0, sizeof(rbuf));
		iov.iov_base = rbuf;
		iov.iov_len = sizeof(rbuf);
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = &_addr;
		msghdr.msg_namelen = sizeof(_addr);
		msghdr.msg_flags = 0;
		ret = recvmsg(s, &msghdr, 0);
		if (ret < 0)
			error(1, errno, "recvmsg() failed");
		printf("= %zd bytes received", ret);
		if (msghdr.msg_flags & MSG_TRUNC)
			printf(" (TRUNCATED)");
		printf(": %.*s\n", (int)ret, rbuf);
	}
}

static void client_sr(int s, const char *text, int mcount,
		struct sockaddr_in *addr, int iter)
{
	struct sockaddr_in _addr;
	socklen_t len = sizeof(_addr);
	int n, tlen;
	ssize_t ret;
	char *tbuf;
	char rbuf[16384];

	tlen = (strlen(text) + 1) * mcount;
	tbuf = malloc(tlen);
	if (!tbuf)
		error(1, ENOMEM, "cannot create message");

	*tbuf = '\0';
	for (n = 0; n < mcount; n++)
		strcat(tbuf, text); /* yep, lazy.. */

	ret = connect(s, (struct sockaddr *)addr, sizeof(*addr));
	if (ret < 0)
		error(1, errno, "connect() failed");

	print_addr("tx", addr);

	for (n = 0; !iter || n < iter; n++) {
		ret = send(s, tbuf, tlen, 0);
		if (ret < 0)
			error(1, errno, "sendmsg() failed");

		memset(rbuf, 0, sizeof(rbuf));
		ret = recv(s, rbuf, sizeof(rbuf), 0);
		if (ret < 0)
			error(1, errno, "recvmsg() failed");
		printf("= %zd bytes received", ret);
		printf(": %.*s\n", (int)ret, rbuf);
	}
}

static void receiver(int s, struct sockaddr_in *addr, int iter)
{
	struct sockaddr_in _addr;
	socklen_t len = sizeof(_addr);
	struct msghdr msghdr;
	struct iovec iov;
	char rbuf[16384];
	ssize_t ret;
	int n;

	ret = bind(s, (struct sockaddr *)addr, sizeof(*addr));
	if (ret < 0)
		error(1, errno, "bind() failed");

	ret = getsockname(s, (struct sockaddr *)&_addr, &len);
	if (ret < 0)
		error(1, errno, "getsockname() failed");

	if (verbosity)
		printf("== bound to port %d\n", ntohs(_addr.sin_port));

	for (n = 0; !iter || n < iter; n++) {
		memset(rbuf, 0, sizeof(rbuf));
		iov.iov_base = rbuf;
		iov.iov_len = sizeof(rbuf);
		msghdr.msg_iov = &iov;
		msghdr.msg_iovlen = 1;
		msghdr.msg_control = NULL;
		msghdr.msg_controllen = 0;
		msghdr.msg_name = &_addr;
		msghdr.msg_namelen = sizeof(_addr);
		msghdr.msg_flags = 0;
		ret = recvmsg(s, &msghdr, 0);
		if (ret < 0)
			error(1, errno, "recvmsg() failed");
		printf("= %zd bytes received", ret);
		if (msghdr.msg_flags & MSG_TRUNC)
			printf(" (TRUNCATED)");
		printf(": %.*s\n", (int)ret, rbuf);
	}
}

int main(int argc, char *argv[])
{
	int s, c, mcount = 1, iter = 0, port = 42042, on = 1;
	const char *text = "Mellow sword!\n", *iface = NULL;
	bool send = false, bcast = false;
	struct sockaddr_in addr;
	const char *ip = NULL;
	ssize_t ret;

	while ((c = getopt(argc, argv, "a:m:n:i:I:p:dsRSb")) != EOF) {
		switch (c) {
		case 'a':
			ip = optarg;
			break;
		case 'd':
			verbosity = 2;
			break;
		case 's':
			verbosity = 0;
			break;
		case 'm':
			text = optarg;
			break;
		case 'n':
			mcount = atoi(optarg);
			break;
		case 'i':
			iface = optarg;
			break;
		case 'I':
			iter = atoi(optarg);
			break;
		case 'p':
			port = atoi(optarg);
			break;
		case 'b':
			bcast = true; /* Force mode, e.g. for directed broadcast */
			break;
		case 'R':
			send = false;
			break;
		case 'S':
			send = true;
			break;
		default:
			usage();
			exit(1);
		}
	}

	if (ip == NULL) {
		usage();
		exit(2);
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	if (!strcmp(ip, "broadcast")) {
		addr.sin_addr.s_addr = INADDR_BROADCAST;
		bcast = true;
	} else if (!inet_pton(AF_INET, ip, &addr.sin_addr)) {
		error(1, EINVAL, "invalid IP address");
	} else if (addr.sin_addr.s_addr == INADDR_BROADCAST) {
		bcast = true;
	}

	/*
	 * Get an UDP socket with out-of-band capabilities.
	 */
	s = socket(AF_INET, SOCK_DGRAM | SOCK_OOB, 0);
	if (s < 0)
		error(1, errno, "cannot create out-of-band UDP socket");

	if (iface) {
		if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface)))
			error(1, errno, "setsockopt(SO_BINDTODEVICE)");
		if (verbosity)
			printf("== bound to %s\n", iface);
	}

	if (send) {
		if (bcast) {
			ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
			if (ret)
				error(1, errno, "cannot enable broadcast for UDP socket");
		}

		if (ret)
			error(1, -ret, "net_solicit()");

		if (verbosity)
			printf("== client mode (=> %s:%d)\n", bcast ? "[broadcast]" : ip, port);

		//sender(s, text, mcount, &addr, iter);
		client_msg(s, text, mcount, &addr, iter);
		//client_sr(s, text, mcount, &addr, iter);
	} else {
		if (verbosity)
			printf("== receiver mode (<= %s:%d)\n", ip, port);

		receiver(s, &addr, iter);
	}

	return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.