Calling zsock_poll() with TCP and UDP sockets

Hi,

I have faced dificulties calling zsock_poll for ZSOCK_POLLIN with multiple opened sockets, expecially when conbined TCP and UDP at the same time. My goal is it poll for incoming data on these sockets.

I tried following scenarious:

  1. zsock_poll() is seperate thread, polling TCP socket + eventfd file descriptor - no issues 
  2. zsock_poll() is seperate thread, polling UTP socket + eventfd file descriptor - no issues 
  3. zsock_poll() is seperate thread, polling TCP socket + UDP socket + eventfd file descriptor - zsock_poll returns error, errno operation not permitted

After that I tried to create seperate thread, one for TCP socket, the second one for UDP socket. This works only partially, zsock_poll() does not return error, but the issue is that call in not canceled immediately after data is receieved, but after timeout expires - ZSOCK_POLLIN is detected. For example if I set timeout to 10 seconds and modem receives data during this period, function detects ZSOCK_POLLIN after 10 seconds, not immidietly.

My setup:

  • nRF9151DK
  • nrf-sdk version 3.0.2
  • modem FW version 2.0.2

static void recv_proxy_thread_func(void *p1, void *p2, void *p3)
{
	enum {
		SOCK = 0,
		EVENT_FD = SLM_MAX_SOCKET_COUNT,
		FD_COUNT
	};

	int ret, err;
	struct zsock_pollfd poll_fds[FD_COUNT];

	enum recv_proxy_type recv_proxy_type = (enum recv_proxy_type) p1;
	int *efd = (int*) p2;
	int timeout = MSEC_PER_SEC * (recv_proxy_type == TCP_RECV_PROXY ? CONFIG_SLM_TCP_POLL_TIME : CONFIG_SLM_UDP_POLL_TIME);

	ARG_UNUSED(p3);

	poll_fds[EVENT_FD].fd = *efd;
	poll_fds[EVENT_FD].events = ZSOCK_POLLIN;

	do {
		// Create list of sockets which should be polled
		err = k_mutex_lock(&recv_proxy_buffer_mtx, K_FOREVER);
		if (err) {
			LOG_ERR("Unable to lock recv_proxy_buffer_mtx");
			continue;
		}
		for (int i = 0; i < SLM_MAX_SOCKET_COUNT; i++) {
			if (recv_proxy_type == TCP_RECV_PROXY && socks[i].fd != INVALID_SOCKET && socks[i].type == SOCK_STREAM) {
				poll_fds[i].fd = socks[i].fd;
				poll_fds[i].events = ZSOCK_POLLIN;
			} else if (recv_proxy_type == UDP_RECV_PROXY && socks[i].fd != INVALID_SOCKET && socks[i].type == SOCK_DGRAM) {
				poll_fds[i].fd = socks[i].fd;
				poll_fds[i].events = ZSOCK_POLLIN;
			} else {
				poll_fds[i].fd = INVALID_SOCKET;
				poll_fds[i].events = 0;
			}
		}
		err = k_mutex_unlock(&recv_proxy_buffer_mtx);
		if (err) {
			LOG_ERR("Unable to unlock recv_proxy_buffer_mtx");
		}
		
		ret = zsock_poll(poll_fds, ARRAY_SIZE(poll_fds), timeout);
		if (ret < 0) {  /* IO error */
			LOG_WRN("poll() error: %d, errno %d", ret, errno);
			continue;
		}
		if (ret == 0) {  /* timeout */
			continue;
		}
		for (int i = 0; i < SLM_MAX_SOCKET_COUNT; i++) {
			LOG_DBG("sock %d events 0x%08x", poll_fds[i].fd, poll_fds[i].revents);
		}
		LOG_DBG("efd events 0x%08x", poll_fds[EVENT_FD].revents);
		// Check for POLLIN on all available sockets
		for (int i = 0; i < SLM_MAX_SOCKET_COUNT; i++) {
			if ((poll_fds[i].revents & ZSOCK_POLLIN) != 0) {
				do_recv_proxy_recv_packet(i);
			}
			else if ((poll_fds[i].revents & ZSOCK_POLLERR) != 0) {
				int value;
				socklen_t len = sizeof(int);

				ret = zsock_getsockopt(poll_fds[i].fd, SOL_SOCKET, SO_ERROR, &value, &len);
				if (ret) {
					LOG_ERR("%d : getsockopt(SO_ERROR) error: %d", poll_fds[i].fd, -errno);
					ret = -EIO;
				} else {
					LOG_WRN("%d : POLLERR", poll_fds[i].fd);
					ret = -EIO;
				}
			}
			else if ((poll_fds[i].revents & ZSOCK_POLLHUP) != 0) {
				/* Lose LTE connection / remote end close */
				LOG_WRN("%d : POLLHUP", poll_fds[i].fd);
				ret = -ECONNRESET;
			}
		}
		/* Events from commands. */
		if ((poll_fds[EVENT_FD].revents & ZSOCK_POLLIN) != 0) {
			LOG_DBG("Terminate thread");
			ret = 0;
			break;
		}
	} while(1);

	safe_close_proxy_efd(efd);
	LOG_INF("Thread terminated");
}

Parents
  • Hello,

    faced dificulties calling zsock_poll for ZSOCK_POLLIN with multiple opened sockets

    How many opened sockets do you have? Please note that the modem supports a maximum number of raw sockets is 4.

    Do you have any logs that you can share with the error? 

    Is the provided function from nRF Connect SDK or your own? If the former, did you change anything i.e. add more functionality? 

    I will have a look at this and get back to you by end of tomorrow.

    Kind regards,
    Øyvind

  • Hi,
    zsock_poll() is function from nRF Connect SDK (respectivelly from plain zephyr and it most likely calls nrf_poll() internally). According to documentation, this function should mimic POSIX poll() function.

    My minimal examples used 2 sockets (1 UDP, 1 TCP) so I should not reach the limit. 

    I will upload the logs later today.

Reply Children
No Data
Related