diff --git a/net/Kconfig b/net/Kconfig index a3d57202863..083e6e1821d 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -117,6 +117,12 @@ config NET_GUARDSIZE packet size will be chopped down to the size indicated in the TCP header. +config NET_RECV_BUFSIZE + int "Net Receive buffer size" + default 0 + ---help--- + This is the default value for receive buffer size. + endmenu # Driver buffer configuration menu "Link layer support" diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c index fd22f315aac..6e424ca7df0 100644 --- a/net/socket/setsockopt.c +++ b/net/socket/setsockopt.c @@ -131,9 +131,71 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, { _SO_SETOPT(psock->s_options, option); } + + return OK; } - return OK; +#if CONFIG_NET_RECV_BUFSIZE > 0 + case SO_RCVBUF: /* Sets receive buffer size */ + { + int buffersize; + + /* Verify that option is the size of an 'int'. Should also check + * that 'value' is properly aligned for an 'int' + */ + + if (value_len != sizeof(int)) + { + return -EINVAL; + } + + /* Get the value. Is the option being set or cleared? */ + + buffersize = *(FAR int *)value; + + if (buffersize < 0 || buffersize > INT_MAX) + { + return -EINVAL; + } + + net_lock(); + +#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK) + if (psock->s_type == SOCK_STREAM) + { + FAR struct tcp_conn_s *conn; + + conn = (FAR struct tcp_conn_s *)psock->s_conn; + + /* Save the receive buffer size */ + + conn->rcv_bufs = buffersize; + } + else +#endif +#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK) + if (psock->s_type == SOCK_DGRAM) + { + FAR struct udp_conn_s *conn; + + conn = (FAR struct udp_conn_s *)psock->s_conn; + + /* Save the receive buffer size */ + + conn->rcvbufs = buffersize; + } + else +#endif + { + net_unlock(); + return -ENOPROTOOPT; + } + + net_unlock(); + + return OK; + } +#endif } #ifdef CONFIG_NET_USRSOCK @@ -274,7 +336,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #endif /* The following are not yet implemented */ - case SO_RCVBUF: /* Sets receive buffer size */ case SO_RCVLOWAT: /* Sets the minimum number of bytes to input */ case SO_SNDBUF: /* Sets send buffer size */ case SO_SNDLOWAT: /* Sets the minimum number of bytes to output */ diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index e1cfe808861..66da9c81daa 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -190,6 +190,9 @@ struct tcp_conn_s uint16_t snd_wnd; /* Sequence and acknowledgement numbers of last * window update */ uint32_t rcv_adv; /* The right edge of the recv window advertized */ +#if CONFIG_NET_RECV_BUFSIZE > 0 + int32_t rcv_bufs; /* Maximum amount of bytes queued in recv */ +#endif #ifdef CONFIG_NET_TCP_WRITE_BUFFERS uint32_t tx_unacked; /* Number bytes sent but not yet ACKed */ #else diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index d78d7f12504..f5ef61d91a0 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -672,6 +672,9 @@ FAR struct tcp_conn_s *tcp_alloc(uint8_t domain) conn->keepidle = 2 * DSEC_PER_HOUR; conn->keepintvl = 2 * DSEC_PER_SEC; conn->keepcnt = 3; +#endif +#if CONFIG_NET_RECV_BUFSIZE > 0 + conn->rcv_bufs = CONFIG_NET_RECV_BUFSIZE; #endif } diff --git a/net/tcp/tcp_recvwindow.c b/net/tcp/tcp_recvwindow.c index 3f0e0b850aa..74129fb8fcd 100644 --- a/net/tcp/tcp_recvwindow.c +++ b/net/tcp/tcp_recvwindow.c @@ -41,6 +41,46 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: tcp_calc_rcvsize + * + * Description: + * Calculate the possible max TCP receive buffer size for the connection. + * + * Input Parameters: + * conn - The TCP connection. + * recvwndo - The TCP receive window size + * + * Returned Value: + * The value of the TCP receive buffer size. + * + ****************************************************************************/ + +static uint16_t tcp_calc_rcvsize(FAR struct tcp_conn_s *conn, + uint16_t recvwndo) +{ +#if CONFIG_NET_RECV_BUFSIZE > 0 + uint32_t recvsize; + uint32_t desire; + + recvsize = conn->readahead ? conn->readahead->io_pktlen : 0; + if (conn->rcv_bufs > recvsize) + { + desire = conn->rcv_bufs - recvsize; + if (recvwndo > desire) + { + recvwndo = desire; + } + } + else + { + recvwndo = 0; + } +#endif + + return recvwndo; +} + /**************************************************************************** * Name: tcp_maxrcvwin * @@ -73,7 +113,7 @@ static uint16_t tcp_maxrcvwin(FAR struct tcp_conn_s *conn) maxwin = maxiob; } - return maxwin; + return tcp_calc_rcvsize(conn, maxwin); } /**************************************************************************** @@ -181,7 +221,7 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev, recvwndo = tailroom; } - return recvwndo; + return tcp_calc_rcvsize(conn, recvwndo); } bool tcp_should_send_recvwindow(FAR struct tcp_conn_s *conn) diff --git a/net/udp/udp.h b/net/udp/udp.h index eb5e73dbe88..71a4b2ef453 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -120,6 +120,9 @@ struct udp_conn_s uint8_t boundto; /* Index of the interface we are bound to. * Unbound: 0, Bound: 1-MAX_IFINDEX */ #endif +#if CONFIG_NET_RECV_BUFSIZE > 0 + int32_t rcvbufs; /* Maximum amount of bytes queued in recv */ +#endif /* Read-ahead buffering. * diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c index 1374dce03a4..47d91f2cfb5 100644 --- a/net/udp/udp_callback.c +++ b/net/udp/udp_callback.c @@ -83,6 +83,14 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR void *src_addr; uint8_t src_addr_size; +#if CONFIG_NET_RECV_BUFSIZE > 0 + while (iob_get_queue_size(&conn->readahead) > conn->rcvbufs) + { + iob = iob_remove_queue(&conn->readahead); + iob_free_chain(iob, IOBUSER_NET_UDP_READAHEAD); + } +#endif + /* Allocate on I/O buffer to start the chain (throttling as necessary). * We will not wait for an I/O buffer to become available in this context. */ diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index 7a784ab900f..c2af6d97782 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -585,6 +585,9 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain) #endif conn->lport = 0; conn->ttl = IP_TTL; +#if CONFIG_NET_RECV_BUFSIZE > 0 + conn->rcvbufs = CONFIG_NET_RECV_BUFSIZE; +#endif #ifdef CONFIG_NET_UDP_WRITE_BUFFERS /* Initialize the write buffer lists */