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

Reply via email to