Un po' di materiale su {{{splice}}} e inizio della ripulitura degli
[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>
36 #include <netinet/in.h>
37 #include <netdb.h>
38
39 #include "macros.h"
40 /**************************************************************************
41  *
42  * Routine ip_ntop
43  *
44  * Return a string with the numeric address translation of the content
45  * of an addrinfo stucture
46  *
47  * Author: Simone Piccardi
48  * Dec. 2004
49  *
50  **************************************************************************/
51 char *ip_ntop(struct addrinfo *addr, char *dst, socklen_t cnt)
52 {
53 //    char buffer[INET6_ADDRSTRLEN];
54     char * ret;
55     struct sockaddr_in *ip4;
56     struct sockaddr_in6 *ip6;
57     switch (addr->ai_family) {
58     case PF_INET:
59         ip4 = (struct sockaddr_in *) addr->ai_addr;
60         ret = inet_ntop(ip4->sin_family, &ip4->sin_addr, dst, cnt);
61         break;
62     case PF_INET6:
63         ip6 = (struct sockaddr_in6 *) addr->ai_addr;
64         ret = inet_ntop(ip6->sin6_family, &ip6->sin6_addr, dst, cnt);
65         break;
66     default:
67         ret = NULL;
68         errno = EAFNOSUPPORT;
69     }
70     return ret;
71 }
72 /****************************************************************
73  *
74  * Routine sockconn
75  * Return a connected socket given hostname, service, and socket type
76  *
77  * Author: Simone Piccardi
78  * Dec. 2004
79  *
80  ****************************************************************/
81 int sockconn(char *host, char *serv, int prot, int type) 
82 {
83     struct addrinfo hint, *addr, *save;
84     int res;
85     int sock;
86     /* initialize hint structure */
87     memset(&hint, 0, sizeof(struct addrinfo)); 
88     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
89     hint.ai_protocol = prot;               /* protocol */
90     hint.ai_socktype = type;               /* socket type */
91     res = getaddrinfo(host, serv, &hint, &addr);    /* calling getaddrinfo */
92     if (res != 0) {                                 /* on error exit */
93         fprintf(stderr, "sockconn: resolution failed:");
94 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
95         fprintf(stderr, " %s\n", gai_strerror(res));
96         errno = 0;                         /* clear errno */
97         return -1;
98     }
99     save = addr;
100     while (addr != NULL) {                 /* loop on possible addresses */
101         /* get a socket */
102         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
103         if (sock < 0) {                    /* on error */
104             if (addr->ai_next != NULL) {   /* if other addresses */
105                 addr=addr->ai_next;        /* take next */
106                 continue;                  /* restart cycle */
107             } else {                       /* else stop */
108                 perror("sockconn: cannot create socket");
109                 return sock;
110             }
111         }
112         /* connect the socket */
113         if ( (res = connect(sock, addr->ai_addr, addr->ai_addrlen) < 0)) {
114             if (addr->ai_next != NULL) {   /* if other addresses */
115                 addr=addr->ai_next;        /* take next */
116                 close(sock);               /* close socket */
117                 continue;                  /* restart cycle */
118             } else {                       /* else stop */
119                 perror("sockconn: cannot connect");
120                 close(sock);
121                 return res;
122             }
123         } else break;                      /* ok, we are connected! */
124     }
125     freeaddrinfo(save);                    /* done, release memory */
126     return sock;
127 }
128 /****************************************************************
129  *
130  * Routine sockbind
131  * Return a binded socket given hostname, service, and socket type
132  *
133  * Author: Simone Piccardi
134  * Dec. 2004
135  *
136  ****************************************************************/
137 int sockbind(char *host, char *serv, int prot, int type) 
138 {
139     struct addrinfo hint, *addr, *save;
140     int res;
141     int sock;
142     char buf[INET6_ADDRSTRLEN];
143     /* initialize hint structure */
144     memset(&hint, 0, sizeof(struct addrinfo)); 
145     hint.ai_flags = AI_PASSIVE;            /* address for binding */
146     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
147     hint.ai_protocol = prot;               /* protocol */
148     hint.ai_socktype = type;               /* socket type */
149     res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
150     if (res != 0) {                                /* on error exit */
151         fprintf(stderr, "sockbind: resolution failed:");
152 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
153         fprintf(stderr, " %s\n", gai_strerror(res));
154         errno = 0;                         /* clear errno */
155         return -1;
156     }
157     save = addr;                           /* saving for freeaddrinfo */
158     while (addr != NULL) {                 /* loop on possible addresses */
159         /* get a socket */
160         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
161         if (sock < 0) {                    /* on error */
162             if (addr->ai_next != NULL) {   /* if other addresses */
163                 addr=addr->ai_next;        /* take next */
164                 continue;                  /* restart cycle */
165             } else {                       /* else stop */
166                 perror("sockbind: cannot create socket");
167                 return sock;
168             }
169         }
170         /* connect the socket */
171         printf("Indirizzo %s\n", ip_ntop(addr, buf, sizeof(buf)));
172         if ( (res = bind(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
173             if (addr->ai_next != NULL) {   /* if other addresses */
174                 addr=addr->ai_next;        /* take next */
175                 close(sock);               /* close socket */
176                 continue;                  /* restart cycle */
177             } else {                       /* else stop */
178                 perror("sockbind: cannot connect");
179                 close(sock);
180                 return res;
181             }
182         } else break;                      /* ok, we are binded! */
183     }
184     freeaddrinfo(save);                    /* done, release memory */
185     return sock;
186 }
187 /****************************************************************
188  *
189  * Routine sockbindopt
190  * Return a binded socket given hostname, service, and socket type
191  * Issue a SO_REUSEADDR on the socket before binding on reuse value.
192  *
193  * Author: Simone Piccardi
194  * Mar. 2005
195  *
196  ****************************************************************/
197 int sockbindopt(char *host, char *serv, int prot, int type, int reuse) 
198 {
199     struct addrinfo hint, *addr, *save;
200     int res;
201     int sock;
202     char buf[INET6_ADDRSTRLEN];
203     /* initialize hint structure */
204     memset(&hint, 0, sizeof(struct addrinfo)); 
205     hint.ai_flags = AI_PASSIVE;            /* address for binding */
206     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
207     hint.ai_protocol = prot;               /* protocol */
208     hint.ai_socktype = type;               /* socket type */
209     res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
210     if (res != 0) {                                /* on error exit */
211         fprintf(stderr, "sockbind: resolution failed:");
212 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
213         fprintf(stderr, " %s\n", gai_strerror(res));
214         errno = 0;                         /* clear errno */
215         return -1;
216     }
217     save = addr;                           /* saving for freeaddrinfo */
218     while (addr != NULL) {                 /* loop on possible addresses */
219         /* get a socket */
220         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
221         if (sock < 0) {                    /* on error */
222             if (addr->ai_next != NULL) {   /* if other addresses */
223                 addr=addr->ai_next;        /* take next */
224                 continue;                  /* restart cycle */
225             } else {                       /* else stop */
226                 perror("sockbind: cannot create socket");
227                 return sock;
228             }
229         }
230         /* connect the socket */
231         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
232                        &reuse, sizeof(reuse))) {
233             printf("error on socket options\n");
234             return -1;
235         }
236         printf("Indirizzo %s\n", ip_ntop(addr, buf, sizeof(buf)));
237         if ( (res = bind(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
238             if (addr->ai_next != NULL) {   /* if other addresses */
239                 addr=addr->ai_next;        /* take next */
240                 close(sock);               /* close socket */
241                 continue;                  /* restart cycle */
242             } else {                       /* else stop */
243                 perror("sockbind: cannot connect");
244                 close(sock);
245                 return res;
246             }
247         } else break;                      /* ok, we are binded! */
248     }
249     freeaddrinfo(save);                    /* done, release memory */
250     return sock;
251 }