From 2c77560870807804465b4e0646a95d874e029608 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 9 Mar 2017 21:49:55 +0100 Subject: [PATCH] My first try at 'recvmsg()', TCP only, for now... --- src/api/sockets.c | 153 +++++++++++++++++++++++++++++++------ src/include/lwip/sockets.h | 8 ++ 2 files changed, 136 insertions(+), 25 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 79a6861b..8de5ce66 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -937,14 +937,18 @@ lwip_recv_tcp_done: } /* Convert a netbuf's address data to struct sockaddr */ -static void +static int lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, struct sockaddr *from, socklen_t *fromlen) { + int truncated = 0; union sockaddr_aligned saddr; LWIP_UNUSED_ARG(conn); + LWIP_ASSERT("from != NULL", from != NULL); + LWIP_ASSERT("fromlen != NULL", fromlen != NULL); + #if LWIP_IPV4 && LWIP_IPV6 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) { @@ -953,17 +957,42 @@ lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, } #endif /* LWIP_IPV4 && LWIP_IPV6 */ - LWIP_DEBUGF(SOCKETS_DEBUG, (" addr=")); IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); - ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"", port)); - if (from && fromlen) - { - if (*fromlen > saddr.sa.sa_len) { - *fromlen = saddr.sa.sa_len; - } - MEMCPY(from, &saddr, *fromlen); + if (*fromlen < saddr.sa.sa_len) { + truncated = 1; + } else if (*fromlen > saddr.sa.sa_len) { + *fromlen = saddr.sa.sa_len; } + MEMCPY(from, &saddr, *fromlen); + return truncated; +} + +static int +lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, int dbg_ret) +{ + if (sock == NULL) { + return 0; + } + LWIP_UNUSED_ARG(dbg_fn); + LWIP_UNUSED_ARG(dbg_s); + LWIP_UNUSED_ARG(dbg_ret); + +#if !SOCKETS_DEBUG + if (from && fromlen) +#endif /* !SOCKETS_DEBUG */ + { + /* get remote addr/port from tcp_pcb */ + u16_t port; + ip_addr_t tmpaddr; + netconn_getaddr(sock->conn, &tmpaddr, &port, 0); + LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); + ip_addr_debug_print(SOCKETS_DEBUG, &tmpaddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, dbg_ret)); + if (from && fromlen) { + return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); + } + } + return 0; } int @@ -980,18 +1009,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { ret = lwip_recv_tcp(sock, mem, len, flags); -#if !SOCKETS_DEBUG - if (from && fromlen) -#endif /* !SOCKETS_DEBUG */ - { - /* get remote addr/port from tcp_pcb */ - u16_t port; - ip_addr_t tmpaddr; - netconn_getaddr(sock->conn, &tmpaddr, &port, 0); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d):", s)); - lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); - LWIP_DEBUGF(SOCKETS_DEBUG, (" len=%d\n", ret)); - } + lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret); done_socket(sock); return ret; } else { @@ -1047,9 +1065,12 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, if (from && fromlen) #endif /* !SOCKETS_DEBUG */ { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d):", s)); - lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), from, fromlen); - LWIP_DEBUGF(SOCKETS_DEBUG, (" len=%d\n", ret)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, netbuf_fromaddr(buf)); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), ret)); + if (from && fromlen) { + lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), from, fromlen); + } } /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */ @@ -1076,6 +1097,88 @@ lwip_recv(int s, void *mem, size_t len, int flags) return lwip_recvfrom(s, mem, len, flags, NULL, NULL); } +int +lwip_recvmsg(int s, struct msghdr *message, int flags) +{ + struct lwip_sock *sock; + int recv_flags = flags; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, message, flags)); + LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); + LWIP_ERROR("lwip_recvmsg: unsupported flags", ((flags == 0) || (flags == MSG_PEEK)), + set_errno(EOPNOTSUPP); return -1;); + + if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) { + set_errno(EMSGSIZE); + return -1; + } + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + int i; + int ret; + /* check for valid vectors */ + ret = 0; + for (i = 0; i < message->msg_iovlen; i++) { + if ((message->msg_iov[i].iov_base == NULL) || (message->msg_iov[i].iov_len == 0) || + ((int)(ret + message->msg_iov[i].iov_len) <= 0)) { + sock_set_errno(sock, ERR_VAL); + done_socket(sock); + return -1; + } + ret += message->msg_iov[i].iov_len; + } + message->msg_flags = 0; + /* recv the data */ + ret = 0; + for (i = 0; i < message->msg_iovlen; i++) { + /* try to receive into this vector's buffer */ + int recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags); + if (recvd_local > 0) { + /* sum up received bytes */ + ret += recvd_local; + } + if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len)) { + /* returned prematurely */ + if (ret <= 0) { + /* nothing received at all, propagate the error */ + ret = recvd_local; + } + break; + } + /* while MSG_DONTWAIT is not supported for this function, we pass it to + lwip_recv_tcp() to prevent waiting for more data */ + recv_flags |= MSG_DONTWAIT; + } + if (ret > 0) { + /* reset socket error since we have received something */ + sock_set_errno(sock, 0); + } + if (message->msg_name && message->msg_namelen) { + if (lwip_recv_tcp_from(sock, (struct sockaddr*)message->msg_name, + &message->msg_namelen, "lwip_recvmsg", s, ret)) { + message->msg_flags |= MSG_CTRUNC; + } + } + done_socket(sock); + return ret; +#else /* LWIP_TCP */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* LWIP_TCP */ + } + /* else, UDP and RAW NETCONNs: TODO! */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +} + int lwip_send(int s, const void *data, size_t size, int flags) { diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 5db92cca..912956ee 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -131,6 +131,10 @@ struct msghdr { int msg_flags; }; +/* struct msghdr->msg_flags bit field values */ +#define MSG_TRUNC 0x04 +#define MSG_CTRUNC 0x08 + /* Socket protocol types (TCP/UDP/RAW) */ #define SOCK_STREAM 1 #define SOCK_DGRAM 2 @@ -433,6 +437,7 @@ void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destro #define lwip_connect connect #define lwip_listen listen #define lwip_recv recv +#define lwip_recvmsg recvmsg #define lwip_recvfrom recvfrom #define lwip_send send #define lwip_sendmsg sendmsg @@ -467,6 +472,7 @@ int lwip_recv(int s, void *mem, size_t len, int flags); int lwip_read(int s, void *mem, size_t len); int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); +int lwip_recvmsg(int s, struct msghdr *message, int flags); int lwip_send(int s, const void *dataptr, size_t size, int flags); int lwip_sendmsg(int s, const struct msghdr *message, int flags); int lwip_sendto(int s, const void *dataptr, size_t size, int flags, @@ -504,6 +510,8 @@ int lwip_fcntl(int s, int cmd, int val); /** @ingroup socket */ #define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) /** @ingroup socket */ +#define recvmsg(s,message,flags) lwip_recvmsg(s,message,flags) +/** @ingroup socket */ #define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) /** @ingroup socket */ #define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags)