cleanup specfile for packaging
[profile/ivi/gpsd.git] / netlib.c
1 /*
2  * This file is Copyright (c) 2010 by the GPSD project
3  * BSD terms apply: see the file COPYING in the distribution root for details.
4  */
5 #include <sys/types.h>
6
7 #include "gpsd_config.h"
8
9 #ifndef S_SPLINT_S
10 #ifdef HAVE_SYS_SOCKET_H
11 #include <sys/socket.h>
12 #endif
13 #ifdef HAVE_NETINET_IN_H
14 #include <netinet/in.h>
15 #endif
16 #ifdef HAVE_NETINET_IN_SYSTM_H
17 #include <netinet/in_systm.h>
18 #endif
19 #ifdef HAVE_NETINET_IN_H
20 #include <netinet/ip.h>
21 #endif
22 #endif /* S_SPLINT_S */
23 #ifndef S_SPLINT_S
24 #ifdef HAVE_NETDB_H
25 #include <netdb.h>
26 #endif /* HAVE_NETDB_H */
27 #ifdef HAVE_ARPA_INET_H
28 #include <arpa/inet.h>
29 #endif /* HAVE_ARPA_INET_H */
30 #endif /* S_SPLINT_S */
31 #include <errno.h>
32 #include <stdlib.h>
33 #ifndef S_SPLINT_S
34 #include <unistd.h>
35 #endif /* S_SPLINT_S */
36 #include <string.h>
37
38 #include "gpsd.h"
39 #include "sockaddr.h"
40
41 #if !defined (INADDR_NONE)
42 #define INADDR_NONE   ((in_addr_t)-1)
43 #endif
44
45 /*@-mustfreefresh -usedef@*/
46 socket_t netlib_connectsock(int af, const char *host, const char *service,
47                             const char *protocol)
48 {
49     struct protoent *ppe;
50     struct addrinfo hints;
51     struct addrinfo *result, *rp;
52     int ret, type, proto, one = 1;
53     socket_t s = -1;
54     bool bind_me;
55
56     /*@-type@*/
57     ppe = getprotobyname(protocol);
58     if (strcmp(protocol, "udp") == 0) {
59         type = SOCK_DGRAM;
60         proto = (ppe) ? ppe->p_proto : IPPROTO_UDP;
61     } else {
62         type = SOCK_STREAM;
63         proto = (ppe) ? ppe->p_proto : IPPROTO_TCP;
64     }
65     /*@+type@*/
66
67     /* we probably ought to pass this in as an explicit flag argument */
68     bind_me = (type == SOCK_DGRAM);
69
70     memset(&hints, 0, sizeof(struct addrinfo));
71     hints.ai_family = af;
72     hints.ai_socktype = type;
73     hints.ai_protocol = proto;
74 #ifndef S_SPLINT_S
75     if (bind_me)
76         hints.ai_flags = AI_PASSIVE;
77     if ((ret = getaddrinfo(host, service, &hints, &result))) {
78         return NL_NOHOST;
79     }
80 #endif /* S_SPLINT_S */
81
82     /*
83      * From getaddrinfo(3):
84      *     Normally, the application should try using the addresses in the
85      *     order in which they are returned.  The sorting function used within
86      *     getaddrinfo() is defined in RFC 3484).
87      * From RFC 3484 (Section 10.3):
88      *     The default policy table gives IPv6 addresses higher precedence than
89      *     IPv4 addresses.
90      * Thus, with the default parameters, we get IPv6 addresses first.
91      */
92     /*@-type@*/
93     for (rp = result; rp != NULL; rp = rp->ai_next) {
94         ret = NL_NOCONNECT;
95         if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
96             ret = NL_NOSOCK;
97         else if (setsockopt
98                  (s, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
99                   sizeof(one)) == -1) {
100             (void)close(s);
101             ret = NL_NOSOCKOPT;
102         } else {
103             if (bind_me) {
104                 if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0) {
105                     ret = 0;
106                     break;
107                 }
108             } else {
109                 if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
110                     ret = 0;
111                     break;
112                 }
113             }
114         }
115
116         if (s > 0) {
117             gpsd_report(LOG_SPIN, "close(%d) in netlib_connectsock()\n", s);
118             (void)close(s);
119         }
120     }
121     /*@+type@*/
122 #ifndef S_SPLINT_S
123     freeaddrinfo(result);
124 #endif /* S_SPLINT_S */
125     if (ret)
126         return ret;
127
128 #ifdef IPTOS_LOWDELAY
129     {
130         int opt = IPTOS_LOWDELAY;
131         /*@ -unrecog @*/
132         (void)setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof opt);
133         /*@ +unrecog @*/
134     }
135 #endif
136 #ifdef TCP_NODELAY
137     if (type == SOCK_STREAM)
138         setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof one);
139 #endif
140
141     gpsd_report(LOG_SPIN, "netlib_connectsock() returns socket on fd %d\n",
142                 s);
143     return s;
144     /*@ +type +mustfreefresh @*/
145 }
146
147 /*@+mustfreefresh +usedef@*/
148
149 char /*@observer@*/ *netlib_errstr(const int err)
150 {
151     switch (err) {
152     case NL_NOSERVICE:
153         return "can't get service entry";
154     case NL_NOHOST:
155         return "can't get host entry";
156     case NL_NOPROTO:
157         return "can't get protocol entry";
158     case NL_NOSOCK:
159         return "can't create socket";
160     case NL_NOSOCKOPT:
161         return "error SETSOCKOPT SO_REUSEADDR";
162     case NL_NOCONNECT:
163         return "can't connect to host/port pair";
164     default:
165         return "unknown error";
166     }
167 }
168
169 char *netlib_sock2ip(int fd)
170 {
171     sockaddr_t fsin;
172     socklen_t alen = (socklen_t) sizeof(fsin);
173     /*@i1@*/ static char ip[INET6_ADDRSTRLEN];
174     int r;
175
176     r = getpeername(fd, &(fsin.sa), &alen);
177     /*@ -branchstate -unrecog @*/
178     if (r == 0) {
179         switch (fsin.sa.sa_family) {
180         case AF_INET:
181             r = !inet_ntop(fsin.sa_in.sin_family, &(fsin.sa_in.sin_addr),
182                            ip, sizeof(ip));
183             break;
184 #ifdef IPV6_ENABLE
185         case AF_INET6:
186             r = !inet_ntop(fsin.sa_in6.sin6_family, &(fsin.sa_in6.sin6_addr),
187                            ip, sizeof(ip));
188             break;
189 #endif
190         default:
191             gpsd_report(LOG_ERROR, "Unhandled address family %d in %s\n",
192                         fsin.sa.sa_family, __FUNCTION__);
193             (void)strlcpy(ip, "<unknown AF>", sizeof(ip));
194             return ip;
195         }
196     }
197     if (r != 0) {
198         gpsd_report(LOG_INF, "getpeername() = %d, error = %s (%d)\n", r,
199                     strerror(errno), errno);
200         (void)strlcpy(ip, "<unknown>", sizeof(ip));
201     }
202     /*@ +branchstate +unrecog @*/
203     return ip;
204 }