TCP Socket - C Language
|
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