IPV6 COMPLIANCE WITH CC++, JAVA, PYTHON AND PERL

Document Sample
IPV6 COMPLIANCE WITH CC++, JAVA, PYTHON AND PERL Powered By Docstoc
					                                                                                                                                                                           Doc. Identifier:

                                                                Note                                                                      EGEE-III-SA2-TEC-971407-
                                                                                                                      IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                                                                                         Date: 27/11/2008




Subject:                     IPV6 COMPLIANCE WITH C/C++, JAVA, PYTHON AND PERL


Author(s):                   Etienne DUBLE – CNRS/UREC
                             EGEE III SA2 Activity : Networking Support


Distribution                 Public

Summary
1. SUBJECT ............................................................................................................................................................................... 2 

2. INTRODUCTION ................................................................................................................................................................. 2 
    2.1. ENVIRONMENT .................................................................................................................................................................. 2 
    2.2. NOTE ON THE COLORS USED FOR THE TESTS ...................................................................................................................... 2 
3. SERVERS AND CLIENTS SAMPLES............................................................................................................................... 3 
    3.1. BEHAVIOUR ....................................................................................................................................................................... 3 
       3.1.1. Preliminary notes ..................................................................................................................................................... 3 
       3.1.2. Servers ...................................................................................................................................................................... 3 
       3.1.3. Clients ....................................................................................................................................................................... 5 
    3.2. CODE PRESENTATION ........................................................................................................................................................ 6 
       3.2.1. Preliminary notes ..................................................................................................................................................... 6 
       3.2.2. Files .......................................................................................................................................................................... 6 
    3.3. SAMPLE PROGRAMS CODE ................................................................................................................................................ 7 
       3.3.1. C language................................................................................................................................................................ 7 
       3.3.2. Python ..................................................................................................................................................................... 17 
       3.3.3. Perl ......................................................................................................................................................................... 24 
       3.3.4. Java ........................................................................................................................................................................ 33 
    3.4. BUILD AND RUN .............................................................................................................................................................. 38 
       3.4.1. C language.............................................................................................................................................................. 38 
       3.4.2. Python ..................................................................................................................................................................... 39 
       3.4.3. Perl ......................................................................................................................................................................... 39 
       3.4.4. Java ........................................................................................................................................................................ 40 
    3.5. ANALYSIS AND COMPARISON ......................................................................................................................................... 41 
       3.5.1. Main function calls ................................................................................................................................................. 41 
       3.5.2. General comments .................................................................................................................................................. 42 
       3.5.3. Specific advantages and drawbacks ....................................................................................................................... 42 
4. MAKING IPV6 EASIER TO HANDLE ........................................................................................................................... 44 
    4.1. HIGH-LEVEL PROGRAMMING LANGUAGES AND NETWORKING LIBRARIES ....................................................................... 44 
       4.1.1. The Java case ......................................................................................................................................................... 44 
       4.1.2. The Python case ...................................................................................................................................................... 44 
       4.1.3. The Perl case .......................................................................................................................................................... 47 
       4.1.4. The C/C++ case ..................................................................................................................................................... 47 
    4.2. XINETD ........................................................................................................................................................................... 48 
5. CONCLUSIONS.................................................................................................................................................................. 49 

TABLE OF REFERENCES ................................................................................................................................................... 49 




EGEE-III                                                                                         PUBLIC                                                               1 / 49
                                                                                                        Doc. Identifier:

                                       Note                                               EGEE-III-SA2-TEC-971407-
                                                                      IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                      Date: 27/11/2008




1. SUBJECT
The purpose of this document is to describe, for each of the 4 major programming languages used in gLite 
(C/C++, Java, Python, and Perl):  
    ‐ How to write an IPv6‐enabled socket‐based TCP client and server. 
    ‐ The limits of IPv6 compliance for applications written in these languages. 
 
In order to compare the different languages, a sample server and a sample client will be created in each of the 
languages. 


2. INTRODUCTION
    2.1. ENVIRONMENT
 
We will use two machines for the tests, “quarks” and “bdii” (node names have no relation to gLite deployment 
modules). 
The operating systems are Linux dual‐stack systems (they have both IPv4 and IPv6 stacks, like most of modern 
operating systems). 
 
Here are the software versions used: 
                                      Quarks                              Bdii 
Linux Operating System                Scientific Linux SL release 3.0.8   Scientific Linux SL release 4.6 
C compiler                            gcc 3.2.3                           gcc 3.4.6 
Python interpreter                    Python 2.2.3                        Python 2.3.4 
Perl interpreter                      Perl 5.8.0                          Perl 5.8.5 
Socket6 Perl library                  Socket6‐0.22                        Socket6‐0.22 
Java virtual machine                  1.5.0_12                            1.5.0_14 
 
The sample programs have been tested on these two hosts. 
 
        

    2.2. NOTE ON THE COLORS USED FOR THE TESTS
 
To help reading we will use the following colors: 

 ‐ Yellow shells are executed on the machine “quarks”, which will run the servers 
 ‐ Pink shells are executed on the machine “bdii”, which will run the clients 
      




EGEE-III                                                 PUBLIC                                      2 / 49
                                                                                                         Doc. Identifier:

                                       Note                                                EGEE-III-SA2-TEC-971407-
                                                                       IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                       Date: 27/11/2008




3. SERVERS AND CLIENTS SAMPLES
    3.1. BEHAVIOUR


        3.1.1. Preliminary notes
In order to ease the comparison of the different languages, the sample clients and servers are intended to have 
the same behavior in all languages. The expected behavior is therefore described in the following sections. 
 

        3.1.2. Servers

3.1.2.1. General behaviour
 
Here is the expected behavior of each server: 
‐ The server is in listen mode, waiting for a connection 
‐ When a client connects, the server sends the message “hi <client_ip>” to the client 
‐ When the client sends a character string 
         o If the string is “bye” the server responds “bye <client_ip>” and close the connection; then it listens 
             for a new connection. 
         o If the string is “stop” the server responds “bye <client_ip>” close the connection and stops. 
         o Any other string is echoed to the client. 
 
The server expects one command line parameter which is the TCP port for the listening socket.  
The server must be able to accept both IPv4 and IPv6 clients. 
 




EGEE-III                                                  PUBLIC                                      3 / 49
                                                                                                              Doc. Identifier:

                                             Note                                               EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008




      3.1.2.2. Example of test
      Here is a sample communication test with a server running on Quarks, using port 5555. 
      (Input is in green and responses from the server are in blue) 
[duble@bdii ~]$ telnet quarks.paris.urec.cnrs.fr 5555
Trying 2001:660:3302:7003::2...
Connected to quarks_v4.paris.urec.cnrs.fr (2001:660:3302:7003::2).
Escape character is '^]'.
hi 2001:660:3302:7003::11
test of echo
test of echo
new test of echo
new test of echo
bye
bye 2001:660:3302:7003::11
Connection closed by foreign host.
[duble@bdii ~]$


      3.1.2.3. Two kinds of socket servers
      On Linux (and most modern operating systems) it is possible to accept IPv4 connections on an IPv6 socket. 
      Consequently there are two ways of building a socket server: 
      ‐ With only one IPv6 socket, or 
      ‐ With one IPv6 socket accepting only IPv6 and one IPv4 socket accepting only IPv4. 
      For more information, see [2]. 
       
      However some high‐level programming languages do not allow this (Java in our case). 
      For the programming languages which allow it (C, Perl and Python in our case), we will build these two kinds of 
      servers.  
      For Java we will build only the version with one socket. 
       
      Note: If IPv6 is not available on the system, both kinds of servers should open only one IPv4 socket. 
       




      EGEE-III                                                  PUBLIC                                     4 / 49
                                                                                                               Doc. Identifier:

                                            Note                                                 EGEE-III-SA2-TEC-971407-
                                                                             IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                             Date: 27/11/2008




               3.1.3. Clients

     3.1.3.1. General behaviour
      
     Here is the expected behavior of the client: 
     ‐ It connects to the server 
     ‐ It reads “hi <ip>” sent by the server 
     ‐ It sends “bye” 
     ‐ It reads “bye <ip>” sent by the server 
     ‐ It closes the connection 
      
     The client expects two command line parameters:  
     ‐ The hostname or IP address of the server  
     ‐ The port number to connect to.  
     However, if the specified hostname has several addresses (usually an IPv6 and an IPv4 address), the client 
     loops and tries all addresses until one connection succeed.  
     On a standard Linux system using GNU libc, the default behavior will be to try IPv6 first if available (unless you 
     set up a specific /etc/gai.conf file). 
      
     3.1.3.2. Example of test
     Here is a sample communication test with a server running on Quarks, using port 5555. 
[duble@bdii test_perl]$ ./client.pl quarks.paris.urec.cnrs.fr 5555
received: hi 2001:660:3302:7003::11
sending: bye
received: bye 2001:660:3302:7003::11
[duble@bdii test_perl]$

      




     EGEE-III                                                   PUBLIC                                      5 / 49
                                                                                                                       Doc. Identifier:

                                             Note                                                     EGEE-III-SA2-TEC-971407-
                                                                                  IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                                     Date: 27/11/2008




    3.2. CODE PRESENTATION

        3.2.1. Preliminary notes
In order to easily compare the different languages: 
‐ The sample clients and servers are implemented in a very similar way (when possible). 
‐ Not all possible failures are checked, and no fork() is done to manage each client (we want to keep it simple). 
 
The code itself is printed is written in the following section (3.3), but you may also want to download it. It is 
included in the archive test_languages_<version>.tar.gz available on the EDMS site, on the page of this 
document (see [1] for a direct link). 
 
By following this sample code you should be able to adapt easily a non‐IPv6 compliant TCP‐based program. 
Some other bugs may appear is some uncommon cases, because of IPv6 address length, for example if your 
program stores IP addresses in a database, or displays them in a too short label on a user interface. 
 

           3.2.2. Files
The  files  needed  to  run  the  samples  are  organised  on  4  different  directories,  one  for  each  programming 
language: test_c, test_python, test_perl and test_java. 
Inside each of these directories: 
‐ client.[c|py|pl|java] is the main client code file 
‐ server_one_socket.[c|py|pl|java] is the main code file for the server using only one socket 
‐ server_two_sockets.[c|py|pl] is the main code file for the server using two sockets 
‐ server_job.[c|py|pl|java]  is  the  code  file  which  allows  the  server  to  manage  the  dialog  with  a 
   client once the connection is established (it is used by server_one_socket and server_two_socket) 
