feat(lwip): Delete socket_mt and update lwip sys_arch from idf

Commit ID: 463a9d8b
This commit is contained in:
yuanjm
2020-03-10 16:04:28 +08:00
parent 2d11c90700
commit 9cf39c5f35
7 changed files with 239 additions and 1140 deletions

View File

@ -9,7 +9,6 @@ set(include_dirs
set(srcs
"apps/dhcpserver/dhcpserver.c"
"apps/multi-threads/sockets_mt.c"
"apps/ping/esp_ping.c"
"apps/ping/ping.c"
"apps/ping/ping_sock.c"
@ -136,10 +135,6 @@ if(CONFIG_ETH_ENABLED)
list(APPEND srcs "port/esp32/netif/ethernetif.c")
endif()
if(CONFIG_LWIP_SOCKET_MULTITHREAD)
set(COMPONENT_OBJEXCLUDE lwip/src/api/sockets.c)
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
LDFRAGMENTS linker.lf
@ -161,3 +156,11 @@ if(GCC_NOT_5_2_0)
-Wno-implicit-fallthrough
)
endif()
# "comparison is always false due to limited range of data type" warning
# when setting CONFIG_LWIP_TCP_WND_DEFAULT to 65535
set_source_files_properties(
lwip/src/core/tcp.c
PROPERTIES COMPILE_FLAGS
-Wno-type-limits
)

View File

@ -124,24 +124,6 @@ menu "LWIP"
help
Enabling this option allows LWIP statistics
config LWIP_SOCKET_MULTITHREAD
bool "LWIP socket supports multithread"
default y
help
Enable the option can enable LWIP socket multithread and all
function will be thread safe.
config SET_SOLINGER_DEFAULT
bool "set socket SO_LINGER default"
default y
depends on LWIP_SOCKET_MULTITHREAD
help
The function is only used by socket multi-thread.
Enable this option can set the target socket to enable the "SO_LINGER" and config timeout to be "0" when it is created.
It means that if close the socket, all send queue will be dropped, so heap memory can be collected immediately,
but some packets which are waiting to be sent will lost.
config LWIP_ETHARP_TRUST_IP_MAC
bool "Enable LWIP ARP trust"
default n

View File

@ -1,826 +0,0 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "lwip/opt.h"
#ifdef SOCKETS_MT
#define SOCKETS_MT_DISABLE_SHUTDOWN
#include "lwip/priv/api_msg.h"
/* disable all LWIP socket API when compiling LWIP raw socket */
#undef lwip_accept
#undef lwip_bind
#undef lwip_shutdown
#undef lwip_getpeername
#undef lwip_getsockname
#undef lwip_setsockopt
#undef lwip_getsockopt
#undef lwip_close
#undef lwip_connect
#undef lwip_listen
#undef lwip_recv
#undef lwip_recvfrom
#undef lwip_send
#undef lwip_sendmsg
#undef lwip_sendto
#undef lwip_socket
#undef lwip_select
#undef lwip_ioctlsocket
#define lwip_accept lwip_accept_esp
#define lwip_bind lwip_bind_esp
#define lwip_shutdown lwip_shutdown_esp
#define lwip_getpeername lwip_getpeername_esp
#define lwip_getsockname lwip_getsockname_esp
#define lwip_setsockopt lwip_setsockopt_esp
#define lwip_getsockopt lwip_getsockopt_esp
#define lwip_close lwip_closesocket_esp
#define lwip_connect lwip_connect_esp
#define lwip_listen lwip_listen_esp
#define lwip_recv lwip_recv_esp
#define lwip_recvfrom lwip_recvfrom_esp
#define lwip_send lwip_send_esp
#define lwip_sendmsg lwip_sendmsg_esp
#define lwip_sendto lwip_sendto_esp
#define lwip_socket lwip_socket_esp
#define lwip_select lwip_select_esp
#define lwip_ioctlsocket lwip_ioctl_esp
#undef lwip_read
#undef lwip_write
#undef lwip_writev
#undef lwip_close
#undef closesocket
#undef lwip_fcntl
#undef lwip_ioctl
#define lwip_read lwip_read_esp
#define lwip_write lwip_write_esp
#define lwip_writev lwip_writev_esp
#define lwip_close lwip_close_esp
#define lwip_fcntl lwip_fcntl_esp
#define lwip_ioctl lwip_ioctl_esp
#include "../../lwip/src/api/sockets.c"
/* disable macros to enable LWIP function */
#undef lwip_accept
#undef lwip_bind
#undef lwip_shutdown
#undef lwip_getpeername
#undef lwip_getsockname
#undef lwip_setsockopt
#undef lwip_getsockopt
#undef lwip_close
#undef lwip_connect
#undef lwip_listen
#undef lwip_recv
#undef lwip_recvfrom
#undef lwip_send
#undef lwip_sendmsg
#undef lwip_sendto
#undef lwip_socket
#undef lwip_select
#undef lwip_ioctlsocket
#undef lwip_read
#undef lwip_write
#undef lwip_writev
#undef lwip_close
#undef closesocket
#undef lwip_fcntl
#undef lwip_ioctl
/********************************************************************/
#define LWIP_SYNC_MT_SLEEP_MS 10
#define SOCK_MT_DEBUG_LEVEL 255
typedef struct socket_conn_sync {
struct tcpip_api_call_data call;
struct netconn *conn;
} socket_conn_sync_t;
typedef int (*lwip_io_mt_fn)(int, int );
/* Use about 2 bit */
#define SOCK_MT_STATE_SOCK 0
#define SOCK_MT_STATE_ACCEPT 1
#define SOCK_MT_STATE_CONNECT 2
#define SOCK_MT_STATE_SEND 3
#define SOCK_MT_STATE_ILL 4
#define SOCK_MT_LOCK_SEND (1 << 0)
#define SOCK_MT_LOCK_RECV (1 << 1)
#define SOCK_MT_LOCK_IOCTL (1 << 2)
#define SOCK_MT_LOCK_MIN SOCK_MT_LOCK_SEND
#define SOCK_MT_LOCK_MAX SOCK_MT_LOCK_IOCTL
#define SOCK_MT_SELECT_RECV (1 << 0)
#define SOCK_MT_SELECT_SEND (1 << 1)
typedef struct _sock_mt {
uint8_t opened : 1;
uint8_t state : 2;
uint8_t select : 2;
uint8_t lock : 3;
} sock_mt_t;
#if (SOCK_MT_DEBUG_LEVEL < 16)
#define SOCK_MT_DEBUG(level, ...) \
if (level >= SOCK_MT_DEBUG_LEVEL) \
printf(__VA_ARGS__);
#else
#define SOCK_MT_DEBUG(level, ...)
#endif
#define SOCK_MT_ENTER_CHECK(s, l, st) \
{ \
if (_sock_lock(s, l) != ERR_OK) \
return -1; \
if (st != SOCK_MT_STATE_ILL) \
_sock_set_state(s, st); \
}
#define SOCK_MT_EXIT_CHECK(s, l, st) \
{ \
if (st != SOCK_MT_STATE_ILL) \
_sock_set_state(s, SOCK_MT_STATE_SOCK); \
if (_sock_unlock(s, l) != ERR_OK) \
return -1; \
}
static volatile sock_mt_t DRAM_ATTR sockets_mt[NUM_SOCKETS];
static inline void _sock_mt_init(int s)
{
memset((void *)&sockets_mt[s - LWIP_SOCKET_OFFSET], 0, sizeof(sock_mt_t));
}
static inline int _sock_is_opened(int s)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].opened != 0;
}
static inline void _sock_set_open(int s, int opened)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].opened = opened;
SYS_ARCH_UNPROTECT(lev);
}
static inline void _sock_set_state(int s, int state)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].state = state;
SYS_ARCH_UNPROTECT(lev);
}
static inline int _sock_get_state(int s)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].state;
}
static inline int _sock_get_select(int s, int select)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].select & select;
}
static int inline _sock_is_lock(int s, int l)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].lock & l;
}
static int inline _sock_next_lock(int lock)
{
return lock << 1;
}
static void inline _sock_set_select(int s, int select)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].select |= select;
SYS_ARCH_UNPROTECT(lev);
}
static void inline _sock_reset_select(int s, int select)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].select &= ~select;
SYS_ARCH_UNPROTECT(lev);
}
static int _sock_try_lock(int s, int l)
{
int ret = ERR_OK;
SYS_ARCH_DECL_PROTECT(lev);
if (!_sock_is_opened(s)) {
ret = ERR_CLSD;
goto exit;
}
if (sockets_mt[s - LWIP_SOCKET_OFFSET].lock & l) {
ret = ERR_INPROGRESS;
goto exit;
}
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].lock |= l;
SYS_ARCH_UNPROTECT(lev);
exit:
return ret;
}
static int _sock_lock(int s, int l)
{
int ret = ERR_OK;
if (tryget_socket_unconn_nouse(s) == NULL)
return -1;
SOCK_MT_DEBUG(1, "s %d l %d enter ", s, l);
while (1) {
ret = _sock_try_lock(s, l);
if (ret != ERR_INPROGRESS)
break;
vTaskDelay(1);
}
SOCK_MT_DEBUG(1, "OK %d\n", ret);
return ret;
}
static int _sock_unlock(int s, int l)
{
int ret = 0;
SYS_ARCH_DECL_PROTECT(lev);
SOCK_MT_DEBUG(1, "s %d l %d exit ", s, l);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].lock &= ~l;
SYS_ARCH_UNPROTECT(lev);
if (!_sock_is_opened(s)) {
ret = ERR_CLSD;
goto exit;
}
exit:
SOCK_MT_DEBUG(1, "OK %d\n", ret);
return ret;
}
static int lwip_enter_mt_select(int s, fd_set *read_set, fd_set *write_set)
{
int i;
if (s > NUM_SOCKETS + LWIP_SOCKET_OFFSET || s < LWIP_SOCKET_OFFSET)
return -1;
for (i = 0; i < s; i++) {
if(FD_ISSET(i, read_set) || FD_ISSET(i, write_set))
if (tryget_socket_unconn_nouse(i) == NULL)
goto failed1;
if (FD_ISSET(i, read_set)) {
err_t err;
_sock_set_select(i, SOCK_MT_SELECT_RECV);
err = _sock_lock(i, SOCK_MT_LOCK_RECV);
if (err != ERR_OK) {
goto failed2;
}
}
if (FD_ISSET(i, write_set)) {
err_t err;
_sock_set_select(i, SOCK_MT_SELECT_SEND);
err = _sock_lock(i, SOCK_MT_LOCK_SEND);
if (err != ERR_OK) {
goto failed3;
}
}
}
return 0;
failed3:
_sock_unlock(i, SOCK_MT_LOCK_SEND);
_sock_reset_select(i, SOCK_MT_SELECT_SEND);
failed2:
if (FD_ISSET(i, read_set)) {
_sock_unlock(i, SOCK_MT_LOCK_RECV);
_sock_reset_select(i, SOCK_MT_SELECT_RECV);
}
failed1:
for (i--; i >=0; i--) {
if (FD_ISSET(i, read_set) ) {
_sock_unlock(i, SOCK_MT_LOCK_RECV);
_sock_reset_select(i, SOCK_MT_SELECT_RECV);
}
if (FD_ISSET(i, write_set)) {
_sock_unlock(i, SOCK_MT_LOCK_SEND);
_sock_reset_select(i, SOCK_MT_SELECT_SEND);
}
}
return -1;
}
static void lwip_exit_mt_select(int s, fd_set *read_set, fd_set *write_set)
{
int i;
for (i = 0; i < s; i++) {
if (FD_ISSET(i, read_set)) {
_sock_unlock(i, SOCK_MT_LOCK_RECV);
_sock_reset_select(i, SOCK_MT_SELECT_RECV);
}
if (FD_ISSET(i, write_set)) {
_sock_unlock(i, SOCK_MT_LOCK_SEND);
_sock_reset_select(i, SOCK_MT_SELECT_SEND);
}
}
}
static err_t lwip_do_sync_accept(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
if (sys_mbox_valid(&conn->acceptmbox))
sys_mbox_trypost(&conn->acceptmbox, NULL);
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static err_t lwip_do_sync_send(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
if (conn->current_msg) {
conn->current_msg->err = ERR_OK;
if (sys_sem_valid(conn->current_msg->op_completed_sem))
sys_sem_signal(conn->current_msg->op_completed_sem);
conn->current_msg = NULL;
}
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static err_t lwip_do_sync_recv_state(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
SOCK_MT_DEBUG(1, "sync recv %d\n", conn->socket);
if (sys_mbox_valid(&conn->recvmbox))
sys_mbox_trypost(&conn->recvmbox, NULL);
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static err_t lwip_do_sync_select_state(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
event_callback(conn, NETCONN_EVT_ERROR, 0);
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static void lwip_sync_state_mt(int s)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
int state = _sock_get_state(s);
socket_conn_sync_t sync = {
.conn = sock->conn,
};
SOCK_MT_DEBUG(1, "sync state %d\n", state);
switch (state) {
case SOCK_MT_STATE_ACCEPT :
tcpip_api_call(lwip_do_sync_accept, &sync.call);
break;
case SOCK_MT_STATE_CONNECT:
case SOCK_MT_STATE_SEND :
tcpip_api_call(lwip_do_sync_send, &sync.call);
break;
default :
break;
}
}
static void lwip_sync_recv_mt(int s)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
socket_conn_sync_t sync = {
.conn = sock->conn,
};
tcpip_api_call(lwip_do_sync_recv_state, &sync.call);
}
static void lwip_sync_select_mt(int s)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
socket_conn_sync_t sync = {
.conn = sock->conn,
};
tcpip_api_call(lwip_do_sync_select_state, &sync.call);
}
static void lwip_sync_mt(int s, int how)
{
int lock = SOCK_MT_LOCK_MIN;
do {
if (_sock_is_lock(s, lock)) {
int need_wait = 0;
if (!_sock_get_select(s, SOCK_MT_SELECT_RECV | SOCK_MT_SELECT_SEND)) {
switch (lock) {
case SOCK_MT_LOCK_SEND:
lwip_sync_state_mt(s);
need_wait = 1;
break;
case SOCK_MT_LOCK_RECV:
lwip_sync_recv_mt(s);
need_wait = 1;
break;
default :
break;
}
} else {
lwip_sync_select_mt(s);
need_wait = 1;
}
if (need_wait)
sys_delay_ms(LWIP_SYNC_MT_SLEEP_MS);
} else
lock = _sock_next_lock(lock);
} while (lock < SOCK_MT_LOCK_MAX);
}
#if SET_SOLINGER_DEFAULT
#if LWIP_SO_LINGER
static void lwip_socket_set_so_link(int s, int linger)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
if (sock) {
/*
* linker:
* -1: nothing
* 0: free sent_buf immediately
*/
sock->conn->linger = linger;
}
}
#else
#error "LWIP_SO_LINGER must be enable"
#endif /* LWIP_SO_LINGER */
#else /* SET_SOLINGER_DEFAULT */
#define lwip_socket_set_so_link(_s, _linger)
#endif /* SET_SOLINGER_DEFAULT */
int lwip_socket(int domain, int type, int protocol)
{
int s;
s = lwip_socket_esp(domain, type, protocol);
if (s < 0)
return -1;
lwip_socket_set_so_link(s, 0);
_sock_mt_init(s);
_sock_set_open(s, 1);
return s;
}
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
ret = lwip_bind_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_CONNECT);
ret = lwip_connect_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_CONNECT);
return ret;
}
int lwip_listen(int s, int backlog)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
lwip_socket_set_so_link(s, -1);
ret = lwip_listen_esp(s, backlog);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ACCEPT)
lwip_socket_set_so_link(s, -1);
ret = lwip_accept_esp(s, addr, addrlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ACCEPT);
if (ret < 0)
return -1;
lwip_socket_set_so_link(ret, 0);
_sock_mt_init(ret);
_sock_set_open(ret, 1);
return ret;
}
int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_getpeername_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_getsockname_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_setsockopt_esp(s, level, optname, optval, optlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
int ret;
if (tryget_socket_unconn_nouse(s) == NULL)
return -1;
if (optname == SO_ERROR) {
int retval = 0;
if (!_sock_is_opened(s))
retval = ENOTCONN;
if (retval) {
*(int *)optval = retval;
return 0;
}
}
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_getsockopt_esp(s, level, optname, optval, optlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_ioctl(int s, long cmd, void *argp)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL)
ret = lwip_ioctl_esp(s, cmd, argp);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_sendto(int s, const void *data, size_t size, int flags,
const struct sockaddr *to, socklen_t tolen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
ret = lwip_sendto_esp(s, data, size, flags, to, tolen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
return ret;
}
int lwip_send(int s, const void *data, size_t size, int flags)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
ret = lwip_send_esp(s, data, size, flags);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
return ret;
}
int lwip_recvfrom(int s, void *mem, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_RECV, SOCK_MT_STATE_ILL);
ret = lwip_recvfrom_esp(s, mem, len, flags, from, fromlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_RECV, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_recv(int s, void *mem, size_t len, int flags)
{
return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
}
int lwip_read(int s, void *mem, size_t len)
{
return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
}
int lwip_write(int s, const void *data, size_t size)
{
return lwip_send(s, data, size, 0);
}
int lwip_fcntl(int s, int cmd, int val)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_fcntl_esp(s, cmd, val);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_shutdown(int s, int how)
{
return 0;
}
int lwip_close(int s)
{
int ret;
SYS_ARCH_DECL_PROTECT(lev);
if (tryget_socket_unconn_nouse(s) == NULL)
return -1;
SYS_ARCH_PROTECT(lev);
if (_sock_is_opened(s)) {
_sock_set_open(s, 0);
SYS_ARCH_UNPROTECT(lev);
} else {
SYS_ARCH_UNPROTECT(lev);
return -1;
}
lwip_sync_mt(s, SHUT_RDWR);
ret = lwip_close_esp(s);
return ret;
}
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset,
fd_set *exceptset, struct timeval *timeout)
{
int ret;
fd_set read_set, write_set;
if (readset)
MEMCPY(&read_set, readset, sizeof(fd_set));
else
FD_ZERO(&read_set);
if (writeset)
MEMCPY(&write_set, writeset, sizeof(fd_set));
else
FD_ZERO(&write_set);
ret = lwip_enter_mt_select(maxfdp1, &read_set, &write_set);
if (ret)
return ret;
ret = lwip_select_esp(maxfdp1, readset, writeset, exceptset, timeout);
lwip_exit_mt_select(maxfdp1, &read_set, &write_set);
return ret;
}
#endif

View File

@ -30,12 +30,6 @@ ifndef CONFIG_IDF_TARGET_ESP32
COMPONENT_OBJEXCLUDE := port/esp8266/netif/ethernetif.o
endif
ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
COMPONENT_SRCDIRS += apps/multi-threads
COMPONENT_OBJEXCLUDE += lwip/src/api/sockets.o
endif
ifdef CONFIG_LWIP_PPP_SUPPORT
COMPONENT_SRCDIRS += lwip/src/netif/ppp lwip/src/netif/ppp/polarssl
endif
@ -47,4 +41,6 @@ lwip/src/netif/ppp/ppp.o: CFLAGS += -Wno-uninitialized
lwip/src/netif/ppp/pppos.o: CFLAGS += -Wno-implicit-fallthrough
endif
lwip/src/core/tcp.o: CFLAGS += -Wno-type-limits
COMPONENT_ADD_LDFRAGMENTS += linker.lf

View File

@ -41,7 +41,9 @@
#include "lwip/stats.h"
#include "esp_log.h"
static const char* TAG = "lwip_arch";
/* This is the number of threads that can be started with sys_thread_new() */
#define SYS_THREAD_MAX 4
#define TAG "lwip_arch"
static sys_mutex_t g_lwip_protect_mutex = NULL;
@ -49,167 +51,160 @@ static pthread_key_t sys_thread_sem_key;
static void sys_thread_sem_free(void* data);
#if !LWIP_COMPAT_MUTEX
/**
* @brief Create a new mutex
*
* @param pxMutex pointer of the mutex to create
* @return ERR_OK on success, ERR_MEM when out of memory
*/
/** Create a new mutex
* @param mutex pointer to the mutex to create
* @return a new mutex */
err_t
sys_mutex_new(sys_mutex_t *pxMutex)
{
err_t xReturn = ERR_MEM;
*pxMutex = xSemaphoreCreateMutex();
if (*pxMutex == NULL) {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: out of mem\r\n"));
return ERR_MEM;
if (*pxMutex != NULL) {
xReturn = ERR_OK;
}
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex));
return ERR_OK;
return xReturn;
}
/**
* @brief Lock a mutex
*
* @param pxMutex pointer of mutex to lock
*/
void
/** Lock a mutex
* @param mutex the mutex to lock */
void ESP_IRAM_ATTR
sys_mutex_lock(sys_mutex_t *pxMutex)
{
BaseType_t ret = xSemaphoreTake(*pxMutex, portMAX_DELAY);
LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS);
}
/**
* @brief Unlock a mutex
*
* @param pxMutex pointer of mutex to unlock
*/
void
err_t
sys_mutex_trylock(sys_mutex_t *pxMutex)
{
if (xSemaphoreTake(*pxMutex, 0) == pdPASS) return 0;
else return -1;
}
/** Unlock a mutex
* @param mutex the mutex to unlock */
void ESP_IRAM_ATTR
sys_mutex_unlock(sys_mutex_t *pxMutex)
{
BaseType_t ret = xSemaphoreGive(*pxMutex);
LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
xSemaphoreGive(*pxMutex);
}
/**
* @brief Delete a mutex
*
* @param pxMutex pointer of mutex to delete
*/
/** Delete a semaphore
* @param mutex the mutex to delete */
void
sys_mutex_free(sys_mutex_t *pxMutex)
{
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex));
vSemaphoreDelete(*pxMutex);
*pxMutex = NULL;
vQueueDelete(*pxMutex);
}
#endif
#endif /* !LWIP_COMPAT_MUTEX */
/**
* @brief Creates a new semaphore
*
* @param sem pointer of the semaphore
* @param count initial state of the semaphore
* @return err_t
*/
/*-----------------------------------------------------------------------------------*/
// Creates and returns a new semaphore. The "count" argument specifies
// the initial state of the semaphore. TBD finish and test
err_t
sys_sem_new(sys_sem_t *sem, u8_t count)
{
LWIP_ASSERT("initial_count invalid (neither 0 nor 1)",
(count == 0) || (count == 1));
err_t xReturn = ERR_MEM;
vSemaphoreCreateBinary(*sem);
*sem = xSemaphoreCreateBinary();
if (*sem == NULL) {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_sem_new: out of mem\r\n"));
return ERR_MEM;
if ((*sem) != NULL) {
if (count == 0) { // Means it can't be taken
xSemaphoreTake(*sem, 1);
}
if (count == 1) {
BaseType_t ret = xSemaphoreGive(*sem);
LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
xReturn = ERR_OK;
} else {
; // TBD need assert
}
return ERR_OK;
return xReturn;
}
/**
* @brief Signals a semaphore
*
* @param sem pointer of the semaphore
*/
void
/*-----------------------------------------------------------------------------------*/
// Signals a semaphore
void ESP_IRAM_ATTR
sys_sem_signal(sys_sem_t *sem)
{
BaseType_t ret = xSemaphoreGive(*sem);
/* queue full is OK, this is a signal only... */
LWIP_ASSERT("sys_sem_signal: sane return value",
(ret == pdTRUE) || (ret == errQUEUE_FULL));
xSemaphoreGive(*sem);
}
/*-----------------------------------------------------------------------------------*/
// Signals a semaphore (from ISR)
int
sys_sem_signal_isr(sys_sem_t *sem)
int sys_sem_signal_isr(sys_sem_t *sem)
{
BaseType_t woken = pdFALSE;
xSemaphoreGiveFromISR(*sem, &woken);
return woken == pdTRUE;
}
/**
* @brief Wait for a semaphore to be signaled
*
* @param sem pointer of the semaphore
* @param timeout if zero, will wait infinitely, or will wait for milliseconds specify by this argument
* @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds).
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
*/
u32_t
u32_t ESP_IRAM_ATTR
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
BaseType_t ret;
portTickType StartTime, EndTime, Elapsed;
unsigned long ulReturn;
if (!timeout) {
/* wait infinite */
ret = xSemaphoreTake(*sem, portMAX_DELAY);
LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
StartTime = xTaskGetTickCount();
if (timeout != 0) {
if (xSemaphoreTake(*sem, timeout / portTICK_PERIOD_MS) == pdTRUE) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
ulReturn = Elapsed;
} else {
TickType_t timeout_ticks = timeout / portTICK_RATE_MS;
ret = xSemaphoreTake(*sem, timeout_ticks);
if (ret == errQUEUE_EMPTY) {
/* timed out */
return SYS_ARCH_TIMEOUT;
ulReturn = SYS_ARCH_TIMEOUT;
}
LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
} else { // must block without a timeout
while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE);
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
return 0;
ulReturn = Elapsed;
}
/**
* @brief Delete a semaphore
*
* @param sem pointer of the semaphore to delete
*/
return ulReturn ; // return time blocked
}
/*-----------------------------------------------------------------------------------*/
// Deallocates a semaphore
void
sys_sem_free(sys_sem_t *sem)
{
vSemaphoreDelete(*sem);
*sem = NULL;
}
/**
* @brief Create an empty mailbox.
*
* @param mbox pointer of the mailbox
* @param size size of the mailbox
* @return ERR_OK on success, ERR_MEM when out of memory
*/
/*-----------------------------------------------------------------------------------*/
// Creates an empty mailbox.
err_t
sys_mbox_new(sys_mbox_t *mbox, int size)
{
@ -222,7 +217,7 @@ sys_mbox_new(sys_mbox_t *mbox, int size)
(*mbox)->os_mbox = xQueueCreate(size, sizeof(void *));
if ((*mbox)->os_mbox == NULL) {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new (*mbox)->os_mbox\n"));
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox->os_mbox\n"));
free(*mbox);
return ERR_MEM;
}
@ -235,32 +230,21 @@ sys_mbox_new(sys_mbox_t *mbox, int size)
return ERR_OK;
}
/**
* @brief Send message to mailbox
*
* @param mbox pointer of the mailbox
* @param msg pointer of the message to send
*/
void
/*-----------------------------------------------------------------------------------*/
// Posts the "msg" to the mailbox.
void ESP_IRAM_ATTR
sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
BaseType_t ret = xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY);
LWIP_ASSERT("mbox post failed", ret == pdTRUE);
while (xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY) != pdTRUE);
}
/**
* @brief Try to post a message to mailbox
*
* @param mbox pointer of the mailbox
* @param msg pointer of the message to send
* @return ERR_OK on success, ERR_MEM when mailbox is full
*/
err_t
/*-----------------------------------------------------------------------------------*/
err_t ESP_IRAM_ATTR
sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
err_t xReturn;
if (xQueueSend((*mbox)->os_mbox, &msg, 0) == pdTRUE) {
if (xQueueSend((*mbox)->os_mbox, &msg, (portTickType)0) == pdPASS) {
xReturn = ERR_OK;
} else {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox));
@ -270,95 +254,83 @@ sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
return xReturn;
}
/**
* @brief Try to post a message to mailbox from ISR
*
* @param mbox pointer of the mailbox
* @param msg pointer of the message to send
* @return ERR_OK on success
* ERR_MEM when mailbox is full
* ERR_NEED_SCHED when high priority task wakes up
*/
err_t
sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
{
BaseType_t ret;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
ret = xQueueSendFromISR((*mbox)->os_mbox, &msg, &xHigherPriorityTaskWoken);
if (ret == pdTRUE) {
if (xHigherPriorityTaskWoken == pdTRUE) {
return ERR_NEED_SCHED;
}
return ERR_OK;
} else {
LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
return ERR_MEM;
}
}
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
/**
* @brief Fetch message from mailbox
*
* @param mbox pointer of mailbox
* @param msg pointer of the received message, could be NULL to indicate the message should be dropped
* @param timeout if zero, will wait infinitely; or will wait milliseconds specify by this argument
* @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
*/
u32_t
u32_t ESP_IRAM_ATTR
sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
BaseType_t ret;
void *msg_dummy;
void *dummyptr;
portTickType StartTime, EndTime, Elapsed;
unsigned long ulReturn;
StartTime = xTaskGetTickCount();
if (msg == NULL) {
msg = &msg_dummy;
msg = &dummyptr;
}
if (*mbox == NULL){
*msg = NULL;
return -1;
}
if (timeout == 0) {
/* wait infinite */
ret = xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY);
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
timeout = portMAX_DELAY;
} else {
TickType_t timeout_ticks = timeout / portTICK_RATE_MS;
ret = xQueueReceive((*mbox)->os_mbox, &(*msg), timeout_ticks);
if (ret == errQUEUE_EMPTY) {
/* timed out */
timeout = timeout / portTICK_PERIOD_MS;
}
*msg = NULL;
return SYS_ARCH_TIMEOUT;
}
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), timeout)) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
return 0;
ulReturn = Elapsed;
} else { // timed out blocking for message
ulReturn = SYS_ARCH_TIMEOUT;
}
/**
* @brief try to fetch message from mailbox
*
* @param mbox pointer of mailbox
* @param msg pointer of the received message
* @return SYS_MBOX_EMPTY if mailbox is empty, 1 otherwise
*/
return ulReturn ; // return time blocked TBD test
}
/*-----------------------------------------------------------------------------------*/
u32_t
sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
BaseType_t ret;
void *msg_dummy;
void *pvDummy;
unsigned long ulReturn;
if (msg == NULL) {
msg = &msg_dummy;
msg = &pvDummy;
}
ret = xQueueReceive((*mbox)->os_mbox, &(*msg), 0);
if (ret == errQUEUE_EMPTY) {
*msg = NULL;
return SYS_MBOX_EMPTY;
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), 0)) {
ulReturn = ERR_OK;
} else {
ulReturn = SYS_MBOX_EMPTY;
}
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
return 0;
return ulReturn;
}
/*-----------------------------------------------------------------------------------*/
void
sys_mbox_set_owner(sys_mbox_t *mbox, void* owner)
{
@ -368,10 +340,10 @@ sys_mbox_set_owner(sys_mbox_t *mbox, void* owner)
}
}
/**
* @brief Delete a mailbox
*
* @param mbox pointer of the mailbox to delete
/*
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
*/
void
sys_mbox_free(sys_mbox_t *mbox)
@ -379,46 +351,37 @@ sys_mbox_free(sys_mbox_t *mbox)
if ( (NULL == mbox) || (NULL == *mbox) ) {
return;
}
UBaseType_t msgs_waiting = uxQueueMessagesWaiting((*mbox)->os_mbox);
LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
vQueueDelete((*mbox)->os_mbox);
free(*mbox);
*mbox = NULL;
}
/**
* @brief Create a new thread
*
* @param name thread name
* @param thread thread function
* @param arg thread arguments
* @param stacksize stacksize of the thread
* @param prio priority of the thread
* @return thread ID
/*-----------------------------------------------------------------------------------*/
/*
Starts a new thread with priority "prio" that will begin its execution in the
function "thread()". The "arg" argument will be passed as an argument to the
thread() function. The id of the new thread is returned. Both the id and
the priority are system dependent.
*/
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
TaskHandle_t rtos_task;
BaseType_t ret;
xTaskHandle created_task;
portBASE_TYPE result;
/* LwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the
thread function without adaption here. */
ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task,
result = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &created_task,
CONFIG_LWIP_TCPIP_TASK_AFFINITY);
if (ret != pdTRUE) {
if (result != pdPASS) {
return NULL;
}
return (sys_thread_t)rtos_task;
return created_task;
}
/**
* @brief Initialize the sys_arch layer
*
*/
/*-----------------------------------------------------------------------------------*/
// Initialize sys arch
void
sys_init(void)
{
@ -432,34 +395,32 @@ sys_init(void)
esp_vfs_lwip_sockets_register();
}
/**
* @brief Get system ticks
*
* @return system tick counts
*/
/*-----------------------------------------------------------------------------------*/
u32_t
sys_jiffies(void)
{
return xTaskGetTickCount();
}
/**
* @brief Get current time, in miliseconds
*
* @return current time
*/
/*-----------------------------------------------------------------------------------*/
u32_t
sys_now(void)
{
return xTaskGetTickCount() * portTICK_PERIOD_MS;
return (xTaskGetTickCount()*portTICK_PERIOD_MS);
}
/**
* @brief Protect critical region
*
* @note This function is only called during very short critical regions.
*
* @return previous protection level
/*
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
*/
sys_prot_t
sys_arch_protect(void)
@ -468,23 +429,23 @@ sys_arch_protect(void)
return (sys_prot_t) 1;
}
/**
* @brief Unprotect critical region
*
* @param pval protection level
/*-----------------------------------------------------------------------------------*/
/*
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
*/
void
sys_arch_unprotect(sys_prot_t pval)
{
LWIP_UNUSED_ARG(pval);
sys_mutex_unlock(&g_lwip_protect_mutex);
}
/*
* get per thread semaphore
* get per thread semphore
*/
sys_sem_t*
sys_thread_sem_get(void)
sys_sem_t* sys_thread_sem_get(void)
{
sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key);
@ -495,8 +456,7 @@ sys_thread_sem_get(void)
return sem;
}
static void
sys_thread_sem_free(void* data) // destructor for TLS semaphore
static void sys_thread_sem_free(void* data) // destructor for TLS semaphore
{
sys_sem_t *sem = (sys_sem_t*)(data);
@ -511,8 +471,7 @@ sys_thread_sem_free(void* data) // destructor for TLS semaphore
}
}
sys_sem_t*
sys_thread_sem_init(void)
sys_sem_t* sys_thread_sem_init(void)
{
sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*));
@ -532,8 +491,7 @@ sys_thread_sem_init(void)
return sem;
}
void
sys_thread_sem_deinit(void)
void sys_thread_sem_deinit(void)
{
sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key);
if (sem != NULL) {
@ -542,8 +500,9 @@ sys_thread_sem_deinit(void)
}
}
void
sys_delay_ms(uint32_t ms)
void sys_delay_ms(uint32_t ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}

