BUG: udp的"addrlen"由局部变量改为全局变量,udp的数据包就无法发送到目标地址。
一.BUG描述
项目上要用到LWIP的UDP协议传输数据,然后弄了一个了UDP的demo;跑通了之后就对这个demo重新封装。我把套接字长度变量(addrlen)由局部改为全局之后,服务器的UDP就只能接收,不能发送数据了。
二.BUG原因
点击查看代码
/*
*sockfd:套接字文件描述符
*buf:接收缓冲区
*len:接收数据长度
*flags:标识
*src_addr:对端套接字地址
*addrlen:对端套接字地址长度,也就是src_addr这个结构体的大小,IPV4网络为16个字节
*/
int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
1.全局变量存储在BSS段,若全局变量没有初始化赋值,则默认为0值;而局部变量保存在栈种,若没有初始化赋值,则局部变量为随机值。
2.在recvfrom()函数中,若addrlen的初始化值大于对端的地址长度;则会被重置为16个字节,若小于对端的地址长度,则直接读对端的地址信息,导致对端地址信息不全,也就无法发送。代码如下:
点击查看代码
int lwip_recvfrom(int s, void *mem, size_t len, int flags,struct sockaddr *from, socklen_t *fromlen)
{
...
...
/* Check to see from where the data was.*/
if (done) {
ip_addr_t fromaddr;
if (from && fromlen) {
struct sockaddr_in sin;
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)) { //sizeof(sin)是ipv4套接字地址的长度
*fromlen = sizeof(sin);
}
MEMCPY(from, &sin, *fromlen); //拷贝对端地址到本地。
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
} else {
#if SOCKETS_DEBUG
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);
}
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
#endif /* SOCKETS_DEBUG */
}
}
...
...
三.解决办法
因采用IPv4网络进行通信,它的套接字地址长度就是16,所以初始化的时候令addrlen = 16即可。
点击查看代码
static struct udp_net_socket udp_socket = {
.sock = -1,
.seraddr = 0,
.addrlen = sizeof(struct sockaddr_in),
};