‐ IPv4_and_IPv6_enabling.[c|py|pl|java] is the code file which handles all specific IPv4 and IPv6 
   related functionality
                                                                    
Notes:  
‐ As explained earlier, we did not build any Java version of the server with two sockets. 
‐ Explanations about this implementation choice: 
           o   A  separate  IPv4_and_IPv6_enabling.[c|py|pl|java]  file  was  written  with  all  specific 
               IPv4  and  IPv6  related  functionality  in  order  to  simplify  the  other  files.  This  file  can  be  seen  as  a 
               library useful for any program expected to work in a mixed IPv4 and IPv6 environment. 
           o   A  separate  server_job.[c|py|pl|java]  file  was  written  because  all  the  part  of  the  code 
               managing  the  dialog  with  the  client  is  the  same  in  server_one_socket  and  server_two_sockets.  
               Moreover, in order to have a similar code, the same was done in Java although there is no version 
               with two sockets in this language. 




EGEE-III                                                               PUBLIC                                      6 / 49
                                                                                                              Doc. Identifier:

                                            Note                                                EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008




         3.3. SAMPLE PROGRAMS CODE
     Here is printed the code of the sample clients of servers in each of the languages. 
     This section is intended for developers. 
     If you just want to get  the result of the comparison, you can go directly to  the section called “ANALYSIS AND 
     COMPARISON“. 
      

             3.3.1. C language

 1   /*************************************
 2   file server_one_socket.c
 3   **************************************/
 4   #include <unistd.h>
 5   #include <stdlib.h>
 6
 7   // constants
 8   #define MAX_CONNECTIONS        1
 9
10   // declarations
11   int createAndSetUpATCPServerSocket(int port, int max_connections);
12   int manageClientConnectedOnServerSocket(int server_socket);
13
14   int main(int argc, char **argv)
15   {
16           int port, server_socket;
17           int should_continue;
18
19              // port is the first parameter
20              port = atoi(argv[1]);
21
22              // get one server socket
23              server_socket = createAndSetUpATCPServerSocket(port, MAX_CONNECTIONS);
24
25              // loop and accept connections
26              should_continue = 1; // true
27              while (should_continue)
28              {
29                      should_continue = manageClientConnectedOnServerSocket(server_socket);
30              }
31
32              // close the server socket
33              close(server_socket);
34
35              return 0;
36   }

 1




     EGEE-III                                                  PUBLIC                                      7 / 49
                                                                                                              Doc. Identifier:

                                            Note                                                EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008



 1   /*************************************
 2   file server_two_sockets.c
 3   **************************************/
 4   #include <unistd.h>
 5   #include <stdlib.h>
 6   #include <sys/select.h>
 7
 8   // constants
 9   #define MAX_CONNECTIONS        1
10   #define MAX_SOCKETS            2
11
12   // declarations
13   void createAndSetUpAllTCPServerSockets(int *nb_sockets, int *tb_sockets,
14                                             int port, int max_connections);
15   int manageClientConnectedOnServerSocket(int server_socket);
16
17   int main(int argc, char **argv)
18   {
19             int port, index_server_socket, server_socket, nb_sockets;
20             int should_continue;
21             int server_socket_list[MAX_SOCKETS];
22             fd_set socket_list_mask;
23
24              // port is the first parameter
25              port = atoi(argv[1]);
26
27              // get available server sockets
28              createAndSetUpAllTCPServerSockets(&nb_sockets, server_socket_list,
29                                              port, MAX_CONNECTIONS);
30
31              // loop and accept connections
32              should_continue = 1; // true
33              while (should_continue)
34              {
35                        // prepare 'select' parameter
36                        FD_ZERO(&socket_list_mask);
37                        for (index_server_socket = 0; index_server_socket < nb_sockets; index_server_socket++)
38                        {
39                                   FD_SET(server_socket_list[index_server_socket], &socket_list_mask);
40                        }
41
42                        // wait on server sockets
43                        select(FD_SETSIZE, &socket_list_mask, NULL, NULL, NULL);
44
45                        // get the server socket which woke up the 'select'
46                        for (index_server_socket = 0; index_server_socket < nb_sockets; index_server_socket++)
47                        {
48                                  if (FD_ISSET(server_socket_list[index_server_socket], &socket_list_mask))
49                                  {
50                                             server_socket = server_socket_list[index_server_socket];
51                                             break;
52                                  }
53                        }
54
55                        // manage the client connection on the server socket
56                        should_continue = manageClientConnectedOnServerSocket(server_socket);
57              }
58
59              // close all server sockets
60              for (index_server_socket = 0; index_server_socket < nb_sockets; index_server_socket++)
61              {
62                        close(server_socket_list[index_server_socket]);



     EGEE-III                                                  PUBLIC                                      8 / 49
                                                                              Doc. Identifier:

                            Note                                EGEE-III-SA2-TEC-971407-
                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                            Date: 27/11/2008



63              }
64
65              return 0;
66   }


 1




     EGEE-III                      PUBLIC                                  9 / 49
                                                                                                              Doc. Identifier:

                                            Note                                                EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008



 1   /*************************************
 2   file server_job.c
 3   **************************************/
 4   #define _GNU_SOURCE
 5   #include <stdio.h>
 6   #include <sys/types.h>
 7   #include <sys/socket.h>
 8   #include <string.h>
 9   #include <unistd.h>
10   #include <stdlib.h>
11
12   #define CLIENT_MAX_CHARS       64
13   #define MESSAGE_MAX_CHARS      1024
14
15   void getIPString(struct sockaddr *paddress, char *host, int host_length);
16
17   int manageClientConnectedOnServerSocket(int server_socket)
18   {
19             struct sockaddr_storage sock_addr;
20             struct sockaddr *client_socket_address = (struct sockaddr *)&sock_addr;
21             int client_socket_address_len = sizeof(sock_addr);
22             int connection_socket, line_size = 0;
23             char client_ip[CLIENT_MAX_CHARS];
24             char *data = NULL;
25             char stripped_data[MESSAGE_MAX_CHARS];
26             int should_continue;
27             FILE *socket_filedesc;
28
29              // accept connection
30              connection_socket = accept(server_socket, client_socket_address, &client_socket_address_len);
31
32              // get file interface for line-by-line reading/writing on socket
33              socket_filedesc = fdopen(connection_socket, "w+");
34
35              // notify client connection
36              getIPString(client_socket_address, client_ip, CLIENT_MAX_CHARS);
37              printf("%s connected!\n", client_ip);
38
39              // send "hi <ip>" to the client
40              fprintf(socket_filedesc, "hi %s\n", client_ip); fflush(socket_filedesc);
41
42              // manage client dialog
43              while (1)
44              {
45                        // read client message
46                        getline(&data, &line_size, socket_filedesc);
47
48                        // strip message
49                        strcpy(stripped_data, &data[strspn(data, "\r\n\t ")]);
50                        stripped_data[strcspn(stripped_data, "\r\n\t ")] = '\0';
51
52                        if ((strcmp(stripped_data, "bye") == 0) || (strcmp(stripped_data, "stop") == 0))
53                        {         // if message is "bye" or "stop" send "bye <ip>" and leave the dialog loop
54                                  fprintf(socket_filedesc, "bye %s\n", client_ip); fflush(socket_filedesc);
55                                  break;
56                        }
57                        else
58                        {         // otherwise resend the message to the client
59                                  fprintf(socket_filedesc, "%s", data); fflush(socket_filedesc);
60
61                        }
62              }



     EGEE-III                                                  PUBLIC                                    10 / 49
                                                                                                      Doc. Identifier:

                                            Note                                        EGEE-III-SA2-TEC-971407-
                                                                    IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                    Date: 27/11/2008



63
64              // notify client disconnection
65              printf("%s disconnected!\n", client_ip);
66
67              // close the connection socket
68              close(connection_socket);
69
70              // should the server continue?
71              if (strcmp(stripped_data, "stop") == 0)
72              {
73                        should_continue = 0; // false
74              }
75              else
76              {
77                        should_continue = 1; // true
78              }
79
80              // free memory
81              free(data);
82
83              return should_continue;
84   }

 1




     EGEE-III                                              PUBLIC                                11 / 49
                                                                                                   Doc. Identifier:

                                          Note                                       EGEE-III-SA2-TEC-971407-
                                                                 IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                 Date: 27/11/2008



 1   /*************************************
 2   file client.c
 3   **************************************/
 4   #define _GNU_SOURCE
 5   #include <stdio.h>
 6   #include <string.h>
 7   #include <stdlib.h>
 8   #include <unistd.h>
 9
10   int firstTCPSocketConnectingCorrectly(char *host, int port);
11
12   int main(int argc, char **argv)
13   {
14           char *host;
15           int port, connection_socket;
16           FILE *socket_filedesc;
17           char *welcomingMessage = NULL;
18           int welcomingMessage_size = 0;
19           char *leavingMessage = NULL;
20           int leavingMessage_size = 0;
21
22              // parameters
23              host = argv[1];
24              port = atoi(argv[2]);
25
26              // try to connect and otherwise exit
27              connection_socket = firstTCPSocketConnectingCorrectly(host, port);
28              if (connection_socket == -1)
29              {
30                      printf("could not open socket\n");
31                      exit(-1);
32              }
33
34              // get a file interface of the socket for easy line-by-line reading/writing
35              socket_filedesc = fdopen(connection_socket, "w+");
36
37              // receive and print the message sent by the server at the connection
38              getline(&welcomingMessage, &welcomingMessage_size, socket_filedesc);
39              printf("received: %s\n", welcomingMessage);
40
41              // send "bye" to the server
42              printf("sending: bye\n");
43              fprintf(socket_filedesc, "bye\n"); fflush(socket_filedesc);
44
45              // receive and print the answer sent by the server
46              getline(&leavingMessage, &leavingMessage_size, socket_filedesc);
47              printf("received: %s\n", leavingMessage);
48
49              // end
50              close(connection_socket);
51
52              // free memory
53              free(welcomingMessage);
54              free(leavingMessage);
55
56              return 0;
57   }




     EGEE-III                                         PUBLIC                                  12 / 49
                                                                                                               Doc. Identifier:

                                            Note                                                 EGEE-III-SA2-TEC-971407-
                                                                             IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                             Date: 27/11/2008



 1   /*************************************
 2   file IPv4_and_IPv6_enabling.c
 3   **************************************/
 4   #include <stdio.h>
 5   #include <sys/types.h>
 6   #include <sys/socket.h>
 7   #include <netdb.h>
 8   #include <arpa/inet.h>
 9   #include <unistd.h>
