diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h index f9050075c..7a4890063 100644 --- a/ports/include/noux_session/noux_session.h +++ b/ports/include/noux_session/noux_session.h @@ -66,6 +66,7 @@ namespace Noux { SYSCALL_SEND, SYSCALL_SENDTO, SYSCALL_RECV, + SYSCALL_RECVFROM, SYSCALL_GETPEERNAME, SYSCALL_SHUTDOWN, SYSCALL_CONNECT, @@ -108,6 +109,7 @@ namespace Noux { NOUX_DECL_SYSCALL_NAME(SEND) NOUX_DECL_SYSCALL_NAME(SENDTO) NOUX_DECL_SYSCALL_NAME(RECV) + NOUX_DECL_SYSCALL_NAME(RECVFROM) NOUX_DECL_SYSCALL_NAME(GETPEERNAME) NOUX_DECL_SYSCALL_NAME(SHUTDOWN) NOUX_DECL_SYSCALL_NAME(CONNECT) diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index 12fb5bb91..753afd9c8 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -380,6 +380,10 @@ namespace Noux { SYSIO_DECL(recv, { int fd; Chunk buf; size_t len; int flags; }, { size_t len; }); + SYSIO_DECL(recvfrom, { int fd; Chunk buf; size_t len; int flags; + struct sockaddr src_addr; socklen_t addrlen; }, + { size_t len; }); + SYSIO_DECL(shutdown, { int fd; int how; }, { }); SYSIO_DECL(connect, { int fd; struct sockaddr addr; socklen_t addrlen; }, diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 9c719eb8c..6d0a08aab 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -583,6 +583,8 @@ namespace { ssize_t sendto(Libc::File_descriptor *, const void *, size_t, int, const struct sockaddr *, socklen_t); ssize_t recv(Libc::File_descriptor *, void *, ::size_t, int); + ssize_t recvfrom(Libc::File_descriptor *, void *, ::size_t, int, + struct sockaddr *, socklen_t*); int getsockopt(Libc::File_descriptor *, int, int, void *, socklen_t *); int setsockopt(Libc::File_descriptor *, int , int , const void *, @@ -1324,9 +1326,9 @@ namespace { return -1; } - Genode::memcpy(buf, sysio()->recv_in.buf, sysio()->recv_in.len); + Genode::memcpy(buf, sysio()->recv_in.buf, sysio()->recv_out.len); - sum_recv_count += sysio()->recv_in.len; + sum_recv_count += sysio()->recv_out.len; if (sysio()->recv_out.len < sysio()->recv_in.len) break; @@ -1341,6 +1343,50 @@ namespace { } + ssize_t Plugin::recvfrom(Libc::File_descriptor *fd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) + { + Genode::size_t sum_recvfrom_count = 0; + + + while (len) { + Genode::size_t curr_len = Genode::min(len, sizeof(sysio()->recvfrom_in.buf)); + + sysio()->recv_in.fd = noux_fd(fd->context); + sysio()->recv_in.len = curr_len; + + if (addrlen == NULL) + sysio()->recvfrom_in.addrlen = 0; + else + sysio()->recvfrom_in.addrlen = *addrlen; + + if (!noux()->syscall(Noux::Session::SYSCALL_RECVFROM)) { + /* XXX set errno */ + return -1; + } + + if (src_addr != NULL && addrlen != NULL) + Genode::memcpy(src_addr, &sysio()->recvfrom_in.src_addr, + sysio()->recvfrom_in.addrlen); + + + Genode::memcpy(buf, sysio()->recvfrom_in.buf, sysio()->recvfrom_out.len); + + sum_recvfrom_count += sysio()->recvfrom_out.len; + + if (sysio()->recvfrom_out.len < sysio()->recvfrom_in.len) + break; + + if (sysio()->recvfrom_out.len <= len) + len -= sysio()->recvfrom_out.len; + else + break; + } + + return sum_recvfrom_count; + } + + ssize_t Plugin::send(Libc::File_descriptor *fd, const void *buf, ::size_t len, int flags) { /* remember original len for the return value */ diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index eddbe8148..37ac92339 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -483,6 +483,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) case SYSCALL_SEND: case SYSCALL_SENDTO: case SYSCALL_RECV: + case SYSCALL_RECVFROM: case SYSCALL_GETPEERNAME: case SYSCALL_SHUTDOWN: case SYSCALL_CONNECT: diff --git a/ports/src/noux/net/net.cc b/ports/src/noux/net/net.cc index e5a962470..bdf5402c8 100644 --- a/ports/src/noux/net/net.cc +++ b/ports/src/noux/net/net.cc @@ -267,6 +267,19 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) _sysio->recv_out.len = len; + return true; + } + case SYSCALL_RECVFROM: + { + GET_SOCKET_IO_CHANNEL(_sysio->recvfrom_in.fd, socket_io_channel) + + ssize_t len = socket_io_channel->recvfrom(_sysio); + + if (len == -1) + return false; + + _sysio->recvfrom_out.len = len; + return true; } case SYSCALL_GETPEERNAME: diff --git a/ports/src/noux/net/socket_io_channel.h b/ports/src/noux/net/socket_io_channel.h index af91e796b..618cb8a9c 100644 --- a/ports/src/noux/net/socket_io_channel.h +++ b/ports/src/noux/net/socket_io_channel.h @@ -241,6 +241,15 @@ namespace Noux { sysio->recv_in.flags); } + ssize_t recvfrom(Sysio *sysio) + { + ssize_t result = ::recvfrom(_socket, sysio->recv_in.buf, sysio->recv_in.len, + sysio->recv_in.flags, (struct sockaddr *)&sysio->recvfrom_in.src_addr, + &sysio->recvfrom_in.addrlen); + + return result; + } + ssize_t send(Sysio *sysio) { return ::send(_socket, sysio->send_in.buf, sysio->send_in.len,