From ac78dd2440d17142f47163b663d58436f72d3aab Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 14 Oct 2013 12:53:43 +0200 Subject: [PATCH] Use getsockopt() and setsockopt() from FreeBSD --- freebsd/sys/kern/uipc_syscalls.c | 68 ++++++++- freebsd/sys/sys/sysproto.h | 12 +- .../include/machine/rtems-bsd-syscall-api.h | 4 + rtemsbsd/rtems/rtems-bsd-syscalls.c | 134 ------------------ testsuite/syscalls01/test_main.c | 101 +++++++++++++ 5 files changed, 182 insertions(+), 137 deletions(-) diff --git a/freebsd/sys/kern/uipc_syscalls.c b/freebsd/sys/kern/uipc_syscalls.c index fbec5462..7377c7f4 100644 --- a/freebsd/sys/kern/uipc_syscalls.c +++ b/freebsd/sys/kern/uipc_syscalls.c @@ -1486,10 +1486,18 @@ shutdown(int socket, int how) } #endif /* __rtems__ */ -#ifndef __rtems__ /* ARGSUSED */ +#ifndef __rtems__ int setsockopt(td, uap) +#else /* __rtems__ */ +static int +kern_setsockopt( struct thread *td, int s, int level, int name, void *val, + enum uio_seg valseg, socklen_t valsize); + +static int +rtems_bsd_setsockopt(td, uap) +#endif /* __rtems__ */ struct thread *td; struct setsockopt_args /* { int s; @@ -1503,6 +1511,30 @@ setsockopt(td, uap) return (kern_setsockopt(td, uap->s, uap->level, uap->name, uap->val, UIO_USERSPACE, uap->valsize)); } +#ifdef __rtems__ +int +setsockopt(int socket, int level, int option_name, const void *option_value, + socklen_t option_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct setsockopt_args ua = { + .s = socket, + .level = level, + .name = option_name, + .val = __DECONST(void *, option_value), + .valsize = option_len + }; + int error; + + if (td != NULL) { + error = rtems_bsd_setsockopt(td, &ua); + } else { + error = ENOMEM; + } + + return rtems_bsd_error_to_status_and_errno(error); +} +#endif /* __rtems__ */ int kern_setsockopt(td, s, level, name, val, valseg, valsize) @@ -1553,8 +1585,17 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize) } /* ARGSUSED */ +#ifndef __rtems__ int getsockopt(td, uap) +#else /* __rtems__ */ +static int +kern_getsockopt( struct thread *td, int s, int level, int name, void *val, + enum uio_seg valseg, socklen_t *valsize); + +static int +rtems_bsd_getsockopt(td, uap) +#endif /* __rtems__ */ struct thread *td; struct getsockopt_args /* { int s; @@ -1580,6 +1621,30 @@ getsockopt(td, uap) error = copyout(&valsize, uap->avalsize, sizeof (valsize)); return (error); } +#ifdef __rtems__ +int +getsockopt(int socket, int level, int option_name, void *__restrict + option_value, socklen_t *__restrict option_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct getsockopt_args ua = { + .s = socket, + .level = level, + .name = option_name, + .val = (caddr_t) option_value, + .avalsize = option_len + }; + int error; + + if (td != NULL) { + error = rtems_bsd_getsockopt(td, &ua); + } else { + error = ENOMEM; + } + + return rtems_bsd_error_to_status_and_errno(error); +} +#endif /* __rtems__ */ /* * Kernel version of getsockopt. @@ -1634,6 +1699,7 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize) return (error); } +#ifndef __rtems__ /* * getsockname1() - Get socket name. */ diff --git a/freebsd/sys/sys/sysproto.h b/freebsd/sys/sys/sysproto.h index eff4528c..3d81aff4 100644 --- a/freebsd/sys/sys/sysproto.h +++ b/freebsd/sys/sys/sysproto.h @@ -382,15 +382,17 @@ struct bind_args { char namelen_l_[PADL_(__socklen_t)]; __socklen_t namelen; char namelen_r_[PADR_(__socklen_t)]; #endif /* __rtems__ */ }; -#ifndef __rtems__ struct setsockopt_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; char level_l_[PADL_(int)]; int level; char level_r_[PADR_(int)]; char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; char val_l_[PADL_(caddr_t)]; caddr_t val; char val_r_[PADR_(caddr_t)]; +#ifndef __rtems__ char valsize_l_[PADL_(int)]; int valsize; char valsize_r_[PADR_(int)]; -}; +#else /* __rtems__ */ + char valsize_l_[PADL_(__socklen_t)]; __socklen_t valsize; char valsize_r_[PADR_(__socklen_t)]; #endif /* __rtems__ */ +}; struct listen_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; char backlog_l_[PADL_(int)]; int backlog; char backlog_r_[PADR_(int)]; @@ -404,13 +406,19 @@ struct getrusage_args { char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)]; char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; }; +#endif /* __rtems__ */ struct getsockopt_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; char level_l_[PADL_(int)]; int level; char level_r_[PADR_(int)]; char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; char val_l_[PADL_(caddr_t)]; caddr_t val; char val_r_[PADR_(caddr_t)]; +#ifndef __rtems__ char avalsize_l_[PADL_(int *)]; int * avalsize; char avalsize_r_[PADR_(int *)]; +#else /* __rtems__ */ + char avalsize_l_[PADL_(__socklen_t *)]; __socklen_t * avalsize; char avalsize_r_[PADR_(__socklen_t *)]; +#endif /* __rtems__ */ }; +#ifndef __rtems__ struct readv_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char iovp_l_[PADL_(struct iovec *)]; struct iovec * iovp; char iovp_r_[PADR_(struct iovec *)]; diff --git a/rtemsbsd/include/machine/rtems-bsd-syscall-api.h b/rtemsbsd/include/machine/rtems-bsd-syscall-api.h index db9781c6..3b60fa6b 100644 --- a/rtemsbsd/include/machine/rtems-bsd-syscall-api.h +++ b/rtemsbsd/include/machine/rtems-bsd-syscall-api.h @@ -61,8 +61,12 @@ int bind(int, const struct sockaddr *, socklen_t); int connect(int, const struct sockaddr *, socklen_t); +int getsockopt(int, int, int, void * __restrict, socklen_t * __restrict); + int listen(int, int); +int setsockopt(int, int, int, const void *, socklen_t); + int shutdown(int, int); int socket(int, int, int); diff --git a/rtemsbsd/rtems/rtems-bsd-syscalls.c b/rtemsbsd/rtems/rtems-bsd-syscalls.c index 0669a70e..cf457122 100644 --- a/rtemsbsd/rtems/rtems-bsd-syscalls.c +++ b/rtemsbsd/rtems/rtems-bsd-syscalls.c @@ -619,140 +619,6 @@ done2: return -1; } -int -kern_setsockopt(td, s, level, name, val, valseg, valsize) - struct thread *td; - int s; - int level; - int name; - void *val; - enum uio_seg valseg; - socklen_t valsize; -{ - int error; - struct socket *so; - struct sockopt sopt; - - if (val == NULL && valsize != 0) - return (EFAULT); - if ((int)valsize < 0) - return (EINVAL); - - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = level; - sopt.sopt_name = name; - sopt.sopt_val = val; - sopt.sopt_valsize = valsize; - switch (valseg) { - case UIO_USERSPACE: - sopt.sopt_td = td; - break; - case UIO_SYSSPACE: - sopt.sopt_td = NULL; - break; - default: - panic("kern_setsockopt called with bad valseg"); - } - - if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { - error = EBADF; - return error; - } - CURVNET_SET(so->so_vnet); - error = sosetopt(so, &sopt); - CURVNET_RESTORE(); - return(error); -} - -int -setsockopt (int s, int level, int name, const void *val, socklen_t valsize) -{ - struct thread *td; - int error; - - td = curthread; - error = kern_setsockopt(td, s, level, name, val, UIO_USERSPACE, valsize); - if( error == 0 ) - { - return error; - } - errno = error; - return -1; -} - -int -kern_getsockopt(td, s, level, name, val, valseg, valsize) - struct thread *td; - int s; - int level; - int name; - void *val; - enum uio_seg valseg; - socklen_t *valsize; -{ - int error; - struct socket *so; - struct sockopt sopt; - - if (val == NULL) - *valsize = 0; - if ((int)*valsize < 0) - return (EINVAL); - - sopt.sopt_dir = SOPT_GET; - sopt.sopt_level = level; - sopt.sopt_name = name; - sopt.sopt_val = val; - sopt.sopt_valsize = (size_t)*valsize; /* checked non-negative above */ - switch (valseg) { - case UIO_USERSPACE: - sopt.sopt_td = td; - break; - case UIO_SYSSPACE: - sopt.sopt_td = NULL; - break; - default: - panic("kern_getsockopt called with bad valseg"); - } - - if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { - error = EBADF; - return error; - } - CURVNET_SET(so->so_vnet); - error = sogetopt(so, &sopt); - CURVNET_RESTORE(); - *valsize = sopt.sopt_valsize; - return (error); -} - -int -getsockopt (int s, int level, int name, void *val, socklen_t *avalsize) -{ - struct thread *td; - socklen_t valsize; - int error = 0; - - td = curthread; - if (val) { - error = copyin(avalsize, &valsize, sizeof (valsize)); - } - - if( error == 0 ) - { - error = kern_getsockopt(td, s, level, name, val, UIO_USERSPACE, &valsize); - - if (error == 0) - error = copyout(&valsize, avalsize, sizeof (valsize)); - } - if( error == 0 ) - { - return error; - } - errno = error; - return -1; -} - int kern_getpeername(struct thread *td, int fd, struct sockaddr **sa, socklen_t *alen) diff --git a/testsuite/syscalls01/test_main.c b/testsuite/syscalls01/test_main.c index c82602c3..6d0746e3 100644 --- a/testsuite/syscalls01/test_main.c +++ b/testsuite/syscalls01/test_main.c @@ -727,6 +727,106 @@ test_socket_accept(void) assert(rtems_resource_snapshot_check(&snapshot)); } +static void +no_mem_socket_getsockopt_and_setsockopt(int fd) +{ + int rv; + int optval; + socklen_t optlen; + + errno = 0; + optlen = sizeof(optval); + rv = getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + assert(rv == -1); + assert(errno == ENOMEM); + + errno = 0; + optlen = sizeof(optval); + rv = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen); + assert(rv == -1); + assert(errno == ENOMEM); +} + +static void +test_socket_getsockopt_and_setsockopt(void) +{ + rtems_resource_snapshot snapshot; + int optval; + socklen_t optlen; + int sd; + int rv; + + puts("test socket getsockopt and setsockopt"); + + rtems_resource_snapshot_take(&snapshot); + + sd = socket(PF_INET, SOCK_STREAM, 0); + assert(sd >= 0); + + do_no_mem_test(no_mem_socket_getsockopt_and_setsockopt, sd); + + errno = 0; + optlen = sizeof(optval); + rv = getsockopt(sd, SOL_SOCKET, -1, &optval, &optlen); + assert(rv == -1); + assert(errno == ENOPROTOOPT); + + errno = 0; + optlen = sizeof(optval); + rv = setsockopt(sd, SOL_SOCKET, -1, &optval, optlen); + assert(rv == -1); + assert(errno == ENOPROTOOPT); + + errno = 0; + optlen = sizeof(optval); + rv = getsockopt(sd, -1, SO_REUSEADDR, &optval, &optlen); + assert(rv == -1); + assert(errno == EINVAL); + + errno = 0; + optlen = sizeof(optval); + rv = setsockopt(sd, -1, SO_REUSEADDR, &optval, optlen); + assert(rv == -1); + assert(errno == EINVAL); + + optval = -1; + optlen = sizeof(optval); + rv = getsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + assert(rv == 0); + assert(optval == 0); + assert(optlen == sizeof(optval)); + + optval = 1; + optlen = sizeof(optval); + rv = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen); + assert(rv == 0); + + optval = 0; + optlen = sizeof(optval); + rv = getsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + assert(rv == 0); + assert(optval != 0); + assert(optlen == sizeof(optval)); + + rv = close(sd); + assert(rv == 0); + + errno = 0; + optlen = sizeof(optval); + rv = getsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + assert(rv == -1); + assert(errno == EBADF); + + errno = 0; + optval = 0; + optlen = sizeof(optval); + rv = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen); + assert(rv == -1); + assert(errno == EBADF); + + assert(rtems_resource_snapshot_check(&snapshot)); +} + static void test_main(void) { @@ -740,6 +840,7 @@ test_main(void) test_socket_connect(); test_socket_listen(); test_socket_accept(); + test_socket_getsockopt_and_setsockopt(); puts("*** END OF " TEST_NAME " TEST ***"); exit(0);