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:
- zsock_poll() is seperate thread, polling TCP socket + eventfd file descriptor - no issues
- zsock_poll() is seperate thread, polling UTP socket + eventfd file descriptor - no issues
- 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");
}