10   #include <string.h>
11
12
13   #define    IP_MAX_CHARS                   64
14   #define    PORT_MAX_DIGITS                8
15   #define    PREFIX_V4_MAPPED               "::ffff:"
16
17   // Function returning the IP string representation of a socket address
18   // ------------------------------------------------------------------------------------
19   void getIPString(struct sockaddr *paddress, char *ip, int ip_length)
20   {
21             // retrieve the ip
22             getnameinfo(paddress, sizeof(struct sockaddr_storage), ip, ip_length, 0, 0, NI_NUMERICHOST);
23
24              // if ipv4-mapped address, we remove the mapping notation in order to get only
25              // the IPv4 address
26              if (strncasecmp(ip, PREFIX_V4_MAPPED, strlen(PREFIX_V4_MAPPED)) == 0)
27              {
28                        memmove(ip, ip + strlen(PREFIX_V4_MAPPED),
29                                   strlen(ip) - strlen(PREFIX_V4_MAPPED) +1);
30              }
31   }
32
33
34   // function trying to connect to all available addresses of an host
35   // and returning the first socket successfully connected, or -1
36   // ------------------------------------------------------------------------------------
37   int firstTCPSocketConnectingCorrectly(char *host, int port)
38   {
39             int connection_socket;
40             struct addrinfo hints, *address_list, *paddress;
41             char port_string[PORT_MAX_DIGITS];
42
43              connection_socket = -1;
44
45              // getaddrinfo parameters
46              memset(&hints, 0, sizeof(hints));          // init
47              hints.ai_family = PF_UNSPEC;               // find both ipv4 and ipv6 addresses
48              hints.ai_socktype = SOCK_STREAM;           // type of socket
49
50              sprintf (port_string, "%d", port);
51              getaddrinfo(host, port_string, &hints, &address_list);
52
53              paddress = address_list;
54              while (paddress)
55              {
56                        // create the socket
57                        connection_socket = socket(paddress->ai_family, paddress->ai_socktype,
58                                                        paddress->ai_protocol);
59                        if (connection_socket == -1)
60                        {
61                                   paddress = paddress->ai_next;
62                                   continue; // try next address



     EGEE-III                                                   PUBLIC                                    13 / 49
                                                                                                                Doc. Identifier:

                                               Note                                               EGEE-III-SA2-TEC-971407-
                                                                              IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                              Date: 27/11/2008



 63                        }
 64
 65                        // connect
 66                        if (connect(connection_socket, paddress->ai_addr, paddress->ai_addrlen) == -1)
 67                        {
 68                                   close(connection_socket); connection_socket = -1;
 69                                   paddress = paddress->ai_next;
 70                                   continue; // try next address
 71                        }
 72
 73                        break;
 74              }
 75
 76              // free the list
 77              freeaddrinfo(address_list);
 78
 79              return connection_socket;
 80   }
 81
 82
 83   // Case of a server with two sockets:
 84   // function trying to create and set up all (ipv4 and ipv6) available server sockets of
 85   // the host. When one socket is IPv6, the IPV6_V6ONLY socket option is set.
 86   // The list of sockets is passed as a parameter to be completed.
 87   // ------------------------------------------------------------------------------------
 88   void createAndSetUpAllTCPServerSockets(int *nb_sockets, int *tb_sockets,
 89                                   int port, int max_connections)
 90   {
 91             int server_socket;
 92             struct addrinfo hints, *address_list, *paddress;
 93             int on = 1;
 94             char ip[IP_MAX_CHARS];
 95             char port_string[PORT_MAX_DIGITS];
 96
 97              *nb_sockets = 0;
 98
 99              // getaddrinfo parameters
100              memset(&hints, 0, sizeof(hints));        //   init
101              hints.ai_flags |= AI_PASSIVE;            //   server behaviour: accept connection on any network address
102              hints.ai_family = AF_UNSPEC;             //   find both ipv4 and ipv6 addresses
103              hints.ai_socktype = SOCK_STREAM;         //   type of socket
104
105              sprintf (port_string, "%d", port);
106              getaddrinfo(NULL, port_string, &hints, &address_list);
107
108              paddress = address_list;
109              while (paddress)
110              {
111                        // create the socket
112                        server_socket = socket(paddress->ai_family, paddress->ai_socktype, paddress->ai_protocol);
113                        if (server_socket == -1)
114                        {
115                                   paddress = paddress->ai_next;
116                                   continue; // try next address
117                        }
118
119                        // set SO_REUSEADDR option
120                        setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
121
122                        if (paddress->ai_family == AF_INET6)
123                        {         // we must set IPV6_V6ONLY in order to allow an IPv4 socket
124                                  // on the same port number.



      EGEE-III                                                   PUBLIC                                    14 / 49
                                                                                                                 Doc. Identifier:

                                               Note                                                EGEE-III-SA2-TEC-971407-
                                                                               IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                               Date: 27/11/2008



125                                    setsockopt(server_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on));
126                        }
127
128                        // bind and listen
129                        if (      (bind(server_socket, paddress->ai_addr, paddress->ai_addrlen) == -1) ||
130                                  (listen(server_socket, max_connections)                       == -1))
131                        {
132                                  close(server_socket);
133                                  paddress = paddress->ai_next;
134                                  continue; // try next address
135                        }
136
137                        // get the ip string, display it with the port number
138                        getIPString(paddress->ai_addr, ip, IP_MAX_CHARS);
139                        printf("Server socket now listening on %s port %d\n", ip, port);
140
141                        tb_sockets[*nb_sockets] = server_socket;
142                        *nb_sockets += 1;
143                        paddress = paddress->ai_next;
144              }
145
146              // free the list
147              freeaddrinfo(address_list);
148   }
149
150
151   // Case of a server with one socket:
152   // function trying to create a server socket using all available addresses of the host
153   // until one is successfully created. If the socket is IPv6, the IPV6_V6ONLY
154   // socket option is unset.
155   // Then the socket is returned, or -1 in case of failure.
156   // ------------------------------------------------------------------------------------
157   int createAndSetUpATCPServerSocket(int port, int max_connections)
158   {
159             int server_socket;
160             struct addrinfo hints, *address_list, *paddress;
161             int on = 1, off = 0;
162             char ip[IP_MAX_CHARS];
163             char port_string[PORT_MAX_DIGITS];
164
165              server_socket = -1;
166
167              // getaddrinfo parameters
168              memset(&hints, 0, sizeof(hints));         //   init
169              hints.ai_flags |= AI_PASSIVE;             //   server behaviour: accept connection on any network address
170              hints.ai_family = AF_UNSPEC;              //   find both ipv4 and ipv6 addresses
171              hints.ai_socktype = SOCK_STREAM;          //   type of socket
172
173              sprintf (port_string, "%d", port);
174              getaddrinfo(NULL, port_string, &hints, &address_list);
175
176              paddress = address_list;
177              while (paddress)
178              {
179                        // create the socket
180                        server_socket = socket(paddress->ai_family, paddress->ai_socktype, paddress->ai_protocol);
181                        if (server_socket == -1)
182                        {
183                                   paddress = paddress->ai_next;
184                                   continue; // try next address
185                        }
186


      EGEE-III                                                    PUBLIC                                    15 / 49
                                                                                                              Doc. Identifier:

                                               Note                                             EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008



187                        // set SO_REUSEADDR option
188                        setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
189
190                        if (paddress->ai_family == AF_INET6)
191                        {         // we must unset IPV6_V6ONLY in order to allow IPv4 clients
192                                  // to connect to the IPv6 socket
193                                  setsockopt(server_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
194                        }
195
196                        // bind and listen
197                        if (      (bind(server_socket, paddress->ai_addr, paddress->ai_addrlen) == -1) ||
198                                  (listen(server_socket, max_connections)                       == -1))
199                        {
200                                  close(server_socket); server_socket = -1;
201                                  paddress = paddress->ai_next;
202                                  continue; // try next address
203                        }
204
205                        // get the ip string, display it with the port number
206                        getIPString(paddress->ai_addr, ip, IP_MAX_CHARS);
207                        printf("Server socket now listening on %s port %d\n", ip, port);
208
209                        break; // break if no error
210              }
211
212              // free the list
213              freeaddrinfo(address_list);
214
215              // return the server socket
216              return server_socket;
217   }




      EGEE-III                                                 PUBLIC                                    16 / 49
                                                                                                Doc. Identifier:

                                     Note                                         EGEE-III-SA2-TEC-971407-
                                                              IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                              Date: 27/11/2008




           3.3.2. Python

 1   #!/usr/bin/python
 2   ######################
 3   # file server_one_socket.py
 4   ######################
 5   from IPv4_and_IPv6_enabling import createAndSetUpATCPServerSocket
 6   import server_job
 7   import sys
 8   import socket
 9
10   # constants
11   MAX_CONNECTIONS = 1
12
13   # port is the first parameter
14   port = sys.argv[1]
15
16   # get one server socket
17   server_socket = createAndSetUpATCPServerSocket(port, MAX_CONNECTIONS)
18
19   # loop and accept connections
20   should_continue = True
21   while should_continue:
22           # manage the client connection on the server socket
23           should_continue = server_job.manageClientConnectedOnServerSocket(server_socket)
24   # end while
25
26   # close the server socket
27   server_socket.close()




     EGEE-III                                       PUBLIC                                 17 / 49
                                                                                                   Doc. Identifier:

                                       Note                                          EGEE-III-SA2-TEC-971407-
                                                                 IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                 Date: 27/11/2008



 1   #!/usr/bin/python
 2   ######################
 3   # file server_two_sockets.py
 4   ######################
 5   from IPv4_and_IPv6_enabling import createAndSetUpAllTCPServerSockets
 6   import server_job
 7   import sys
 8   import socket
 9   import select
10
11   # constants
12   MAX_CONNECTIONS = 1
13
14   # port is the first parameter
15   port = sys.argv[1]
16
17   # get available server sockets
18   server_socket_list = createAndSetUpAllTCPServerSockets(port, MAX_CONNECTIONS)
19
20   # loop and accept connections
21   should_continue = True
22   while should_continue:
23           # wait on server sockets
24           ready_to_read, ready_to_write, in_error = \
25                    select.select(
26                            server_socket_list,
27                            [], [], None)
28
29              # get the server socket which woke up the 'select'
30              server_socket = ready_to_read[0]
31
32           # manage the client connection on the server socket
33           should_continue = server_job.manageClientConnectedOnServerSocket(server_socket)
34   # end while
35
36   # Close all server sockets
37   [server_socket.close() for server_socket in server_socket_list]




     EGEE-III                                         PUBLIC                                  18 / 49
                                                                                                           Doc. Identifier:

                                           Note                                              EGEE-III-SA2-TEC-971407-
                                                                         IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                         Date: 27/11/2008



 1   #!/usr/bin/python
 2   ######################
 3   # file server_job.py
 4   ######################
 5   from IPv4_and_IPv6_enabling import getIPString
 6   import socket
 7
 8   def manageClientConnectedOnServerSocket(server_socket):
 9           # accept connection
10           connection_socket, client_addr = server_socket.accept()
11
12              # get file interface for line-by-line reading on socket
13              fs = connection_socket.makefile()
14
15              # notify client connection
16              client_ip = getIPString(client_addr)
17              print client_ip, 'connected!'
18
19              # send "hi <ip>" to the client
20              connection_socket.send('hi ' + client_ip + '\n')
21
22              # manage client dialog
23              while True:
24                      # read client message
25                      data = fs.readline()
26
27                      if data.strip() == 'bye' or data.strip() == 'stop':
28                               # if message is "bye" or "stop" send "bye <ip>" and leave the dialog loop
29                               connection_socket.send('bye ' + client_ip + '\n')
30                               break
31                      else:
32                               # otherwise resend the message to the client
33                               connection_socket.send(data)
34                      # end if
35              # end while
36
37              # notify client disconnection
38              print client_ip, 'disconnected!'
39
40              # close the connection socket
41              connection_socket.close()
42
43           # should the server continue?
44           if data.strip() == 'stop':
45                    return False
46           else:
47                    return True
48           # end if
49   # end def manageClientConnectedOnServerSocket




     EGEE-III                                                PUBLIC                                   19 / 49
                                                                                                Doc. Identifier:

                                       Note                                       EGEE-III-SA2-TEC-971407-
                                                              IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                              Date: 27/11/2008



 1   #!/usr/bin/python
 2   ######################
 3   # file client.py
 4   ######################
 5   import sys
 6   import IPv4_and_IPv6_enabling
 7
 8   # parameters
 9   host=sys.argv[1]
10   port=sys.argv[2]
11
12   # try to connect and otherwise exit
13   connection_socket = IPv4_and_IPv6_enabling.firstTCPSocketConnectingCorrectly(host, port)
14   if connection_socket is None:
15            print 'could not open socket'
16            sys.exit(1)
17   # end if
18
19   # get a file interface of the socket for easy line-by-line reading
20   fs = connection_socket.makefile()
21
22   # receive and print the message sent by the server at the connection
23   welcomingMessage = fs.readline()
24   print "received: " + welcomingMessage
25
26   # send "bye" to the server
27   print "sending: bye"
28   connection_socket.send('bye\n')
29
30   # receive and print the answer sent by the server
31   leavingMessage = fs.readline()
32   print "received: " + leavingMessage
33
34   # end
35   connection_socket.close()




     EGEE-III                                       PUBLIC                                 20 / 49
                                                                                                    Doc. Identifier:

                                       Note                                           EGEE-III-SA2-TEC-971407-
                                                                  IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                  Date: 27/11/2008



 1   #!/usr/bin/python
 2   ######################
 3   # file IPv4_and_IPv6_enabling.py
 4   ######################
 5   import socket
 6
 7   # There is no symbol "socket.IPV6_V6ONLY" defined in python yet.
 8   # We got the value of this socket option in the C language include file
 9   # /usr/include/bits/in.h
10   IPV6_V6ONLY = 26
11
12   # other constants
13   PREFIX_V4_MAPPED = "::ffff:"
14
15   # Function returning the IP string representation of a socket address
16   # ------------------------------------------------------------------------------------
17   def getIPString(socket_address):
18
19              # retrieve the ip
20              ip, port_number = socket.getnameinfo(socket_address, \
21                               socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
22
23              # if ipv4-mapped address, we remove the mapping notation in order to get only
24              # the IPv4 address
25              if ip.startswith(PREFIX_V4_MAPPED) == True:
26                       ip = ip.lstrip(":f")
27              # end if
28
29              # return ip
30              return ip
31
32   # end def getIPString
33
34
35   # function trying to connect to all available addresses of an host
36   # and returning the first socket successfully connected, or None
37   # ------------------------------------------------------------------------------------
38   def firstTCPSocketConnectingCorrectly(host, port):
39           connection_socket = None
40           for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
41                    address_family, socket_type, proto, canon_name, socket_address = res
42                    try:
43                            # create the socket
44                            connection_socket = socket.socket(address_family, socket_type, proto)
45
46                      except socket.error, msg:
47                              # in case of a problem continue with next address
48                              connection_socket = None
49                              continue
50                      # end try
51
52                      try:
53                              # try to connect
54                              connection_socket.connect(socket_address)
55
56                      except socket.error, msg:
57                              # in case of a problem continue with next address
58                              connection_socket.close()
59                              connection_socket = None
60                              continue
61                      # end try
62                      break



     EGEE-III                                          PUBLIC                                  21 / 49
                                                                                                  Doc. Identifier:

                                     Note                                           EGEE-III-SA2-TEC-971407-
                                                                IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                Date: 27/11/2008



 63           # end for
 64           return connection_socket
 65   # end def firstTCPSocketConnectingCorrectly
 66
 67
 68   # Case of a server with two sockets:
 69   # function trying to create and set up all (ipv4 and ipv6) available server sockets of
 70   # the host. When one socket is IPv6, the IPV6_V6ONLY socket option is set.
 71   # Then the list of sockets is returned.
 72   # ------------------------------------------------------------------------------------
 73   def createAndSetUpAllTCPServerSockets(port, max_connections):
 74           server_socket_list = []
 75           server_socket = None
 76           for res in socket.getaddrinfo(None, port, socket.AF_UNSPEC, socket.SOCK_STREAM, \
 77                            0, socket.AI_PASSIVE):
 78                    address_family, socket_type, proto, canon_name, socket_address = res
 79                    try:
 80                            # create the socket
 81                            server_socket = socket.socket(address_family, socket_type, proto)
 82
 83                            # set SO_REUSEADDR option
 84                            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 85
 86                            if address_family == socket.AF_INET6:
 87                                     # we must set IPV6_V6ONLY in order to allow an IPv4 socket
 88                                     # on the same port number.
 89                                     server_socket.setsockopt(socket.IPPROTO_IPV6, IPV6_V6ONLY, 1)
 90                            # end if
 91
 92                            # bind and listen
 93                            server_socket.bind(socket_address)
 94                            server_socket.listen(max_connections)
 95
 96                            # get the ip string, display it with the port number
 97                            ip = getIPString(socket_address)
 98                            print "Server socket now listening on ", ip, " port ", port
 99
100                            # add the socket to the list
101                            server_socket_list.append(server_socket)
102                    except socket.error, msg:
103                            continue
104                    # end try
105           # end for
106           return server_socket_list
107   # end def createAndSetUpATCPServerSocket
108
109
110   # Case of a server with one socket:
111   # function trying to create a server socket using all available addresses of the host
112   # until one is successfully created. If the socket is IPv6, the IPV6_V6ONLY
113   # socket option is unset.
114   # Then the socket is returned, or None in case of failure.
115   # ------------------------------------------------------------------------------------
116   def createAndSetUpATCPServerSocket(port, max_connections):
117           server_socket = None
118           for res in socket.getaddrinfo(None, port, socket.AF_UNSPEC, socket.SOCK_STREAM, \
119                             0, socket.AI_PASSIVE):
120                    address_family, socket_type, proto, canon_name, socket_address = res
121                    try:
122                             # create the socket
123                             server_socket = socket.socket(address_family, socket_type, proto)
124


      EGEE-III                                       PUBLIC                                  22 / 49
                                                                                                  Doc. Identifier:

                                     Note                                           EGEE-III-SA2-TEC-971407-
                                                                IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                Date: 27/11/2008



125                            # set SO_REUSEADDR option
126                            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
127
128                            if address_family == socket.AF_INET6:
129                                     # we must unset IPV6_V6ONLY in order to allow IPv4 clients
130                                     # to connect to the IPv6 socket
131                                     server_socket.setsockopt(socket.IPPROTO_IPV6, IPV6_V6ONLY, 0)
132                            # end if
133
134                            # bind and listen
135                            server_socket.bind(socket_address)
136                            server_socket.listen(max_connections)
137
138                            # get the ip string, display it with the port number
139                            ip = getIPString(socket_address)
140                            print "Server socket now listening on ", ip, " port ", port
141                    except socket.error, msg:
142                            continue
143                    # end try
144                    break
145           # end for
146           return server_socket
147   # end def createAndSetUpATCPServerSocket




      EGEE-III                                       PUBLIC                                  23 / 49
                                                                                                Doc. Identifier:

                                     Note                                         EGEE-III-SA2-TEC-971407-
                                                              IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                              Date: 27/11/2008




           3.3.3. Perl

 1   #!/usr/bin/perl -w
 2   #--------------------
 3   # server_one_socket.pl
 4   #--------------------
 5
 6   use strict;
 7   require "IPv4_and_IPv6_enabling.pl";
 8   require "server_job.pl";
 9
10   # constants
11   my $MAX_CONNECTIONS = 1;
12
13   # variables
14   my (    $port, $server_socket, $should_continue);
15
16   # port is the first parameter
17   $port = shift;
18
19   # get one server socket
20   $server_socket = &createAndSetUpATCPServerSocket($port, $MAX_CONNECTIONS);
21
22   # loop and accept connections
23   $should_continue = 1;
24   while ($should_continue)
25   {
26           # manage the client connection on the server socket
27           $should_continue = manageClientConnectedOnServerSocket($server_socket);
28   }
29
30   # close the server socket
31   close $server_socket;




     EGEE-III                                       PUBLIC                                 24 / 49
                                                                                                    Doc. Identifier:

                                       Note                                           EGEE-III-SA2-TEC-971407-
                                                                  IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                  Date: 27/11/2008



 1   #!/usr/bin/perl -w
 2   #--------------------
 3   # server_two_sockets.pl
 4   #--------------------
 5
 6   use strict;
 7   use Socket;
 8   use Socket6;
 9   require "IPv4_and_IPv6_enabling.pl";
10   require "server_job.pl";
11
12   # constant
13   my $MAX_CONNECTIONS = 1;
14
15   # variables
16   my (    $port, $server_socket, $should_continue,
17           @server_socket_list, $socket_list_mask, $server_socket_woken_up);
18
19   # port is the first parameter
20   $port = shift;
21
22   # get available server sockets
23   @server_socket_list = &createAndSetUpAllTCPServerSockets($port, $MAX_CONNECTIONS);
24
25   # loop and accept connections
26   $should_continue = 1;
27   while ($should_continue)
28   {
29           # prepare 'select' parameter
30           $socket_list_mask = '';
31           for $server_socket (@server_socket_list)
32           {
33                    vec($socket_list_mask,fileno($server_socket),1) = 1;
34           }
35
36              # wait on server sockets
37              select($socket_list_mask, undef, undef, undef);
38
39              # get the server socket which woke up the 'select'
40              for $server_socket (@server_socket_list)
41              {
42                      if (vec($socket_list_mask,fileno($server_socket),1) == 1)
43                      {
44                               $server_socket_woken_up = $server_socket;
45                               last;
46                      }
47              }
48
49              # manage the client connection on the server socket
50              $should_continue = manageClientConnectedOnServerSocket($server_socket_woken_up);
51   }
52
53   # close all server sockets
54   for $server_socket (@server_socket_list)
55   {
56           close $server_socket;
57   }




     EGEE-III                                         PUBLIC                                   25 / 49
                                                                                                           Doc. Identifier:

                                          Note                                               EGEE-III-SA2-TEC-971407-
                                                                         IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                         Date: 27/11/2008



 1   #!/usr/bin/perl -w
 2   #--------------------
 3   # server_job.pl
 4   #--------------------
 5
 6   use strict;
 7   use Socket;
 8   use Socket6;
 9   require "IPv4_and_IPv6_enabling.pl";
10
11   sub manageClientConnectedOnServerSocket
12   {
13           # variables
14           my (     $client_socket_address, $server_socket, $client_ip, $port_number, $data, $stripped_data);
15
16              # function parameters
17              $server_socket = shift;
18
19              # accept connection
20              $client_socket_address = accept(connection_socket, $server_socket);
21
22              # disable buffering on connection_socket
23              select((select(connection_socket), $|=1)[0]);
24
25              # notify client connection
26              $client_ip = getIPString($client_socket_address);
27              print "$client_ip connected!\n";
28
29              # send "hi <ip>" to the client
30              print connection_socket "hi $client_ip\n";
31
32              # manage client dialog
33              while (1)
34              {       # read client message
35                      $data = readline(connection_socket);
36
37                       # strip message
38                       $stripped_data = $data;
39                       $stripped_data =~ s/^\s+//;
40                       $stripped_data =~ s/\s+$//;
41
42                       if (("$stripped_data" eq 'bye') || ("$stripped_data" eq 'stop'))
43                       {       # if message is "bye" or "stop" send "bye <ip>" and leave the dialog loop
44                               print connection_socket "bye $client_ip\n";
45                               last;
46                       }
47                       else
48                       {       # otherwise resend the message to the client
49                               print connection_socket "$data";
50                       }
51              }
52
53              # notify client disconnection
54              print "$client_ip disconnected!\n";
55
56              # close the connection socket
57              close connection_socket;
58
59              # should the server continue?
60              if ("$stripped_data" eq 'stop')
61              {
62                      0;       # return false



     EGEE-III                                               PUBLIC                                    26 / 49
                                                                                                Doc. Identifier:

                                    Note                                          EGEE-III-SA2-TEC-971407-
                                                              IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                              Date: 27/11/2008



63              }
64              else
65              {
66                     1;     # return true
67              }
68   }
69
70   # being included this file must return "true"
71   1;




     EGEE-III                                        PUBLIC                                27 / 49
                                                                                                 Doc. Identifier:

                                    Note                                           EGEE-III-SA2-TEC-971407-
                                                               IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                               Date: 27/11/2008



 1   #!/usr/bin/perl -w
 2   #----------------
 3   # client.pl
 4   #----------------
 5
 6   use strict;
 7   use Socket;
 8   require "IPv4_and_IPv6_enabling.pl";
 9
10   # variables
11   my (    $host, $port, $connection_socket, $welcomingMessage,
12           $leavingMessage);
13
14   # parameters
15   $host = shift;
16   $port = shift;
17
18   # try to connect and otherwise exit
19   $connection_socket = firstTCPSocketConnectingCorrectly($host, $port);
20   if (!defined($connection_socket))
21   {
22           die "could not open socket\n";
23   }
24
25   # disable buffering on connection_socket
26   select((select($connection_socket), $|=1)[0]);
27
28   # receive and print the message sent by the server at the connection
29   $welcomingMessage = readline($connection_socket);
30   print "received: $welcomingMessage\n";
31
32   # send "bye" to the server
33   print "sending: bye\n";
34   print $connection_socket "bye\n";
35
36   # receive and print the answer sent by the server
37   $leavingMessage = readline($connection_socket);
38   print "received: $leavingMessage\n";
39
40   # end
41   close($connection_socket);




     EGEE-III                                         PUBLIC                                28 / 49
                                                                                                              Doc. Identifier:

                                              Note                                              EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008



 1   #!/usr/bin/perl -w
 2   #--------------------
 3   # IPv4_and_IPv6_enabling.pl
 4   #--------------------
 5
 6   use strict;
 7   use Socket;
 8   use Socket6;
 9
10   # There is no symbol "IPV6_V6ONLY" defined in perl yet.
11   # We got the value of this socket option in the C language include file
12   # /usr/include/bits/in.h
13   my $IPV6_V6ONLY = 26;
14
15   # other constants
16   my $PREFIX_V4_MAPPED = "::ffff:";
17
18
19   # Function returning the IP string representation of a socket address
20   # ------------------------------------------------------------------------------------
21   sub getIPString
22   {
23             # variables
24             my (       $ip, $port_number, $socket_address);
25
26              # function parameters
27              $socket_address = shift;
28
29              # retrieve the ip
30              ($ip, $port_number) = getnameinfo($socket_address, NI_NUMERICHOST | NI_NUMERICSERV);
31
32              # if ipv4-mapped address, we remove the mapping notation in order to get only
33              # the IPv4 address
34              $ip =~ s/^$PREFIX_V4_MAPPED//;
35
36              # return ip
37              $ip;
38   }
39
40   # function trying to connect to all available addresses of an host
41   # and returning the first socket successfully connected, or undef
42   # ------------------------------------------------------------------------------------
43   sub firstTCPSocketConnectingCorrectly
44   {
45             # variables
46             my (       $host, $port, $connection_socket, @res, $address_family,
47                        $socket_type, $proto, $socket_address, $canon_name);
48
49              # function parameters
50              $host = shift;
51              $port = shift;
52
53              $connection_socket = undef;
54
55              @res = getaddrinfo($host, $port, AF_UNSPEC, SOCK_STREAM);
56              while (scalar(@res) >= 5) {
57                        ($address_family, $socket_type, $proto, $socket_address, $canon_name, @res) = @res;
58
59                        # create the socket
60                        if (!socket($connection_socket, $address_family, $socket_type, $proto))
61                        {
62                                  # in case of a problem continue with next address



     EGEE-III                                                  PUBLIC                                    29 / 49
                                                                                                               Doc. Identifier:

                                             Note                                               EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008



 63                                  $connection_socket = undef;
 64                                  next;
 65                        }
 66
 67                        # connect
 68                        if (!connect($connection_socket, $socket_address))
 69                        {
 70                                  # in case of a problem continue with next address
 71                                  close($connection_socket);
 72                                  $connection_socket = undef;
 73                                  next;
 74                        }
 75
 76                        last; # break
 77              }
 78
 79              # return the connection socket
 80              $connection_socket;
 81   }
 82
 83
 84
 85   # Case of a server with two sockets:
 86   # function trying to create and set up all (ipv4 and ipv6) available server sockets of
 87   # the host. When one socket is IPv6, the IPV6_V6ONLY socket option is set.
 88   # Then the list of sockets is returned.
 89   # ------------------------------------------------------------------------------------
 90   sub createAndSetUpAllTCPServerSockets
 91   {
 92             # variables
 93             my (       $port, $max_connections, $ip, $socket_type, $socket_address, $proto, $canon_name,
 94                        @server_socket_list, $port_number, $client_addr, $address_family, @res, $index);
 95
 96              # function parameters
 97              $port = shift;
 98              $max_connections = shift;
 99
100              $index = 0;
101              @server_socket_list = ();
102
103              @res = getaddrinfo("", $port, AF_UNSPEC, SOCK_STREAM, 0, AI_PASSIVE);
104              $address_family = -1;
105              while (scalar(@res) >= 5) {
106                        ($address_family, $socket_type, $proto, $socket_address, $canon_name, @res) = @res;
107
108                        # create the socket
109                        socket($server_socket_list[$index], $address_family, $socket_type, $proto) or next;
110
111                        # set SO_REUSEADDR option
112                        setsockopt($server_socket_list[$index], SOL_SOCKET, SO_REUSEADDR, 1);
113
114                        if ($address_family == AF_INET6)
115                        {         # we must set IPV6_V6ONLY in order to allow an IPv4 socket
116                                  # on the same port number.
117                                  setsockopt($server_socket_list[$index], IPPROTO_IPV6, $IPV6_V6ONLY, 1);
118                        }
119
120                        # bind and listen
121                        if (      !bind($server_socket_list[$index], $socket_address) or
122                                  !listen($server_socket_list[$index], $max_connections))
123                        {
124                                  close($server_socket_list[$index]);



      EGEE-III                                                  PUBLIC                                   30 / 49
                                                                                                               Doc. Identifier:

                                                Note                                            EGEE-III-SA2-TEC-971407-
                                                                            IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                            Date: 27/11/2008



125                                     next;    # try next address
126                        }
127
128                        # get the ip string, display it with the port number
129                        $ip = getIPString($socket_address);
130                        print "Server socket now listening on $ip port $port\n";
131
132                        $index = $index +1;
133              }
134
135              # return the list
136              @server_socket_list;
137   }
138
139
140   # Case of a server with one socket:
141   # function trying to create a server socket using all available addresses of the host
142   # until one is successfully created. If the socket is IPv6, the IPV6_V6ONLY
143   # socket option is unset.
144   # Then the socket is returned, or undef in case of failure.
145   # ------------------------------------------------------------------------------------
146   sub createAndSetUpATCPServerSocket
147   {
148             # variables
149             my (       $port, $max_connections, $ip, $socket_type, $socket_address, $proto, $canon_name,
150                        $port_number, $client_addr, $address_family, @res, $server_socket);
151
152              # function parameters
153              $port = shift;
154              $max_connections = shift;
155
156              $server_socket = undef;
157
158              @res = getaddrinfo("", $port, AF_UNSPEC, SOCK_STREAM, 0, AI_PASSIVE);
159              $address_family = -1;
160              while (scalar(@res) >= 5) {
161                        ($address_family, $socket_type, $proto, $socket_address, $canon_name, @res) = @res;
162
163                        # create the socket
164                        socket($server_socket, $address_family, $socket_type, $proto) or next;
165
166                        # set SO_REUSEADDR option
167                        setsockopt($server_socket, SOL_SOCKET, SO_REUSEADDR, 1);
168
169                        if ($address_family == AF_INET6)
170                        {         # we must unset IPV6_V6ONLY in order to allow IPv4 clients
171                                  # to connect to the IPv6 socket
172                                  setsockopt($server_socket, IPPROTO_IPV6, $IPV6_V6ONLY, 0);
173                        }
174
175                        # bind and listen
176                        if (      !bind($server_socket, $socket_address) or
177                                  !listen($server_socket, $max_connections))
178                        {
179                                  close($server_socket);
180                                  next;     # try next address
181                        }
182
183                        # get the ip string, display it with the port number
184                        $ip = getIPString($socket_address);
185                        print "Server socket now listening on $ip port $port\n";
186


      EGEE-III                                                  PUBLIC                                   31 / 49
                                                                                                  Doc. Identifier:

                                              Note                                  EGEE-III-SA2-TEC-971407-
                                                                IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                Date: 27/11/2008



187                        last; # break if no error
188              }
189
190              # return the server socket
191              $server_socket;
192   }
193
194   # being included this file must return "true"
195   1;




      EGEE-III                                         PUBLIC                                32 / 49
                                                                                                           Doc. Identifier:

                                          Note                                               EGEE-III-SA2-TEC-971407-
                                                                         IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                         Date: 27/11/2008




           3.3.4. Java

 1   /*
 2    * server_one_socket.java file
 3    */
 4
 5   import java.lang.Exception;
 6   import java.net.ServerSocket;
 7
 8   public class server_one_socket
 9   {
10           public static void main(String [] args) throws Exception
11           {
12                    int port;
13                    ServerSocket server_socket;
14                    server_job job = new server_job();
15                    boolean should_continue;
16
17                       // port is the first parameter
18                       port = Integer.parseInt(args[0]);
19
20                       // get one server socket
21                       server_socket = new ServerSocket(port);
22
23                       // loop and accept connections
24                       should_continue = true;
25                       while(should_continue)
26                       {
27                               // manage the client connection on the server socket
28                               should_continue = job.manageClientConnectedOnServerSocket(server_socket);
29                       }
30
31                       // close the server socket
32                       server_socket.close();
33              }
34   }




     EGEE-III                                               PUBLIC                                    33 / 49
                                                                                                            Doc. Identifier:

                                          Note                                                EGEE-III-SA2-TEC-971407-
                                                                          IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                          Date: 27/11/2008



 1   /*
 2    * server_job.java file
 3    */
 4
 5   import   java.lang.Exception;
 6   import   java.net.ServerSocket;
 7   import   java.net.Socket;
 8   import   java.io.*;
 9
10   public class server_job
11   {
12           public boolean manageClientConnectedOnServerSocket(ServerSocket server_socket) throws Exception {
13
14                       Socket connection_socket;
15                       String client_ip, data, trimmed_data;
16                       PrintWriter out;
17                       BufferedReader in;
18
19                       // accept connection
20                       connection_socket = server_socket.accept();
21
22                       // Get stream interfaces for line-by-line reading and writing on socket
23                       out = new PrintWriter(connection_socket.getOutputStream(), true);
24                       in = new BufferedReader(new InputStreamReader(connection_socket.getInputStream()));
25
26                       // notify client connection
27                       client_ip = connection_socket.getInetAddress().getHostAddress();
28                       System.out.println(client_ip + " connected!");
29
30                       // send "hi <ip>" to the client
31                       out.println("hi " + client_ip);
32
33                       // manage client dialog
34                       while(true)
35                       {
36                               // read client message
37                               data = in.readLine();
38
39                                 // trim it
40                                 trimmed_data = data.trim();
41
42                                 if (trimmed_data.equals("bye") || trimmed_data.equals("stop"))
43                                 {       // if message is "bye" send "bye <ip>" and leave the dialog loop
44                                         out.println("bye " + client_ip);
45                                         break;
46                                 }
47                                 else
48                                 {       // otherwise resend the message to the client
49                                         out.println(data);
50                                 }
51                       }
52
53                       // notify client disconnection
54                       System.out.println(client_ip + " disconnected!");
55
56                       // close socket
57                       connection_socket.close();
58
59                       // should the server continue?
60                       if (trimmed_data.equals("stop"))
61                       {
62                               return false;



     EGEE-III                                                PUBLIC                                    34 / 49
                                                                                     Doc. Identifier:

                                 Note                                  EGEE-III-SA2-TEC-971407-
                                                   IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                   Date: 27/11/2008



63                  }
64                  else
65                  {
66                         return true;
67                  }
68              }
69   }




     EGEE-III                             PUBLIC                                35 / 49
                                                                                                        Doc. Identifier:

                                      Note                                                EGEE-III-SA2-TEC-971407-
                                                                      IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                      Date: 27/11/2008



 1   /*
 2    * client.java file
 3    */
 4
 5   import java.lang.Exception;
 6   import java.net.Socket;
 7   import java.io.*;
 8
 9   public class client
10   {
11           public static void main(String [] args) throws Exception
12           {
13                    Socket connection_socket = null;
14                    int port;
15                    String host, welcomingMessage, leavingMessage;
16                    PrintWriter out;
17                    BufferedReader in;
18                    IPv4_and_IPv6_enabling connection_tester = new IPv4_and_IPv6_enabling();
19
20                   // parameters
21                   host = args[0];
22                   port = Integer.parseInt(args[1]);
23
24                   // try to connect and otherwise exit
25                   connection_socket = connection_tester.firstTCPSocketConnectingCorrectly(host, port);
26                   if (connection_socket == null)
27                   {
28                             System.out.println("could not open socket");
29                             System.exit(1);
30                   }
31
32                   // get stream interfaces for line-by-line reading and writing on socket
33                   out = new PrintWriter(connection_socket.getOutputStream(), true);
34                   in = new BufferedReader(new InputStreamReader(connection_socket.getInputStream()));
35
36                   // receive and print the message sent by the server at the connection
37                   welcomingMessage = in.readLine();
38                   System.out.println("received: " + welcomingMessage);
39
40                   // send "bye" to the server
41                   System.out.println("sending: bye");
42                   out.println("bye");
43
44                   // receive and print the answer sent by the server
45                   leavingMessage = in.readLine();
46                   System.out.println("received: " + leavingMessage);
47
48                   // end
49                   connection_socket.close();
50              }
51   }




     EGEE-III                                            PUBLIC                                    36 / 49
                                                                                                            Doc. Identifier:

                                          Note                                                EGEE-III-SA2-TEC-971407-
                                                                          IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                          Date: 27/11/2008



 1   /*
 2    * IPv4_and_IPv6_enabling.java file
 3    */
 4
 5   import java.lang.Exception;
 6   import java.net.Socket;
 7   import java.net.InetAddress;
 8
 9   public class IPv4_and_IPv6_enabling
10   {
11           public Socket firstTCPSocketConnectingCorrectly(String host, int port) throws Exception {
12                     int index_address;
13                     Socket connection_socket = null;
14
15                       InetAddress[] possible_addresses = InetAddress.getAllByName(host);
16                       for(index_address=0; index_address<possible_addresses.length; index_address++)
17                       {
18                                 try {
19                                            // try to connect
20                                            connection_socket = new Socket(possible_addresses[index_address], port);
21                                 }
22                                 catch(Exception e)
23                                 {          // in case of a problem continue with next address
24                                            connection_socket = null;
25                                            continue;
26                                 }
27                                 break;
28                       }
29
30                       return connection_socket;
31              }
32   }




     EGEE-III                                                PUBLIC                                    37 / 49
                                                                                                               Doc. Identifier:

                                              Note                                               EGEE-III-SA2-TEC-971407-
                                                                             IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                             Date: 27/11/2008




          3.4. BUILD AND RUN
     Here are the instructions if you want to build and run these sample programs.  

               3.4.1. C language
     Build: 
[duble@quarks test_c]$ gcc -Wall -o server_one_socket server_one_socket.c server_job.c IPv4_and_IPv6_enabling.c
[duble@quarks test_c]$ gcc -Wall -o server_two_sockets server_two_sockets.c server_job.c IPv4_and_IPv6_enabling.c
[duble@bdii test_c]$ gcc -Wall -o client client.c IPv4_and_IPv6_enabling.c

      
     Run the server with one socket:  
[duble@quarks test_c]$ ./server_one_socket 5555
Server socket now listening on :: port 5555

      
     Run the server with two sockets:  
[duble@quarks test_c]$ ./server_two_sockets 5555
Server socket now listening on :: port 5555
Server socket now listening on 0.0.0.0 port 5555

      
     Run the client:  
[duble@bdii test_c]$ ./client quarks.paris.urec.cnrs.fr 5555
received: hi 2001:660:3302:7003::11
sending: bye
received: bye 2001:660:3302:7003::11
[duble@bdii test_c]$




     EGEE-III                                                  PUBLIC                                     38 / 49
                                                                                                         Doc. Identifier:

                                              Note                                         EGEE-III-SA2-TEC-971407-
                                                                       IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                       Date: 27/11/2008




               3.4.2. Python
     Run the server with one socket:  
[duble@quarks test_python]$ ./server_one_socket.py 5555
Server socket now listening on :: port 5555

      
     Run the server with two sockets:  
[duble@quarks test_python]$ ./server_two_sockets.py 5555
Server socket now listening on :: port 5555
Server socket now listening on 0.0.0.0 port 5555

      
     Run the client:  
[duble@bdii test_python]$ ./client.py quarks.paris.urec.cnrs.fr 5555
received: hi 2001:660:3302:7003::11
sending: bye
received: bye 2001:660:3302:7003::11
[duble@bdii test_python]$




               3.4.3. Perl
     Run the server with one socket:  
[duble@quarks test_perl]$ ./server_one_socket.pl 5555
Server socket now listening on :: port 5555

      
     Run the server with two sockets:  
[duble@quarks test_perl]$ ./server_two_sockets.pl 5555
Server socket now listening on :: port 5555
Server socket now listening on 0.0.0.0 port 5555

      
     Run the client:  
[duble@bdii test_perl]$ ./client.pl quarks.paris.urec.cnrs.fr 5555
received: hi 2001:660:3302:7003::11
sending: bye
received: bye 2001:660:3302:7003::11
[duble@bdii test_perl]$

      




     EGEE-III                                                 PUBLIC                                39 / 49
                                                                                                         Doc. Identifier:

                                           Note                                            EGEE-III-SA2-TEC-971407-
                                                                       IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                       Date: 27/11/2008




               3.4.4. Java
     Build: 
[duble@quarks test_java]$ javac *.java
[duble@bdii test_java]$ javac *.java

      
     Run the server:  
[duble@quarks test_java]$ java server_one_socket 5555




     Run the client:  
[duble@bdii test_java]$ java client quarks.paris.urec.cnrs.fr 5555
received: hi 2001:660:3302:7003::11
sending: bye
received: bye 2001:660:3302:7003::11
[duble@bdii test_java]$



      
      
      
      
      




     EGEE-III                                                 PUBLIC                                40 / 49
                                                                                                                                                 Doc. Identifier:

                                                            Note                                                           EGEE-III-SA2-TEC-971407-
                                                                                                       IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                                                               Date: 27/11/2008




       3.5. ANALYSIS AND COMPARISON

           3.5.1. Main function calls

3.5.1.1. Server
Main purpose of the function call                                     C                      Python                        Perl                        Java 
Return  the  list  of  generic  interface  addresses  to        getaddrinfo()               getaddrinfo()              getaddrinfo() 
listen on:                                                    with host=NULL              with host=None               with host=”” 
‐   “::” and “0.0.0.0” if IPv6 is available 
                                                             AF_UNSPEC, SOCK‐           AF_UNSPEC, SOCK‐           AF_UNSPEC, SOCK‐
‐   “0.0.0.0” only if not                                   STREAM, AI_PASSIVE         STREAM, AI_PASSIVE         STREAM, AI_PASSIVE           new ServerSocket() 
Create the server socket                                          socket()                    socket()                   socket() 
Bind the server socket to an interface                             bind()                      bind()                     bind() 
Listen on the server socket                                        listen()                    listen()                   listen() 
Choose  if  the  IPv6  socket  should  accept  IPv4             setsockopt(                 setsockopt(                setsockopt( 
connections or not (must be done before bind())                                                                                                    Unavailable 
                                                            ..., IPV6_V6ONLY, ...)      ..., IPV6_V6ONLY, ...)     ..., IPV6_V6ONLY, ...) 
Free the result of getaddrinfo                                                         nothing to do (garbage     nothing to do (garbage 
                                                                    free()                                                                        not applicable 
                                                                                             collected)                 collected) 
Wait on several sockets                                                                                                                          possible but not 
                                                                   select()                    select()                   select() 
(case of a server with two sockets)                                                                                                              applicable here 
Accept a client connection                                        accept()                    accept()                   accept()                    accept() 
Read data line by line 
                                                                  getline()                  readline()                 readline()                  readLine() 
(other commands may be possible for this) 
Write data 
                                                                  fprintf()                    send()                     print()                    println() 
(other commands may be possible for this) 



3.5.1.2. Client
Main purpose of the function call                                     C                      Python                        Perl                        Java 
Return  the  list  of  addresses  to  connect  to  the          getaddrinfo()               getaddrinfo()              getaddrinfo() 
                                                                                                                                                   InetAddress. 
server host                                                  with AF_UNSPEC,             with AF_UNSPEC,            with AF_UNSPEC, 
                                                                                                                                              getAllByName(<host>) 
                                                              SOCK‐STREAM                 SOCK‐STREAM                SOCK‐STREAM 
Create the client socket                                          socket()                    socket()                   socket() 
                                                                                                                                                  new Socket() 
Connect to the server                                             connect()                   connect()                  connect() 
Free the result of getaddrinfo/getAllByName                                            nothing to do (garbage     nothing to do (garbage      nothing to do (garbage 
                                                                    free() 
                                                                                             collected)                 collected)                  collected) 
Read data line by line  
                                                                  getline()                  readline()                 readline()                  readLine() 
(other commands may be possible for this) 
Write data 
                                                                  fprintf()                    send()                     print()                    println() 
(other commands may be possible for this) 



3.5.1.3. Other useful calls
Main purpose of the function call                                     C                      Python                        Perl                        Java 
Get a character string representing an IP address            getnameinfo(...,            getnameinfo(...,           getnameinfo(..., 
                                                                                                                                                getHostAddress() 
                                                            NI_NUMERICHOST)             NI_NUMERICHOST)            NI_NUMERICHOST) 




EGEE-III                                                                              PUBLIC                                                 41 / 49
                                                                                                                     Doc. Identifier:

                                            Note                                                     EGEE-III-SA2-TEC-971407-
                                                                                 IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                                   Date: 27/11/2008



         3.5.2. General comments


The code shows that it is possible to build IPv6 compliant applications in C, Python, Perl and Java.  
The C, Python and Perl codes are very similar, because these sample programs use the same low‐level calls.  
(However, we will see later that it is possible to write more high‐level code in these languages.) 
 
All the code is address‐family agnostic except the test needed in C, Python and Perl to know if the server socket 
is  an  IPv4  one  or  an  IPv6  one:  if  it  is  an  IPv6  one,  we  must  set  or  unset  the  IPV6_V6ONLY  option  on  it  (see 
IPv4_and_IPv6_enabling.[c|py|pl]).  
Having a code is highly recommended to minimize any work needed to adapt future changes of the socket APIs. 
Tips about this can be found at [6].  
We can also notice that some protocols, which are not as famous as IP for now, like HIP for example, simply do 
not use any address as an identifier.  Because of this, these protocols would surely be easier to adapt when a 
major change occurs in the underlying APIs. 


         3.5.3. Specific advantages and drawbacks
 
3.5.3.1. C language
 
Drawback: If your non‐IPv6 compliant program stores “struct sockaddr” structures, you will have to use “struct 
sockaddr_storage” structures instead, because “struct sockaddr” structures are not large enough to contain an 
IPv6 address. See for example what is done on lines 19 and 20 of server_job.c. 
 
Drawback: C language is low level, so it's quite verbose. 
                                                                        
3.5.3.2. Python
 
Drawback: There is no IPV6_V6ONLY symbol defined in Python (yet).  
In our code this socket option integer constant has been defined manually (see IPv4AndIPv6Enabling.py), 
according to the value obtained in the C language source files.   
 




EGEE-III                                                          PUBLIC                                        42 / 49
                                                                                                               Doc. Identifier:

                                            Note                                                 EGEE-III-SA2-TEC-971407-
                                                                             IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                             Date: 27/11/2008




    3.5.3.3. Perl
     
    Drawback: There is no IPV6_V6ONLY symbol defined in Perl (yet).  
    In our code this socket option integer constant has been defined manually (see IPv4AndIPv6Enabling.pl), 
    according to the value obtained in the C language source files.  
     
    Drawback: Perl does not include the Socket6 library in its standard distribution.  
    You have to download it at [3]. 
    If you try to run the script on a machine which does not have this library installed, you will get this kind of error: 
     
etienne@g1:~/test_perl$ ./server_one_socket.pl 5555
Can't locate Socket6.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.8.8
/usr/local/share/perl/5.8.8 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8
/usr/local/lib/site_perl .) at IPv4_and_IPv6_enabling.pl line 7.
BEGIN failed--compilation aborted at IPv4_and_IPv6_enabling.pl line 7.
Compilation failed in require at ./server_one_socket.pl line 6.
etienne@g1:~/test_perl$

     
    Drawback: On older Perl versions, the getnameinfo() call, which is used to get the character string 
    representation of an IP address, seemed to be broken for IPv6 addresses:  
    In the sample script (line 30 of IPv4_and_IPv6_enabling.pl) it worked correctly with perl 5.8.5 but 
    returned a wrong string with perl 5.8.0). 
     
    3.5.3.4. Java


    Advantage: The sample Java code is the shortest because some important functionality is handled by the Java 
    environment itself in a transparent way. 
     
    Drawback: The parameter /proc/sys/net/ipv6/bindv6only must be set to 0 on the operating system where the 
    programs are run. 
    Otherwise: 
    ‐ A server will not accept IPv4 clients 
    ‐ A client will fail to connect to an IPv4 server (it will say “Network is unreachable”!) 
    It seems that, when bindv6only is set to 1, the Java Virtual Machine considers it is running in an IPv6‐only 
    environment (and so it disables IPv4). It seems to be a misunderstanding of the parameter bindv6only, which 
    should only affect the behavior of the bind system call (See [2]). 
     




    EGEE-III                                                    PUBLIC                                    43 / 49
                                                                                                            Doc. Identifier:

                                        Note                                                  EGEE-III-SA2-TEC-971407-
                                                                          IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                          Date: 27/11/2008




