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