Practical session on C++ IPv6 Programming

Exercise 1 : if_nameindex usage example.

#include <stdio.h>
#include <net/if.h>

int main(int argc, char *argv[])
{
        int i;
        struct if_nameindex *ifs = if_nameindex();
        if (ifs == NULL) {
                perror("could not run if_nameindex");
                return 1;
        }
        for (i=0; (i>=0) &&
                (ifs[i].if_index != 0) && (ifs[i].if_name != NULL);
                i++)
        {
                printf("%3d  %3d  %s\n", i, ifs[i].if_index, ifs[i].if_name);
        }
        if_freenameindex(ifs);
}

-

IPV6_V6ONLY usage example


#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>

int
main (int argc, char *argv[])
{

   struct sockaddr_in6 sin6, sin6_accept;
   socklen_t sin6_len; int s0, s;  int on; char hbuf[NI_MAXHOST];

   memset(&sin6,0,sizeof(sin6));
   sin6.sin6_family=AF_INET6; sin6.sin6_len=sizeof(sin6);
   sin6.sin6_port=htons(5001);

   s0=socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP);
   on=1; setsockopt=(s0,SOL_SOCKET, SO_REUSEADDR, &on,sizeof(on));

#ifdef USE_IPV6_V6ONLY
     on=1;
     setsockopt(s0,IPPROTO_IPV6, IPV6_V6ONLY,&on,sizeof(on));
#endif

   bind(s0,(const struct sockaddr *)&sin6, sizeof(sin6));
   listen(s0,1);
   while(1){
      sin6_len=sizeof(sin6_accept);
      s=accept(s0,(struct sockaddr *)&sin6_accept, &sin6_len);
      getnameinfo((struct sockaddr *)&sin6_accept, sin6_len, hbuf,
          sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
      printf("accept a connection from %s\n",hbuf);
      close(s);
   }
}

getnameinfo-example-1

#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>

int
main (int argc, char *argv[])
{

    struct addrinfo hints,*res,*res0; int error; int s;

    memset(&hints,0,sizeof(hints));
    hints.ai_family=AF_UNSPEC;
    hints.ai_socktype=SOCK_STREAM;
    error=getaddrinfo("www.kame.net","http",&hints,&res0);

    s=-1;
    for(res=res0; res; res=res->ai_next)
    {
     s=socket(res->ai_family, res->ai_socktype,res->ai_protocol);
       if(s<0) continue;
       if(connect(s,res->ai_addr,res->ai_addrlen)<0){
            close(s); s=-1; continue;}
       break; // we got one!
    }
    if(s<0){fprintf(stderr,"No addresses are reachable");exit(1);}
    freeaddrinfo(res0);
    }
}

getnameinfo-example-2

#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>

int
main (int argc, char *argv[])
{

    struct addrinfo hints, *res, *res0;
    int error; int s[MAXSOCK]; int nsock; const char *cause=NULL;
    memset (&hints, 0, sizeof(hints));
      hints.ai_family = AF_UNSPEC;
      hints.aisocktype = SOCK_STREAM;
      hints.ai_flags = AI_PASSIVE;
      error=getaddrinfo(NULL,"http", &hints, &res0);
      nsock=0;
     for(res=res0; res && nsock<MAXSOCK; res=res->ai_next)
       {  
         s[nsock]=socket(res->ai_family, res->ai_socktype, res->ai_protocol);
         if(s[nsock]<0) continue;
#ifdef IPV6_V6ONLY
          if(res->ai_family == AF_INET6){int on=1;
          if(setsockopt(s[nsock],IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on)))
         {close(s[nsock]);continue;}}
#endif
       if(bind(s[nsock], res->ai_addr, res->ai_addrlen)<0)
        {close(s[nsock]);continue;}
        if(listen(s[nsock],SOMAXCONN)<0){close(s[nsock]);continue;}
     nsock++;
      }
    if(nsock==0){ /*no listening socket is available*/}
    freeaddrinfo(res0);
}

}

Separated Stack example


#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>

#define MAX(a,b) ((a)<(b)?(b):(a))

#define BUF_SIZE 255

