/* 套接字结构体 */
struct lwip_sock
{
/* API连接指针 */
struct netconn *conn;
/* 前一次读剩下的数据 */
void *lastdata;
/* 前一次读数据的偏移量 */
u16_t lastoffset;
/* 接收数据的次数 */
s16_t rcvevent;
/* 发送成功的次数 */
u16_t sendevent;
/* 错误发生次数 */
u16_t errevent;
/* 最近发生的错误 */
int err;
/* 所有select描述符个数 */
int select_waiting;
};
/* select控制块 */
struct lwip_select_cb
{
/* 用于将所有控制块连接起来 */
struct lwip_select_cb *next;
struct lwip_select_cb *prev;
/* 读描述符集合 */
fd_set *readset;
/* 写描述符集合 */
fd_set *writeset;
/* 异常描述符集合 */
fd_set *exceptset;
/* 触发事件设1 */
int sem_signalled;
/* 信号量 */
sys_sem_t sem;
};
/* 套接字属性数据 */
struct lwip_setgetsockopt_data
{
/* 所属套接字 */
struct lwip_sock *sock;
int level; //层
int optname; //选项名字
void *optval; //数据
socklen_t *optlen; //数据长度
err_t err;
};
/* 套接字数组 */
static struct lwip_sock sockets[NUM_SOCKETS];
/* select链表 */
static struct lwip_select_cb *select_cb_list;
/* 链表发生改变时就加一 */
static volatile int select_cb_ctr;
/* 错误类型 */
static const int err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* 内存不足 */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* 参数错误 */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ISCONN -9 Already connected. */
ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
ECONNRESET, /* ERR_RST -11 Connection reset. */
ENOTCONN, /* ERR_CLSD -12 Connection closed. */
ENOTCONN, /* ERR_CONN -13 Not connected. */
EIO, /* 内部错误 */
-1, /* ERR_IF -15 Low-level netif error */
};
#define ERR_TO_ERRNO_TABLE_SIZE \
(sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
#define err_to_errno(err) \
((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
err_to_errno_table[-(err)] : EIO)
#define set_errno(err)
/* 套接字设置错误 */
#define sock_set_errno(sk, e) do { \
sk->err = (e); \
set_errno(sk->err); \
} while (0)
static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
static void lwip_getsockopt_internal(void *arg);
static void lwip_setsockopt_internal(void *arg);
/* socket编程初始化 */
void lwip_socket_init(void)
{
}
/* 根据套接字描述符获取套接字结构体指针 */
static struct lwip_sock *get_socket(int s)
{
struct lwip_sock *sock;
if((s < 0) || (s >= NUM_SOCKETS))
{
set_errno(EBADF);
return NULL;
}
sock = &sockets[s];
if(!sock->conn)
{
set_errno(EBADF);
return NULL;
}
return sock;
}
/* 通过套接字描述符获取套接字 */
static struct lwip_sock *tryget_socket(int s)
{
if((s < 0) || (s >= NUM_SOCKETS))
{
return NULL;
}
if(!sockets[s].conn)
{
return NULL;
}
return &sockets[s];
}
/* 创建套接字描述符 */
static int alloc_socket(struct netconn *newconn, int accepted)
{
int i;
/* 找一个空的套接字描述符 */
for(i = 0; i < NUM_SOCKETS; ++i)
{
if(!sockets[i].conn)
{
/* 初始化所有参数 */
sockets[i].conn = newconn;
SYS_ARCH_UNPROTECT(lev);
sockets[i].lastdata = NULL;
sockets[i].lastoffset = 0;
sockets[i].rcvevent = 0;
sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
sockets[i].errevent = 0;
sockets[i].err = 0;
sockets[i].select_waiting = 0;
return i;
}
}
return -1;
}
/* 释放套接字 */
static void free_socket(struct lwip_sock *sock, int is_tcp)
{
void *lastdata;
lastdata = sock->lastdata;
sock->lastdata = NULL;
sock->lastoffset = 0;
sock->err = 0;
sock->conn = NULL;
/* 释放已经收到未取用的数据 */
if(lastdata != NULL)
{
if(is_tcp)
{
pbuf_free((struct pbuf *)lastdata);
}
else
{
netbuf_delete((struct netbuf *)lastdata);
}
}
}
/* 接受连接 */
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
struct lwip_sock *sock, *nsock;
struct netconn *newconn;
ip_addr_t naddr;
u16_t port;
int newsock;
struct sockaddr_in sin;
err_t err;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* 非阻塞,并且没有连接事件,返回错误 */
if(netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0))
{
sock_set_errno(sock, EWOULDBLOCK);
return -1;
}
/* 接受连接 */
err = netconn_accept(sock->conn, &newconn);
if(err != ERR_OK)
{
if(netconn_type(sock->conn) != NETCONN_TCP)
{
sock_set_errno(sock, EOPNOTSUPP);
return EOPNOTSUPP;
}
sock_set_errno(sock, err_to_errno(err));
return -1;
}
/* 设置不自动接收数据 */
netconn_set_noautorecved(newconn, 1);
/* 获取本地IP和端口号 */
err = netconn_peer(newconn, &naddr, &port);
if(err != ERR_OK)
{
netconn_delete(newconn);
sock_set_errno(sock, err_to_errno(err));
return -1;
}
/* 填充sockaddr_in结构体 */
if(NULL != addr)
{
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
if(*addrlen > sizeof(sin))
*addrlen = sizeof(sin);
MEMCPY(addr, &sin, *addrlen);
}
/* 为新连接创建新的套接字描述符 */
newsock = alloc_socket(newconn, 1);
if(newsock == -1)
{
netconn_delete(newconn);
sock_set_errno(sock, ENFILE);
return -1;
}
nsock = &sockets[newsock];
nsock->rcvevent += (s16_t)(-1 - newconn->socket);
newconn->socket = newsock;
sock_set_errno(sock, 0);
/* 返回套接字描述符 */
return newsock;
}
/* 绑定本地端口 */
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
struct lwip_sock *sock;
ip_addr_t local_addr;
u16_t local_port;
err_t err;
const struct sockaddr_in *name_in;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* 类型转换 */
name_in = (const struct sockaddr_in *)(void *)name;
/* 取出IP地址和端口号 */
inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
local_port = name_in->sin_port;
/* 绑定本地端口 */
err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
if(err != ERR_OK)
{
sock_set_errno(sock, err_to_errno(err));
return -1;
}
sock_set_errno(sock, 0);
return 0;
}
/* 关闭套接字 */
int lwip_close(int s)
{
struct lwip_sock *sock;
int is_tcp = 0;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
if(sock->conn != NULL)
{
is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
}
/* 删除连接 */
netconn_delete(sock->conn);
/* 释放套接字 */
free_socket(sock, is_tcp);
set_errno(0);
return 0;
}
/* 连接远程端口 */
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
struct lwip_sock *sock;
err_t err;
const struct sockaddr_in *name_in;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* 类型转换 */
name_in = (const struct sockaddr_in *)(void*)name;
if(name_in->sin_family == AF_UNSPEC)
{
err = netconn_disconnect(sock->conn);
}
else
{
ip_addr_t remote_addr;
u16_t remote_port;
/* 取出IP和端口号 */
inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
remote_port = name_in->sin_port;
/* 连接远程端口 */
err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
}
if(err != ERR_OK)
{
sock_set_errno(sock, err_to_errno(err));
return -1;
}
sock_set_errno(sock, 0);
return 0;
}
/* 侦听 */
int lwip_listen(int s, int backlog)
{
struct lwip_sock *sock;
err_t err;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* 监听队列最大数 */
backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
/* 开始侦听 */
err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
if(err != ERR_OK)
{
if(netconn_type(sock->conn) != NETCONN_TCP)
{
sock_set_errno(sock, EOPNOTSUPP);
return EOPNOTSUPP;
}
sock_set_errno(sock, err_to_errno(err));
return -1;
}
sock_set_errno(sock, 0);
return 0;
}
/* 接收数据(可选非阻塞/数据接收后不删除,返回远程IP和端口号) */
int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{
struct lwip_sock *sock;
void *buf = NULL;
struct pbuf *p;
u16_t buflen, copylen;
int off = 0;
ip_addr_t *addr;
u16_t port;
u8_t done = 0;
err_t err;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
do
{
/* 前一次读剩下数据 */
if(sock->lastdata)
{
buf = sock->lastdata;
}
/* 前一次没有读剩下数据 */
else
{
/* 非阻塞态,且没有数据 */
if(((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && (sock->rcvevent <= 0))
{
if(off > 0)
{
netconn_recved(sock->conn, (u32_t)off);
sock_set_errno(sock, 0);
return off;
}
sock_set_errno(sock, EWOULDBLOCK);
return -1;
}
/* 接收数据 */
if(netconn_type(sock->conn) == NETCONN_TCP)
{
err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
}
else
{
err = netconn_recv(sock->conn, (struct netbuf **)&buf);
}
/* 更新接收窗口 */
if(err != ERR_OK)
{
if(off > 0)
{
netconn_recved(sock->conn, (u32_t)off);
sock_set_errno(sock, 0);
return off;
}
sock_set_errno(sock, err_to_errno(err));
if(err == ERR_CLSD)
{
return 0;
}
else
{
return -1;
}
}
sock->lastdata = buf;
}
/* 取出数据pbuf */
if(netconn_type(sock->conn) == NETCONN_TCP)
{
p = (struct pbuf *)buf;
}
else
{
p = ((struct netbuf *)buf)->p;
}
/* 数据长度 */
buflen = p->tot_len;
buflen -= sock->lastoffset;
if(len > buflen)
{
copylen = buflen;
}
else
{
copylen = (u16_t)len;
}
/* 将数据拷贝出来 */
pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
off += copylen;
/* 数据是否读完 */
if(netconn_type(sock->conn) == NETCONN_TCP)
{
len -= copylen;
if((len <= 0) || (p->flags & PBUF_FLAG_PUSH) || (sock->rcvevent <= 0) || ((flags & MSG_PEEK) != 0))
{
done = 1;
}
}
else
{
done = 1;
}
/* 数据读完 */
if(done)
{
ip_addr_t fromaddr;
if(from && fromlen)
{
struct sockaddr_in sin;
/* 获取远程IP和端口号 */
if(netconn_type(sock->conn) == NETCONN_TCP)
{
addr = &fromaddr;
netconn_getaddr(sock->conn, addr, &port, 0);
}
else
{
addr = netbuf_fromaddr((struct netbuf *)buf);
port = netbuf_fromport((struct netbuf *)buf);
}
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_addr_from_ipaddr(&sin.sin_addr, addr);
if(*fromlen > sizeof(sin))
{
*fromlen = sizeof(sin);
}
MEMCPY(from, &sin, *fromlen);
}
}
/* 释放已经读取的数据 */
if((flags & MSG_PEEK) == 0)
{
if((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0))
{
sock->lastdata = buf;
sock->lastoffset += copylen;
}
else
{
sock->lastdata = NULL;
sock->lastoffset = 0;
if(netconn_type(sock->conn) == NETCONN_TCP)
{
pbuf_free((struct pbuf *)buf);
}
else
{
netbuf_delete((struct netbuf *)buf);
}
}
}
}while(!done);
/* 更新接收窗口 */
if(off > 0)
{
netconn_recved(sock->conn, (u32_t)off);
}
sock_set_errno(sock, 0);
return off;
}
/* 接收数据 */
int lwip_read(int s, void *mem, size_t len)
{
return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
}
/* 接收数据 */
int lwip_recv(int s, void *mem, size_t len, int flags)
{
return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
}
/* 发送数据(用于已经绑定远程IP和端口号) */
int lwip_send(int s, const void *data, size_t size, int flags)
{
struct lwip_sock *sock;
err_t err;
u8_t write_flags;
size_t written;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* 发送非TCP数据 */
if(sock->conn->type != NETCONN_TCP)
{
return lwip_sendto(s, data, size, flags, NULL, 0);
}
/* TCP发送数据 */
write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
written = 0;
err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? (int)written : -1);
}
/* 发送数据(用于未绑定远程IP和端口号) */
int lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
{
struct lwip_sock *sock;
err_t err;
u16_t short_size;
const struct sockaddr_in *to_in;
u16_t remote_port;
struct netbuf buf;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* TCP发送数据 */
if(sock->conn->type == NETCONN_TCP)
{
return lwip_send(s, data, size, flags);
}
short_size = (u16_t)size;
to_in = (const struct sockaddr_in *)(void*)to;
buf.p = buf.ptr = NULL;
/* 设置netbuf远程IP和端口号 */
if(to)
{
inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
remote_port = ntohs(to_in->sin_port);
netbuf_fromport(&buf) = remote_port;
}
else
{
remote_port = 0;
ip_addr_set_any(&buf.addr);
netbuf_fromport(&buf) = 0;
}
/* 为netbuf申请PBUF_REF型pbuf内存,指向已存在RAM */
err = netbuf_ref(&buf, data, short_size);
/* UDP或RAW发送数据 */
if(err == ERR_OK)
{
err = netconn_send(sock->conn, &buf);
}
/* 释放netbuf */
netbuf_free(&buf);
sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? short_size : -1);
}
/* 创建套接字 */
int lwip_socket(int domain, int type, int protocol)
{
struct netconn *conn;
int i;
/* 判断套接字类型 */
switch(type)
{
/* 原始套接字 */
case SOCK_RAW:
/* 创建一个原始IP连接并且设置回调函数 */
conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
break;
/* 数据报套接字 */
case SOCK_DGRAM:
/* 创建一个UDP连接结构体并且设置回调函数 */
conn = netconn_new_with_callback((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP, event_callback);
break;
/* 流式套接字 */
case SOCK_STREAM:
/* 创建一个TCP连接结构体并且设置回调函数 */
conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
if(conn != NULL)
{
/* 设置不自动接收数据 */
netconn_set_noautorecved(conn, 1);
}
break;
default:
set_errno(EINVAL);
return -1;
}
if(!conn)
{
set_errno(ENOBUFS);
return -1;
}
/* 创建套接字描述符 */
i = alloc_socket(conn, 0);
/* 失败 */
if(i == -1)
{
/* 删除连接 */
netconn_delete(conn);
set_errno(ENFILE);
return -1;
}
/* 套接字描述符 */
conn->socket = i;
set_errno(0);
return i;
}
/* 发送数据(用于已经绑定远程IP和端口号) */
int lwip_write(int s, const void *data, size_t size)
{
return lwip_send(s, data, size, 0);
}
/* 扫描读写错误集合有没有事件发生 */
static int lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
{
int i, nready = 0;
fd_set lreadset, lwriteset, lexceptset;
struct lwip_sock *sock;
/* 清空所有集合 */
FD_ZERO(&lreadset);
FD_ZERO(&lwriteset);
FD_ZERO(&lexceptset);
/* 检查所有描述符 */
for(i = 0; i < maxfdp1; i++)
{
void* lastdata = NULL;
s16_t rcvevent = 0;
u16_t sendevent = 0;
u16_t errevent = 0;
/* 通过套接字描述符获取套接字 */
sock = tryget_socket(i);
/* 获取套接字已经发生的事件数 */
if(sock != NULL)
{
lastdata = sock->lastdata;
rcvevent = sock->rcvevent;
sendevent = sock->sendevent;
errevent = sock->errevent;
}
/* 该描述符发生读事件且属于读集合 */
if(readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0)))
{
/* 设置读事件 */
FD_SET(i, &lreadset);
nready++;
}
/* 该描述符发生写事件且属于写集合 */
if(writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0))
{
/* 设置写事件 */
FD_SET(i, &lwriteset);
nready++;
}
/* 该描述符发生异常事件且属于异常集合 */
if(exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0))
{
/* 设置异常事件 */
FD_SET(i, &lexceptset);
nready++;
}
}
/* 返回读写异常事件集合 */
*readset_out = lreadset;
*writeset_out = lwriteset;
*exceptset_out = lexceptset;
return nready;
}
/* 多路复用 */
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)
{
u32_t waitres = 0;
int nready;
fd_set lreadset, lwriteset, lexceptset;
u32_t msectimeout;
struct lwip_select_cb select_cb;
err_t err;
int i;
/* 扫描读写错误集合有没有事件发生 */
nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
/* 没有事件发生 */
if(!nready)
{
/* 阻塞时间0 */
if(timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
{
goto return_copy_fdsets;
}
/* 创建select信号 */
select_cb.next = NULL;
select_cb.prev = NULL;
select_cb.readset = readset;
select_cb.writeset = writeset;
select_cb.exceptset = exceptset;
select_cb.sem_signalled = 0;
err = sys_sem_new(&select_cb.sem, 0);
if(err != ERR_OK)
{
set_errno(ENOMEM);
return -1;
}
/* 插入select链表 */
select_cb.next = select_cb_list;
if(select_cb_list != NULL)
{
select_cb_list->prev = &select_cb;
}
select_cb_list = &select_cb;
select_cb_ctr++;
/* 统计需要select描述符个数 */
for(i = 0; i < maxfdp1; i++)
{
if((readset && FD_ISSET(i, readset)) ||
(writeset && FD_ISSET(i, writeset)) ||
(exceptset && FD_ISSET(i, exceptset)))
{
struct lwip_sock *sock = tryget_socket(i);
sock->select_waiting++;
}
}
/* 扫描读写错误集合有没有事件发生 */
nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
/* 没有事件发生 */
if(!nready)
{
/* 永远阻塞 */
if(timeout == 0)
{
msectimeout = 0;
}
/* 阻塞时间 */
else
{
msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000));
if(msectimeout == 0)
{
msectimeout = 1;
}
}
/* 等待事件发生 */
waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
}
/* 检查是否有改变 */
for(i = 0; i < maxfdp1; i++)
{
if((readset && FD_ISSET(i, readset)) ||
(writeset && FD_ISSET(i, writeset)) ||
(exceptset && FD_ISSET(i, exceptset)))
{
struct lwip_sock *sock = tryget_socket(i);
sock->select_waiting--;
}
}
/* 将select控制块从链表删除 */
if(select_cb.next != NULL)
{
select_cb.next->prev = select_cb.prev;
}
if(select_cb_list == &select_cb)
{
select_cb_list = select_cb.next;
}
else
{
select_cb.prev->next = select_cb.next;
}
select_cb_ctr++;
/* 释放信号量 */
sys_sem_free(&select_cb.sem);
/* 超时 */
if(waitres == SYS_ARCH_TIMEOUT)
{
goto return_copy_fdsets;
}
/* 扫描读写错误集合有没有事件发生 */
nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
}
return_copy_fdsets:
set_errno(0);
/* 返回发生事件集合 */
if(readset)
{
*readset = lreadset;
}
if(writeset)
{
*writeset = lwriteset;
}
if(exceptset)
{
*exceptset = lexceptset;
}
return nready;
}
/* 套接字回调函数 */
static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
{
int s;
struct lwip_sock *sock;
struct lwip_select_cb *scb;
int last_select_cb_ctr;
if(conn)
{
s = conn->socket;
if(s < 0)
{
if(conn->socket < 0)
{
if(evt == NETCONN_EVT_RCVPLUS)
{
conn->socket--;
}
return;
}
s = conn->socket;
}
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return;
}
}
else
{
return;
}
/* 事件处理 */
switch(evt)
{
case NETCONN_EVT_RCVPLUS:
sock->rcvevent++;
break;
case NETCONN_EVT_RCVMINUS:
sock->rcvevent--;
break;
case NETCONN_EVT_SENDPLUS:
sock->sendevent = 1;
break;
case NETCONN_EVT_SENDMINUS:
sock->sendevent = 0;
break;
case NETCONN_EVT_ERROR:
sock->errevent = 1;
break;
default:
break;
}
if(sock->select_waiting == 0)
{
return;
}
again:
/* 检查是否存在select事件 */
for(scb = select_cb_list; scb != NULL; scb = scb->next)
{
if(scb->sem_signalled == 0)
{
int do_signal = 0;
if(sock->rcvevent > 0)
{
if(scb->readset && FD_ISSET(s, scb->readset))
{
do_signal = 1;
}
}
if(sock->sendevent != 0)
{
if(!do_signal && scb->writeset && FD_ISSET(s, scb->writeset))
{
do_signal = 1;
}
}
if(sock->errevent != 0)
{
if(!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset))
{
do_signal = 1;
}
}
/* 存在则解除阻塞 */
if(do_signal)
{
scb->sem_signalled = 1;
sys_sem_signal(&scb->sem);
}
}
last_select_cb_ctr = select_cb_ctr;
if(last_select_cb_ctr != select_cb_ctr)
{
goto again;
}
}
}
/* 关闭套接字连接方向 */
int lwip_shutdown(int s, int how)
{
struct lwip_sock *sock;
err_t err;
u8_t shut_rx = 0, shut_tx = 0;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
if(sock->conn != NULL)
{
if(netconn_type(sock->conn) != NETCONN_TCP)
{
sock_set_errno(sock, EOPNOTSUPP);
return EOPNOTSUPP;
}
}
else
{
sock_set_errno(sock, ENOTCONN);
return ENOTCONN;
}
/* 关闭连接方向 */
if(how == SHUT_RD)
{
shut_rx = 1;
}
else if(how == SHUT_WR)
{
shut_tx = 1;
}
else if(how == SHUT_RDWR)
{
shut_rx = 1;
shut_tx = 1;
}
else
{
sock_set_errno(sock, EINVAL);
return EINVAL;
}
err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? 0 : -1);
}
/* 获取本地或者远程IP和端口号 */
static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
{
struct lwip_sock *sock;
struct sockaddr_in sin;
ip_addr_t naddr;
/* 根据套接字描述符获取套接字结构体指针 */
sock = get_socket(s);
if(!sock)
{
return -1;
}
/* 获取本地或者远程IP和端口号 */
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
sin.sin_port = htons(sin.sin_port);
inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
if(*namelen > sizeof(sin))
{
*namelen = sizeof(sin);
}
MEMCPY(name, &sin, *namelen);
sock_set_errno(sock, 0);
return 0;
}
/* 获取远程IP和端口号 */
int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
return lwip_getaddrname(s, name, namelen, 0);
}
/* 获取本地IP和端口号 */
int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
return lwip_getaddrname(s, name, namelen, 1);
}
/* 获取套接字属性 */
int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
err_t err = ERR_OK;
struct lwip_sock *sock = get_socket(s);
struct lwip_setgetsockopt_data data;
if(!sock)
{
return -1;
}
if((NULL == optval) || (NULL == optlen))
{
sock_set_errno(sock, EFAULT);
return -1;
}
/* 判断参数合不合理 */
switch(level)
{
/* 套接字层 */
case SOL_SOCKET:
/* 选项名 */
switch (optname)
{
case SO_ACCEPTCONN:
case SO_BROADCAST:
/* UNIMPL case SO_DEBUG: */
/* UNIMPL case SO_DONTROUTE: */
case SO_ERROR:
case SO_KEEPALIVE:
/* UNIMPL case SO_CONTIMEO: */
/* UNIMPL case SO_OOBINLINE: */
/* UNIMPL case SO_SNDBUF: */
/* UNIMPL case SO_RCVLOWAT: */
/* UNIMPL case SO_SNDLOWAT: */
case SO_TYPE:
/* UNIMPL case SO_USELOOPBACK: */
if(*optlen < sizeof(int))
{
err = EINVAL;
}
break;
case SO_NO_CHECK:
if(*optlen < sizeof(int))
{
err = EINVAL;
}
if((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0))
{
err = EAFNOSUPPORT;
}
break;
default:
err = ENOPROTOOPT;
}
break;
/* IP层 */
case IPPROTO_IP:
switch(optname)
{
/* UNIMPL case IP_HDRINCL: */
/* UNIMPL case IP_RCVDSTADDR: */
/* UNIMPL case IP_RCVIF: */
case IP_TTL:
case IP_TOS:
if(*optlen < sizeof(int))
{
err = EINVAL;
}
break;
default:
err = ENOPROTOOPT;
}
break;
/* TCP层 */
case IPPROTO_TCP:
if(*optlen < sizeof(int))
{
err = EINVAL;
break;
}
if(sock->conn->type != NETCONN_TCP)
return 0;
/* 选项名 */
switch(optname)
{
case TCP_NODELAY:
case TCP_KEEPALIVE:
break;
default:
err = ENOPROTOOPT;
}
break;
/* Level: IPPROTO_UDPLITE */
case IPPROTO_UDPLITE:
if(*optlen < sizeof(int))
{
err = EINVAL;
break;
}
if(sock->conn->type != NETCONN_UDPLITE)
{
return 0;
}
switch(optname)
{
case UDPLITE_SEND_CSCOV:
case UDPLITE_RECV_CSCOV:
break;
default:
err = ENOPROTOOPT;
}
break;
/* UNDEFINED LEVEL */
default:
err = ENOPROTOOPT;
}
if(err != ERR_OK)
{
sock_set_errno(sock, err);
return -1;
}
/* 通知内核调用lwip_getsockopt_internal函数来处理套接字选项 */
data.sock = sock;
data.level = level;
data.optname = optname;
data.optval = optval;
data.optlen = optlen;
data.err = err;
tcpip_callback(lwip_getsockopt_internal, &data);
sys_arch_sem_wait(&sock->conn->op_completed, 0);
err = data.err;
sock_set_errno(sock, err);
return err ? -1 : 0;
}
/* 获取套接字选项 */
static void lwip_getsockopt_internal(void *arg)
{
struct lwip_sock *sock;
int level, optname;
void *optval;
struct lwip_setgetsockopt_data *data;
data = (struct lwip_setgetsockopt_data *)arg;
sock = data->sock;
level = data->level;
optname = data->optname;
optval = data->optval;
switch(level)
{
/* 套接字层 */
case SOL_SOCKET:
switch(optname)
{
case SO_ACCEPTCONN:
case SO_BROADCAST:
/* UNIMPL case SO_DEBUG: */
/* UNIMPL case SO_DONTROUTE: */
case SO_KEEPALIVE:
/* UNIMPL case SO_OOBINCLUDE: */
/*case SO_USELOOPBACK: UNIMPL */
*(int *)optval = ip_get_option(sock->conn->pcb.ip, optname);
break;
case SO_TYPE:
switch(NETCONNTYPE_GROUP(sock->conn->type))
{
case NETCONN_RAW:
*(int*)optval = SOCK_RAW;
break;
case NETCONN_TCP:
*(int*)optval = SOCK_STREAM;
break;
case NETCONN_UDP:
*(int*)optval = SOCK_DGRAM;
break;
default:
*(int*)optval = sock->conn->type;
}
break;
case SO_ERROR:
if((sock->err == 0) || (sock->err == EINPROGRESS))
{
sock_set_errno(sock, err_to_errno(sock->conn->last_err));
}
*(int *)optval = sock->err;
sock->err = 0;
break;
case SO_NO_CHECK:
*(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
break;
default:
break;
}
break;
/* Level: IPPROTO_IP */
case IPPROTO_IP:
switch(optname)
{
case IP_TTL:
*(int*)optval = sock->conn->pcb.ip->ttl;
break;
case IP_TOS:
*(int*)optval = sock->conn->pcb.ip->tos;
break;
default:
break;
}
break;
case IPPROTO_TCP:
switch(optname)
{
case TCP_NODELAY:
*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
break;
case TCP_KEEPALIVE:
*(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
break;
default:
LWIP_ASSERT("unhandled optname", 0);
break;
}
break;
case IPPROTO_UDPLITE:
switch(optname)
{
case UDPLITE_SEND_CSCOV:
*(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
break;
case UDPLITE_RECV_CSCOV:
*(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
break;
default:
break;
}
break;
default:
break;
}
sys_sem_signal(&sock->conn->op_completed);
}
/* 设置套接字属性 */
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
struct lwip_sock *sock = get_socket(s);
err_t err = ERR_OK;
struct lwip_setgetsockopt_data data;
if(!sock)
{
return -1;
}
if(NULL == optval)
{
sock_set_errno(sock, EFAULT);
return -1;
}
/* 判断参数合不合理 */
switch(level)
{
/* Level: SOL_SOCKET */
case SOL_SOCKET:
switch (optname)
{
case SO_BROADCAST:
/* UNIMPL case SO_DEBUG: */
/* UNIMPL case SO_DONTROUTE: */
case SO_KEEPALIVE:
/* UNIMPL case case SO_CONTIMEO: */
/* UNIMPL case SO_OOBINLINE: */
/* UNIMPL case SO_SNDBUF: */
/* UNIMPL case SO_RCVLOWAT: */
/* UNIMPL case SO_SNDLOWAT: */
/* UNIMPL case SO_USELOOPBACK: */
if(optlen < sizeof(int))
{
err = EINVAL;
}
break;
case SO_NO_CHECK:
if(optlen < sizeof(int))
{
err = EINVAL;
}
if((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0))
{
err = EAFNOSUPPORT;
}
break;
default:
err = ENOPROTOOPT;
}
break;
/* Level: IPPROTO_IP */
case IPPROTO_IP:
switch(optname)
{
/* UNIMPL case IP_HDRINCL: */
/* UNIMPL case IP_RCVDSTADDR: */
/* UNIMPL case IP_RCVIF: */
case IP_TTL:
case IP_TOS:
if(optlen < sizeof(int))
{
err = EINVAL;
}
break;
default:
err = ENOPROTOOPT;
}
break;
/* Level: IPPROTO_TCP */
case IPPROTO_TCP:
if(optlen < sizeof(int))
{
err = EINVAL;
break;
}
if(sock->conn->type != NETCONN_TCP)
return 0;
switch(optname)
{
case TCP_NODELAY:
case TCP_KEEPALIVE:
break;
default:
err = ENOPROTOOPT;
}
break;
/* Level: IPPROTO_UDPLITE */
case IPPROTO_UDPLITE:
if(optlen < sizeof(int))
{
err = EINVAL;
break;
}
if(sock->conn->type != NETCONN_UDPLITE)
return 0;
switch(optname)
{
case UDPLITE_SEND_CSCOV:
case UDPLITE_RECV_CSCOV:
break;
default:
err = ENOPROTOOPT;
}
break;
/* UNDEFINED LEVEL */
default:
err = ENOPROTOOPT;
}
if(err != ERR_OK)
{
sock_set_errno(sock, err);
return -1;
}
/* 通知内核调用lwip_setsockopt_internal函数来处理套接字选项 */
data.sock = sock;
data.level = level;
data.optname = optname;
data.optval = (void*)optval;
data.optlen = &optlen;
data.err = err;
tcpip_callback(lwip_setsockopt_internal, &data);
sys_arch_sem_wait(&sock->conn->op_completed, 0);
err = data.err;
sock_set_errno(sock, err);
return err ? -1 : 0;
}
/* 设置套接字选项 */
static void lwip_setsockopt_internal(void *arg)
{
struct lwip_sock *sock;
int level, optname;
const void *optval;
struct lwip_setgetsockopt_data *data;
data = (struct lwip_setgetsockopt_data*)arg;
sock = data->sock;
level = data->level;
optname = data->optname;
optval = data->optval;
switch(level)
{
/* Level: SOL_SOCKET */
case SOL_SOCKET:
switch(optname)
{
/* The option flags */
case SO_BROADCAST:
/* UNIMPL case SO_DEBUG: */
/* UNIMPL case SO_DONTROUTE: */
case SO_KEEPALIVE:
/* UNIMPL case SO_OOBINCLUDE: */
/* UNIMPL case SO_USELOOPBACK: */
if(*(int*)optval)
{
ip_set_option(sock->conn->pcb.ip, optname);
}
else
{
ip_reset_option(sock->conn->pcb.ip, optname);
}
break;
case SO_NO_CHECK:
if(*(int*)optval)
{
udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
}
else
{
udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
}
break;
default:
break;
} /* switch (optname) */
break;
/* Level: IPPROTO_IP */
case IPPROTO_IP:
switch(optname)
{
case IP_TTL:
sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", s, sock->conn->pcb.ip->ttl));
break;
case IP_TOS:
sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", s, sock->conn->pcb.ip->tos));
break;
default:
break;
}
break;
/* Level: IPPROTO_TCP */
case IPPROTO_TCP:
switch(optname)
{
case TCP_NODELAY:
if(*(int*)optval)
{
tcp_nagle_disable(sock->conn->pcb.tcp);
}
else
{
tcp_nagle_enable(sock->conn->pcb.tcp);
}
break;
case TCP_KEEPALIVE:
sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
break;
default:
break;
}
break;
case IPPROTO_UDPLITE:
switch (optname)
{
case UDPLITE_SEND_CSCOV:
if((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff)))
{
sock->conn->pcb.udp->chksum_len_tx = 8;
}
else
{
sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
}
break;
case UDPLITE_RECV_CSCOV:
if((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff)))
{
sock->conn->pcb.udp->chksum_len_rx = 8;
}
else
{
sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
}
break;
default:
break;
}
break;
default:
break;
}
/* 通知完成 */
sys_sem_signal(&sock->conn->op_completed);
}
/* 设置IO属性 */
int lwip_ioctl(int s, long cmd, void *argp)
{
/* 根据套接字描述符获取套接字结构体指针 */
struct lwip_sock *sock = get_socket(s);
u8_t val;
if(!sock)
{
return -1;
}
switch(cmd)
{
/* 设置非阻塞 */
case FIONBIO:
val = 0;
if(argp && *(u32_t*)argp)
{
val = 1;
}
netconn_set_nonblocking(sock->conn, val);
sock_set_errno(sock, 0);
return 0;
default:
sock_set_errno(sock, ENOSYS); /* not yet implemented */
return -1;
}
}
/* 文件属性操作 */
int lwip_fcntl(int s, int cmd, int val)
{
struct lwip_sock *sock = get_socket(s);
int ret = -1;
if(!sock || !sock->conn)
{
return -1;
}
switch(cmd)
{
case F_GETFL:
ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
break;
case F_SETFL:
if((val & ~O_NONBLOCK) == 0)
{
netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
ret = 0;
}
break;
default:
break;
}
return ret;
}