TCP Socket - C Language
|
#include "comm.h"
Vai al codice sorgente di questo file.
Funzioni | |
comm * | newServerChannel (const char *service) |
int | acceptConnection (comm *srvComm) |
int | closeServerSocket (comm *srvComm) |
int | sendMessage (int sc, message_t *msg) |
int | receiveMessage (int sc, message_t *msg) |
int | closeConnection (int sc) |
int | retryConnection (const char *hostname, const char *portno) |
This program is free software; you can redistribuite it and/or modify it under the terms of the GNU/General Pubblic License as published the Free software Foundation; either version 2 of the License, or (at your opinion) any later version.
Definizione nel file commv6.c.
comm* newServerChannel | ( | const char * | service | ) |
Crea le sockets di ascolto. Open passive (server) sockets for the indicated inet service & protocol. Notice in the last sentence that "sockets" is plural. During the interim transition period while everyone is switching over to IPv6, the server application has to open two sockets on which to listen for connections... one for IPv4 traffic and one for IPv6 traffic.
service | Pointer to a character string representing the well-known port on which to listen (can be a service name or a decimal number). |
Definizione alla linea 17 del file commv6.c.
{ struct addrinfo hints, *addrInfo=NULL, *ai=NULL; comm *srvComm = NULL; int err = 0, v6Only = 1, count = 0, i = 0; if (!service){ errno = EINVAL; gen_err(__FILE__,__LINE__, "Server: newServerChannel 'service' nullo.\n"); return NULL; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Sia ipv4 che ipv6 */ hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; if ((err = getaddrinfo(NULL, service, &hints, &addrInfo)) != 0){ gen_err(__FILE__,__LINE__, "Server: newServerChannel getaddrinfo: %s\n",gai_strerror(err)); return NULL; } for (ai=addrInfo; ai; ai = ai->ai_next) count++; /* Inzializzazione dei parametri di ritorno. */ if (!(srvComm = malloc(sizeof(comm)))){ sys_err(__FILE__,__LINE__,"Server: newServerChannel malloc: "); freeaddrinfo(addrInfo); return NULL; } srvComm->skDim = count; if (!(srvComm->sk = calloc(count, sizeof(struct pollfd)))){ sys_err(__FILE__,__LINE__,"Server: newServerChannel calloc: "); free (srvComm); freeaddrinfo(addrInfo); return NULL; } /* Inizializziamo le sockets */ for (ai=addrInfo, i=0; ai; ai = ai->ai_next, i++){ srvComm->sk[i].fd = INVALID_DESC; srvComm->sk[i].events = POLLIN; srvComm->sk[i].revents = 0; /* Creo il socket usando le informazioni della struttura addrinfo */ if ((srvComm->sk[i].fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) { sys_err(__FILE__,__LINE__, "Server: newServerChannel socket create: "); free (srvComm->sk); free (srvComm); freeaddrinfo(addrInfo); return NULL; } /* Here is the code that prevents "IPv4 mapped addresses", * as discussed in Section 22.1.3.1. * @see http://tldp.org/HOWTO/Linux+IPv6-HOWTO/chapter-section-using-api.html * If an IPv6 socket was just created, then set the IPV6_V6ONLY * socket option. * (IPV6_V6ONLY @see /usr/include/... ../bits/in.h) */ if (ai->ai_family == PF_INET6){ #if defined(IPV6_V6ONLY) /* Disable IPv4 mapped addresses. */ if((setsockopt(srvComm->sk[i].fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6Only, sizeof(v6Only))) == -1){ sys_err(__FILE__,__LINE__, "Server: newServerChannel socket create: "); free (srvComm->sk); free (srvComm); freeaddrinfo(addrInfo); return NULL; } #else /* If IPV6_V6ONLY is not defined, then the socket option can't * be set and thus IPv4 mapped addresses can't be disabled. */ gen_err(__FILE__,__LINE__, "Server: newServerChannel Cannot set IPV6_V6ONLY socket option. Closing IPv6 TCP socket.\n"); if (close(srvComm->sk->fd[i])) { sys_err(__FILE__,__LINE__, "Server: newServerChannel socket close: "); } continue; #endif } /* Rendiamo il socket visibile nel dominio */ if (bind(srvComm->sk[i].fd, ai->ai_addr, ai->ai_addrlen) < 0) { sys_err(__FILE__,__LINE__, "Server: newServerChannel socket bind: "); free (srvComm->sk); free (srvComm); freeaddrinfo(addrInfo); return NULL; } /* Mettiamo il socket in attesa di connessioni */ if (listen(srvComm->sk[i].fd, MAXCONN) < 0) { sys_err(__FILE__,__LINE__, "Server: newServerChannel socket listen: "); close(srvComm->sk[i].fd); free (srvComm->sk); free (srvComm); freeaddrinfo(addrInfo); return NULL; } } if (ai){ gen_err(__FILE__,__LINE__, "Server: Some address records were not processed due to insufficient array space.\n"); } freeaddrinfo(addrInfo); return srvComm; }
int acceptConnection | ( | comm * | srvComm | ) |
Accetta una connessione da parte di un client
srvComm | Struttura delle sockets di ascolto del server |
Definizione alla linea 131 del file commv6.c.
{ struct sockaddr_in6 cli_addr; /* socket del client */ int status=0, i=0; /* Salva la dimensione dell'indirizzo del client. * This is needed for the accept system call. * Valgrind suggerisce di inizializzare il valore. */ socklen_t clilen = 0; int cli_sk = -1; if (!srvComm){ errno = EINVAL; gen_err(__FILE__,__LINE__, "Server: acceptConnection 'srvComm' nullo\n"); return -1; } /* Wait indefinitely for input. */ if ((status = poll(srvComm->sk, srvComm->skDim, -1)) == -1){ sys_err(__FILE__,__LINE__,"Server: acceptConnection poll: "); return -1; } for (i=0; i<srvComm->skDim; i++){ switch (srvComm->sk[i].revents){ case 0: /* Nessuna attivita' su questa socket; proviamo la successiva. */ continue; case POLLIN: /* Attivita' di rete. Go process it. */ if ((cli_sk = accept(srvComm->sk[i].fd, (struct sockaddr *) &cli_addr, &clilen)) == -1){ sys_err(__FILE__,__LINE__, "Server: acceptConnection accept: "); return -1; } return cli_sk; break; default: gen_err(__FILE__,__LINE__, "Server: acceptConnection Invalid poll event: %d.\n", srvComm->sk[i].revents); return -1; } } return -1; }
int closeServerSocket | ( | comm * | srvComm | ) |
Distrugge le sockets di ascolto del server
srvComm | Struttura delle sockets del server da distruggere |
Definizione alla linea 175 del file commv6.c.
{ int i = 0; if (!srvComm){ errno = EINVAL; sys_err(__FILE__,__LINE__, "Server: closeServerSocket 'srvComm' nullo: "); return -1; } for (i=0; i<srvComm->skDim; i++){ if (close(srvComm->sk[i].fd)){ sys_err(__FILE__,__LINE__,"Server: socket close: "); return -1; } } free (srvComm->sk); free (srvComm); srvComm = NULL; return 0; }
int sendMessage | ( | int | sc, |
message_t * | msg | ||
) |
Scrive un messaggio sul canale di trasmissione
sc | channel di trasmissione |
msg | struttura che contiene il messaggio da scrivere |
Definizione alla linea 197 del file commv6.c.
{ int char_sent=0, sent=0; if (!msg){ errno = EINVAL; sys_err(__FILE__,__LINE__,"Error send message 'msg' nullo: "); return -1; } if ((sent = write(sc, &(msg->type), sizeof(char))) == -1) { sys_err(__FILE__,__LINE__,"Error send message 'type': "); return -1; } char_sent = sent; if ((sent = write(sc, &(msg->length), sizeof(unsigned int))) == -1) { sys_err(__FILE__,__LINE__,"Error send message 'length': "); return -1; } char_sent += sent; if (msg->length!=0) { if ((sent = write(sc, msg->buffer, msg->length)) == -1) { sys_err(__FILE__,__LINE__,"Error send message 'buffer': "); return -1; } char_sent += sent; } return char_sent; }
int receiveMessage | ( | int | sc, |
message_t * | msg | ||
) |
Legge un messaggio dal canale di trasmissione
sc | channel di trasmissione |
msg | struttura che conterra' il messagio letto (deve essere allocata all'esterno della funzione, tranne il campo buffer) |
Definizione alla linea 229 del file commv6.c.
{ int ricevuti=0, tmp_cnt=0, read_cnt=0; char * buffer = NULL; #ifdef _DEBUG_MODE int cycle_count=0; #endif /* Se la struttura del messaggio non e' allocata.. */ if (!msg && !(msg = calloc(1, sizeof(message_t)))){ sys_err(__FILE__,__LINE__,"Error calloc 'msg': "); return -1; } /* Leggo il tipo del messaggio */ if ((ricevuti = read(sc, &(msg->type), sizeof(char))) < 1) { if (ricevuti==0) return SEOF; sys_err(__FILE__,__LINE__,"Error read message 'type': "); return -1; } read_cnt = ricevuti; /* Leggo la dimensione del messaggio */ if ((ricevuti = read(sc, &(msg->length), sizeof(unsigned int))) < 1){ if (ricevuti==0) return SEOF; sys_err(__FILE__,__LINE__,"Error read message 'length': "); return -1; } read_cnt += ricevuti; /* Leggo il messaggio reale */ if (msg->length!=0) { if (!(buffer = calloc(msg->length+1, sizeof(char)))) { sys_err(__FILE__,__LINE__,"Error calloc 'buffer': "); return -1; } if (!(msg->buffer = calloc(msg->length+1, sizeof(char)))) { sys_err(__FILE__,__LINE__,"Error calloc 'msg->buffer': "); free (buffer); return -1; } while(tmp_cnt < msg->length) { if ((ricevuti = read(sc, buffer, msg->length-tmp_cnt)) < 1){ free (buffer); free (msg->buffer); msg->buffer = NULL; if (ricevuti==0) return SEOF; sys_err(__FILE__,__LINE__,"Error read message 'buffer': "); return -1; } tmp_cnt += ricevuti; /* Pelagatti docet: usare sempre le fuonzioni con la 'n' */ if (ricevuti > 0) strncat (msg->buffer, buffer, ricevuti); #ifdef _DEBUG_MODE fprintf(stderr, "Esecuzioni della read = %i, ric = %i, ricTot = %i\n", ++cycle_count, ricevuti, tmp_cnt); #endif } free (buffer); read_cnt += tmp_cnt; } return read_cnt; }
int closeConnection | ( | int | sc | ) |
int retryConnection | ( | const char * | hostname, |
const char * | service | ||
) |
Crea una socket di trasmissione verso il server, tentando la connessione per un massimo di due minuti se MAXSLEEP e' 128
hostname | Indirizzo del server |
service | Nome del servizio (noto) o numero di porta del server |
Definizione alla linea 299 del file commv6.c.
{ int sk = -1, err = 0; struct addrinfo addrinfo, *res = NULL, *r = NULL; if (!hostname){ errno = EINVAL; gen_err(__FILE__,__LINE__, "Server: retryConnection 'hostname' nullo.\n"); return -1; } if (!portno){ errno = EINVAL; gen_err(__FILE__,__LINE__, "Server: retryConnection 'portno' nullo.\n"); return -1; } memset(&addrinfo, 0, sizeof(addrinfo)); addrinfo.ai_flags = 0; addrinfo.ai_family = AF_UNSPEC; /* sia ipv4 che ipv6 */ addrinfo.ai_socktype = SOCK_STREAM; addrinfo.ai_protocol = IPPROTO_TCP; /* tcp */ if ((err = getaddrinfo(hostname, portno, &addrinfo, &res)) != 0) { gen_err(__FILE__,__LINE__, "Client: getaddrinfo: %s\n",gai_strerror(err)); return -1; } /* getaddrinfo() returns a list of address structures. * Try each address until we successfully connect(2). * If socket(2) (or connect(2)) fails, we (close the socket and) * try the next address. */ for (r = res; r; r = r->ai_next) { if ((sk = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0){ sys_err(__FILE__,__LINE__,"Client: socket create: "); continue; } if (connect(sk, r->ai_addr, r->ai_addrlen) == 0) { freeaddrinfo(res); return sk; } sys_err(__FILE__,__LINE__-3,"Client: failed attempt to connected: "); close(sk); } sys_err(__FILE__,__LINE__-6,"Client: failed to connect: "); freeaddrinfo(res); return -1; }