Hi, The attached patch is an attempt to support getting and setting buffer sizes in pflocal. A simple test case is also attached, with output inlined here. Limits are set on min and max buffer sizes, as on GNU/Linux, however not the same values. Additionally, setsockopt() does not return a buffer twice as big as requested as Linux does. Furthermore, the RPC for socket_setopt in socket.defs is wrong: The set value should be returned in parameter optval, see http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html and setsockopt(2). This can be fixed at a later time if needed.
Hurd output: ============ test_get+setsockopt.c:main(): domain = AF_UNIX type = SOCK_STREAM Socket sfd = 3 CASE: SO_RCVBUF main(): Requested: max_msg_size = 20480 set_sock_size_rcvbuf():getsockopt(SO_RCVBUF): optval=16384, optlen=4 set_sock_size_rcvbuf(): Requested: *max_msg_size = 20480 set_sock_size_rcvbuf():setsockopt(SO_RCVBUF): GNU/Hurd: S_sock_setopt RPC is wrong: No return value set_sock_size_rcvbuf: Checking set values set_sock_size_rcvbuf():getsockopt(SO_RCVBUF): optval=20480, optlen=4 main():set_sock_size_rcvbuf(): max_msg_size=20480 CASE: SO_SNDBUF main(): Requested: max_msg_size = 163840 set_sock_size_sndbuf():getsockopt(SO_SNDBUF): optval=20480, optlen=4 set_sock_size_sndbuf(): Requested: *max_msg_size = 163840 set_sock_size_sndbuf():setsockopt(SO_SNDBUF): GNU/Hurd: S_sock_setopt RPC is wrong: No return value set_sock_size_rsnduf: Checking set values set_sock_size_sndbuf():getsockopt(SO_SNDBUF): optval=163840, optlen=4 main():set_sock_size_sndbuf(): max_msg_size=163840 Linux output: ============= test_get+setsockopt.c:main(): domain = AF_UNIX type = SOCK_STREAM Socket sfd = 3 CASE: SO_RCVBUF main(): Requested: max_msg_size = 20480 set_sock_size_rcvbuf():getsockopt(SO_RCVBUF): optval=212992, optlen=4 set_sock_size_rcvbuf(): Requested: *max_msg_size = 20480 set_sock_size_rcvbuf():setsockopt(SO_RCVBUF): optval=20480, optlen=4 set_sock_size_rcvbuf(): Returned: optval = 20480 set_sock_size_rcvbuf: Checking set values set_sock_size_rcvbuf():getsockopt(SO_RCVBUF): optval=40960, optlen=4 main():set_sock_size_rcvbuf(): max_msg_size=40960 CASE: SO_SNDBUF main(): Requested: max_msg_size = 327680 set_sock_size_sndbuf():getsockopt(SO_SNDBUF): optval=212992, optlen=4 set_sock_size_sndbuf(): Requested: *max_msg_size = 327680 set_sock_size_sndbuf():setsockopt(SO_SNDBUF): optval=327680, optlen=4 set_sock_size_sndbuf(): Returned: optval = 327680 set_sock_size_rsnduf: Checking set values set_sock_size_sndbuf():getsockopt(SO_SNDBUF): optval=425984, optlen=4 main():set_sock_size_sndbuf(): max_msg_size=327680
/* gcc -g -Wall -o ./test_get+setsockopt ./test_get+setsockopt.c */ #define _GNU_SOURCE #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define TEST_GETSOCKOPT1 1 #define TEST_SETSOCKOPT1 1 #define TEST_GETSOCKOPT2 1 #define TEST_GETSOCKOPT3 1 #define TEST_SETSOCKOPT2 1 #define TEST_GETSOCKOPT4 1 #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) static int32_t set_sock_size_rcvbuf(int sockfd, int *max_msg_size) { unsigned int optval = 0; socklen_t optlen = sizeof(optval); error_t err = 0; #if TEST_GETSOCKOPT1 err = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); if (err) { printf ("set_sock_size_rcvbuf():getsockopt(SO_RCVBUF) failed: errno=%d (%s)\n", errno, strerror(errno)); printf ("set_sock_size_rcvbuf():getsockopt(SO_RCVBUF) failed: optval=%d, optlen=%d\n", optval, optlen); return err; } printf ("set_sock_size_rcvbuf():getsockopt(SO_RCVBUF): optval=%d, optlen=%d\n", optval, optlen); #endif #if TEST_SETSOCKOPT1 printf ("set_sock_size_rcvbuf(): Requested: *max_msg_size = %d\n", *max_msg_size); optval = *max_msg_size; optlen = sizeof(*max_msg_size); err = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &optval, optlen); if (err) { printf ("set_sock_size_rcvbuf():setsockopt(SO_RCVBUF) failed: errno=%d (%s)\n", errno, strerror(errno)); printf ("set_sock_size_rcvbuf():setsockopt(SO_RCVBUF) failed: optval=%d, *max_msg_size=%d\n", *max_msg_size, optlen); return err; } #ifdef __GNU__ printf ("set_sock_size_rcvbuf():setsockopt(SO_RCVBUF): GNU/Hurd: S_sock_setopt RPC is wrong: No return value\n"); #else printf ("set_sock_size_rcvbuf():setsockopt(SO_RCVBUF): optval=%d, optlen=%d\n", optval, optlen); printf ("set_sock_size_rcvbuf(): Returned: optval = %d\n", optval); #endif #endif #if TEST_GETSOCKOPT2 printf( "set_sock_size_rcvbuf: Checking set values\n"); err = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); if (err) { printf ("set_sock_size_rcvbuf():getsockopt(SO_RCVBUF) failed: errno=%d (%s)\n", errno, strerror(errno)); printf ("set_sock_size_rcvbuf():getsockopt(SO_RCVBUF) failed: optval=%d, optlen=%d\n", optval, optlen); return err; } printf ("set_sock_size_rcvbuf():getsockopt(SO_RCVBUF): optval=%d, optlen=%d\n", optval, optlen); *max_msg_size = optval; #endif return err; } static int32_t set_sock_size_sndbuf(int sockfd, int *max_msg_size) { int32_t err; unsigned int optval = 0; socklen_t optlen = sizeof(optval); #if TEST_GETSOCKOPT3 err = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen); if (err) { printf ("set_sock_size_sndbuf():getsockopt(SO_SNDBUF) failed: errno=%d (%s)\n", errno, strerror(errno)); printf ("set_sock_size_sndbuf():getsockopt(SO_SNDBUF) failed: optval=%d, optlen=%d\n", optval, optlen); return err; } printf ("set_sock_size_sndbuf():getsockopt(SO_SNDBUF): optval=%d, optlen=%d\n", optval, optlen); #endif #if TEST_SETSOCKOPT2 optval = *max_msg_size; optlen = sizeof(*max_msg_size); printf ("set_sock_size_sndbuf(): Requested: *max_msg_size = %d\n", optval); err = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &optval, optlen); if (err) { printf ("set_sock_size_sndbuf():setsockopt(SO_SNDBUF) failed: errno=%d (%s)\n", errno, strerror(errno)); printf ("set_sock_size_sndbuf():setsockopt(SO_SNDBUF) failed: optval=%d, *max_msg_size=%d\n", *max_msg_size, optlen); return err; } #ifdef __GNU__ printf ("set_sock_size_sndbuf():setsockopt(SO_SNDBUF): GNU/Hurd: S_sock_setopt RPC is wrong: No return value\n"); #else printf ("set_sock_size_sndbuf():setsockopt(SO_SNDBUF): optval=%d, optlen=%d\n", optval, optlen); printf ("set_sock_size_sndbuf(): Returned: optval = %d\n", optval); #endif #endif #if TEST_GETSOCKOPT4 printf( "set_sock_size_rsnduf: Checking set values\n"); err = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen); if (err) { printf ("set_sock_size_sndbuf():getsockopt(SO_SNDBUF) failed: errno=%d (%s)\n", errno, strerror(errno)); printf ("set_sock_size_sndbuf():getsockopt(SO_SNDBUF) failed: optval=%d, optlen=%d\n", optval, optlen); return err; } printf ("set_sock_size_sndbuf():getsockopt(SO_SNDBUF): optval=%d, optlen=%d\n", optval, optlen); #endif return err; } #include "./defs.inc" int main(void) { //int max_msg_size = 128*1024; /* 131072 = 128 kiB */; //int max_msg_size = 256*1024; /* 262144 = 256 kiB */ int max_msg_size = 20*1024; /* 20480 = 20 kiB */ /* Linux default: 208*1024 = 212992 */ /* Hurd default: libpipe/pipe.c write_limit = 16*1024 = 16384 */ int err = -1; #ifdef USE_SOCK_STREAM #define type SOCK_STREAM #else #define type SOCK_DGRAM #endif #ifdef USE_AF_UNIX #define domain AF_UNIX #else #define domain AF_INET #endif int sfd = socket(domain, type, 0); //int sfd = 5; if (sfd == -1) handle_error("socket"); printf("\ntest_get+setsockopt.c:main():\n"); printf ("domain = %s ", domain==AF_UNIX ? "AF_UNIX" : "AF_INET"); printf ("type = %s ", type==SOCK_DGRAM ? "SOCK_DGRAM" : "SOCK_STREAM"); printf("Socket sfd = %d\n", sfd); printf ("\nCASE: SO_RCVBUF\n"); printf ("main(): Requested: max_msg_size = %d\n", max_msg_size); err = set_sock_size_rcvbuf (sfd, &max_msg_size); if (err == -1) printf ("\nmain():set_sock_size_rcvbuf() failed: errno = %d (%s)\n", errno, strerror(errno)); else printf ("\nmain():set_sock_size_rcvbuf(): max_msg_size=%d\n", max_msg_size); printf( "\nCASE: SO_SNDBUF\n"); max_msg_size = 8*max_msg_size; printf ("main(): Requested: max_msg_size = %d\n", max_msg_size); err = set_sock_size_sndbuf (sfd, &max_msg_size); if (err == -1) printf ("\nmain():set_sock_size_sndbuf() failed: errno = %d (%s)\n", errno, strerror(errno)); else printf ("\nmain():set_sock_size_sndbuf(): max_msg_size=%d\n", max_msg_size); exit((err == 0) ? EXIT_SUCCESS : EXIT_FAILURE); }
Index: hurd-0.7/pflocal/socket.c =================================================================== --- hurd-0.7.orig/pflocal/socket.c +++ hurd-0.7/pflocal/socket.c @@ -429,12 +429,17 @@ S_socket_getopt (struct sock_user *user, int level, int opt, char **value, size_t *value_len) { - int ret = 0; + struct sock *sock = user->sock; + struct pipe *pipe; + error_t err = 0; if (!user) return EOPNOTSUPP; - pthread_mutex_lock (&user->sock->lock); + if (!sock) + return EBADF; + + pthread_mutex_lock (&sock->lock); switch (level) { case SOL_SOCKET: @@ -442,40 +447,136 @@ S_socket_getopt (struct sock_user *user, { case SO_TYPE: assert (*value_len >= sizeof (int)); - *(int *)*value = user->sock->pipe_class->sock_type; + *(int *)*value = sock->pipe_class->sock_type; + *value_len = sizeof (int); + break; + case SO_RCVBUF: + assert (*value_len >= sizeof (int)); + pipe = sock->read_pipe; + if (!pipe) + { + err = EPIPE; + goto out; + } + *(int *)*value = pipe->write_limit; + *value_len = sizeof (int); + break; + case SO_SNDBUF: + assert (*value_len >= sizeof (int)); + /* XXX: write_pipe might not exist: but sock is the same */ + //pipe = sock->write_pipe; + pipe = sock->read_pipe; + if (!pipe) + { + err = EPIPE; + goto out; + } + *(int *)*value = pipe->write_limit; *value_len = sizeof (int); break; default: - ret = ENOPROTOOPT; + err = ENOPROTOOPT; break; } break; default: - ret = ENOPROTOOPT; + err = ENOPROTOOPT; break; } - pthread_mutex_unlock (&user->sock->lock); - return ret; + out: + pthread_mutex_unlock (&sock->lock); + + return err; } error_t S_socket_setopt (struct sock_user *user, int level, int opt, char *value, size_t value_len) { - int ret = 0; + struct sock *sock = user->sock; + struct pipe *pipe; + int write_limit = 0; + error_t err = 0; if (!user) return EOPNOTSUPP; - pthread_mutex_lock (&user->sock->lock); + if (!sock) + return EBADF; + + pthread_mutex_lock (&sock->lock); switch (level) { + case SOL_SOCKET: + switch (opt) + { + case SO_RCVBUF: + if (value_len != sizeof (int)) + { + err = EINVAL; + goto out; + } + pipe = sock->read_pipe; + if (!pipe) + { + err = EPIPE; + goto out; + } + write_limit = *(int *)value; + if (write_limit > 0) + { + if (write_limit > WRITE_LIMIT_MAX) + pipe->write_limit = WRITE_LIMIT_MAX; + else + pipe->write_limit = write_limit; + } + else + { + err = EINVAL; + goto out; + } + break; + case SO_SNDBUF: + if (value_len != sizeof (int)) + { + err = EINVAL; + goto out; + } + /* XXX: write_pipe might not exist: but sock is the same */ + //pipe = sock->write_pipe; + pipe = sock->read_pipe; + if (!pipe) + { + err = EPIPE; + goto out; + } + write_limit = *(int *)value; + if (write_limit > 0) + { + if (write_limit > WRITE_LIMIT_MAX) + pipe->write_limit = WRITE_LIMIT_MAX; + else + pipe->write_limit = write_limit; + } + else + { + err = EINVAL; + goto out; + } + break; + default: + err = ENOPROTOOPT; + break; + } + break; default: - ret = ENOPROTOOPT; + err = ENOPROTOOPT; break; } - pthread_mutex_unlock (&user->sock->lock); - return ret; + out: + pthread_mutex_unlock (&sock->lock); + + return err; } Index: hurd-0.7/libpipe/pipe.h =================================================================== --- hurd-0.7.orig/libpipe/pipe.h +++ hurd-0.7/libpipe/pipe.h @@ -69,6 +69,11 @@ struct pipe_select_cond pthread_cond_t cond; }; +#define WRITE_LIMIT_DEFAULT 16*1024 +#define WRITE_LIMIT_MAX 1024*1024 +//#define WRITE_LIMIT_MAX 64*1024 +#define WRITE_ATOMIC_DEFAULT 16*1024 + /* A unidirectional data pipe; it transfers data from READER to WRITER. */ struct pipe { Index: hurd-0.7/libpipe/pipe.c =================================================================== --- hurd-0.7.orig/libpipe/pipe.c +++ hurd-0.7/libpipe/pipe.c @@ -55,8 +55,8 @@ pipe_create (struct pipe_class *class, s new->writers = 0; new->flags = 0; new->class = class; - new->write_limit = 16*1024; - new->write_atomic = 16*1024; + new->write_limit = WRITE_LIMIT_DEFAULT; + new->write_atomic = WRITE_ATOMIC_DEFAULT; memset (&new->read_time, 0, sizeof(new->read_time)); memset (&new->write_time, 0, sizeof(new->write_time));
/* File: defs.inc: Case definitions for test_socket_server and test_socket_client */ #define USE_SOCK_STREAM //#undef USE_SOCK_STREAM #define USE_AF_UNIX //#undef USE_AF_UNIX