mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-05 22:29:49 +00:00
sockets: clean up all the if/else in lwip_recvfrom and use new nonblocking features in netconn API: I'm OK with code duplication if it gets more readable :-/
This commit is contained in:
parent
1945582c10
commit
c295717ce7
@ -810,69 +810,58 @@ lwip_listen(int s, int backlog)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
/* Helper function to loop over receiving pbufs from netconn
|
||||
* until "len" bytes are received or we're otherwise done.
|
||||
*/
|
||||
static int
|
||||
lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
|
||||
{
|
||||
struct lwip_sock *sock;
|
||||
void *buf = NULL;
|
||||
struct pbuf *p;
|
||||
u16_t buflen, copylen;
|
||||
int off = 0;
|
||||
u8_t done = 0;
|
||||
err_t err;
|
||||
u8_t apiflags;
|
||||
int recvd = 0;
|
||||
int recv_left = len;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
|
||||
sock = get_socket(s);
|
||||
if (!sock) {
|
||||
return -1;
|
||||
LWIP_ASSERT("no socket given", sock != NULL);
|
||||
LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP);
|
||||
|
||||
if (flags & MSG_DONTWAIT) {
|
||||
apiflags = NETCONN_DONTBLOCK;
|
||||
} else {
|
||||
apiflags = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
|
||||
struct pbuf *p;
|
||||
err_t err;
|
||||
u16_t copylen;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", sock->lastdata));
|
||||
/* Check if there is data left from the last recv operation. */
|
||||
if (sock->lastdata) {
|
||||
buf = sock->lastdata;
|
||||
p = (struct pbuf *)sock->lastdata;
|
||||
} else {
|
||||
/* If this is non-blocking call, then check first */
|
||||
if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
|
||||
(sock->rcvevent <= 0)) {
|
||||
if (off > 0) {
|
||||
/* already received data, return that */
|
||||
sock_set_errno(sock, 0);
|
||||
done_socket(sock);
|
||||
return off;
|
||||
}
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
|
||||
set_errno(EWOULDBLOCK);
|
||||
done_socket(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No data was left from the previous operation, so we try to get
|
||||
some from the network. */
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
||||
err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
|
||||
} else {
|
||||
err = netconn_recv_udp_raw_netbuf(sock->conn, (struct netbuf **)&buf);
|
||||
}
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
|
||||
err, buf));
|
||||
err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n",
|
||||
err, p));
|
||||
|
||||
if (err != ERR_OK) {
|
||||
if (off > 0) {
|
||||
if (recvd > 0) {
|
||||
/* already received data, return that (this trusts in getting the same error from
|
||||
netconn layer again next time netconn_recv is called) */
|
||||
if (err == ERR_CLSD) {
|
||||
/* closed but already received data, ensure select gets the FIN, too */
|
||||
event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0);
|
||||
if (sock->conn->callback != NULL) {
|
||||
sock->conn->callback(sock->conn, NETCONN_EVT_RCVPLUS, 0);
|
||||
}
|
||||
}
|
||||
/* already received data, return that */
|
||||
sock_set_errno(sock, 0);
|
||||
done_socket(sock);
|
||||
return off;
|
||||
return recvd;
|
||||
}
|
||||
/* We should really do some error checking here. */
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
|
||||
s, lwip_strerr(err)));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n",
|
||||
lwip_strerr(err)));
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
done_socket(sock);
|
||||
if (err == ERR_CLSD) {
|
||||
@ -881,20 +870,144 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
sock->lastdata = p;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" len=%"SZT_F" off=%d\n",
|
||||
p->tot_len, recv_left, recvd));
|
||||
|
||||
if (recv_left > p->tot_len) {
|
||||
copylen = p->tot_len;
|
||||
} else {
|
||||
copylen = (u16_t)recv_left;
|
||||
}
|
||||
|
||||
/* copy the contents of the received buffer into
|
||||
the supplied memory pointer mem */
|
||||
pbuf_copy_partial(p, (u8_t*)mem + recvd, copylen, 0);
|
||||
|
||||
recvd += copylen;
|
||||
|
||||
/* TCP combines multiple pbufs for one recv */
|
||||
LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen);
|
||||
recv_left -= copylen;
|
||||
|
||||
/* Unless we peek the incoming message... */
|
||||
if ((flags & MSG_PEEK) == 0) {
|
||||
/* ... check if there is data left in the pbuf */
|
||||
LWIP_ASSERT("invalid copylen", p->tot_len >= copylen);
|
||||
if (p->tot_len - copylen > 0) {
|
||||
/* If so, it should be saved in the sock structure for the next recv call.
|
||||
We store the pbuf but hide/free the consumed data: */
|
||||
sock->lastdata = p;
|
||||
sock->lastoffset += copylen;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", sock->lastdata));
|
||||
} else {
|
||||
sock->lastdata = NULL;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", p));
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
/* once we have some data to return, only add more if we don't need to wait */
|
||||
apiflags |= NETCONN_DONTBLOCK;
|
||||
/* @todo: do we need to support peeking more than one pbuf? */
|
||||
} while ((recv_left > 0) || (flags & MSG_PEEK));
|
||||
return recvd;
|
||||
}
|
||||
|
||||
/* Convert a netbuf's address data to struct sockaddr */
|
||||
static void
|
||||
lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
union sockaddr_aligned saddr;
|
||||
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
/* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
|
||||
if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) {
|
||||
ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
|
||||
IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
struct lwip_sock *sock;
|
||||
int ret;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
|
||||
sock = get_socket(s);
|
||||
if (!sock) {
|
||||
return -1;
|
||||
}
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
struct netbuf *buf;
|
||||
u16_t buflen, copylen;
|
||||
err_t err;
|
||||
u8_t apiflags;
|
||||
/* UDP / RAW */
|
||||
if (flags & MSG_DONTWAIT) {
|
||||
apiflags = NETCONN_DONTBLOCK;
|
||||
} else {
|
||||
apiflags = 0;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW]: top sock->lastdata=%p\n", sock->lastdata));
|
||||
/* Check if there is data left from the last recv operation. */
|
||||
buf = (struct netbuf *)sock->lastdata;
|
||||
if (buf == NULL) {
|
||||
/* No data was left from the previous operation, so we try to get
|
||||
some from the network. */
|
||||
err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n",
|
||||
err, buf));
|
||||
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
|
||||
s, lwip_strerr(err)));
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
done_socket(sock);
|
||||
return -1;
|
||||
}
|
||||
LWIP_ASSERT("buf != NULL", buf != NULL);
|
||||
sock->lastdata = buf;
|
||||
}
|
||||
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
||||
p = (struct pbuf *)buf;
|
||||
} else {
|
||||
p = ((struct netbuf *)buf)->p;
|
||||
}
|
||||
buflen = p->tot_len;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
|
||||
buflen, len, off, sock->lastoffset));
|
||||
|
||||
buflen -= sock->lastoffset;
|
||||
buflen = buf->p->tot_len;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F"\n",
|
||||
buflen, len));
|
||||
|
||||
if (len > buflen) {
|
||||
copylen = buflen;
|
||||
@ -904,91 +1017,29 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||
|
||||
/* copy the contents of the received buffer into
|
||||
the supplied memory pointer mem */
|
||||
pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
|
||||
|
||||
off += copylen;
|
||||
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
||||
LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
|
||||
len -= copylen;
|
||||
if ((len <= 0) ||
|
||||
(p->flags & PBUF_FLAG_PUSH) ||
|
||||
(sock->rcvevent <= 0) ||
|
||||
((flags & MSG_PEEK) != 0)) {
|
||||
done = 1;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
pbuf_copy_partial(buf->p, (u8_t*)mem, copylen, 0);
|
||||
ret = copylen;
|
||||
|
||||
/* Check to see from where the data was.*/
|
||||
if (done) {
|
||||
#if !SOCKETS_DEBUG
|
||||
if (from && fromlen)
|
||||
if (from && fromlen)
|
||||
#endif /* !SOCKETS_DEBUG */
|
||||
{
|
||||
u16_t port;
|
||||
ip_addr_t tmpaddr;
|
||||
ip_addr_t *fromaddr;
|
||||
union sockaddr_aligned saddr;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
||||
fromaddr = &tmpaddr;
|
||||
netconn_getaddr(sock->conn, fromaddr, &port, 0);
|
||||
} else {
|
||||
port = netbuf_fromport((struct netbuf *)buf);
|
||||
fromaddr = netbuf_fromaddr((struct netbuf *)buf);
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
/* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
|
||||
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) {
|
||||
ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
|
||||
IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
|
||||
}
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
|
||||
IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
|
||||
#if SOCKETS_DEBUG
|
||||
if (from && fromlen)
|
||||
#endif /* SOCKETS_DEBUG */
|
||||
{
|
||||
if (*fromlen > saddr.sa.sa_len) {
|
||||
*fromlen = saddr.sa.sa_len;
|
||||
}
|
||||
MEMCPY(from, &saddr, *fromlen);
|
||||
}
|
||||
}
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/* If we don't peek the incoming message... */
|
||||
/* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */
|
||||
if ((flags & MSG_PEEK) == 0) {
|
||||
/* If this is a TCP socket, check if there is data left in the
|
||||
buffer. If so, it should be saved in the sock structure for next
|
||||
time around. */
|
||||
if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
|
||||
sock->lastdata = buf;
|
||||
sock->lastoffset += copylen;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
|
||||
} else {
|
||||
sock->lastdata = NULL;
|
||||
sock->lastoffset = 0;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
||||
pbuf_free((struct pbuf *)buf);
|
||||
} else {
|
||||
netbuf_delete((struct netbuf *)buf);
|
||||
}
|
||||
buf = NULL;
|
||||
}
|
||||
sock->lastdata = NULL;
|
||||
netbuf_delete(buf);
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
sock_set_errno(sock, 0);
|
||||
done_socket(sock);
|
||||
return off;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user