From 7ca4fd817ef657abf790248e03e4af01f34653e0 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 10 Dec 2014 21:46:49 +0100 Subject: [PATCH] - fixed bug #43797 set/getsockopt: SO_SNDTIMEO/SO_RCVTIMEO take int as option but should take timeval (LWIP_SO_SNDRCVTIMEO_STANDARD==0 can be used to revert to the old 'winsock' style behaviour); - Fixed implementation of SO_ACCEPTCONN to just look at the pcb state; - cleaned up the SO/SOF defines (only 3 left a ip_pcb level); --- CHANGELOG | 6 ++ src/api/sockets.c | 116 +++++++++++++++++++++++++++++-------- src/core/init.c | 6 -- src/core/tcp.c | 1 - src/include/lwip/ip.h | 11 +--- src/include/lwip/opt.h | 8 +++ src/include/lwip/sockets.h | 42 +++++++------- 7 files changed, 129 insertions(+), 61 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8bfae789..f30d2f34 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -143,6 +143,12 @@ HISTORY ++ Bugfixes: + 2014-12-10: Simon Goldschmidt + * sockets.c, tcp.c, others: fixed bug #43797 set/getsockopt: SO_SNDTIMEO/SO_RCVTIMEO + take int as option but should take timeval (LWIP_SO_SNDRCVTIMEO_STANDARD==0 can + be used to revert to the old 'winsock' style behaviour) + Fixed implementation of SO_ACCEPTCONN to just look at the pcb state + 2014-12-09: Simon Goldschmidt * ip4.c: fixed bug #43596 IGMP queries from 0.0.0.0 are discarded diff --git a/src/api/sockets.c b/src/api/sockets.c index 71060fbe..4a9c91ef 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1536,7 +1536,7 @@ lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { - err_t err = ERR_OK; + u8_t err = 0; struct lwip_sock *sock = get_socket(s); LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); @@ -1563,12 +1563,6 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) case SO_ERROR: case SO_KEEPALIVE: /* UNIMPL case SO_CONTIMEO: */ -#if LWIP_SO_SNDTIMEO - case SO_SNDTIMEO: -#endif /* LWIP_SO_SNDTIMEO */ -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: -#endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: #endif /* LWIP_SO_RCVBUF */ @@ -1586,6 +1580,24 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) err = EINVAL; } break; +#if LWIP_SO_SNDTIMEO || LWIP_SO_RCVTIMEO +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ + if (*optlen < +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + sizeof(int) +#else /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + sizeof(struct timeval) +#endif /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD*/ + ) { + err = EINVAL; + } + break; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_RCVTIMEO */ case SO_NO_CHECK: if (*optlen < sizeof(int)) { @@ -1746,7 +1758,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* switch */ - if (err != ERR_OK) { + if (err != 0) { sock_set_errno(sock, err); return -1; } @@ -1811,8 +1823,19 @@ lwip_getsockopt_internal(void *arg) case SOL_SOCKET: switch (optname) { - /* The option flags */ case SO_ACCEPTCONN: + if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) { + if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { + *(int*)optval = 1; + } else { + *(int*)optval = 0; + } + } else { + data->err = ENOPROTOOPT; + } + break; + + /* The option flags */ case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ @@ -1862,12 +1885,28 @@ lwip_getsockopt_internal(void *arg) #if LWIP_SO_SNDTIMEO case SO_SNDTIMEO: - *(int *)optval = netconn_get_sendtimeout(sock->conn); + { + s32_t val = netconn_get_sendtimeout(sock->conn); +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + *(int *)optval = val; +#else /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + ((struct timeval *)optval)->tv_sec = val / 1000U; + ((struct timeval *)optval)->tv_sec = (val % 1000U) * 1000U; +#endif /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + } break; #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: - *(int *)optval = netconn_get_recvtimeout(sock->conn); + { + s32_t val = netconn_get_recvtimeout(sock->conn); +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + *(int *)optval = (int)val; +#else /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + ((struct timeval *)optval)->tv_sec = val / 1000U; + ((struct timeval *)optval)->tv_sec = (val % 1000U) * 1000U; +#endif /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + } break; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF @@ -2033,7 +2072,7 @@ int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { struct lwip_sock *sock = get_socket(s); - err_t err = ERR_OK; + u8_t err = 0; LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); if (!sock) { @@ -2057,12 +2096,6 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt /* UNIMPL case SO_DONTROUTE: */ case SO_KEEPALIVE: /* UNIMPL case case SO_CONTIMEO: */ -#if LWIP_SO_SNDTIMEO - case SO_SNDTIMEO: -#endif /* LWIP_SO_SNDTIMEO */ -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: -#endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: #endif /* LWIP_SO_RCVBUF */ @@ -2079,6 +2112,24 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt err = EINVAL; } break; +#if LWIP_SO_SNDTIMEO || LWIP_SO_RCVTIMEO +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ + if (optlen < +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + sizeof(int) +#else /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + sizeof(struct timeval) +#endif /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD*/ + ) { + err = EINVAL; + } + break; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_RCVTIMEO */ case SO_NO_CHECK: if (optlen < sizeof(int)) { err = EINVAL; @@ -2269,7 +2320,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } /* switch (level) */ - if (err != ERR_OK) { + if (err != 0) { sock_set_errno(sock, err); return -1; } @@ -2356,12 +2407,28 @@ lwip_setsockopt_internal(void *arg) break; #if LWIP_SO_SNDTIMEO case SO_SNDTIMEO: - netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval); + { + s32_t val; +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + val = (s32_t)*(int*)optval; +#else /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + val = (((struct timeval *)optval)->tv_sec * 1000U) + (((struct timeval *)optval)->tv_usec / 1000U); +#endif /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + netconn_set_sendtimeout(sock->conn, val); + } break; #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: - netconn_set_recvtimeout(sock->conn, *(int*)optval); + { + s32_t val; +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + val = (s32_t)*(int*)optval; +#else /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + val = (((struct timeval *)optval)->tv_sec * 1000U) + (((struct timeval *)optval)->tv_usec / 1000U); +#endif /* LWIP_SO_SNDRCVTIMEO_NONSTANDARD */ + netconn_set_recvtimeout(sock->conn, (int)val); + } break; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF @@ -2415,17 +2482,18 @@ lwip_setsockopt_internal(void *arg) case IP_DROP_MEMBERSHIP: { /* If this is a TCP or a RAW socket, ignore these options. */ + err_t err; struct ip_mreq *imr = (struct ip_mreq *)optval; ip_addr_t if_addr; ip_addr_t multi_addr; inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); if(optname == IP_ADD_MEMBERSHIP){ - data->err = igmp_joingroup(&if_addr, &multi_addr); + err = igmp_joingroup(&if_addr, &multi_addr); } else { - data->err = igmp_leavegroup(&if_addr, &multi_addr); + err = igmp_leavegroup(&if_addr, &multi_addr); } - if(data->err != ERR_OK) { + if(err != ERR_OK) { data->err = EADDRNOTAVAIL; } } diff --git a/src/core/init.c b/src/core/init.c index 5c64b339..b0c42dd3 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -213,9 +213,6 @@ #endif /* LWIP_NETCONN && LWIP_TCP */ #if LWIP_SOCKET /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ -#if SO_ACCEPTCONN != SOF_ACCEPTCONN - #error "SO_ACCEPTCONN != SOF_ACCEPTCONN" -#endif #if SO_REUSEADDR != SOF_REUSEADDR #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" #endif @@ -225,9 +222,6 @@ #if SO_BROADCAST != SOF_BROADCAST #error "WARNING: SO_BROADCAST != SOF_BROADCAST" #endif -#if SO_LINGER != SOF_LINGER - #error "WARNING: SO_LINGER != SOF_LINGER" -#endif #endif /* LWIP_SOCKET */ diff --git a/src/core/tcp.c b/src/core/tcp.c index 3002977c..4a6dbffe 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -563,7 +563,6 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) lpcb->state = LISTEN; lpcb->prio = pcb->prio; lpcb->so_options = pcb->so_options; - ip_set_option(lpcb, SOF_ACCEPTCONN); lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; #if LWIP_IPV6 diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index fdd9eb02..e3cfead5 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -98,21 +98,14 @@ struct ip_pcb { }; /* - * Option flags per-socket. These are the same like SO_XXX. + * Option flags per-socket. These are the same like SO_XXX in sockets.h */ -/*#define SOF_DEBUG 0x01U Unimplemented: turn on debugging info recording */ -#define SOF_ACCEPTCONN 0x02U /* socket has had listen() */ #define SOF_REUSEADDR 0x04U /* allow local address reuse */ #define SOF_KEEPALIVE 0x08U /* keep connections alive */ -/*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */ #define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -/*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */ -#define SOF_LINGER 0x80U /* linger on close if data present */ -/*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */ -/*#define SOF_REUSEPORT 0x0200U Unimplemented: allow local address & port reuse */ /* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ -#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) /* Global variables of this module, kept in a struct for efficient access using base+index. */ struct ip_globals diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index f3dd8aa7..3eec7d63 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1548,6 +1548,14 @@ #define LWIP_SO_RCVTIMEO 0 #endif +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#ifndef LWIP_SO_SNDRCVTIMEO_NONSTANDARD +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif + /** * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. */ diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 53204b34..4c952e99 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -142,32 +142,32 @@ struct lwip_setgetsockopt_data { /* * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) */ -#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ -#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ -#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ -#define SO_KEEPALIVE 0x0008 /* keep connections alive */ -#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ -#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ -#define SO_LINGER 0x0080 /* linger on close if data present */ -#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ -#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -#define SO_DONTLINGER ((int)(~SO_LINGER)) /* * Additional options, not kept in so_options. */ -#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ -#define SO_RCVBUF 0x1002 /* receive buffer size */ -#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ -#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ -#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ -#define SO_RCVTIMEO 0x1006 /* receive timeout */ -#define SO_ERROR 0x1007 /* get error status and clear */ -#define SO_TYPE 0x1008 /* get socket type */ -#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ -#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_DONTLINGER ((int)(~SO_LINGER)) +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ /*