TCP Socket - C Language
commv6.c
Vai alla documentazione di questo file.
00001 
00010 #include "comm.h"
00011 
00012 /*
00013  * TODO Permettere di identificare su quale interfaccia rimanere in ascolto\n
00014  * TODO Convertire read e write con (send/sendto) e (recv/recvfrom)\n
00015  * TODO Leggere davvero tutte le parti del messaggio */
00016 
00017 comm * newServerChannel(const char *service){
00018         struct addrinfo hints, *addrInfo=NULL, *ai=NULL;
00019         comm *srvComm = NULL;
00020         int err = 0, v6Only = 1, count = 0, i = 0;
00021         
00022         if (!service){
00023                 errno = EINVAL;
00024                 gen_err(__FILE__,__LINE__,
00025                         "Server: newServerChannel 'service' nullo.\n");
00026                 return NULL;
00027         }
00028 
00029         memset(&hints, 0, sizeof(hints));
00030         hints.ai_family   = AF_UNSPEC;          /* Sia ipv4 che ipv6 */
00031         hints.ai_socktype = SOCK_STREAM;
00032         hints.ai_protocol = IPPROTO_TCP;
00033         hints.ai_flags    = AI_PASSIVE;
00034 
00035         if ((err = getaddrinfo(NULL, service, &hints, &addrInfo)) != 0){
00036                 gen_err(__FILE__,__LINE__,
00037                         "Server: newServerChannel getaddrinfo: %s\n",gai_strerror(err));
00038                 return NULL;
00039         }
00040 
00041         for (ai=addrInfo; ai; ai = ai->ai_next) count++;
00042 
00043         /* Inzializzazione dei parametri di ritorno. */
00044         if (!(srvComm = malloc(sizeof(comm)))){
00045                 sys_err(__FILE__,__LINE__,"Server: newServerChannel malloc: ");
00046                 freeaddrinfo(addrInfo);
00047                 return NULL;
00048         }
00049 
00050         srvComm->skDim = count;
00051 
00052         if (!(srvComm->sk = calloc(count, sizeof(struct pollfd)))){
00053                 sys_err(__FILE__,__LINE__,"Server: newServerChannel calloc: ");
00054                 free (srvComm);
00055                 freeaddrinfo(addrInfo);
00056                 return NULL;
00057         }
00058 
00059         /* Inizializziamo le sockets */
00060         for (ai=addrInfo, i=0; ai; ai = ai->ai_next, i++){
00061                 srvComm->sk[i].fd = INVALID_DESC;
00062                 srvComm->sk[i].events = POLLIN;
00063                 srvComm->sk[i].revents = 0;
00064         
00065                 /* Creo il socket usando le informazioni della struttura addrinfo */
00066                 if ((srvComm->sk[i].fd =
00067                                 socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
00068                         sys_err(__FILE__,__LINE__,
00069                                 "Server: newServerChannel socket create: ");
00070                         free (srvComm->sk); free (srvComm);
00071                         freeaddrinfo(addrInfo);
00072                         return NULL;
00073                 }
00074 
00075                 /* Here is the code that prevents "IPv4 mapped addresses",
00076                  * as discussed in Section 22.1.3.1.
00077                  * @see http://tldp.org/HOWTO/Linux+IPv6-HOWTO/chapter-section-using-api.html
00078                  * If an IPv6 socket was just created, then set the IPV6_V6ONLY
00079                  * socket option.
00080                  * (IPV6_V6ONLY @see /usr/include/... ../bits/in.h) */
00081                 if (ai->ai_family == PF_INET6){
00082 #if defined(IPV6_V6ONLY)
00083                         /* Disable IPv4 mapped addresses. */
00084                         if((setsockopt(srvComm->sk[i].fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6Only, sizeof(v6Only))) == -1){
00085                                 sys_err(__FILE__,__LINE__,
00086                                         "Server: newServerChannel socket create: ");
00087                                 free (srvComm->sk); free (srvComm);
00088                                 freeaddrinfo(addrInfo);
00089                         return NULL;
00090                         }
00091 #else
00092                         /* If IPV6_V6ONLY is not defined, then the socket option can't
00093                          * be set and thus IPv4 mapped addresses can't be disabled. */
00094                         gen_err(__FILE__,__LINE__,
00095                                 "Server: newServerChannel Cannot set IPV6_V6ONLY socket option. Closing IPv6 TCP socket.\n");
00096                         if (close(srvComm->sk->fd[i])) {
00097                                 sys_err(__FILE__,__LINE__,
00098                                         "Server: newServerChannel socket close: ");
00099                         }
00100                         continue;
00101 #endif
00102                 }
00103                 /* Rendiamo il socket visibile nel dominio */
00104                 if (bind(srvComm->sk[i].fd, ai->ai_addr, ai->ai_addrlen) < 0) {
00105                         sys_err(__FILE__,__LINE__,
00106                                 "Server: newServerChannel socket bind: ");
00107                         free (srvComm->sk); free (srvComm);
00108                         freeaddrinfo(addrInfo);
00109                         return NULL;
00110                 }
00111 
00112                 /* Mettiamo il socket in attesa di connessioni */
00113                 if (listen(srvComm->sk[i].fd, MAXCONN) < 0) {
00114                         sys_err(__FILE__,__LINE__,
00115                                 "Server: newServerChannel socket listen: ");
00116                         close(srvComm->sk[i].fd);
00117                         free (srvComm->sk); free (srvComm);
00118                         freeaddrinfo(addrInfo);
00119                         return NULL;
00120                 }
00121         }
00122 
00123         if (ai){
00124                 gen_err(__FILE__,__LINE__,
00125                         "Server: Some address records were not processed due to insufficient array space.\n");
00126         }
00127         freeaddrinfo(addrInfo);
00128         return srvComm;
00129 }
00130 
00131 int acceptConnection(comm * srvComm){
00132         struct sockaddr_in6 cli_addr; /* socket del client */
00133         int status=0, i=0;
00134         /* Salva la dimensione dell'indirizzo del client.
00135          * This is needed for the accept system call.
00136          * Valgrind suggerisce di inizializzare il valore. */
00137         socklen_t clilen = 0;
00138         int cli_sk = -1;
00139 
00140         if (!srvComm){
00141                 errno = EINVAL;
00142                 gen_err(__FILE__,__LINE__,
00143                         "Server: acceptConnection 'srvComm' nullo\n");
00144                 return -1;
00145         }
00146 
00147         /* Wait indefinitely for input. */
00148         if ((status = poll(srvComm->sk, srvComm->skDim, -1)) == -1){
00149                 sys_err(__FILE__,__LINE__,"Server: acceptConnection poll: ");
00150                 return -1;
00151         }
00152 
00153         for (i=0; i<srvComm->skDim; i++){
00154                 switch (srvComm->sk[i].revents){
00155                         case 0:                 /* Nessuna attivita' su questa socket; proviamo la successiva. */
00156                         continue;
00157                         case POLLIN:    /* Attivita' di rete.  Go process it. */
00158                                 if ((cli_sk = accept(srvComm->sk[i].fd, (struct sockaddr *) &cli_addr, &clilen)) == -1){
00159                                         sys_err(__FILE__,__LINE__,
00160                                                 "Server: acceptConnection accept: ");
00161                                         return -1;
00162                                 }
00163                                 return cli_sk;
00164                         break;
00165                         default:
00166                                 gen_err(__FILE__,__LINE__,
00167                                         "Server: acceptConnection Invalid poll event: %d.\n",
00168                                         srvComm->sk[i].revents);
00169                                 return -1;
00170                 }
00171         }
00172         return -1;
00173 }
00174 
00175 int closeServerSocket(comm * srvComm){
00176         int i = 0;
00177 
00178         if (!srvComm){
00179                 errno = EINVAL;
00180                 sys_err(__FILE__,__LINE__,
00181                         "Server: closeServerSocket 'srvComm' nullo: ");
00182                 return -1;
00183         }
00184 
00185         for (i=0; i<srvComm->skDim; i++){
00186                 if (close(srvComm->sk[i].fd)){
00187                         sys_err(__FILE__,__LINE__,"Server: socket close: ");
00188                         return -1;
00189                 }
00190         }
00191         free (srvComm->sk);
00192         free (srvComm);
00193         srvComm = NULL;
00194         return 0;
00195 }
00196 
00197 int sendMessage(int sc, message_t *msg){
00198         int char_sent=0, sent=0;
00199 
00200         if (!msg){
00201                 errno = EINVAL;
00202                 sys_err(__FILE__,__LINE__,"Error send message 'msg' nullo: ");
00203                 return -1;
00204         }
00205 
00206         if ((sent = write(sc, &(msg->type), sizeof(char))) == -1) {
00207                 sys_err(__FILE__,__LINE__,"Error send message 'type': ");
00208                 return -1;
00209         }
00210         char_sent = sent;
00211 
00212         if ((sent = write(sc, &(msg->length), sizeof(unsigned int))) == -1) {
00213                 sys_err(__FILE__,__LINE__,"Error send message 'length': ");
00214                 return -1;
00215         }
00216         char_sent += sent;
00217 
00218         if (msg->length!=0) {
00219                 if ((sent = write(sc, msg->buffer, msg->length)) == -1) {
00220                         sys_err(__FILE__,__LINE__,"Error send message 'buffer': ");
00221                         return -1;
00222                 }
00223                 char_sent += sent;
00224         }
00225 
00226         return char_sent;
00227 }
00228 
00229 int receiveMessage(int sc, message_t *msg){
00230         int ricevuti=0, tmp_cnt=0, read_cnt=0;
00231         char * buffer = NULL;
00232 #ifdef _DEBUG_MODE
00233         int cycle_count=0;
00234 #endif
00235 
00236         /* Se la struttura del messaggio non e' allocata.. */
00237         if (!msg && !(msg = calloc(1, sizeof(message_t)))){
00238                 sys_err(__FILE__,__LINE__,"Error calloc 'msg': ");
00239                 return -1;
00240         }
00241 
00242         /* Leggo il tipo del messaggio */
00243         if ((ricevuti = read(sc, &(msg->type), sizeof(char))) < 1) {
00244                 if (ricevuti==0) return SEOF;
00245                 sys_err(__FILE__,__LINE__,"Error read message 'type': ");
00246                 return -1;
00247         }
00248         read_cnt = ricevuti;
00249 
00250         /* Leggo la dimensione del messaggio */
00251         if ((ricevuti = read(sc, &(msg->length), sizeof(unsigned int))) < 1){
00252                 if (ricevuti==0) return SEOF;
00253                 sys_err(__FILE__,__LINE__,"Error read message 'length': ");
00254                 return -1;
00255         }
00256         read_cnt += ricevuti;
00257 
00258         /* Leggo il messaggio reale */
00259         if (msg->length!=0) {
00260                 if (!(buffer = calloc(msg->length+1, sizeof(char)))) {
00261                         sys_err(__FILE__,__LINE__,"Error calloc 'buffer': ");
00262                         return -1;
00263                 }
00264                 if (!(msg->buffer = calloc(msg->length+1, sizeof(char)))) {
00265                         sys_err(__FILE__,__LINE__,"Error calloc 'msg->buffer': ");
00266                         free (buffer);
00267                         return -1;
00268                 }
00269                 while(tmp_cnt < msg->length) {
00270                         if ((ricevuti = read(sc, buffer, msg->length-tmp_cnt)) < 1){
00271                                 free (buffer); free (msg->buffer); msg->buffer = NULL;
00272                                 if (ricevuti==0) return SEOF;
00273                                 sys_err(__FILE__,__LINE__,"Error read message 'buffer': ");
00274                                 return -1;
00275                         }
00276                         tmp_cnt += ricevuti;
00277                         /* Pelagatti docet: usare sempre le fuonzioni con la 'n' */
00278                         if (ricevuti > 0) strncat (msg->buffer, buffer, ricevuti);
00279 #ifdef _DEBUG_MODE
00280                         fprintf(stderr,
00281                                 "Esecuzioni della read = %i, ric = %i, ricTot = %i\n",
00282                                         ++cycle_count, ricevuti, tmp_cnt);
00283 #endif
00284                 }
00285                 free (buffer);
00286                 read_cnt += tmp_cnt;
00287         }
00288         return read_cnt;
00289 }
00290 
00291 int closeConnection(int sc){
00292         if (close(sc)){
00293                 sys_err(__FILE__,__LINE__,"client: socket close: ");
00294                 return -1;
00295         }
00296         return 0;
00297 }
00298 
00299 int retryConnection(const char* hostname, const char * portno){
00300         int sk = -1, err = 0;
00301         struct addrinfo addrinfo, *res = NULL, *r = NULL;
00302         
00303         if (!hostname){
00304                 errno = EINVAL;
00305                 gen_err(__FILE__,__LINE__,
00306                         "Server: retryConnection 'hostname' nullo.\n");
00307                 return -1;
00308         }
00309         if (!portno){
00310                 errno = EINVAL;
00311                 gen_err(__FILE__,__LINE__,
00312                         "Server: retryConnection 'portno' nullo.\n");
00313                 return -1;
00314         }
00315         
00316         memset(&addrinfo, 0, sizeof(addrinfo));
00317         addrinfo.ai_flags = 0;
00318         addrinfo.ai_family = AF_UNSPEC;                 /* sia ipv4 che ipv6 */
00319         addrinfo.ai_socktype = SOCK_STREAM;
00320         addrinfo.ai_protocol = IPPROTO_TCP;             /* tcp */
00321         
00322         if ((err = getaddrinfo(hostname, portno, &addrinfo, &res)) != 0) {
00323                 gen_err(__FILE__,__LINE__,
00324                         "Client: getaddrinfo: %s\n",gai_strerror(err));
00325                 return -1;
00326         }
00327 
00328         /* getaddrinfo() returns a list of address structures.
00329          * Try each address until we successfully connect(2).
00330          * If socket(2) (or connect(2)) fails, we (close the socket and)
00331          * try the next address. */
00332         for (r = res; r; r = r->ai_next) {
00333                 if ((sk = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0){
00334                         sys_err(__FILE__,__LINE__,"Client: socket create: ");
00335                         continue;
00336                 }               
00337                 if (connect(sk, r->ai_addr, r->ai_addrlen) == 0) {
00338                         freeaddrinfo(res);
00339                         return sk;
00340                 }
00341                 sys_err(__FILE__,__LINE__-3,"Client: failed attempt to connected: ");
00342                 close(sk);
00343         }       
00344         sys_err(__FILE__,__LINE__-6,"Client: failed to connect: ");
00345         freeaddrinfo(res);
00346         return -1;
00347 }
00348