4. MAKING IPV6 EASIER TO HANDLE
The  ideas  presented  in  this  part  should  make  IPv6  programming  &  transition  easier:  it  will  show  specific 
examples which allow handling IPv6 in a more user friendly and immediate way, instead of having to use the low 
level network programming calls. 
 

    4.1. HIGH-LEVEL PROGRAMMING LANGUAGES AND NETWORKING LIBRARIES


        4.1.1. The Java case
 
If we compare the size of the IPv4_and_IPv6_enabling.java file with the corresponding C, Python and 
Perl files, we see that it is much smaller.  
In  this  file  there  is  only  one  function;  the  other  corresponding  functions  we  have  in  the 
IPv4_and_IPv6_enabling.[c|pl|py]  files  were  not  needed  in  Java  because  the  Java  environment 
provides these functionalities transparently. 
This shows that programming with a high‐level and IPv6 compliant programming language considerably reduces 
the amount of work. 
 

        4.1.2. The Python case
 
Although the sample provided was low‐level, Python also provides a set of higher level classes to be used for 
TCP server building. They are provided by a package called "SocketServer". 
An example is the ThreadingTCPServer class. 
When the developer uses this class, he must only provide a “handler” class with three methods which will 
describe what the server must do: 
‐ At client connection 
‐ When the client is connected 
‐ When the client disconnects 
The ThreadingTCPServer class itself will handle the low‐level socket‐related system calls, and create one thread 
for each client. 
 
