mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-02-04 21:39:49 +00:00
Implemented timeout on send (TCP only, bug #33820)
This commit is contained in:
parent
8d5514603e
commit
a2aa43a426
@ -6,6 +6,10 @@ HISTORY
|
||||
|
||||
++ New features:
|
||||
|
||||
2011-09-21: Simon Goldschmidt
|
||||
* opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on
|
||||
send (TCP only, bug #33820)
|
||||
|
||||
2011-09-21: Simon Goldschmidt
|
||||
* init.c: Converted runtime-sanity-checks into compile-time checks that can
|
||||
be disabled (since runtime checks can often not be seen on embedded targets)
|
||||
|
@ -611,12 +611,26 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
|
||||
msg.msg.msg.w.dataptr = dataptr;
|
||||
msg.msg.msg.w.apiflags = apiflags;
|
||||
msg.msg.msg.w.len = size;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
if (conn->send_timeout != 0) {
|
||||
/* get the time we started, which is later compared to
|
||||
sys_now() + conn->send_timeout */
|
||||
msg.msg.msg.w.time_started = sys_now();
|
||||
} else {
|
||||
msg.msg.msg.w.time_started = 0;
|
||||
}
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
|
||||
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
||||
but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
||||
non-blocking version here. */
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
if ((err == ERR_OK) && (bytes_written != NULL)) {
|
||||
if (dontblock) {
|
||||
if (dontblock
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
|| (conn->send_timeout != 0)
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
) {
|
||||
/* nonblocking write: maybe the data has been sent partly */
|
||||
*bytes_written = msg.msg.msg.w.len;
|
||||
} else {
|
||||
|
@ -626,6 +626,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||
conn->current_msg = NULL;
|
||||
conn->write_offset = 0;
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
conn->send_timeout = 0;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
conn->recv_timeout = 0;
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
@ -1217,79 +1220,95 @@ do_writemore(struct netconn *conn)
|
||||
LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
|
||||
conn->write_offset < conn->current_msg->msg.w.len);
|
||||
|
||||
dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
|
||||
diff = conn->current_msg->msg.w.len - conn->write_offset;
|
||||
if (diff > 0xffffUL) { /* max_u16_t */
|
||||
len = 0xffff;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
} else {
|
||||
len = (u16_t)diff;
|
||||
}
|
||||
available = tcp_sndbuf(conn->pcb.tcp);
|
||||
if (available < len) {
|
||||
/* don't try to write more than sendbuf */
|
||||
len = available;
|
||||
if (dontblock){
|
||||
if (!len) {
|
||||
err = ERR_WOULDBLOCK;
|
||||
goto err_mem;
|
||||
}
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
if ((conn->send_timeout != 0) &&
|
||||
((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
|
||||
write_finished = 1;
|
||||
if (conn->write_offset == 0) {
|
||||
/* nothing has been written */
|
||||
err = ERR_WOULDBLOCK;
|
||||
conn->current_msg->msg.w.len = 0;
|
||||
} else {
|
||||
/* partial write */
|
||||
err = ERR_OK;
|
||||
conn->current_msg->msg.w.len = conn->write_offset;
|
||||
}
|
||||
} else
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
{
|
||||
dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
|
||||
diff = conn->current_msg->msg.w.len - conn->write_offset;
|
||||
if (diff > 0xffffUL) { /* max_u16_t */
|
||||
len = 0xffff;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
} else {
|
||||
len = (u16_t)diff;
|
||||
}
|
||||
}
|
||||
LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
|
||||
err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
|
||||
/* if OK or memory error, check available space */
|
||||
if ((err == ERR_OK) || (err == ERR_MEM)) {
|
||||
available = tcp_sndbuf(conn->pcb.tcp);
|
||||
if (available < len) {
|
||||
/* don't try to write more than sendbuf */
|
||||
len = available;
|
||||
if (dontblock){
|
||||
if (!len) {
|
||||
err = ERR_WOULDBLOCK;
|
||||
goto err_mem;
|
||||
}
|
||||
} else {
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
}
|
||||
}
|
||||
LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
|
||||
err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
|
||||
/* if OK or memory error, check available space */
|
||||
if ((err == ERR_OK) || (err == ERR_MEM)) {
|
||||
err_mem:
|
||||
if (dontblock && (len < conn->current_msg->msg.w.len)) {
|
||||
/* non-blocking write did not write everything: mark the pcb non-writable
|
||||
and let poll_tcp check writable space to mark the pcb writable again */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
|
||||
} else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
|
||||
(tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
|
||||
/* The queued byte- or pbuf-count exceeds the configured low-water limit,
|
||||
let select mark this pcb as non-writable. */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
if (dontblock && (len < conn->current_msg->msg.w.len)) {
|
||||
/* non-blocking write did not write everything: mark the pcb non-writable
|
||||
and let poll_tcp check writable space to mark the pcb writable again */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
|
||||
} else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
|
||||
(tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
|
||||
/* The queued byte- or pbuf-count exceeds the configured low-water limit,
|
||||
let select mark this pcb as non-writable. */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ERR_OK) {
|
||||
conn->write_offset += len;
|
||||
if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
|
||||
/* return sent length */
|
||||
conn->current_msg->msg.w.len = conn->write_offset;
|
||||
/* everything was written */
|
||||
write_finished = 1;
|
||||
conn->write_offset = 0;
|
||||
}
|
||||
tcp_output(conn->pcb.tcp);
|
||||
} else if ((err == ERR_MEM) && !dontblock) {
|
||||
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
|
||||
we do NOT return to the application thread, since ERR_MEM is
|
||||
only a temporary error! */
|
||||
if (err == ERR_OK) {
|
||||
conn->write_offset += len;
|
||||
if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
|
||||
/* return sent length */
|
||||
conn->current_msg->msg.w.len = conn->write_offset;
|
||||
/* everything was written */
|
||||
write_finished = 1;
|
||||
conn->write_offset = 0;
|
||||
}
|
||||
tcp_output(conn->pcb.tcp);
|
||||
} else if ((err == ERR_MEM) && !dontblock) {
|
||||
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
|
||||
we do NOT return to the application thread, since ERR_MEM is
|
||||
only a temporary error! */
|
||||
|
||||
/* tcp_write returned ERR_MEM, try tcp_output anyway */
|
||||
tcp_output(conn->pcb.tcp);
|
||||
/* tcp_write returned ERR_MEM, try tcp_output anyway */
|
||||
tcp_output(conn->pcb.tcp);
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
} else {
|
||||
/* On errors != ERR_MEM, we don't try writing any more but return
|
||||
the error to the application thread. */
|
||||
write_finished = 1;
|
||||
conn->current_msg->msg.w.len = 0;
|
||||
} else {
|
||||
/* On errors != ERR_MEM, we don't try writing any more but return
|
||||
the error to the application thread. */
|
||||
write_finished = 1;
|
||||
conn->current_msg->msg.w.len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (write_finished) {
|
||||
/* everything was written: set back connection state
|
||||
and back to application task */
|
||||
|
@ -1535,7 +1535,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
|
||||
case SO_ERROR:
|
||||
case SO_KEEPALIVE:
|
||||
/* UNIMPL case SO_CONTIMEO: */
|
||||
/* UNIMPL case SO_SNDTIMEO: */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
@ -1780,6 +1782,11 @@ lwip_getsockopt_internal(void *arg)
|
||||
s, *(int *)optval));
|
||||
break;
|
||||
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
*(int *)optval = netconn_get_sendtimeout(sock->conn);
|
||||
break;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
*(int *)optval = netconn_get_recvtimeout(sock->conn);
|
||||
@ -1934,7 +1941,9 @@ 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: */
|
||||
/* UNIMPL case case SO_SNDTIMEO: */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
@ -2160,6 +2169,11 @@ lwip_setsockopt_internal(void *arg)
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
|
||||
s, optname, (*(int*)optval?"on":"off")));
|
||||
break;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval);
|
||||
break;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
netconn_set_recvtimeout(sock->conn, *(int*)optval);
|
||||
|
@ -180,6 +180,11 @@ struct netconn {
|
||||
#if LWIP_SOCKET
|
||||
int socket;
|
||||
#endif /* LWIP_SOCKET */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
/** timeout to wait for sending data (which means enqueueing data for sending
|
||||
in internal buffers) */
|
||||
s32_t send_timeout;
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
/** timeout to wait for new data to be received
|
||||
(or connections to arrive for listening netconns) */
|
||||
@ -299,6 +304,12 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
|
||||
/** 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_SNDTIMEO
|
||||
/** Set the send timeout in milliseconds */
|
||||
#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout))
|
||||
/** Get the send timeout in milliseconds */
|
||||
#define netconn_get_sendtimeout(conn) ((conn)->send_timeout)
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
/** Set the receive timeout in milliseconds */
|
||||
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
|
||||
|
@ -89,6 +89,9 @@ struct api_msg_msg {
|
||||
const void *dataptr;
|
||||
size_t len;
|
||||
u8_t apiflags;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
u32_t time_started;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
} w;
|
||||
/** used for do_recv */
|
||||
struct {
|
||||
|
@ -1434,6 +1434,14 @@
|
||||
#define LWIP_TCP_KEEPALIVE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
|
||||
* SO_SNDTIMEO processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_SNDTIMEO
|
||||
#define LWIP_SO_SNDTIMEO 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
|
||||
* SO_RCVTIMEO processing.
|
||||
|
Loading…
x
Reference in New Issue
Block a user