title: Multicast groups Linux - Joining and Leaving
body: <p>I am building a overlay network system to test a protocol (Uni research). I need to join and leave multicast groups in order to receive packets from different sources. </p>
  
  <p>I am unsure about the correct setup of the socket so I can close the socket and leave the multicast group and then rejoin the same multicast group later. When I try to join the same multicast group I get "<code>bind error: Address already in use</code>". </p>
  
  <pre><code>//for setting up individual groups
  int setUpForGroup(struct locgro_node* node, const char* port)
  {
      char mcastaddr[INET6_ADDRSTRLEN];
  
      struct in6_addr* full_addr_gro = &amp;(node-&gt;group);
      if( NULL == inet_ntop(AF_INET6, full_addr_gro, mcastaddr, INET6_ADDRSTRLEN))
      {   
          printf("error inet_pton, retval: \n");
          return -1;
      }
  
      if (buildAdd(mcastaddr, port, AF_INET6, SOCK_DGRAM, &amp;(node-&gt;addr_st)) &lt;0) 
      {
          fprintf(stderr, "get_addr error:: could not find multicast, address=[%s] port=[%s]\n", mcastaddr, port);
          return -1;
      }
  
      node-&gt;sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
  
      if (bind(node-&gt;sockfd, (struct sockaddr *)&amp;(node-&gt;addr_st), sizeof(node-&gt;addr_st)) &lt; 0) {
          perror("bind error:: ");
          close(node-&gt;sockfd);
          return -1;
      }
  
      if (joinGroup(node-&gt;sockfd, 0 , 8, &amp;(node-&gt;addr_st)) &lt;0) {
          close(node-&gt;sockfd);
          return -1;
      }
  
      return 0;
  }
  //internal function
  int joinGroup(int sockfd, int loopBack, int mcastTTL, struct sockaddr_in6 *addr_st)
  {
      int r1, r2, r3, retval;
      retval=-1;
      struct ipv6_mreq mreq6;
  
      memcpy(&amp;mreq6.ipv6mr_multiaddr, &amp;((addr_st)-&gt;sin6_addr), sizeof(struct in6_addr));
  
      mreq6.ipv6mr_interface= 0; // allow any interface
  
      //set the loopback case
      r1 = setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &amp;loopBack, sizeof(loopBack));
      if (r1&lt;0) perror("joinGroup:: IPV6_MULTICAST_LOOP:: ");
  
  /*
      setsockopt(sock_fd, IPPROTO_IPV6, SO_REUSEADDR, &amp;mreq6, sizeof(mreq6));
  
      setsockopt(sock_fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &amp;multicast_req, sizeof(multicast_req));
  */
      //set the time to live for the packets (hops)
      r2 = setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &amp;mcastTTL, sizeof(mcastTTL));
      if (r2&lt;0) perror("joinGroup:: IPV6_MULTICAST_HOPS::  ");
  
      //add this address to the group
      r3 = setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &amp;mreq6, sizeof(mreq6));
      if (r3&lt;0) perror("joinGroup:: IPV6_ADD_MEMBERSHIP:: ");
  
      if ((r1&gt;=0) &amp;&amp; (r2&gt;=0) &amp;&amp; (r3&gt;=0)) retval=0;
  
      return retval;
  }
  
  
  //internal function
  int buildAdd(const char *hostname, const char *service, int family, int socktype,  struct sockaddr_in6 *addr_st)
  {
      struct addrinfo hints, *res, *ressave;
      int n, sockfd, retval;
  
      retval = -1;
  
      memset(&amp;hints, 0, sizeof(struct addrinfo));
      hints.ai_family = family;
      hints.ai_socktype = socktype;
  
      n = getaddrinfo(hostname, service, &amp;hints, &amp;res);
  
      if (n &lt;0) 
      {
          fprintf(stderr, "getaddrinfo error: [%s]\n", gai_strerror(n));
          return retval;
      }
  
      ressave = res;
  
      sockfd=-1;
      while(res) 
      {
          sockfd = socket(res-&gt;ai_family, res-&gt;ai_socktype, res-&gt;ai_protocol);
  
          if (!(sockfd &lt; 0)) 
          {
              int opval = 1;
              setsockopt(sockfd, IPPROTO_IPV6, SO_REUSEADDR, &amp;opval, res-&gt;ai_addrlen);
  
              if (bind(sockfd, res-&gt;ai_addr, res-&gt;ai_addrlen) == 0) 
              {
              //to test that the address really is correct
                  close(sockfd);
                  memcpy(addr_st, res-&gt;ai_addr, sizeof(*addr_st));
                  retval=0;
                  break;
              }
              perror("build addr : bind error");
              close(sockfd);
              sockfd=-1;
          }
          res=res-&gt;ai_next;
      }
  
      freeaddrinfo(ressave); //free the struct
  
      return retval;
  }
  </code></pre>
  
  <p>This are the functions I used for joining a group. 
  When leaving I simply do: (that happens inside another function)</p>
  
  <pre><code>    struct ipv6_mreq mreq6;
      memcpy(&amp;mreq6.ipv6mr_multiaddr, &amp;(temp_lnode-&gt;group), sizeof(struct in6_addr));
      mreq6.ipv6mr_interface= 0; // allow any interface
      setsockopt(temp_lnode-&gt;sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &amp;mreq6, sizeof(mreq6));
  
      close(temp_lnode-&gt;sockfd); //close socket
  </code></pre>
  
  <p>I am getting a "Address already in use" error when I try to bind the address inside the build address function. 
  I tried solving that by setting SO_REUSEADDR but it didn't help, also added the DROP_MEMBERSHIP but bind still fails. </p>
  
  <p>Do I need to bind in order to get it to work? What should I call or do to allow for joining and leaving of groups without this issues? I would need to do this during intervals of 30s. </p>
  
  <p>Thanks a lot
  M</p>