From: Florian Schmidt Date: Mon, 20 May 2019 11:29:51 +0000 (+0200) Subject: Provide poll() and select() wrappers around lwip versions X-Git-Tag: RELEASE-0.4~65 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=6a316c1b659642912fe8d1f88ed0e39a59d9aa22;p=unikraft%2Flibs%2Flwip.git Provide poll() and select() wrappers around lwip versions This takes the vfscore-provided file descriptors, translates them into lwip file descriptors, and will run the lwip versions on those sockets. If any of the file descriptors provided isn't an LWIP socket, the call will fail with a return of -1, errno EBADF. Signed-off-by: Florian Schmidt Reviewed-by: Felipe Huici --- diff --git a/exportsyms.uk b/exportsyms.uk index b17b5e1..1720e00 100644 --- a/exportsyms.uk +++ b/exportsyms.uk @@ -9,7 +9,7 @@ listen lwip_ioctl lwip_htonl lwip_htons -lwip_select +poll recv recvfrom select diff --git a/patches/0002-Don-t-provide-file-status-flags-when-we-have-a-libc.patch b/patches/0002-Don-t-provide-file-status-flags-when-we-have-a-libc.patch index eb0da0f..34a4238 100644 --- a/patches/0002-Don-t-provide-file-status-flags-when-we-have-a-libc.patch +++ b/patches/0002-Don-t-provide-file-status-flags-when-we-have-a-libc.patch @@ -17,30 +17,30 @@ index d70d36c4..72169cd0 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -39,6 +39,8 @@ - #ifndef LWIP_HDR_SOCKETS_H - #define LWIP_HDR_SOCKETS_H - -+#include -+ - #include "lwip/opt.h" - - #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -@@ -438,6 +440,7 @@ typedef struct ipv6_mreq { - #define F_SETFL 4 - #endif - -+#ifndef CONFIG_HAVE_LIBC - /* File status flags and file access modes for fnctl, - these are bits in an int. */ - #ifndef O_NONBLOCK -@@ -455,6 +458,7 @@ typedef struct ipv6_mreq { - #ifndef O_RDWR - #define O_RDWR (O_RDONLY|O_WRONLY) - #endif -+#endif /* CONFIG_HAVE_LIBC */ - - #ifndef SHUT_RD - #define SHUT_RD 0 + #ifndef LWIP_HDR_SOCKETS_H + #define LWIP_HDR_SOCKETS_H + ++#include ++ + #include "lwip/opt.h" + + #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +@@ -438,6 +440,7 @@ typedef struct ipv6_mreq { + #define F_SETFL 4 + #endif + ++#ifndef CONFIG_HAVE_LIBC + /* File status flags and file access modes for fnctl, + these are bits in an int. */ + #ifndef O_NONBLOCK +@@ -455,6 +458,7 @@ typedef struct ipv6_mreq { + #ifndef O_RDWR + #define O_RDWR (O_RDONLY|O_WRONLY) + #endif ++#endif /* CONFIG_HAVE_LIBC */ + + #ifndef SHUT_RD + #define SHUT_RD 0 -- 2.21.0 diff --git a/sockets.c b/sockets.c index b2a65bb..9ad5cfb 100644 --- a/sockets.c +++ b/sockets.c @@ -333,6 +333,143 @@ EXIT: return ret; } +int poll(struct pollfd fds[], nfds_t nfds, int timeout) +{ + unsigned int i; + struct sock_net_file *file; + struct pollfd lwip_fds[nfds]; + + for (i = 0; i < nfds; i++) { + if (fds[i].fd < 0) + lwip_fds[i].fd = fds[i].fd; + else { + file = sock_net_file_get(fds[i].fd); + if (PTRISERR(file)) { + LWIP_DEBUGF(SOCKETS_DEBUG, + ("failed to identify socket descriptor\n")); + /* Setting the errno */ + SOCK_NET_SET_ERRNO(PTR2ERR(file)); + return -1; + } + lwip_fds[i].fd = file->sock_fd; + lwip_fds[i].events = fds[i].events; + } + } + + lwip_poll(lwip_fds, nfds, timeout); + + for (i = 0; i < nfds; i++) { + if (fds[i].fd < 0) + fds[i].revents = 0; + else + fds[i].revents = lwip_fds[i].revents; + } + return 0; +} + +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + uint64_t nsecs; + fd_set rd, wr, xc; + int i, ret, maxfd; + struct sock_net_file *file; + + if (nfds == 0 && timeout != NULL) { + nsecs = timeout->tv_sec * 1000000000; + nsecs += timeout->tv_usec * 1000; + uk_sched_thread_sleep(nsecs); + return 0; + } + + /* translate the public (vfscore) fds into lwIP socket fds */ + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&xc); + maxfd = 0; + for (i = 0; i < nfds; i++) { + if (readfds && FD_ISSET(i, readfds)) { + maxfd = i; + file = sock_net_file_get(i); + if (PTRISERR(file)) { + LWIP_DEBUGF(SOCKETS_DEBUG, + ("failed to identify socket descriptor\n")); + ret = -1; + /* Setting the errno */ + SOCK_NET_SET_ERRNO(PTR2ERR(file)); + goto EXIT; + } + FD_SET(file->sock_fd, &rd); + } + if (writefds && FD_ISSET(i, writefds)) { + maxfd = i; + file = sock_net_file_get(i); + if (PTRISERR(file)) { + LWIP_DEBUGF(SOCKETS_DEBUG, + ("failed to identify socket descriptor\n")); + ret = -1; + /* Setting the errno */ + SOCK_NET_SET_ERRNO(PTR2ERR(file)); + goto EXIT; + } + FD_SET(file->sock_fd, &wr); + } + if (exceptfds && FD_ISSET(i, exceptfds)) { + maxfd = i; + file = sock_net_file_get(i); + if (PTRISERR(file)) { + LWIP_DEBUGF(SOCKETS_DEBUG, + ("failed to identify socket descriptor\n")); + ret = -1; + /* Setting the errno */ + SOCK_NET_SET_ERRNO(PTR2ERR(file)); + goto EXIT; + } + FD_SET(file->sock_fd, &xc); + } + } + + ret = lwip_select(maxfd+1, &rd, &wr, &xc, timeout); + if (ret < 0) + return ret; + + /* translate back from lwIP socket fds to public (vfscore) fds. + * But there's no way to go from lwIP to vfscore, so iterate over + * everything again. Check which ones were set originally, and if + * they aren't also set in lwip_select()'s return, clear them. + */ + for (i = 0; i < nfds; i++) { + if (readfds && FD_ISSET(i, readfds)) { + /* This lookup can't fail, or it would already have + * failed during the translation above. + */ + file = sock_net_file_get(i); + if (!FD_ISSET(file->sock_fd, &rd)) + FD_CLR(i, readfds); + } + if (writefds && FD_ISSET(i, writefds)) { + /* This lookup can't fail, or it would already have + * failed during the translation above. + */ + file = sock_net_file_get(i); + if (!FD_ISSET(file->sock_fd, &wr)) + FD_CLR(i, writefds); + } + if (exceptfds && FD_ISSET(i, exceptfds)) { + /* This lookup can't fail, or it would already have + * failed during the translation above. + */ + file = sock_net_file_get(i); + if (!FD_ISSET(file->sock_fd, &xc)) + FD_CLR(i, exceptfds); + } + } + return 0; + +EXIT: + return ret; +} + int shutdown(int s, int how) { int ret = 0;