mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2025-08-03 21:14:40 +08:00
Fixed bug #22110 (recv() makes receive window update for data that wasn't received by application); added function-like macros to correctly access/change conn->recv_timeout and conn->recv_bufsize
This commit is contained in:
parent
7699b59e27
commit
306f2203fa
@ -103,6 +103,12 @@ HISTORY
|
|||||||
|
|
||||||
++ Bugfixes:
|
++ Bugfixes:
|
||||||
|
|
||||||
|
2010-02-09: Simon Goldschmidt
|
||||||
|
* api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110
|
||||||
|
(recv() makes receive window update for data that wasn't received by
|
||||||
|
application)
|
||||||
|
|
||||||
|
|
||||||
2010-02-09: Simon Goldschmidt/Stephane Lesage
|
2010-02-09: Simon Goldschmidt/Stephane Lesage
|
||||||
* sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out
|
* sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out
|
||||||
or any netconn_recv() error)
|
or any netconn_recv() error)
|
||||||
|
@ -388,6 +388,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
|||||||
buf->port = 0;
|
buf->port = 0;
|
||||||
buf->addr = NULL;
|
buf->addr = NULL;
|
||||||
|
|
||||||
|
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
|
||||||
/* Let the stack know that we have taken the data. */
|
/* Let the stack know that we have taken the data. */
|
||||||
/* TODO: Speedup: Don't block and wait for the answer here
|
/* TODO: Speedup: Don't block and wait for the answer here
|
||||||
(to prevent multiple thread-switches). */
|
(to prevent multiple thread-switches). */
|
||||||
@ -400,6 +401,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
|||||||
}
|
}
|
||||||
/* don't care for the return value of do_recv */
|
/* don't care for the return value of do_recv */
|
||||||
TCPIP_APIMSG(&msg);
|
TCPIP_APIMSG(&msg);
|
||||||
|
}
|
||||||
#endif /* LWIP_TCP */
|
#endif /* LWIP_TCP */
|
||||||
} else {
|
} else {
|
||||||
#if (LWIP_UDP || LWIP_RAW)
|
#if (LWIP_UDP || LWIP_RAW)
|
||||||
@ -427,6 +429,33 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
|||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP: update the receive window: by calling this, the application
|
||||||
|
* tells the stack that it has processed data and is able to accept
|
||||||
|
* new data.
|
||||||
|
* ATTENTION: use with care, this is mainly used for sockets!
|
||||||
|
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
|
||||||
|
*
|
||||||
|
* @param conn the netconn for which to update the receive window
|
||||||
|
* @param length amount of data processed (ATTENTION: this must be accurate!)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netconn_recved(struct netconn *conn, u32_t length)
|
||||||
|
{
|
||||||
|
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
|
||||||
|
(netconn_get_noautorecved(conn))) {
|
||||||
|
struct api_msg msg;
|
||||||
|
/* Let the stack know that we have taken the data. */
|
||||||
|
/* TODO: Speedup: Don't block and wait for the answer here
|
||||||
|
(to prevent multiple thread-switches). */
|
||||||
|
msg.function = do_recv;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.r.len = length;
|
||||||
|
/* don't care for the return value of do_recv */
|
||||||
|
TCPIP_APIMSG(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data (in form of a netbuf) to a specific remote IP address and port.
|
* Send data (in form of a netbuf) to a specific remote IP address and port.
|
||||||
* Only to be used for UDP and RAW netconns (not TCP).
|
* Only to be used for UDP and RAW netconns (not TCP).
|
||||||
|
@ -1102,7 +1102,12 @@ do_recv(struct api_msg_msg *msg)
|
|||||||
} else
|
} else
|
||||||
#endif /* TCP_LISTEN_BACKLOG */
|
#endif /* TCP_LISTEN_BACKLOG */
|
||||||
{
|
{
|
||||||
tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
|
u32_t remaining = msg->msg.r.len;
|
||||||
|
do {
|
||||||
|
u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
|
||||||
|
tcp_recved(msg->conn->pcb.tcp, recved);
|
||||||
|
remaining -= recved;
|
||||||
|
}while(remaining != 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,6 +304,8 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
LWIP_ASSERT("newconn != NULL", newconn != NULL);
|
LWIP_ASSERT("newconn != NULL", newconn != NULL);
|
||||||
|
/* Prevent automatic window updates, we do this on our own! */
|
||||||
|
netconn_set_noautorecved(newconn, 1);
|
||||||
|
|
||||||
/* get the IP address and port of the remote host */
|
/* get the IP address and port of the remote host */
|
||||||
err = netconn_peer(newconn, &naddr, &port);
|
err = netconn_peer(newconn, &naddr, &port);
|
||||||
@ -519,6 +521,8 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
|||||||
if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
|
if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
|
||||||
(sock->rcvevent <= 0)) {
|
(sock->rcvevent <= 0)) {
|
||||||
if (off > 0) {
|
if (off > 0) {
|
||||||
|
/* update receive window */
|
||||||
|
netconn_recved(sock->conn, (u32_t)off);
|
||||||
/* already received data, return that */
|
/* already received data, return that */
|
||||||
sock_set_errno(sock, 0);
|
sock_set_errno(sock, 0);
|
||||||
return off;
|
return off;
|
||||||
@ -536,6 +540,8 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
|||||||
|
|
||||||
if (err != ERR_OK) {
|
if (err != ERR_OK) {
|
||||||
if (off > 0) {
|
if (off > 0) {
|
||||||
|
/* update receive window */
|
||||||
|
netconn_recved(sock->conn, (u32_t)off);
|
||||||
/* already received data, return that */
|
/* already received data, return that */
|
||||||
sock_set_errno(sock, 0);
|
sock_set_errno(sock, 0);
|
||||||
return off;
|
return off;
|
||||||
@ -649,6 +655,10 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
|||||||
}
|
}
|
||||||
} while (!done);
|
} while (!done);
|
||||||
|
|
||||||
|
if (off > 0) {
|
||||||
|
/* update receive window */
|
||||||
|
netconn_recved(sock->conn, (u32_t)off);
|
||||||
|
}
|
||||||
sock_set_errno(sock, 0);
|
sock_set_errno(sock, 0);
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
@ -819,6 +829,10 @@ lwip_socket(int domain, int type, int protocol)
|
|||||||
conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
|
conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
|
||||||
domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
|
domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
|
||||||
|
if (conn != NULL) {
|
||||||
|
/* Prevent automatic window updates, we do this on our own! */
|
||||||
|
netconn_set_noautorecved(conn, 1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
|
||||||
@ -1488,12 +1502,12 @@ lwip_getsockopt_internal(void *arg)
|
|||||||
|
|
||||||
#if LWIP_SO_RCVTIMEO
|
#if LWIP_SO_RCVTIMEO
|
||||||
case SO_RCVTIMEO:
|
case SO_RCVTIMEO:
|
||||||
*(int *)optval = sock->conn->recv_timeout;
|
*(int *)optval = netconn_get_recvtimeout(sock->conn);
|
||||||
break;
|
break;
|
||||||
#endif /* LWIP_SO_RCVTIMEO */
|
#endif /* LWIP_SO_RCVTIMEO */
|
||||||
#if LWIP_SO_RCVBUF
|
#if LWIP_SO_RCVBUF
|
||||||
case SO_RCVBUF:
|
case SO_RCVBUF:
|
||||||
*(int *)optval = sock->conn->recv_bufsize;
|
*(int *)optval = netconn_get_recvbufsize(sock->conn);
|
||||||
break;
|
break;
|
||||||
#endif /* LWIP_SO_RCVBUF */
|
#endif /* LWIP_SO_RCVBUF */
|
||||||
#if LWIP_UDP
|
#if LWIP_UDP
|
||||||
@ -1833,12 +1847,12 @@ lwip_setsockopt_internal(void *arg)
|
|||||||
break;
|
break;
|
||||||
#if LWIP_SO_RCVTIMEO
|
#if LWIP_SO_RCVTIMEO
|
||||||
case SO_RCVTIMEO:
|
case SO_RCVTIMEO:
|
||||||
sock->conn->recv_timeout = ( *(int*)optval );
|
netconn_set_recvtimeout(sock->conn, *(int*)optval);
|
||||||
break;
|
break;
|
||||||
#endif /* LWIP_SO_RCVTIMEO */
|
#endif /* LWIP_SO_RCVTIMEO */
|
||||||
#if LWIP_SO_RCVBUF
|
#if LWIP_SO_RCVBUF
|
||||||
case SO_RCVBUF:
|
case SO_RCVBUF:
|
||||||
sock->conn->recv_bufsize = ( *(int*)optval );
|
netconn_set_recvbufsize(sock->conn, *(int*)optval);
|
||||||
break;
|
break;
|
||||||
#endif /* LWIP_SO_RCVBUF */
|
#endif /* LWIP_SO_RCVBUF */
|
||||||
#if LWIP_UDP
|
#if LWIP_UDP
|
||||||
|
@ -69,7 +69,7 @@ extern "C" {
|
|||||||
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
|
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
|
||||||
/** If this is set, a TCP netconn must call netconn_recved() to update
|
/** If this is set, a TCP netconn must call netconn_recved() to update
|
||||||
the TCP receive window (done automatically if not set). */
|
the TCP receive window (done automatically if not set). */
|
||||||
#define NETCONN_FLAG_UPDATE_TCPWIN_MANUALLY 0x08
|
#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
|
||||||
|
|
||||||
|
|
||||||
/* Helpers to process several netconn_types by the same code */
|
/* Helpers to process several netconn_types by the same code */
|
||||||
@ -214,6 +214,7 @@ err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
|
|||||||
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
|
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
|
||||||
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
|
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
|
||||||
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
|
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
|
||||||
|
void netconn_recved(struct netconn *conn, u32_t length);
|
||||||
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
|
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
|
||||||
ip_addr_t *addr, u16_t port);
|
ip_addr_t *addr, u16_t port);
|
||||||
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
|
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
|
||||||
@ -240,6 +241,27 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
|
|||||||
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
|
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
|
||||||
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
|
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
|
||||||
|
|
||||||
|
/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
|
||||||
|
#define netconn_set_noautorecved(conn, val) do { if(val) { \
|
||||||
|
(conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
|
||||||
|
} else { \
|
||||||
|
(conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
|
||||||
|
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
|
||||||
|
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
|
||||||
|
|
||||||
|
#if LWIP_SO_RCVTIMEO
|
||||||
|
/** Set the receive timeout in miliseconds */
|
||||||
|
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
|
||||||
|
/** Get the receive timeout in miliseconds */
|
||||||
|
#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
|
||||||
|
#endif /* LWIP_SO_RCVTIMEO */
|
||||||
|
#if LWIP_SO_RCVBUF
|
||||||
|
/** Set the receive buffer in bytes */
|
||||||
|
#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
|
||||||
|
/** Get the receive buffer in bytes */
|
||||||
|
#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
|
||||||
|
#endif /* LWIP_SO_RCVBUF*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,7 +87,7 @@ struct api_msg_msg {
|
|||||||
} w;
|
} w;
|
||||||
/** used for do_recv */
|
/** used for do_recv */
|
||||||
struct {
|
struct {
|
||||||
u16_t len;
|
u32_t len;
|
||||||
} r;
|
} r;
|
||||||
#if LWIP_IGMP
|
#if LWIP_IGMP
|
||||||
/** used for do_join_leave_group */
|
/** used for do_join_leave_group */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user