Aggiornamento note copyright
[gapil.git] / sources / SockUtil.c
1 /* SockUtil.c
2  * 
3  * Copyright (C) 2004 Simone Piccardi
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /***************************************************************
20  *
21  * File SockUtil.c 
22  * Routines for socket operations. 
23  *
24  * Define routines for socket handling 
25  *
26  * Author: S. Piccardi
27  *
28  ***************************************************************/
29 #include <sys/types.h>   /* primitive system data types */
30 #include <stdio.h>       /* standard I/O library */
31 #include <unistd.h>      /* unix standard library */
32 #include <string.h>      /* C strings library */
33 #include <errno.h>       /* error definitions and routines */
34 #include <sys/socket.h>  /* socket constants, types and functions */
35 #include <arpa/inet.h>   /* IP addresses conversion utilities */
36 #include <netdb.h>       /* C resolver library */
37
38 #include "macros.h"
39 /**************************************************************************
40  *
41  * Routine ip_ntop
42  *
43  * Return a string with the numeric address translation of the content
44  * of an addrinfo stucture
45  *
46  * Author: Simone Piccardi
47  * Dec. 2004
48  *
49  **************************************************************************/
50 char *ip_ntop(struct addrinfo *addr, char *dst, socklen_t cnt)
51 {
52 //    char buffer[INET6_ADDRSTRLEN];
53     char * ret;
54     struct sockaddr_in *ip4;
55     struct sockaddr_in6 *ip6;
56     switch (addr->ai_family) {
57     case PF_INET:
58         ip4 = (struct sockaddr_in *) addr->ai_addr;
59         ret = inet_ntop(ip4->sin_family, &ip4->sin_addr, dst, cnt);
60         break;
61     case PF_INET6:
62         ip6 = (struct sockaddr_in6 *) addr->ai_addr;
63         ret = inet_ntop(ip6->sin6_family, &ip6->sin6_addr, dst, cnt);
64         break;
65     default:
66         ret = NULL;
67         errno = EAFNOSUPPORT;
68     }
69     return ret;
70 }
71 /****************************************************************
72  *
73  * Routine sockconn
74  * Return a connected socket given hostname, service, and socket type
75  *
76  * Author: Simone Piccardi
77  * Dec. 2004
78  *
79  ****************************************************************/
80 int sockconn(char *host, char *serv, int prot, int type) 
81 {
82     struct addrinfo hint, *addr, *save;
83     int res;
84     int sock;
85     /* initialize hint structure */
86     memset(&hint, 0, sizeof(struct addrinfo)); 
87     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
88     hint.ai_protocol = prot;               /* protocol */
89     hint.ai_socktype = type;               /* socket type */
90     res = getaddrinfo(host, serv, &hint, &addr);    /* calling getaddrinfo */
91     if (res != 0) {                                 /* on error exit */
92         fprintf(stderr, "sockconn: resolution failed:");
93 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
94         fprintf(stderr, " %s\n", gai_strerror(res));
95         errno = 0;                         /* clear errno */
96         return -1;
97     }
98     save = addr;
99     while (addr != NULL) {                 /* loop on possible addresses */
100         /* get a socket */
101         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
102         if (sock < 0) {                    /* on error */
103             if (addr->ai_next != NULL) {   /* if other addresses */
104                 addr=addr->ai_next;        /* take next */
105                 continue;                  /* restart cycle */
106             } else {                       /* else stop */
107                 perror("sockconn: cannot create socket");
108                 return sock;
109             }
110         }
111         /* connect the socket */
112         if ( (res = connect(sock, addr->ai_addr, addr->ai_addrlen) < 0)) {
113             if (addr->ai_next != NULL) {   /* if other addresses */
114                 addr=addr->ai_next;        /* take next */
115                 close(sock);               /* close socket */
116                 continue;                  /* restart cycle */
117             } else {                       /* else stop */
118                 perror("sockconn: cannot connect");
119                 close(sock);
120                 return res;
121             }
122         } else break;                      /* ok, we are connected! */
123     }
124     freeaddrinfo(save);                    /* done, release memory */
125     return sock;
126 }
127 /****************************************************************
128  *
129  * Routine sockbind
130  * Return a binded socket given hostname, service, and socket type
131  *
132  * Author: Simone Piccardi
133  * Dec. 2004
134  *
135  ****************************************************************/
136 int sockbind(char *host, char *serv, int prot, int type) 
137 {
138     struct addrinfo hint, *addr, *save;
139     int res;
140     int sock;
141     char buf[INET6_ADDRSTRLEN];
142     /* initialize hint structure */
143     memset(&hint, 0, sizeof(struct addrinfo)); 
144     hint.ai_flags = AI_PASSIVE;            /* address for binding */
145     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
146     hint.ai_protocol = prot;               /* protocol */
147     hint.ai_socktype = type;               /* socket type */
148     res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
149     if (res != 0) {                                /* on error exit */
150         fprintf(stderr, "sockbind: resolution failed:");
151 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
152         fprintf(stderr, " %s\n", gai_strerror(res));
153         errno = 0;                         /* clear errno */
154         return -1;
155     }
156     save = addr;                           /* saving for freeaddrinfo */
157     while (addr != NULL) {                 /* loop on possible addresses */
158         /* get a socket */
159         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
160         if (sock < 0) {                    /* on error */
161             if (addr->ai_next != NULL) {   /* if other addresses */
162                 addr=addr->ai_next;        /* take next */
163                 continue;                  /* restart cycle */
164             } else {                       /* else stop */
165                 perror("sockbind: cannot create socket");
166                 return sock;
167             }
168         }
169         /* connect the socket */
170         printf("Indirizzo %s\n", ip_ntop(addr, buf, sizeof(buf)));
171         if ( (res = bind(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
172             if (addr->ai_next != NULL) {   /* if other addresses */
173                 addr=addr->ai_next;        /* take next */
174                 close(sock);               /* close socket */
175                 continue;                  /* restart cycle */
176             } else {                       /* else stop */
177                 perror("sockbind: cannot connect");
178                 close(sock);
179                 return res;
180             }
181         } else break;                      /* ok, we are binded! */
182     }
183     freeaddrinfo(save);                    /* done, release memory */
184     return sock;
185 }
186 /****************************************************************
187  *
188  * Routine sockbindopt
189  * Return a binded socket given hostname, service, and socket type
190  * Issue a SO_REUSEADDR on the socket before binding on reuse value.
191  *
192  * Author: Simone Piccardi
193  * Mar. 2005
194  *
195  ****************************************************************/
196 int sockbindopt(char *host, char *serv, int prot, int type, int reuse) 
197 {
198     struct addrinfo hint, *addr, *save;
199     int res;
200     int sock;
201     char buf[INET6_ADDRSTRLEN];
202     /* initialize hint structure */
203     memset(&hint, 0, sizeof(struct addrinfo)); 
204     hint.ai_flags = AI_PASSIVE;            /* address for binding */
205     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
206     hint.ai_protocol = prot;               /* protocol */
207     hint.ai_socktype = type;               /* socket type */
208     res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
209     if (res != 0) {                                /* on error exit */
210         fprintf(stderr, "sockbind: resolution failed:");
211 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
212         fprintf(stderr, " %s\n", gai_strerror(res));
213         errno = 0;                         /* clear errno */
214         return -1;
215     }
216     save = addr;                           /* saving for freeaddrinfo */
217     while (addr != NULL) {                 /* loop on possible addresses */
218         /* get a socket */
219         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
220         if (sock < 0) {                    /* on error */
221             if (addr->ai_next != NULL) {   /* if other addresses */
222                 addr=addr->ai_next;        /* take next */
223                 continue;                  /* restart cycle */
224             } else {                       /* else stop */
225                 perror("sockbind: cannot create socket");
226                 return sock;
227             }
228         }
229         /* connect the socket */
230         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
231                        &reuse, sizeof(reuse))) {
232             printf("error on socket options\n");
233             return -1;
234         }
235         printf("Indirizzo %s\n", ip_ntop(addr, buf, sizeof(buf)));
236         if ( (res = bind(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
237             if (addr->ai_next != NULL) {   /* if other addresses */
238                 addr=addr->ai_next;        /* take next */
239                 close(sock);               /* close socket */
240                 continue;                  /* restart cycle */
241             } else {                       /* else stop */
242                 perror("sockbind: cannot connect");
243                 close(sock);
244                 return res;
245             }
246         } else break;                      /* ok, we are binded! */
247     }
248     freeaddrinfo(save);                    /* done, release memory */
249     return sock;
250 }