1 /*
2 *
3 * XASTIR, Amateur Station Tracking and Information Reporting
4 * Copyright (C) 1999,2000 Frank Giannandrea
5 * Copyright (C) 2000-2019 The Xastir Group
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * Look at the README for more information on the program.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif // HAVE_CONFIG_H
27
28 #include "snprintf.h"
29
30 #include <Xm/XmAll.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <netdb.h>
36 #include <signal.h>
37
38 //Needed for Solaris 2.5
39 #include <netinet/in.h>
40
41 #include <arpa/inet.h>
42 #include <sys/socket.h>
43 #include <setjmp.h>
44 #include <netinet/in.h>
45 #include <sys/wait.h>
46 #include <errno.h>
47
48 #include "xastir.h"
49 #include "main.h"
50 #include "lang.h"
51
52 // Must be last include file
53 #include "leak_detection.h"
54 #include "forked_getaddrinfo.h"
55
56 #ifndef HAVE_SIGHANDLER_T
57 #ifdef HAVE_SIG_T
58 typedef sig_t sighandler_t;
59 #else
60 typedef void (*sighandler_t)(int);
61 #endif
62 #endif
63
64
65 #ifndef __LCLINT__
66 #ifndef HAVE_SIGJMP_BUF
67 jmp_buf ret_place;
68 #else // HAVE_SIGJMP_BUF
69 static sigjmp_buf ret_place; /* Jump address if alarm */
70 #endif // HAVE_SIGJMP_BUF
71 #endif // __LCLINT__
72
73
74
75
76
77 /*************************************************************************/
78 /* Time out on connect */
79 /* In case there is a problem in getting the hostname or connecting */
80 /* (see setjmp below). */
81 /*************************************************************************/
82
host_time_out(int UNUSED (sig))83 static void host_time_out( int UNUSED(sig) )
84 {
85 #ifndef __LCLINT__
86 siglongjmp(ret_place,0);
87 #endif // __LCLINT__
88 }
89
90
91
92
93
94 /*************************************************************************/
95 /* do a nice host lookup (don't thread!!) */
96 /* */
97 /* host: name to lookup */
98 /* ip: buffer for ip's must be 400 bytes at least */
99 /* time: time in seconds to wait */
100 /* */
101 /* return the ip or ip's of the host name */
102 /* or these strings: */
103 /* NOHOST for no host by that name found */
104 /* NOIP for host found but no ip address available */
105 /* TIMEOUT for time exceeded */
106 /*************************************************************************/
107
forked_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** resout,int time)108 int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time)
109 {
110
111 #ifdef RETSIGTYPE
112 RETSIGTYPE * previous_loc;
113 #else
114 #error RETSIGTYPE not defined
115 #endif
116
117 pid_t host_pid;
118 int status;
119 int fp[2];
120 int tm;
121 int i;
122 int rc = EAI_FAIL;
123 char ttemp[60];
124 int wait_host;
125 struct addrinfo *res0;
126 struct addrinfo *res;
127
128 if (debug_level & 1024)
129 {
130 fprintf(stderr,"Start Host lookup\n");
131 }
132
133 busy_cursor(appshell);
134
135 if (debug_level & 1024)
136 {
137 fprintf(stderr,"Creating pipe\n");
138 }
139
140 // Create a pipe for communication
141 if (pipe(fp)!=0)
142 {
143 fprintf(stderr, "Error creating pipe for hostname lookup: %s\n",
144 strerror(errno));
145 return rc;
146 }
147
148 host_pid = fork(); // Fork off a child process
149
150 if (debug_level & 1024)
151 {
152 fprintf(stderr,"Host fork\n");
153 }
154
155 if (host_pid!=-1) // If the fork was successful
156 {
157
158 //---------------------------------------------------------------------------------------
159 if (host_pid==0) // We're in the child process
160 {
161
162
163 // Go back to default signal handler instead of
164 // calling restart() on SIGHUP
165 (void) signal(SIGHUP,SIG_DFL);
166
167
168 // Change the name of the new child process. So far
169 // this only works for "ps" listings, not for "top".
170 // This code only works on Linux. For BSD use
171 // setproctitle(3), NetBSD can use setprogname(2).
172 #ifdef __linux__
173 init_set_proc_title(my_argc, my_argv, my_envp);
174 set_proc_title("%s", "hostname lookup (xastir)");
175 //fprintf(stderr,"DEBUG: %s\n", Argv[0]);
176 #endif // __linux__
177
178
179 // Close the end of the pipe we don't need here
180
181 if (debug_level & 1024)
182 {
183 fprintf(stderr,"Child closing read end of pipe\n");
184 }
185
186 close(fp[0]); // Read end of the pipe
187
188 if (debug_level & 1024)
189 {
190 fprintf(stderr,"Set alarm \n");
191 }
192
193 #ifdef RETSIGTYPE
194 previous_loc = (RETSIGTYPE *)signal(SIGALRM, host_time_out);
195 #else
196 previous_loc = signal(SIGALRM, host_time_out);
197 #endif
198
199 // Set up to jump here if we time out on SIGALRM
200 if (sigsetjmp(ret_place,-1)!=0)
201 {
202
203 // Turn off the alarm
204 (void)alarm(0);
205
206 // Reset the SIGALRM handler to its previous value
207 (void)signal(SIGALRM, (sighandler_t)previous_loc);
208
209 // Return net connection time out
210 rc = FAI_TIMEOUT;
211
212 if (write(fp[1],&rc, sizeof(int)) == -1)
213 {
214 // Write error. Do nothing as we did prior
215 // to checking the return value.
216 }
217
218 if (debug_level & 1024)
219 {
220 fprintf(stderr,"Child closing write end of pipe\n");
221 }
222
223 close(fp[1]); // All done writing to the pipe
224 exit(EXIT_FAILURE); // Exit from child process
225 }
226 (void)alarm(time); // Start the timer
227
228 // Make the call that may time out if no response from DNS
229 /*hostinfo = gethostbyname2(host,AF_INET); some systems don't have this*/
230 rc = getaddrinfo(hostname, servname, hints, &res0);
231
232 // If we get to here, we haven't timed out
233 // and we have an answer to process.
234
235 // Turn off the alarm
236 (void)alarm(0);
237 // Reset the SIGALRM handler to its previous value
238 (void)signal(SIGALRM, (sighandler_t)previous_loc);
239
240 if (write(fp[1], &rc, sizeof(int)) == -1) // Send status
241 {
242 // Write error. Do nothing as we did prior
243 // to checking the return value.
244 }
245
246 for (res = res0; res; res = res->ai_next)
247 {
248 // Signal that an entry is coming.
249 rc = 1;
250
251 if (write(fp[1], &rc, sizeof(int)) == -1)
252 {
253 // Write error. Do nothing as we did prior
254 // to checking the return value.
255 }
256
257 // Send entry
258 if (write(fp[1], res, sizeof(struct addrinfo)) == -1)
259 {
260 // Write error. Do nothing as we did prior
261 // to checking the return value.
262 }
263
264 if (write(fp[1], res->ai_addr, res->ai_addrlen) == -1)
265 {
266 // Write error. Do nothing as we did prior
267 // to checking the return value.
268 }
269
270 }
271 // Signal that there is nothing left
272 rc = 0;
273
274 if (write(fp[1], &rc, sizeof(int)) == -1)
275 {
276 // Write error. Do nothing as we did prior
277 // to checking the return value.
278 }
279
280 if (debug_level & 1024)
281 {
282 fprintf(stderr,"Child closing write end of pipe\n");
283 }
284
285 freeaddrinfo(res0);
286 close(fp[1]); // All done writing to the pipe
287 exit(EXIT_FAILURE); // Exit from child process
288
289 } // End of child process
290 //---------------------------------------------------------------------------------------
291 else
292 {
293 // We're in the parent process at this point
294
295 // Close the end of the pipe we don't need here
296
297 if (debug_level & 1024)
298 {
299 fprintf(stderr,"Parent closing write end of pipe\n");
300 }
301
302 close(fp[1]); // Write end of the pipe
303
304 tm=1;
305 wait_host=1;
306 while (wait_host!=-1)
307 {
308 xastir_snprintf(ttemp, sizeof(ttemp), langcode("BBARSTA031"), tm++);
309 statusline(ttemp,1); // Looking up hostname...
310
311 for (i=0; i < 60 && wait_host!=-1; i++)
312 {
313 wait_host=waitpid(host_pid,&status,WNOHANG);
314 /* update display while waiting */
315 // XmUpdateDisplay(XtParent(da));
316 //usleep(500);
317 sched_yield();
318 }
319 }
320 // Get the return code
321 if (read(fp[0],&rc,sizeof(int)) == -1)
322 {
323 // Read error. Do nothing as we did prior
324 // to checking the return value.
325 }
326
327 if(rc!=0)
328 {
329 close(fp[0]);
330 return rc;
331 }
332
333 if (read(fp[0], &status, sizeof(int)) == -1)
334 {
335 // Read error. Do nothing as we did prior
336 // to checking the return value.
337 }
338
339 while(status)
340 {
341 *resout = (struct addrinfo*) malloc(sizeof(struct addrinfo));
342 res = *resout;
343
344 if (read(fp[0], res, sizeof(struct addrinfo)) == -1)
345 {
346 // Read error. Do nothing as we did prior
347 // to checking the return value.
348 }
349
350 res->ai_addr = (struct sockaddr*) malloc(res->ai_addrlen);
351
352 if (read(fp[0], res->ai_addr, res->ai_addrlen) == -1)
353 {
354 // Read error. Do nothing as we did prior
355 // to checking the return value.
356 }
357
358 res->ai_canonname = NULL;
359 resout = &res->ai_next;
360
361 // See if there is another
362 if (read(fp[0], &status, sizeof(int)) == -1)
363 {
364 // Read error. Do nothing as we did prior
365 // to checking the return value.
366 }
367 }
368 *resout = NULL;
369
370 if (debug_level & 1024)
371 {
372 fprintf(stderr,"Parent closing read end of pipe\n");
373 }
374
375 close(fp[0]); // Close the read end of the pipe
376 }
377 }
378 else // We didn't fork
379 {
380 // Close both ends of the pipe to make
381 // sure we've cleaned up properly
382 close(fp[0]);
383 close(fp[1]);
384 }
385 return rc;
386 }
387
forked_freeaddrinfo(struct addrinfo * ai)388 void forked_freeaddrinfo(struct addrinfo *ai)
389 {
390 struct addrinfo *next = ai;
391 struct addrinfo *current = ai;
392
393 while(next)
394 {
395 current = next;
396 next = current->ai_next;
397
398 free(current->ai_addr);
399 free(current);
400 }
401 }
402
403
404