The problem is that this class does not have an IPv6 behaviour: 
The server socket created will be IPv4 by default. It is possible to change it to IPv6 but then: 
    1) The program will fail if IPv6 is not available on the system 
    2) The socket option IPV6_V6ONLY will not be unset on the IPv6 socket 
 
One  solution  is  to  provide  a  subclass  of  ThreadingTCPServer,  called  IPv4AndIPv6ThreadingTCPServer for 
example, which solves these problems by modifying the corresponding methods.  
Then you may use this class IPv4AndIPv6ThreadingTCPServer the same way as you would use 
ThreadingTCPServer, and you will get a TCP server accepting IPv4 and IPv6 clients.  


EGEE-III                                                    PUBLIC                                     44 / 49
                                                                                                                      Doc. Identifier:

                                                Note                                                   EGEE-III-SA2-TEC-971407-
                                                                                   IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                                     Date: 27/11/2008



     This has been done in the following code “threading_server.py”. The behaviour of this sample server is similar to 
     the ones seen earlier, but this time the “forking” feature of the server is also managed: one thread is created for 
     each client, thanks to the base‐class ThreadingTCPServer. 
     More  generally  speaking,  when  you  use  high‐level  objects  in  your  code  it  is  easier  to  make  it  IPv6  compliant: 
     once you have programmed an IPv6 compliant version of these high‐level objects, you just have to replace the 
     name of the old class with the new one in your code.  
      

 1   #!/usr/bin/python
 2   ######################
 3   # file threading_server.py
 4   ######################
 5   import sys
 6   import socket
 7   from SocketServer import BaseRequestHandler
 8   from SocketServer import ThreadingTCPServer
 9   from IPv4_and_IPv6_enabling import IPV6_V6ONLY
