mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-12-25 18:14:53 +00:00
fixed bug #38165 (socket with mulicast): ensure igmp membership are dropped when socket (not netconn!) is closed.
This commit is contained in:
parent
612e33c499
commit
c8581e4cd9
@ -202,6 +202,10 @@ HISTORY
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2015-02-25: Simon Goldschmidt
|
||||
* sockets.c: fixed bug #38165 (socket with mulicast): ensure igmp membership
|
||||
are dropped when socket (not netconn!) is closed.
|
||||
|
||||
2015-02-25: Simon Goldschmidt
|
||||
* ip4.h/.c, udp.c: fixed bug #38061 (wrong multicast routing in IPv4) by
|
||||
adding an optional default netif for multicast routing
|
||||
|
@ -237,6 +237,29 @@ union sockaddr_aligned {
|
||||
struct sockaddr_in sin;
|
||||
};
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* Define the number of IPv4 multicast memberships, default is one per socket */
|
||||
#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
|
||||
#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
|
||||
#endif
|
||||
|
||||
/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
|
||||
a socket is closed */
|
||||
struct lwip_socket_multicast_pair {
|
||||
/** the socket (+1 to not require initialization) */
|
||||
int sa;
|
||||
/** the interface address */
|
||||
ip_addr_t if_addr;
|
||||
/** the group address */
|
||||
ip_addr_t multi_addr;
|
||||
};
|
||||
|
||||
struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
|
||||
|
||||
static int lwip_socket_register_membership(int s, ip_addr_t *if_addr, ip_addr_t *multi_addr);
|
||||
static void lwip_socket_unregister_membership(int s, ip_addr_t *if_addr, ip_addr_t *multi_addr);
|
||||
static void lwip_socket_drop_registered_memberships(int s);
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
/** The global array of available sockets */
|
||||
static struct lwip_sock sockets[NUM_SOCKETS];
|
||||
@ -577,6 +600,11 @@ lwip_close(int s)
|
||||
LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
|
||||
}
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* drop all possibly joined IGMP memberships */
|
||||
lwip_socket_drop_registered_memberships(s);
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
err = netconn_delete(sock->conn);
|
||||
if (err != ERR_OK) {
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
@ -2162,10 +2190,17 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
|
||||
inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
|
||||
inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
|
||||
if(optname == IP_ADD_MEMBERSHIP){
|
||||
igmp_err = igmp_joingroup(&if_addr, &multi_addr);
|
||||
if(optname == IP_ADD_MEMBERSHIP) {
|
||||
if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
|
||||
/* cannot track membership (out of memory) */
|
||||
err = ENOMEM;
|
||||
igmp_err = ERR_OK;
|
||||
} else {
|
||||
igmp_err = igmp_joingroup(&if_addr, &multi_addr);
|
||||
}
|
||||
} else {
|
||||
igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
|
||||
lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
|
||||
}
|
||||
if (igmp_err != ERR_OK) {
|
||||
err = EADDRNOTAVAIL;
|
||||
@ -2454,4 +2489,79 @@ lwip_fcntl(int s, int cmd, int val)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if LWIP_IGMP
|
||||
/** Register a new IGMP membership. On socket close, the membership is dropped automatically.
|
||||
*
|
||||
* ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
|
||||
*
|
||||
* @return 1 on success, 0 on failure
|
||||
*/
|
||||
static int
|
||||
lwip_socket_register_membership(int s, ip_addr_t *if_addr, ip_addr_t *multi_addr)
|
||||
{
|
||||
/* s+1 is stored in the array to prevent having to initialize the array
|
||||
(default initialization is to 0) */
|
||||
int sa = s + 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
||||
if (socket_ipv4_multicast_memberships[i].sa == 0) {
|
||||
socket_ipv4_multicast_memberships[i].sa = sa;
|
||||
ip_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
|
||||
ip_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Unregister a previously registered membership. This prevents dropping the membership
|
||||
* on socket close.
|
||||
*
|
||||
* ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
|
||||
*/
|
||||
static void
|
||||
lwip_socket_unregister_membership(int s, ip_addr_t *if_addr, ip_addr_t *multi_addr)
|
||||
{
|
||||
/* s+1 is stored in the array to prevent having to initialize the array
|
||||
(default initialization is to 0) */
|
||||
int sa = s + 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
||||
if ((socket_ipv4_multicast_memberships[i].sa == sa) &&
|
||||
ip_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
|
||||
ip_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
|
||||
socket_ipv4_multicast_memberships[i].sa = 0;
|
||||
ip_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
|
||||
ip_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
|
||||
*
|
||||
* ATTENTION: this function is called NOT called from tcpip_thread (or under CORE_LOCK).
|
||||
*/
|
||||
static void lwip_socket_drop_registered_memberships(int s)
|
||||
{
|
||||
/* s+1 is stored in the array to prevent having to initialize the array
|
||||
(default initialization is to 0) */
|
||||
int sa = s + 1;
|
||||
int i;
|
||||
|
||||
LWIP_ASSERT("socket has no netconn", sockets[s].conn != NULL);
|
||||
|
||||
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
||||
if (socket_ipv4_multicast_memberships[i].sa == sa) {
|
||||
netconn_join_leave_group(sockets[s].conn, &socket_ipv4_multicast_memberships[i].if_addr,
|
||||
&socket_ipv4_multicast_memberships[i].multi_addr, NETCONN_LEAVE);
|
||||
socket_ipv4_multicast_memberships[i].sa = 0;
|
||||
ip_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
|
||||
ip_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
Loading…
Reference in New Issue
Block a user