1 /* -*- c-file-style: "java"; indent-tabs-mode: nil; tab-width: 4; fill-column: 78 -*-
2 *
3 * distcc -- A simple distributed compiler system
4 *
5 * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
21 */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <netdb.h>
32
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <sys/un.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
39
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42
43 #ifdef HAVE_ARPA_NAMESER_H
44 # include <arpa/nameser.h>
45 #endif
46
47 #include <arpa/inet.h>
48
49 #ifdef HAVE_RESOLV_H
50 # include <resolv.h>
51 #endif
52
53 #include <netdb.h>
54
55 #include "types.h"
56 #include "exitcode.h"
57 #include "distcc.h"
58 #include "trace.h"
59 #include "util.h"
60 #include "srvnet.h"
61 #include "access.h"
62 #include "netutil.h"
63 #include "snprintf.h"
64
65
66 /* work out what fcntl flag to use for non-blocking */
67 #ifdef O_NONBLOCK
68 # define NONBLOCK_FLAG O_NONBLOCK
69 #elif defined(SYSV)
70 # define NONBLOCK_FLAG O_NDELAY
71 #else
72 # define NONBLOCK_FLAG FNDELAY
73 #endif
74
75 #ifndef AF_UNIX
76 # define AF_UNIX AF_LOCAL
77 #endif
78
79
80 #ifndef HAVE_HSTRERROR
81 /* Missing on e.g. Solaris 2.6 */
hstrerror(int err)82 const char *hstrerror(int err) {
83 switch (err) {
84 case HOST_NOT_FOUND:
85 return "Host not found";
86 case TRY_AGAIN:
87 return "Name server not contacted";
88 case NO_RECOVERY:
89 return "Non-recoverable error";
90 case NO_ADDRESS:
91 return "No IP address for host";
92 default:
93 return "Unknown error";
94 }
95 }
96 #endif
97
98
99 /**
100 * Set a fd into blocking mode
101 **/
dcc_set_blocking(int fd)102 void dcc_set_blocking(int fd)
103 {
104 int val;
105
106 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
107 return;
108 if (val & NONBLOCK_FLAG) {
109 val &= ~NONBLOCK_FLAG;
110 fcntl(fd, F_SETFL, val);
111 }
112 }
113
114
115 /**
116 * Set a fd into nonblocking mode
117 **/
dcc_set_nonblocking(int fd)118 void dcc_set_nonblocking(int fd)
119 {
120 int val;
121
122 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
123 return;
124 if (!(val & NONBLOCK_FLAG)) {
125 val |= NONBLOCK_FLAG;
126 fcntl(fd, F_SETFL, val);
127 }
128 }
129
130
131 /* Ask for the server not to be awakened until some data has arrived
132 * on the socket. This works for our protocol because the client
133 * sends a request immediately after connection without waiting for
134 * anything from the server. */
dcc_defer_accept(int POSSIBLY_UNUSED (listen_fd))135 void dcc_defer_accept(int POSSIBLY_UNUSED(listen_fd))
136 {
137 #ifdef TCP_DEFER_ACCEPT
138 int val = 1;
139
140 if (!dcc_getenv_bool("DISTCC_TCP_DEFER_ACCEPT", 1)) {
141 rs_trace("TCP_DEFER_ACCEPT disabled");
142 return;
143 }
144
145 if (setsockopt(listen_fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof val) == -1) {
146 rs_log_warning("failed to set TCP_DEFER_ACCEPT: %s", strerror(errno));
147 } else {
148 rs_trace("TCP_DEFER_ACCEPT turned on");
149 }
150 #endif
151 }
152
153
154
155 #ifdef ENABLE_RFC2553
156 /* TODO: Make the returned strings consistent with the other
157 * implementation. */
dcc_sockaddr_to_string(struct sockaddr * sa,size_t salen,char ** p_buf)158 int dcc_sockaddr_to_string(struct sockaddr *sa,
159 size_t salen,
160 char **p_buf)
161 {
162 int err;
163 char host[1024];
164 char port[32];
165
166 if (!sa) {
167 *p_buf = strdup("NOTSOCKET");
168 return 0;
169 } else if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
170 err = getnameinfo(sa, salen,
171 host, sizeof host,
172 port, sizeof port,
173 NI_NUMERICHOST | NI_NUMERICSERV);
174 if (err) {
175 rs_log_warning("getnameinfo failed: %s", gai_strerror(err));
176 *p_buf = strdup("(UNKNOWN)");
177 return 0; /* it's still a valid string */
178 }
179
180 checked_asprintf(p_buf, "%s:%s", host, port);
181 } else if (sa->sa_family == AF_UNIX) {
182 /* NB: The word 'sun' is predefined on Solaris */
183 struct sockaddr_un *sa_un = (struct sockaddr_un *) sa;
184 checked_asprintf(p_buf, "UNIX-DOMAIN %s", sa_un->sun_path);
185 } else {
186 checked_asprintf(p_buf, "UNKNOWN-FAMILY %d", sa->sa_family);
187 }
188
189 return 0;
190 }
191 #else /* ndef ENABLE_RFC2553 */
dcc_sockaddr_to_string(struct sockaddr * sa,size_t UNUSED (salen),char ** p_buf)192 int dcc_sockaddr_to_string(struct sockaddr *sa,
193 size_t UNUSED(salen),
194 char **p_buf)
195 {
196 if (!sa) {
197 *p_buf = strdup("NOTSOCKET");
198 return 0;
199 } else if (sa->sa_family == AF_INET) {
200 /* The double-cast here suppresses warnings from -Wcast-align. */
201 struct sockaddr_in *sain = (struct sockaddr_in *) (void *) sa;
202
203 checked_asprintf(p_buf, "%s:%d", inet_ntoa(sain->sin_addr),
204 ntohs(sain->sin_port));
205 } else if (sa->sa_family == AF_UNIX) {
206 /* NB: The word 'sun' is predefined on Solaris */
207 struct sockaddr_un *sa_un = (struct sockaddr_un *) sa;
208 checked_asprintf(p_buf, "UNIX-DOMAIN %s", sa_un->sun_path);
209 } else {
210 checked_asprintf(p_buf, "UNKNOWN-FAMILY %d", sa->sa_family);
211 }
212
213 return 0;
214 }
215 #endif /* ndef ENABLE_RFC2553 */
216