View File

@ -44,22 +44,15 @@ extern "C" {
#endif
typedef SemaphoreHandle_t sys_sem_t;
typedef SemaphoreHandle_t sys_mutex_t;
typedef TaskHandle_t sys_thread_t;
typedef xSemaphoreHandle sys_sem_t;
typedef xSemaphoreHandle sys_mutex_t;
typedef xTaskHandle sys_thread_t;
typedef struct sys_mbox_s {
QueueHandle_t os_mbox;
xQueueHandle os_mbox;
void *owner;
}* sys_mbox_t;
/** This is returned by _fromisr() sys functions to tell the outermost function
* that a higher priority task was woken and the scheduler needs to be invoked.
*/
#define ERR_NEED_SCHED 123
void sys_delay_ms(uint32_t ms);
#define sys_msleep(ms) sys_delay_ms(ms)
#define LWIP_COMPAT_MUTEX 0

View File

@ -567,13 +567,6 @@
*/
#define LWIP_SO_RCVBUF CONFIG_LWIP_SO_RCVBUF
/**
* LWIP_SO_LINGER==1: Enable SO_LINGER processing.
*/
#define LWIP_SO_LINGER 1
#define SET_SOLINGER_DEFAULT CONFIG_SET_SOLINGER_DEFAULT
/**
* SO_REUSE==1: Enable SO_REUSEADDR option.
* This option is set via menuconfig.
@ -792,9 +785,7 @@
#define LWIP_SOCKET_OFFSET (FD_SETSIZE - CONFIG_LWIP_MAX_SOCKETS)
/* Enable all Espressif-only options */
#ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
#define SOCKETS_MT
#endif
#define ESP_LWIP 1
#define ESP_LWIP_ARP 1
#define ESP_PER_SOC_TCP_WND 0
@ -824,6 +815,7 @@
#define ESP_IPV6 LWIP_IPV6
#define ESP_SOCKET 1
#define ESP_LWIP_SELECT 1
#define ESP_LWIP_LOCK 1
#ifdef ESP_IRAM_ATTR
#undef ESP_IRAM_ATTR