2

I am trying to use the function getaddrinfo with a passive socket/listener instead of filling directly the old sockaddr structure. My purpose is to open a socket and bind it to a port. Essentially I am building a server.

I don't know why but getaddrinfo returns 2 results; because of this in the loop below the second time I call bind it exit with an error saying "address already in use". Do you know how to fix this and if it is correct to have it in a loop ?

         struct addrinfo addr;
         memset(&addr,0,sizeof(addrinfo));
         addr.ai_family   = AF_INET;
         addr.ai_socktype = SOCK_STREAM;
         addr.ai_protocol = 0;
         addr.ai_flags    = AI_PASSIVE;

         struct addrinfo * rp,* result;
         getaddrinfo( "localhost","59001",&addr,&result );
         for( rp = result; rp != NULL; rp = rp->ai_next ){

              int sd = socket( AF_INET, SOCK_STREAM, 0 );
              if(-1==sd ){ 
              printf( "error creating the socket %m");
              return -1; 
              }             

             if( -1==bind( sd, result->ai_addr, result->ai_addrlen ) ){                 
             printf( "error binding %m")
             return -1;
             }

             if( -1== listen(sd, MAX_BACKLOG ) ){
             std::cerr << "listen didn't work" << std::endl;
             return -1;
             }       
         }
Abruzzo Forte e Gentile
  • 14,423
  • 28
  • 99
  • 173

2 Answers2

4

There are a couple of things going on here. For the multiple results from getaddrinfo(), that's because it returns an IPv4 address and a IPv6 address (you have both). As for the "address already in use", you need to set the SO_REUSEADDR option. Put this between your calls to socket() and bind():

int opval = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
klsdjfhsalkjfhl
  • 173
  • 1
  • 10
Linuxios
  • 34,849
  • 13
  • 91
  • 116
  • Hi Linuxios. You are right and it works. The thing is that ( I have realized only now ). That I have to call also listen ( and eventually accept ). Once I call listen then the address becomes in use and I got that error. In this case which of the 2 results do I have to discard ( If I have to ? ) . – Abruzzo Forte e Gentile Jan 21 '13 at 17:37
  • 2
    @AbruzzoForteeGentile: You should use the first one that successfully creates a socket. – Linuxios Jan 21 '13 at 17:39
  • Ok. I will do that Despite it is IPV4 or IPV6 ( and I will go back understanding what the difference could be ). Thanks a lot! – Abruzzo Forte e Gentile Jan 21 '13 at 17:43
  • 2
    `getaddrinfo()` should not be returning both IPv4 and IPv6 addresses in this situation since the `hints` address family is being set to `AF_INET` ie IPv4 only. If the `hints` address family were being set to `AF_UNSPEC` instead, then yet, it could return both IPv4 and IPv6 addresses. So the fact that `getaddrinfo()` is returning multiple addresses means that `"localhost"` really does resolve to multiple IPv4 addresses, maybe `127.0.0.1` as well as an actual network adapter IP like `192.168.0.1`. – Remy Lebeau Jan 21 '13 at 20:35
  • Hi Remy. I didn't check the IP that are returned. Let me check and see whether I have really 2 different ips. I am using UBUNTU as os. – Abruzzo Forte e Gentile Jan 24 '13 at 06:00
0

Is this on a redhat machine perchance? There is a wellknown bug on those, that because /etc/hosts/ lists localhost twice, when you request specifically AF_INET you actually get the same result twice; once for IPv4 and once for IPv6 translated a bit.

See also https://bugzilla.redhat.com/show_bug.cgi?id=496300

LeoNerd
  • 8,344
  • 1
  • 29
  • 36