Altre correzioni alle funzioni, con riscrittura di ip_ntop per usare switch,
[gapil.git] / sources / SockUtil.c
1 /* Sockutils.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 SockUtils.c 
22  * Routines for socket operations. 
23  *
24  * Define routines for socket handling 
25  *
26  * Author: S. Piccardi
27  *
28  * $Id$
29  *
30  ***************************************************************/
31 #include <sys/types.h>
32 #include <stdio.h>                                 /* standard I/O functions */
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <arpa/inet.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <netdb.h>
41
42 #include "macros.h"
43 /**************************************************************************
44  *
45  * Routine ip_ntop
46  *
47  * Return a string with the numeric address translation of the content
48  * of an addrinfo stucture
49  *
50  * Author: Simone Piccardi
51  * Dec. 2004
52  *
53  * $Id$ 
54  *
55  **************************************************************************/
56 char *ip_ntop(struct addrinfo *addr, char *dst, socklen_t cnt)
57 {
58 //    char buffer[INET6_ADDRSTRLEN];
59     char * ret;
60     struct sockaddr_in *ip4;
61     struct sockaddr_in6 *ip6;
62     switch (addr->ai_family) {
63     case PF_INET:
64         ip4 = (struct sockaddr_in *) addr->ai_addr;
65         ret = inet_ntop(ip4->sin_family, &ip4->sin_addr, dst, cnt);
66         break;
67     case PF_INET6:
68         ip6 = (struct sockaddr_in6 *) addr->ai_addr;
69         ret = inet_ntop(ip6->sin6_family, &ip6->sin6_addr, dst, cnt);
70         break;
71     default:
72         ret = NULL;
73         errno = EAFNOSUPPORT;
74     }
75     return ret;
76 }
77 /****************************************************************
78  *
79  * Routine sockconn
80  * Return a connected socket given hostname, service, and socket type
81  *
82  * Author: Simone Piccardi
83  * Dec. 2004
84  *
85  * $Id$ 
86  *
87  ****************************************************************/
88 int sockconn(char *host, char *serv, int prot, int type) 
89 {
90     struct addrinfo hint, *addr, *save;
91     int res;
92     int sock;
93     /* initialize hint structure */
94     memset(&hint, 0, sizeof(struct addrinfo)); 
95     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
96     hint.ai_protocol = prot;               /* protocol */
97     hint.ai_socktype = type;               /* socket type */
98     res = getaddrinfo(host, serv, &hint, &addr);    /* calling getaddrinfo */
99     if (res != 0) {                                 /* on error exit */
100         fprintf(stderr, "sockconn: resolution failed:");
101 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
102         fprintf(stderr, " %s\n", gai_strerror(res));
103         errno = 0;                         /* clear errno */
104         return -1;
105     }
106     save = addr;
107     while (addr != NULL) {                 /* loop on possible addresses */
108         /* get a socket */
109         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
110         if (sock < 0) {                    /* on error */
111             if (addr->ai_next != NULL) {   /* if other addresses */
112                 addr=addr->ai_next;        /* take next */
113                 continue;                  /* restart cycle */
114             } else {                       /* else stop */
115                 perror("sockconn: cannot create socket");
116                 return sock;
117             }
118         }
119         /* connect the socket */
120         if ( (res = connect(sock, addr->ai_addr, addr->ai_addrlen) < 0)) {
121             if (addr->ai_next != NULL) {   /* if other addresses */
122                 addr=addr->ai_next;        /* take next */
123                 close(sock);               /* close socket */
124                 continue;                  /* restart cycle */
125             } else {                       /* else stop */
126                 perror("sockconn: cannot connect");
127                 close(sock);
128                 return res;
129             }
130         } else break;                      /* ok, we are connected! */
131     }
132     freeaddrinfo(save);                    /* done, release memory */
133     return sock;
134 }
135 /****************************************************************
136  *
137  * Routine sockbind
138  * Return a binded socket given hostname, service, and socket type
139  *
140  * Author: Simone Piccardi
141  * Dec. 2004
142  *
143  * $Id$ 
144  *
145  ****************************************************************/
146 int sockbind(char *host, char *serv, int prot, int type) 
147 {
148     struct addrinfo hint, *addr, *save;
149     int res;
150     int sock;
151     char buf[INET6_ADDRSTRLEN];
152     /* initialize hint structure */
153     memset(&hint, 0, sizeof(struct addrinfo)); 
154     hint.ai_flags = AI_PASSIVE;            /* address for binding */
155     hint.ai_family = PF_UNSPEC;            /* generic address (IPv4 or IPv6) */
156     hint.ai_protocol = prot;               /* protocol */
157     hint.ai_socktype = type;               /* socket type */
158     res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
159     if (res != 0) {                                /* on error exit */
160         fprintf(stderr, "sockbind: resolution failed:");
161 //      fprintf(stderr, "host %s, service %s, protocol %d", host, serv, prot);
162         fprintf(stderr, " %s\n", gai_strerror(res));
163         errno = 0;                         /* clear errno */
164         return -1;
165     }
166     save = addr;                           /* saving for freeaddrinfo */
167     while (addr != NULL) {                 /* loop on possible addresses */
168         /* get a socket */
169         sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
170         if (sock < 0) {                    /* on error */
171             if (addr->ai_next != NULL) {   /* if other addresses */
172                 addr=addr->ai_next;        /* take next */
173                 continue;                  /* restart cycle */
174             } else {                       /* else stop */
175                 perror("sockbind: cannot create socket");
176                 return sock;
177             }
178         }
179         /* connect the socket */
180         printf("Indirizzo %s\n", ip_ntop(addr, buf, sizeof(buf)));
181         if ( (res = bind(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
182             if (addr->ai_next != NULL) {   /* if other addresses */
183                 addr=addr->ai_next;        /* take next */
184                 close(sock);               /* close socket */
185                 continue;                  /* restart cycle */
186             } else {                       /* else stop */
187                 perror("sockbind: cannot connect");
188                 close(sock);
189                 return res;
190             }
191         } else break;                      /* ok, we are binded! */
192     }
193     freeaddrinfo(save);                    /* done, release memory */
194     return sock;
195 }