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