diff --git a/src/api/sockets.c b/src/api/sockets.c index fbba47b8..3763b653 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -3149,13 +3149,15 @@ lwip_ioctl(int s, long cmd, void *argp) /** A minimal implementation of fcntl. * Currently only the commands F_GETFL and F_SETFL are implemented. - * Only the flag O_NONBLOCK is implemented. + * The flag O_NONBLOCK and access modes are supported for F_GETFL, only + * the flag O_NONBLOCK is implemented for F_SETFL. */ int lwip_fcntl(int s, int cmd, int val) { struct lwip_sock *sock = get_socket(s); int ret = -1; + int op_mode = 0; if (!sock) { return -1; @@ -3165,6 +3167,25 @@ lwip_fcntl(int s, int cmd, int val) case F_GETFL: ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; sock_set_errno(sock, 0); + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCPIP_CORE_LOCKING + LOCK_TCPIP_CORE(); + LWIP_ASSERT("sock->conn->pcb.tcp != NULL", sock->conn->pcb.tcp != NULL); + if(!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) { + op_mode |= O_RDONLY; + } + if (!(sock->conn->pcb.tcp->flags & TF_FIN)) { + op_mode |= O_WRONLY; + } + UNLOCK_TCPIP_CORE(); +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + } else { + op_mode |= O_RDWR; + } + + ret |= (op_mode == (O_RDONLY|O_WRONLY)) ? O_RDWR : op_mode; + break; case F_SETFL: if ((val & ~O_NONBLOCK) == 0) { diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index c6ca1917..6b487f3f 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -374,6 +374,15 @@ typedef struct ip_mreq { #ifndef O_NDELAY #define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ #endif +#ifndef O_RDONLY +#define O_RDONLY 2 +#endif +#ifndef O_WRONLY +#define O_WRONLY 4 +#endif +#ifndef O_RDWR +#define O_RDWR (O_RDONLY|O_WRONLY) +#endif #ifndef SHUT_RD #define SHUT_RD 0 diff --git a/test/unit/api/test_sockets.c b/test/unit/api/test_sockets.c index 0acee819..9be117e4 100644 --- a/test/unit/api/test_sockets.c +++ b/test/unit/api/test_sockets.c @@ -254,8 +254,8 @@ static void test_sockets_msgapi_tcp(int domain) /* set s2 to non-blocking, not inherited from listener */ opt = lwip_fcntl(s2, F_GETFL, 0); - fail_unless(opt == 0); - opt |= O_NONBLOCK; + fail_unless(opt == 6); + opt = O_NONBLOCK; ret = lwip_fcntl(s2, F_SETFL, opt); fail_unless(ret == 0);