11
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>

void error(char *msg)
{
  perror(msg);
  exit(0);
}
int main(int argc, char *argv[])
{
   int sock, length, fromlen, n;
   struct sockaddr_in6 server;
   struct sockaddr_in6  from;

   int portNr = 5555;
   char buf[1024];

   length = sizeof (struct sockaddr_in6);

   sock=socket(AF_INET6, SOCK_DGRAM, 0);
   if (sock < 0) error("Opening socket");

   bzero((char *)&server, length);
   server.sin6_family=AF_INET6;
   server.sin6_addr=in6addr_any;
   server.sin6_port=htons(portNr);

   inet_pton( AF_INET6, "fe80::21f:29ff:feed:2f7e", (void *)&server.sin6_addr.s6_addr);
   //inet_pton( AF_INET6, "::1", (void *)&server.sin6_addr.s6_addr);

   if (bind(sock,(struct sockaddr *)&server,length)<0)
       error("binding");
   fromlen = sizeof(struct sockaddr_in6);
   while (1) {
       n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
       if (n < 0) error("recvfrom");
       write(1,"Received a datagram: ",21);
       write(1,buf,n);
       n = sendto(sock,"Got your message\n",17,
                  0,(struct sockaddr *)&from,fromlen);
       if (n  < 0) error("sendto");
   }
}

when I compile and run the above code I got :

binding: Invalid argument

and if change to bind the ::1 and leave other thing unchanged in the source code, the code works! so could you tell me what's wrong with my code ? thanks in advance.

Ale
  • 887
  • 10
  • 14
Haiyuan Zhang
  • 40,802
  • 41
  • 107
  • 134

1 Answers1

17

For link-local addresses, you also need to specify the scope ID of the network interface that is associated with the address... something like this:

server.sin6_scope_id = 5;   /* or whatever the scope ID is for the network interface you want to communicate over */

You can use getifaddrs() to find the various scope IDs available on your systems, and the network interfaces they correspond to.

(Yes, it's a pain... alternatively you might be able to append something like "%en0" to the end of the string you pass to inet_pton(), and inet_pton() might do the work for you... I'm not sure if inet_pton() handles that syntax or not)

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • 3
    inet_pton doesn't handle %if appended strings. You can use getaddrinfo to work with % appended ip6 address string representations. See man page http://linux.die.net/man/3/getaddrinfo – Benjamin Maurer Feb 06 '13 at 11:36
  • 3
    For those reading this answer, please note the `scope_id` is the index of the interface you want to communicate over. Since fe80 is present for each interfaces by default, we need to specify which interface that link local address is referring to. So the value `5` is given as an example. To get that index, you need to use `if_nametoindex (const char *ifname)` from the interface name. The interface name is returned by interating over the data structure populated by `getifaddrs(struct ifaddrs **ifap)`. – wget Oct 14 '19 at 18:09