int 
main()
{
struct sockaddr_in sin, sin_accept;
struct sockaddr_in6 sin6, sin6_accept;
socklen_t       from_len;

fd_set          fdset;

int             s[2], csock;

int             on;
char            sbuf[BUF_SIZE];
char            hbuf[NI_MAXHOST];

if ((s[0] = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
   perror("Errore apertura socket IPv4\n");
   exit(1);
   }
if ((s[1] = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
   perror("Errore apertura socket IPv6\n");
   exit(2);
   }

on = 1;
setsockopt(s[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
on = 1;
setsockopt(s[0], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
on = 1;
setsockopt(s[1], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

memset(&sin, 0, sizeof(sin));
#ifdef __BSD__
sin.sin_len = sizeof(sin);
#endif
sin.sin_family = AF_INET;
sin.sin_port = htons(5002);

if (bind(s[0], (const struct sockaddr *) & sin, sizeof(sin)) < 0) {
   perror("Errore bind() IPv4: ");
   exit(1);
   }

memset(&sin6, 0, sizeof(sin6));
#ifdef __BSD__
sin6.sin6_len = sizeof(sin6);
#endif
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(5002);

if (bind(s[1], (const struct sockaddr *) & sin6, sizeof(sin6)) < 0) {
   perror("Errore bind() IPv6: ");
   exit(2);
   }
if (listen(s[0], 0) < 0) {
   perror("Errore listen() IPv4: ");
   exit(1);
   }
if (listen(s[1], 0) < 0) {
   perror("Errore listen() IPv6: ");
   exit(2);
   }
while (1) {
   FD_ZERO(&fdset);
   FD_SET(s[0], &fdset);
   FD_SET(s[1], &fdset);
   
   printf("Entering select...\n");
   if (select(MAX(s[0], s[1]) + 1, &fdset, 0, 0, 0) < 0) {
      perror("Errore Select()\n");
      exit(3);
      }
   printf("Exiting select...\n");
   if (FD_ISSET(s[0], &fdset)) {
      //IPv4 connection
      printf("IPv4 connection\n");
      from_len = sizeof(struct sockaddr_in);  /* !!!! */
      csock = accept(s[0], (struct sockaddr *) & sin_accept, &from_len);
      getnameinfo((struct sockaddr *) & sin_accept, from_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
   } else if (FD_ISSET(s[1], &fdset)) {
      //IPv6 connection
      printf("IPv6 connection\n");
      from_len = sizeof(struct sockaddr_in6);  /* !!!! */
      csock = accept(s[1], (struct sockaddr *) & sin6_accept, &from_len);
      getnameinfo((struct sockaddr *) & sin6_accept, from_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
      }
   printf("accept a connection from %s\n", hbuf);
   snprintf(sbuf, BUF_SIZE, "hello %s\n", hbuf);
   write(csock, sbuf, strlen(sbuf));
   close(csock);
}

exit(0);
}

--+++ A basic TCP/IP Client/Server under IPv4 and IPv6

In this very fist example, students will compile and build both a TCP/IP server and a client under both protocols: IPv4 and IPv6. They will be pointed to the main/key differences in the code and the idea is to get the C-S connection working on Dual Stack for the two protocols, then stop IPv4 and verify that the IPv6 C-S is still working.

IPv4 Server

#include <error.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/poll.h>

int main (int argc, char *argv[])
{
      struct servent *s = getservbyname ("echo", "tcp");
      if (s == NULL)<br>
          error (EXIT_FAILURE, errno, "getservent");
      struct pollfd fds[1];

      int nfds = 0;<br>

      fds[nfds].fd = socket (AF_INET, SOCK_STREAM, 0);

      if (fds[nfds].fd == -1)
          error (EXIT_FAILURE, errno, "socket");
      fds[nfds].events = POLLIN;
      int opt = 1;

      setsockopt (fds[nfds].fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof (opt));

      struct sockaddr_in sin;
      sin.sin_family = AF_INET;
      sin.sin_port = s->s_port;
      sin.sin_addr.s_addr = INADDR_ANY;
      if (bind (fds[nfds].fd,
             &sin, sizeof (sin)) != 0)

      error (EXIT_FAILURE, errno, "bind");

      if (listen (fds[nfds].fd, SOMAXCONN) != 0)
          error (EXIT_FAILURE, errno, "listen");
      ++nfds;
      int i = 0;

      while (1)
       {
            int n = poll (fds, nfds, -1);
            if (n > 0)

            if (fds[i].revents & POLLIN)
              {
                 struct sockaddr_in rem;
                 socklen_t remlen = sizeof (rem);
                 int fd = accept (fds[i].fd, (struct sockaddr *) &rem, &remlen);
                 if (fd != -1)
                      {
                          struct hostent *h = gethostbyaddr (&rem.sin_addr, sizeof (rem.sin_addr), rem.sin_family);
                          char *buf1 = h ? h->h_name : "???";
                          char *buf2 = inet_ntoa (rem.sin_addr);

                          printf ("connection from %s (%s)\n", buf1, buf2);
                          char buf[1000];
                          ssize_t l = read (fd, buf, sizeof (buf));
                          write (fd, buf, l);
                          close (fd);
                   }
           }
      }
}

IPv6 Server

#include <error.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <netinet/in.h>
#include <sys/poll.h>

int
main (int argc, char *argv[])
{
  struct addrinfo *ai;
  struct addrinfo hints;
  memset (&hints, '\0', sizeof (hints));
  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
  hints.ai_socktype = SOCK_STREAM;
  int e = getaddrinfo (NULL, "echo", &hints, &ai);
  if (e != 0)
    error (EXIT_FAILURE, 0, "getaddrinfo: %s", gai_strerror (e));
  struct pollfd fds[2];
  int nfds = 0;
  struct addrinfo *runp = ai;
  while (runp != NULL && nfds < sizeof (fds) / sizeof (fds[0]))
   {
      fds[nfds].fd = socket (runp->ai_family, runp->ai_socktype,
                             runp->ai_protocol);
      if (fds[nfds].fd == -1)
        error (EXIT_FAILURE, errno, "socket");
      fds[nfds].events = POLLIN;
      int opt = 1;
      setsockopt (fds[nfds].fd, SOL_SOCKET, SO_REUSEADDR,
                  opt, sizeof (opt));

      if (bind (fds[nfds].fd,
                runp->ai_addr, runp->ai_addrlen) != 0)
        {
          if (errno != EADDRINUSE)
            error (EXIT_FAILURE, errno, "bind");
          close (fds[nfds].fd);
        }
      else
        {
          if (listen (fds[nfds].fd, SOMAXCONN) != 0)
            error (EXIT_FAILURE, errno, "listen");
          ++nfds;
        }
      runp = runp->ai_next;
    }

  freeaddrinfo (ai);
  while (1)
    {
      int i;
      int n = poll (fds, nfds, -1);
      if (n>0)
        for (i = 0; i < nfds; ++i)
          if (fds[i].revents & POLLIN)
            {
              struct sockaddr_storage rem;
              socklen_t remlen = sizeof (rem);
              int fd = accept (fds[i].fd, (struct sockaddr *) &rem, &remlen);
              if (fd != -1)
                {
                  char buf1[200];
                  if (getnameinfo ((struct sockaddr *) &rem, remlen,
                                   buf1, sizeof (buf1), NULL, 0, 0) != 0)
                    strcpy (buf1, "???");
                  char buf2[100];
                  (void) getnameinfo ((struct sockaddr *) &rem, remlen,
                                      buf2, sizeof (buf2), NULL, 0,
                                      NI_NUMERICHOST);
                  printf ("connection from %s (%s)\n", buf1, buf2);
                  char buf[1000];
                  ssize_t l = read (fd, buf, sizeof (buf));
                  write (fd, buf, l);
                  close (fd);
                }
            }
    }
}

IPv4 Client

Note the usage of gethostbyname.

#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>

int
main (int argc, char *argv[])
{

  int result = 0;
  struct hostent *h = gethostbyname (argv[1]);
  if (h == NULL)
     error (EXIT_FAILURE, errno, "gethostbyname");
  struct servent *s = getservbyname ("echo", "tcp");
  if (s == NULL)
    error (EXIT_FAILURE, errno, "getservbyname");
  struct in_addr **addrs = (struct in_addr **) h->h_addr_list;
  while (*addrs != NULL)

    {
      int sock = socket (PF_INET, SOCK_STREAM, 0);

      if (sock != -1)

        {
           struct sockaddr_in sin;
           sin.sin_family = AF_INET;
           sin.sin_port = s->s_port;
           sin.sin_addr = **addrs;
           if (connect (sock,
                        (struct sockaddr *) &sin, sizeof (sin)) == 0)
              {
                char *line = NULL;
                size_t len = 0;
                ssize_t n = getline (&line, &len, stdin);
                write (sock, line, n);
                n = read (sock, line, len);
                write (STDOUT_FILENO, line, n);
                close (sock);
                goto out;
               }
             close (sock);
          }
        ++addrs;
     }
   error (0, 0, "cannot contact %s", argv[1]);
   result = 1;
 out:

  return result;
}

IPv6 Client

Note the usage of getaddrinfo.
#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
int
main (int argc, char *argv[])
{
  int result = 0;
  struct addrinfo *ai;
  struct addrinfo hints;
  memset (&hints, '\0', sizeof (hints));
  hints.ai_flags = AI_ADDRCONFIG;
  hints.ai_socktype = SOCK_STREAM;
  int e = getaddrinfo (argv[1], "echo", &hints, &ai);
  if (e != 0)
    error (EXIT_FAILURE, 0, "getaddrinfo: %s", gai_strerror (e));
  struct addrinfo *runp = ai;
  while (runp != NULL)
    {
      int sock = socket (runp->ai_family, runp->ai_socktype,
                         runp->ai_protocol);
      if (sock != -1)
        {
          if (connect (sock,
                       runp->ai_addr, runp->ai_addrlen) == 0)
            {
              char *line = NULL;
              size_t len = 0;
              ssize_t n = getline (&line, &len, stdin);
              write (sock, line, n);
              n = read (sock, line, len);
              write (STDOUT_FILENO, line, n);
              close (sock);
              goto out;
            }
          close (sock);
        }
      runp = runp->ai_next;
    }
  error (0, 0, "cannot contact %s", argv[1]);
  result = 1;
 out:
  freeaddrinfo (ai);
  return result;
}



-- MarioReale - 20 Dec 2007

Edit | Attach | Watch | Print version | History: r4 < r3 < r2 < r1 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r4 - 2008-01-15 - MarioReale
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    EGEE All webs login

This site is powered by the TWiki collaboration platform Powered by Perl This site is powered by the TWiki collaboration platformCopyright & by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Ask a support question or Send feedback