exanic-software icon indicating copy to clipboard operation
exanic-software copied to clipboard

structs.h:487: exa_hashtable_mcast_remove: Assertion `memb_to_insert != ((void *)0)' failed

Open chtrading opened this issue 4 years ago • 1 comments

I'm having problems with DROP_MEMBERSHIP + exasock.

When I comment the unsubscribe line of my application, the program runs normally. If present, the unsubscribe results in a segmentation fault that occur at libexasock side.

I discovered the option "--debug" and I have the following error:

a.out: structs.h:487: exa_hashtable_mcast_remove: Assertion `memb_to_insert != ((void *)0)' failed.
Aborted (core dumped)

To repeat the problem, you can use this minimal program. It does ADD_MEMBERSHIP and after a interval it does DROP_MEMBERSHIP:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <stdexcept>
#include <sys/epoll.h>
#include <unistd.h>
#include <iostream>

int main()
{
	const char *interface = "192.168.2.2";

	constexpr int SIZE_OF_BUFFER = 2048;
	char buffer[SIZE_OF_BUFFER];

	int fd0 = socket(AF_INET, SOCK_DGRAM, 0);

	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));

	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(10001);
	servaddr.sin_addr.s_addr = inet_addr("233.252.14.1");

	if (::bind(fd0, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) 
	{
		throw std::runtime_error("socket couldn't bind.");
	}
	
	int epoll_fd = epoll_create(1);
	struct epoll_event event;
	
	event.events = EPOLLIN;
	event.data.u32 = 10000;
	epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd0, &event);
	
	ip_mreq mreq;

	mreq.imr_multiaddr.s_addr = inet_addr("233.252.14.1");
	mreq.imr_interface.s_addr = inet_addr(interface);
	if (setsockopt(fd0, IPPROTO_IP, IP_ADD_MEMBERSHIP,
			&mreq, sizeof(mreq)) < 0)
	{
		throw std::runtime_error(
				std::string("subscribe: ") + strerror(errno) );
	}

	int j = 1;
	for (;;)
	{
		
		constexpr int max_events = 64;
		struct epoll_event events[max_events];
		int n = epoll_wait(epoll_fd, events, max_events, 0);

		for (int i = 0; i < n; i++)
		{
			std::cout << "events[i].data.u32: " << events[i].data.u32 << std::endl;
			
			
			if(events[i].data.u32 == 10000)
			{
				int n_bytes = recvfrom(fd0, buffer, SIZE_OF_BUFFER, 0 , 0, 0);

				j++;
				std::cout << "j= " << j << std::endl;
				std::cout << "n_bytes: " << n_bytes << std::endl;

				if(j == 100)
				{		
					mreq.imr_multiaddr.s_addr = inet_addr("233.252.14.1");
					mreq.imr_interface.s_addr = inet_addr(interface);
					if (setsockopt(fd0, IPPROTO_IP, IP_DROP_MEMBERSHIP,
							&mreq, sizeof(mreq)) < 0)
					{
						throw std::runtime_error(
								std::string("unsubscribe: ") + strerror(errno) );
					} 
				}
			}

		}

	}
}

Network organization: image

To run: $ exasock --debug ./a.out

I would like to know if my software is using correctly the lib. I will try to debug this assert to find a fix in the meantime.

chtrading avatar Dec 28 '20 19:12 chtrading

I minimally changed the example multicast-echo.c in order to confirm that this is a bug.

The modified version is here:

#include <time.h>
#include <poll.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>

int main(int argc, char *argv[])
{
    int j = 0;
    struct sockaddr_in mcast_addr;//, send_addr;
    struct ip_mreq im;
    int recv_fd; // , send_fd;
    char *p, *q;

    /* Parse command line arguments */

    if (argc != 2)
        goto usage_error;

    mcast_addr.sin_family = AF_INET;
//    send_addr.sin_family = AF_INET;

    if ((p = strtok(argv[1], ":")) == NULL ||
        inet_aton(p, &mcast_addr.sin_addr) == 0)
        goto usage_error;
    if ((p = strtok(NULL, ":")) == NULL ||
        inet_aton(p, &im.imr_interface) == 0)
        goto usage_error;
    if ((p = strtok(NULL, "")) == NULL)
        goto usage_error;
    mcast_addr.sin_port = htons(strtol(p, &q, 10));
    if (*p == '\0' || *q != '\0')
        goto usage_error;

    im.imr_multiaddr = mcast_addr.sin_addr;

/*    if ((p = strtok(argv[2], ":")) == NULL ||
        inet_aton(p, &send_addr.sin_addr) == 0)
        goto usage_error;
    if ((p = strtok(NULL, "")) == NULL)
        goto usage_error;
    send_addr.sin_port = htons(strtol(p, &q, 10));
    if (*p == '\0' || *q != '\0')
        goto usage_error;
*/

    /* Create and bind sockets */

    recv_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (recv_fd == -1)
    {
        fprintf(stderr, "socket: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

   /*
    send_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (send_fd == -1)
    {
        fprintf(stderr, "socket: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }
    */

    if (setsockopt(recv_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&im, sizeof(im)) == -1)
    {
        fprintf(stderr, "setsockopt: IP_ADD_MEMBERSHIP failed: %s\n",
                strerror(errno));
        return EXIT_FAILURE;
    }

    if (bind(recv_fd, (struct sockaddr *)&mcast_addr, sizeof(mcast_addr)) == -1)
    {
        fprintf(stderr, "bind: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

/*    if (connect(send_fd, (struct sockaddr *)&send_addr, sizeof(send_addr)) == -1)
    {
        fprintf(stderr, "connect: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }
*/

    /* Echo packets */

    while (1)
    {
        char buf[65536];
        ssize_t len;

        len = recv(recv_fd, buf, sizeof(buf), 0);
	std::cout << "len: " << len << std::endl;
        if (len == -1)
        {
            fprintf(stderr, "recv: %s\n", strerror(errno));
            return EXIT_FAILURE;
        }

	
	j++;
	if(j == 100)
	{
	    std::cout << "***" << std::endl;
	    if (setsockopt(recv_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&im, sizeof(im)) == -1)
	    {
		    return -1;
	    }

	}
	/*
        if (send(send_fd, buf, len, 0) == -1)
        {
            fprintf(stderr, "send: %s\n", strerror(errno));
            return EXIT_FAILURE;
        }
	*/
    }

    close(recv_fd);
  //  close(send_fd);

    return 0;

usage_error:
    fprintf(stderr,
            "Usage: %s <multicast-group>:<interface-addr>:<port> <send-addr>:<port>\n"
            "\n"
            "Receive multicast UDP packets on <interface-addr> addressed to\n"
            "multicast group <multicast-group> at port <port>, and echo a copy of\n"
            "each packets to <send-addr>:<port>.\n",
            argv[0]);

    return 0;
}

The result is the same:

[ch@localhost exasock]$ exasock --debug ./a.out 233.252.14.1:192.168.2.2:10001
a.out: structs.h:487: exa_hashtable_mcast_remove: Assertion `memb_to_insert != ((void *)0)' failed.

I am trying to understand what is happening (debugging).

chtrading avatar Dec 28 '20 21:12 chtrading