10   from IPv4_and_IPv6_enabling import getIPString
11
12   port = sys.argv[1]
13
14   # This class represents a socket server able to accept both IPv4 and IPv6
15   # clients.
16   # All the job is done is done by the base class except the
17   # specific parameters to achieve IPv4 and IPv6 connectivity.
18   # ------------------------------------------------------------------------------------
19   class IPv4AndIPv6ThreadingTCPServer(ThreadingTCPServer):
20
21              def __init__(self, port, request_handler):
22                        # we get the first available server socket for our socket server.
23                        # if ipv6 is available on the host, the getaddrinfo call will
24                        # return an IPv6 socket first.
25                        # address_family and socket_address are recorded as data attributes
26                        # of the object.
27                        result = socket.getaddrinfo(None, port, socket.AF_UNSPEC, \
28                                                        socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
29                        self.address_family, socket_type, proto, canon_name, self.socket_address = result[0]
30
31                        # we now call the base-class constructor, which will create a server socket
32                        # with the family specified in self.address_family.
33                        ThreadingTCPServer.__init__(self, self.socket_address, request_handler)
34              # end def __init__
35
36              def server_bind(self):
37                        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
38                        if self.address_family == socket.AF_INET6:
39                                   # we must unset IPV6_V6ONLY in order to allow IPv4 clients to
40                                   # connect to the IPv6 socket
41                                   self.socket.setsockopt(socket.IPPROTO_IPV6, IPV6_V6ONLY, 0)
42                        # end if
43                        ThreadingTCPServer.server_bind(self)
44              # end def server_bind
45
46              def server_activate(self):
47                        ThreadingTCPServer.server_activate(self)
48
49                          # get the ip string, display it with the port number
50                          ip = getIPString(self.socket_address)
51                          print "Server socket now listening on ", ip, " port ", port


     EGEE-III                                                        PUBLIC                                       45 / 49
                                                                                                                Doc. Identifier:

                                             Note                                                 EGEE-III-SA2-TEC-971407-
                                                                              IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                              Date: 27/11/2008



 52              # end def server_bind
 53
 54   # end class IPv4AndIPv6ThreadingTCPServer
 55
 56
 57   # Definition of our request handler
 58   # This object handles the requests of the TCP server.
 59   # --------------------------------------------------------------------------------------
 60   class EchoRequestHandler(BaseRequestHandler):
 61             # event on client connection
 62             def setup(self):
 63                        # get file interface for line-by-line reading on socket
 64                        self.fs = self.request.makefile()
 65
 66                        # notify client connection
 67                        self.client_ip, port_number = socket.getnameinfo(self.client_address, \
 68                                             socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
 69                        print self.client_ip, 'connected!'
 70
 71                        # send "hi <ip>" to the client
 72                        self.request.send('hi ' + self.client_ip + '\n')
 73              # end def setup
 74
 75              # client connection handling
 76              def handle(self):
 77                        while True:
 78                                   # read client message
 79                                   data = self.fs.readline()
 80
 81                                  if data.strip() == 'bye':
 82                                            # if message is "bye" send "bye <ip>" and leave the dialog loop
 83                                            self.request.send('bye ' + self.client_ip + '\n')
 84                                            return
 85                                  else:
 86                                            # otherwise resend the message to the client
 87                                            self.request.send(data)
 88                                  # end if
 89                        # end while
 90              # end def handle
 91
 92             # event on client disconnection
 93             def finish(self):
 94                        # notify client disconnection
 95                        print self.client_ip, 'disconnected!'
 96             # end def finish
 97   # end class EchoRequestHandler
 98
 99   # Creation and launching of the server
100   server = IPv4AndIPv6ThreadingTCPServer(port, EchoRequestHandler)
101   server.serve_forever()

       
      Note: This code is also included for download in the archive at [1]. 
       
      If the application is more specific to a protocol, for example HTTP, you may find more adapted libraries, like 
      httplib, in order to program in a high‐level and IPv6 compliant way. (I did not personally test its IPv6 
      compliance.) 




      EGEE-III                                                    PUBLIC                                   46 / 49
                                                                                                           Doc. Identifier:

                                        Note                                                 EGEE-III-SA2-TEC-971407-
                                                                         IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                         Date: 27/11/2008




        4.1.3. The Perl case

Perl also provides higher‐level libraries. 
The most common one for IPv6 socket programming is IO::Socket::INET6. 
 
This library currently provides very interesting functionalities. 
For example, for a client, you can create a socket and try all address families for the connection to the server, all 
in one single call: 
 
$sock = IO::Socket::INET6->new(PeerAddr => 'www.perl.org',
                                                PeerPort => 'http(80)',
                                                Multihomed => 1,
                                                Proto    => 'tcp');
 
The problem with this library is that, according to the README file of the library, this kind of functionality and 
any IPv4‐related functionality will probably be removed in the future! Here is what we can read:  
WARNING: You should use this module mainly to program IPv6 
domain. Most pobably future releases will not support AF_INET | AF_UNSPEC 
options, as the module seems to fail on some given corner cases. If you require 
IPv4, you are encouraged to use IO::Socket::INET from the application 
level. Be warned. 
 
Consequently using such a library would not be possible in a mixed IPv4/IPv6 environment. 
 
 

        4.1.4. The C/C++ case


High level programming is also possible in C/C++ by using IPv6 compliant networking libraries. 
An example is the “boost::asio” library. See [4]. 
Another, if your application is restricted to one specific protocol, for example HTTP, is to use specific IPv6 
compliant libraries like libcurl. (I did not test its IPv6 compliance personally.) 
 




EGEE-III                                                   PUBLIC                                     47 / 49
                                                                                                                   Doc. Identifier:

                                              Note                                                   EGEE-III-SA2-TEC-971407-
                                                                                 IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                                 Date: 27/11/2008




          4.2. XINETD
     If the application is a standard TCP server, it is possible to design it as a xinetd service.  
     This way, xinetd will be responsible for the low level socket networking part, and in the application you will just 
     have to read/write on a file descriptor. 
     By default, xinetd opens IPv4 sockets. So you have to specify in the /etc/xinetd.d related script that your service 
     needs an IPv6 socket.  
     For example, for an installation of the xinetd‐based telnet daemon, you will set the option “flags=IPv6” in the 
     file /etc/xinetd.d/krb5‐telnet: 
      

[root@quarks root]# cat /etc/xinetd.d/krb5-telnet
# default: off
# description: The kerberized telnet server accepts normal telnet sessions, \
#                 but can also use Kerberos 5 authentication.
service telnet
{
         flags            = REUSE
         socket_type      = stream
         wait             = no
         user             = root
         server           = /usr/kerberos/sbin/telnetd
         log_on_failure += USERID
         disable          = no
         flags            = IPv6
}

      
     And it is enough to make your service IPv6 compliant. 
      
     Note: it will accept both IPv4 and IPv6 clients, which is what we want. 




     EGEE-III                                                      PUBLIC                                     48 / 49
                                                                                                                Doc. Identifier:

                                          Note                                                   EGEE-III-SA2-TEC-971407-
                                                                             IPV6_Compliance_C_Cpp_Java_Python_Perl-v1.4.doc

                                                                                                               Date: 27/11/2008




5. CONCLUSIONS
 
                                                                    C/C++     Python      Perl         Java 
Most  of  previously  written  networking  source  code  Yes                  Yes         Yes          No 
require adaptations 
The  program  is  able  to  override  the  default  IPv6  socket  Yes         Yes         Yes          No 
behaviour  (regarding  IPv4  connections)  defined  by  the 
bindv6only system parameter 
Client connections to an IPv4 server will still be possible  Yes              Yes         Yes          No 
if bindv6only system parameter is set to 1  
Additional installation of a library is usually required            No        No          Yes          No 
Note: these statements are of course subject to change due to incoming versions of the programming languages 
and libraries. 
                                                               
Consequences on the amount of work needed during a migration to IPv6:  
‐ System setting up is needed for Perl (library installation) and Java (checking of system parameter); not for 
  C/C++ and Python. 
‐ Development part with C/C++, Perl and Python will be much longer than for Java. 
The  samples  code  also  shows  that  programming  and  transition  to  an  IPv6‐compliant  and  mostly  address‐
family‐independent code is an easy process.  
For new programs, some efficient ways are:  
‐ To create a xinetd‐based service when possible 
‐ To use an high‐level IPv6 compliant networking library when using low‐level programming languages 
With these techniques you can write a high‐level code mostly address‐family agnostic. 




TABLE OF REFERENCES
[1] https://edms.cern.ch/file/971407/1/test_languages_1.2.tar.gz 
[2] Paragraph 2 of the document at https://edms.cern.ch/document/930868/1 
[3] http://search.cpan.org/dist/Socket6/ 
[4] https://edms.cern.ch/document/935729 
[5] “UNIX Network Programming”‐ W. Richard Stevens, Bill Fener, Andrew M. Rudoff 
[6] http://www.kame.net/newsletter/19980604/ 




EGEE-III                                                          PUBLIC                                  49 / 49