1 | /* sonar.c --- Simulate a sonar screen. |
---|
2 | * |
---|
3 | * This is an implementation of a general purpose reporting tool in the |
---|
4 | * format of a Sonar display. It is designed such that a sensor is read |
---|
5 | * on every movement of a sweep arm and the results of that sensor are |
---|
6 | * displayed on the screen. The location of the display points (targets) on the |
---|
7 | * screen are determined by the current localtion of the sweep and a distance |
---|
8 | * value associated with the target. |
---|
9 | * |
---|
10 | * Currently the only two sensors that are implemented are the simulator |
---|
11 | * (the default) and the ping sensor. The simulator randomly creates a set |
---|
12 | * of bogies that move around on the scope while the ping sensor can be |
---|
13 | * used to display hosts on your network. |
---|
14 | * |
---|
15 | * The ping code is only compiled in if you define HAVE_ICMP or HAVE_ICMPHDR, |
---|
16 | * because, unfortunately, different systems have different ways of creating |
---|
17 | * these sorts of packets. |
---|
18 | * |
---|
19 | * Also: creating an ICMP socket is a privileged operation, so the program |
---|
20 | * needs to be installed SUID root if you want to use the ping mode. If you |
---|
21 | * check the code you will see that this privilige is given up immediately |
---|
22 | * after the socket is created. |
---|
23 | * |
---|
24 | * It should be easy to extend this code to support other sorts of sensors. |
---|
25 | * Some ideas: |
---|
26 | * - search the output of "netstat" for the list of hosts to ping; |
---|
27 | * - plot the contents of /proc/interrupts; |
---|
28 | * - plot the process table, by process size, cpu usage, or total time; |
---|
29 | * - plot the logged on users by idle time or cpu usage. |
---|
30 | * |
---|
31 | * Copyright (C) 1998, 2001 |
---|
32 | * by Stephen Martin (smartin@vanderfleet-martin.net). |
---|
33 | * Permission to use, copy, modify, distribute, and sell this software and its |
---|
34 | * documentation for any purpose is hereby granted without fee, provided that |
---|
35 | * the above copyright notice appear in all copies and that both that |
---|
36 | * copyright notice and this permission notice appear in supporting |
---|
37 | * documentation. No representations are made about the suitability of this |
---|
38 | * software for any purpose. It is provided "as is" without express or |
---|
39 | * implied warranty. |
---|
40 | * |
---|
41 | * $Revision: 1.3 $ |
---|
42 | * |
---|
43 | * Version 1.0 April 27, 1998. |
---|
44 | * - Initial version |
---|
45 | * - Submitted to RedHat Screensaver Contest |
---|
46 | * |
---|
47 | * Version 1.1 November 3, 1998. |
---|
48 | * - Added simulation mode. |
---|
49 | * - Added enhancements by Thomas Bahls <thommy@cs.tu-berlin.de> |
---|
50 | * - Fixed huge memory leak. |
---|
51 | * - Submitted to xscreensavers |
---|
52 | * |
---|
53 | * Version 1.2 |
---|
54 | * - All ping code is now ifdef-ed by the compile time symbol HAVE_PING; |
---|
55 | * use -DHAVE_PING to include it when you compile. |
---|
56 | * - Sweep now uses gradients. |
---|
57 | * - Fixed portability problems with icmphdr on some systems. |
---|
58 | * - removed lowColor option/resource. |
---|
59 | * - changed copyright notice so that it could be included in the xscreensavers |
---|
60 | * collection. |
---|
61 | * |
---|
62 | * Version 1.3 November 16, 1998. |
---|
63 | * - All ping code is now ifdef-ed by the compile time symbol PING use -DPING |
---|
64 | * to include it when you compile. |
---|
65 | * - Sweep now uses gradients. |
---|
66 | * - Fixed portability problems with icmphdr on some systems. |
---|
67 | * - removed lowcolour option/resource. |
---|
68 | * - changed copyright notice so that it could be included in the xscreensavers |
---|
69 | * collection. |
---|
70 | * |
---|
71 | * Version 1.4 November 18, 1998. |
---|
72 | * - More ping portability fixes. |
---|
73 | * |
---|
74 | * Version 1.5 November 19, 1998. |
---|
75 | * - Synced up with jwz's changes. |
---|
76 | * - Now need to define HAVE_PING to compile in the ping stuff. |
---|
77 | */ |
---|
78 | |
---|
79 | /* These are computed by configure now: |
---|
80 | #define HAVE_ICMP |
---|
81 | #define HAVE_ICMPHDR |
---|
82 | */ |
---|
83 | |
---|
84 | |
---|
85 | /* Include Files */ |
---|
86 | |
---|
87 | #include <stdlib.h> |
---|
88 | #include <stdio.h> |
---|
89 | #include <math.h> |
---|
90 | #include <sys/stat.h> |
---|
91 | |
---|
92 | #include "screenhack.h" |
---|
93 | #include "colors.h" |
---|
94 | #include "hsv.h" |
---|
95 | |
---|
96 | #if defined(HAVE_ICMP) || defined(HAVE_ICMPHDR) |
---|
97 | # include <unistd.h> |
---|
98 | # include <limits.h> |
---|
99 | # include <signal.h> |
---|
100 | # include <fcntl.h> |
---|
101 | # include <sys/types.h> |
---|
102 | # include <sys/time.h> |
---|
103 | # include <sys/ipc.h> |
---|
104 | # include <sys/shm.h> |
---|
105 | # include <sys/socket.h> |
---|
106 | # include <netinet/in_systm.h> |
---|
107 | # include <netinet/in.h> |
---|
108 | # include <netinet/ip.h> |
---|
109 | # include <netinet/ip_icmp.h> |
---|
110 | # include <netinet/udp.h> |
---|
111 | # include <arpa/inet.h> |
---|
112 | # include <netdb.h> |
---|
113 | #endif /* HAVE_ICMP || HAVE_ICMPHDR */ |
---|
114 | |
---|
115 | |
---|
116 | /* Defines */ |
---|
117 | |
---|
118 | #undef MY_MIN |
---|
119 | #define MY_MIN(a,b) ((a)<(b)?(a - 50):(b - 10)) |
---|
120 | |
---|
121 | #ifndef LINE_MAX |
---|
122 | # define LINE_MAX 2048 |
---|
123 | #endif |
---|
124 | |
---|
125 | /* Frigging icmp */ |
---|
126 | |
---|
127 | #if defined(HAVE_ICMP) |
---|
128 | # define HAVE_PING |
---|
129 | # define ICMP icmp |
---|
130 | # define ICMP_TYPE(p) (p)->icmp_type |
---|
131 | # define ICMP_CODE(p) (p)->icmp_code |
---|
132 | # define ICMP_CHECKSUM(p) (p)->icmp_cksum |
---|
133 | # define ICMP_ID(p) (p)->icmp_id |
---|
134 | # define ICMP_SEQ(p) (p)->icmp_seq |
---|
135 | #elif defined(HAVE_ICMPHDR) |
---|
136 | # define HAVE_PING |
---|
137 | # define ICMP icmphdr |
---|
138 | # define ICMP_TYPE(p) (p)->type |
---|
139 | # define ICMP_CODE(p) (p)->code |
---|
140 | # define ICMP_CHECKSUM(p) (p)->checksum |
---|
141 | # define ICMP_ID(p) (p)->un.echo.id |
---|
142 | # define ICMP_SEQ(p) (p)->un.echo.sequence |
---|
143 | #else |
---|
144 | # undef HAVE_PING |
---|
145 | #endif |
---|
146 | |
---|
147 | |
---|
148 | #ifdef HAVE_PING |
---|
149 | # if defined(__DECC) || defined(_IP_VHL) |
---|
150 | /* This is how you do it on DEC C, and possibly some BSD systems. */ |
---|
151 | # define IP_HDRLEN(ip) ((ip)->ip_vhl & 0x0F) |
---|
152 | # else |
---|
153 | /* This is how you do it on everything else. */ |
---|
154 | # define IP_HDRLEN(ip) ((ip)->ip_hl) |
---|
155 | # endif |
---|
156 | #endif /* HAVE_PING */ |
---|
157 | |
---|
158 | |
---|
159 | /* Forward References */ |
---|
160 | |
---|
161 | #ifdef HAVE_PING |
---|
162 | static u_short checksum(u_short *, int); |
---|
163 | #endif |
---|
164 | static long delta(struct timeval *, struct timeval *); |
---|
165 | |
---|
166 | |
---|
167 | /* Data Structures */ |
---|
168 | |
---|
169 | /* |
---|
170 | * The Bogie. |
---|
171 | * |
---|
172 | * This represents an object that is visible on the scope. |
---|
173 | */ |
---|
174 | |
---|
175 | typedef struct Bogie { |
---|
176 | char *name; /* The name of the thing being displayed */ |
---|
177 | int distance; /* The distance to this thing (0 - 100) */ |
---|
178 | int tick; /* The tick that it was found on */ |
---|
179 | int ttl; /* The time to live */ |
---|
180 | int age; /* How long it's been around */ |
---|
181 | struct Bogie *next; /* The next one in the list */ |
---|
182 | } Bogie; |
---|
183 | |
---|
184 | /* |
---|
185 | * Sonar Information. |
---|
186 | * |
---|
187 | * This contains all of the runtime information about the sonar scope. |
---|
188 | */ |
---|
189 | |
---|
190 | typedef struct { |
---|
191 | Display *dpy; /* The X display */ |
---|
192 | Window win; /* The window */ |
---|
193 | GC hi, /* The leading edge of the sweep */ |
---|
194 | lo, /* The trailing part of the sweep */ |
---|
195 | erase, /* Used to erase things */ |
---|
196 | grid, /* Used to draw the grid */ |
---|
197 | text; /* Used to draw text */ |
---|
198 | Colormap cmap; /* The colormap */ |
---|
199 | XFontStruct *font; /* The font to use for the labels */ |
---|
200 | int text_steps; /* How many steps to fade text. */ |
---|
201 | XColor *text_colors; /* Pixel values used to fade text */ |
---|
202 | int sweep_degrees; /* How much of the circle the sweep uses */ |
---|
203 | int sweep_segs; /* How many gradients in the sweep. */ |
---|
204 | XColor *sweep_colors; /* The sweep pixel values */ |
---|
205 | int width, height; /* Window dimensions */ |
---|
206 | int minx, miny, maxx, maxy, /* Bounds of the scope */ |
---|
207 | centrex, centrey, radius; /* Parts of the scope circle */ |
---|
208 | Bogie *visible; /* List of visible objects */ |
---|
209 | int current; /* Current position of sweep */ |
---|
210 | int sweepnum; /* The current id of the sweep */ |
---|
211 | int delay; /* how long between each frame of the anim */ |
---|
212 | |
---|
213 | int TTL; /* The number of ticks that bogies are visible |
---|
214 | on the screen before they fade away. */ |
---|
215 | } sonar_info; |
---|
216 | |
---|
217 | static Bool debug_p = False; |
---|
218 | |
---|
219 | |
---|
220 | /* |
---|
221 | * Variables to support the differnt Sonar modes. |
---|
222 | */ |
---|
223 | |
---|
224 | Bogie *(*sensor)(sonar_info *, void *); /* The current sensor */ |
---|
225 | void *sensor_info; /* Information about the sensor */ |
---|
226 | |
---|
227 | /* |
---|
228 | * A list of targets to ping. |
---|
229 | */ |
---|
230 | |
---|
231 | typedef struct ping_target { |
---|
232 | char *name; /* The name of the target */ |
---|
233 | #ifdef HAVE_PING |
---|
234 | struct sockaddr address; /* The address of the target */ |
---|
235 | #endif /* HAVE_PING */ |
---|
236 | struct ping_target *next; /* The next one in the list */ |
---|
237 | } ping_target; |
---|
238 | |
---|
239 | |
---|
240 | #ifdef HAVE_PING |
---|
241 | /* |
---|
242 | * Ping Information. |
---|
243 | * |
---|
244 | * This contains the information for the ping sensor. |
---|
245 | */ |
---|
246 | |
---|
247 | typedef struct { |
---|
248 | int icmpsock; /* Socket for sending pings */ |
---|
249 | int pid; /* Our process ID */ |
---|
250 | int seq; /* Packet sequence number */ |
---|
251 | int timeout; /* Timeout value for pings */ |
---|
252 | ping_target *targets; /* List of targets to ping */ |
---|
253 | int numtargets; /* The number of targets to ping */ |
---|
254 | } ping_info; |
---|
255 | |
---|
256 | /* Flag to indicate that the timer has expired on us */ |
---|
257 | |
---|
258 | static int timer_expired; |
---|
259 | |
---|
260 | #endif /* HAVE_PING */ |
---|
261 | |
---|
262 | /* |
---|
263 | * A list of targets for the simulator |
---|
264 | */ |
---|
265 | |
---|
266 | typedef struct sim_target { |
---|
267 | char *name; /* The name of the target */ |
---|
268 | int nexttick; /* The next tick that this will be seen */ |
---|
269 | int nextdist; /* The distance on that tick */ |
---|
270 | int movedonsweep; /* The number of the sweep this last moved */ |
---|
271 | } sim_target; |
---|
272 | |
---|
273 | /* |
---|
274 | * Simulator Information. |
---|
275 | * |
---|
276 | * This contains the information for the simulator mode. |
---|
277 | */ |
---|
278 | |
---|
279 | typedef struct { |
---|
280 | sim_target *teamA; /* The bogies for the A team */ |
---|
281 | int numA; /* The number of bogies in team A */ |
---|
282 | char *teamAID; /* The identifier for bogies in team A */ |
---|
283 | sim_target *teamB; /* The bogies for the B team */ |
---|
284 | int numB; /* The number of bogies in team B */ |
---|
285 | char *teamBID; /* The identifier for bogies in team B */ |
---|
286 | } sim_info; |
---|
287 | |
---|
288 | /* Name of the Screensaver hack */ |
---|
289 | |
---|
290 | char *progclass="sonar"; |
---|
291 | |
---|
292 | /* Application Defaults */ |
---|
293 | |
---|
294 | char *defaults [] = { |
---|
295 | ".background: #000000", |
---|
296 | ".sweepColor: #00FF00", |
---|
297 | "*delay: 100000", |
---|
298 | "*scopeColor: #003300", |
---|
299 | "*gridColor: #00AA00", |
---|
300 | "*textColor: #FFFF00", |
---|
301 | "*ttl: 90", |
---|
302 | "*mode: default", |
---|
303 | "*font: fixed", |
---|
304 | "*sweepDegrees: 30", |
---|
305 | |
---|
306 | "*textSteps: 80", /* npixels */ |
---|
307 | "*sweepSegments: 80", /* npixels */ |
---|
308 | |
---|
309 | "*pingTimeout: 3000", |
---|
310 | |
---|
311 | "*teamAName: F18", |
---|
312 | "*teamBName: MIG", |
---|
313 | "*teamACount: 4", |
---|
314 | "*teamBCount: 4", |
---|
315 | |
---|
316 | "*ping: default", |
---|
317 | ".debug: false", |
---|
318 | 0 |
---|
319 | }; |
---|
320 | |
---|
321 | /* Options passed to this program */ |
---|
322 | |
---|
323 | XrmOptionDescRec options [] = { |
---|
324 | {"-background", ".background", XrmoptionSepArg, 0 }, |
---|
325 | {"-sweep-color", ".sweepColor", XrmoptionSepArg, 0 }, |
---|
326 | {"-scope-color", ".scopeColor", XrmoptionSepArg, 0 }, |
---|
327 | {"-grid-color", ".gridColor", XrmoptionSepArg, 0 }, |
---|
328 | {"-text-color", ".textColor", XrmoptionSepArg, 0 }, |
---|
329 | {"-ttl", ".ttl", XrmoptionSepArg, 0 }, |
---|
330 | {"-font", ".font", XrmoptionSepArg, 0 }, |
---|
331 | #ifdef HAVE_PING |
---|
332 | {"-ping-timeout", ".pingTimeout", XrmoptionSepArg, 0 }, |
---|
333 | #endif /* HAVE_PING */ |
---|
334 | {"-team-a-name", ".teamAName", XrmoptionSepArg, 0 }, |
---|
335 | {"-team-b-name", ".teamBName", XrmoptionSepArg, 0 }, |
---|
336 | {"-team-a-count", ".teamACount", XrmoptionSepArg, 0 }, |
---|
337 | {"-team-b-count", ".teamBCount", XrmoptionSepArg, 0 }, |
---|
338 | |
---|
339 | {"-ping", ".ping", XrmoptionSepArg, 0 }, |
---|
340 | {"-debug", ".debug", XrmoptionNoArg, "True" }, |
---|
341 | { 0, 0, 0, 0 } |
---|
342 | }; |
---|
343 | |
---|
344 | /* |
---|
345 | * Create a new Bogie and set some initial values. |
---|
346 | * |
---|
347 | * Args: |
---|
348 | * name - The name of the bogie. |
---|
349 | * distance - The distance value. |
---|
350 | * tick - The tick value. |
---|
351 | * ttl - The time to live value. |
---|
352 | * |
---|
353 | * Returns: |
---|
354 | * The newly allocated bogie or null if a memory problem occured. |
---|
355 | */ |
---|
356 | |
---|
357 | static Bogie * |
---|
358 | newBogie(char *name, int distance, int tick, int ttl) |
---|
359 | { |
---|
360 | |
---|
361 | /* Local Variables */ |
---|
362 | |
---|
363 | Bogie *new; |
---|
364 | |
---|
365 | distance *= 1000; |
---|
366 | /* Allocate a bogie and initialize it */ |
---|
367 | |
---|
368 | if ((new = (Bogie *) calloc(1, sizeof(Bogie))) == NULL) { |
---|
369 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
370 | return NULL; |
---|
371 | } |
---|
372 | new->name = name; |
---|
373 | new->distance = distance; |
---|
374 | new->tick = tick; |
---|
375 | new->ttl = ttl; |
---|
376 | new->age = 0; |
---|
377 | new->next = (Bogie *) 0; |
---|
378 | return new; |
---|
379 | } |
---|
380 | |
---|
381 | /* |
---|
382 | * Free a Bogie. |
---|
383 | * |
---|
384 | * Args: |
---|
385 | * b - The bogie to free. |
---|
386 | */ |
---|
387 | |
---|
388 | |
---|
389 | static void |
---|
390 | freeBogie(Bogie *b) |
---|
391 | { |
---|
392 | if (b->name != (char *) 0) |
---|
393 | free(b->name); |
---|
394 | free(b); |
---|
395 | } |
---|
396 | |
---|
397 | /* |
---|
398 | * Find a bogie by name in a list. |
---|
399 | * |
---|
400 | * This does a simple linear search of the list for a given name. |
---|
401 | * |
---|
402 | * Args: |
---|
403 | * bl - The Bogie list to search. |
---|
404 | * name - The name to look for. |
---|
405 | * |
---|
406 | * Returns: |
---|
407 | * The requested Bogie or null if it wasn't found. |
---|
408 | */ |
---|
409 | |
---|
410 | static Bogie * |
---|
411 | findNode(Bogie *bl, char *name) |
---|
412 | { |
---|
413 | |
---|
414 | /* Local Variables */ |
---|
415 | |
---|
416 | Bogie *p; |
---|
417 | |
---|
418 | /* Abort if the list is empty or no name is given */ |
---|
419 | |
---|
420 | if ((name == NULL) || (bl == NULL)) |
---|
421 | return NULL; |
---|
422 | |
---|
423 | /* Search the list for the desired name */ |
---|
424 | |
---|
425 | p = bl; |
---|
426 | while (p != NULL) { |
---|
427 | if (strcmp(p->name, name) == 0) |
---|
428 | return p; |
---|
429 | p = p->next; |
---|
430 | } |
---|
431 | |
---|
432 | /* Not found */ |
---|
433 | |
---|
434 | return NULL; |
---|
435 | } |
---|
436 | |
---|
437 | #ifdef HAVE_PING |
---|
438 | |
---|
439 | /* |
---|
440 | * Lookup the address for a ping target; |
---|
441 | * |
---|
442 | * Args: |
---|
443 | * target - The ping_target fill in the address for. |
---|
444 | * |
---|
445 | * Returns: |
---|
446 | * 1 if the host was successfully resolved, 0 otherwise. |
---|
447 | */ |
---|
448 | |
---|
449 | static int |
---|
450 | lookupHost(ping_target *target) |
---|
451 | { |
---|
452 | struct hostent *hent; |
---|
453 | struct sockaddr_in *iaddr; |
---|
454 | |
---|
455 | int iip[4]; |
---|
456 | char c; |
---|
457 | |
---|
458 | iaddr = (struct sockaddr_in *) &(target->address); |
---|
459 | iaddr->sin_family = AF_INET; |
---|
460 | |
---|
461 | if (4 == sscanf(target->name, "%d.%d.%d.%d%c", |
---|
462 | &iip[0], &iip[1], &iip[2], &iip[3], &c)) |
---|
463 | { |
---|
464 | /* It's an IP address. |
---|
465 | */ |
---|
466 | unsigned char ip[4]; |
---|
467 | |
---|
468 | ip[0] = iip[0]; |
---|
469 | ip[1] = iip[1]; |
---|
470 | ip[2] = iip[2]; |
---|
471 | ip[3] = iip[3]; |
---|
472 | |
---|
473 | if (ip[3] == 0) |
---|
474 | { |
---|
475 | if (debug_p > 1) |
---|
476 | fprintf (stderr, "%s: ignoring bogus IP %s\n", |
---|
477 | progname, target->name); |
---|
478 | return 0; |
---|
479 | } |
---|
480 | |
---|
481 | iaddr->sin_addr.s_addr = ((ip[3] << 24) | |
---|
482 | (ip[2] << 16) | |
---|
483 | (ip[1] << 8) | |
---|
484 | (ip[0])); |
---|
485 | hent = gethostbyaddr ((const char *) ip, 4, AF_INET); |
---|
486 | |
---|
487 | if (debug_p > 1) |
---|
488 | fprintf (stderr, "%s: %s => %s\n", |
---|
489 | progname, target->name, |
---|
490 | ((hent && hent->h_name && *hent->h_name) |
---|
491 | ? hent->h_name : "<unknown>")); |
---|
492 | |
---|
493 | if (hent && hent->h_name && *hent->h_name) |
---|
494 | target->name = strdup (hent->h_name); |
---|
495 | } |
---|
496 | else |
---|
497 | { |
---|
498 | /* It's a host name. |
---|
499 | */ |
---|
500 | hent = gethostbyname (target->name); |
---|
501 | if (!hent) |
---|
502 | { |
---|
503 | fprintf (stderr, "%s: could not resolve host: %s\n", |
---|
504 | progname, target->name); |
---|
505 | return 0; |
---|
506 | } |
---|
507 | |
---|
508 | memcpy (&iaddr->sin_addr, hent->h_addr_list[0], |
---|
509 | sizeof(iaddr->sin_addr)); |
---|
510 | |
---|
511 | if (debug_p > 1) |
---|
512 | fprintf (stderr, "%s: %s => %d.%d.%d.%d\n", |
---|
513 | progname, target->name, |
---|
514 | iaddr->sin_addr.s_addr & 255, |
---|
515 | iaddr->sin_addr.s_addr >> 8 & 255, |
---|
516 | iaddr->sin_addr.s_addr >> 16 & 255, |
---|
517 | iaddr->sin_addr.s_addr >> 24 & 255); |
---|
518 | } |
---|
519 | return 1; |
---|
520 | } |
---|
521 | |
---|
522 | |
---|
523 | static void |
---|
524 | print_host (FILE *out, unsigned long ip, const char *name) |
---|
525 | { |
---|
526 | char ips[50]; |
---|
527 | sprintf (ips, "%lu.%lu.%lu.%lu", |
---|
528 | (ip) & 255, |
---|
529 | (ip >> 8) & 255, |
---|
530 | (ip >> 16) & 255, |
---|
531 | (ip >> 24) & 255); |
---|
532 | if (!name || !*name) name = "<unknown>"; |
---|
533 | fprintf (out, "%-16s %s\n", ips, name); |
---|
534 | } |
---|
535 | |
---|
536 | |
---|
537 | /* |
---|
538 | * Create a target for a host. |
---|
539 | * |
---|
540 | * Args: |
---|
541 | * name - The name of the host. |
---|
542 | * |
---|
543 | * Returns: |
---|
544 | * A newly allocated target or null if the host could not be resolved. |
---|
545 | */ |
---|
546 | |
---|
547 | static ping_target * |
---|
548 | newHost(char *name) |
---|
549 | { |
---|
550 | |
---|
551 | /* Local Variables */ |
---|
552 | |
---|
553 | ping_target *target = NULL; |
---|
554 | |
---|
555 | /* Create the target */ |
---|
556 | |
---|
557 | if ((target = calloc(1, sizeof(ping_target))) == NULL) { |
---|
558 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
559 | goto target_init_error; |
---|
560 | } |
---|
561 | if ((target->name = strdup(name)) == NULL) { |
---|
562 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
563 | goto target_init_error; |
---|
564 | } |
---|
565 | |
---|
566 | /* Lookup the host */ |
---|
567 | |
---|
568 | if (! lookupHost(target)) |
---|
569 | goto target_init_error; |
---|
570 | |
---|
571 | /* Don't ever use loopback (127.0.0) hosts */ |
---|
572 | { |
---|
573 | struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address); |
---|
574 | unsigned long ip = iaddr->sin_addr.s_addr; |
---|
575 | if ((ip & 255) == 127 && |
---|
576 | ((ip >> 8) & 255) == 0 && |
---|
577 | ((ip >> 16) & 255) == 0) |
---|
578 | { |
---|
579 | if (debug_p) |
---|
580 | fprintf (stderr, "%s: ignoring loopback host %s\n", |
---|
581 | progname, target->name); |
---|
582 | goto target_init_error; |
---|
583 | } |
---|
584 | } |
---|
585 | |
---|
586 | /* Done */ |
---|
587 | |
---|
588 | if (debug_p) |
---|
589 | { |
---|
590 | struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address); |
---|
591 | unsigned long ip = iaddr->sin_addr.s_addr; |
---|
592 | fprintf (stderr, "%s: added ", progname); |
---|
593 | print_host (stderr, ip, target->name); |
---|
594 | } |
---|
595 | |
---|
596 | return target; |
---|
597 | |
---|
598 | /* Handle errors here */ |
---|
599 | |
---|
600 | target_init_error: |
---|
601 | if (target != NULL) |
---|
602 | free(target); |
---|
603 | return NULL; |
---|
604 | } |
---|
605 | |
---|
606 | /* |
---|
607 | * Generate a list of ping targets from the entries in a file. |
---|
608 | * |
---|
609 | * Args: |
---|
610 | * fname - The name of the file. This file is expected to be in the same |
---|
611 | * format as /etc/hosts. |
---|
612 | * |
---|
613 | * Returns: |
---|
614 | * A list of targets to ping or null if an error occured. |
---|
615 | */ |
---|
616 | |
---|
617 | static ping_target * |
---|
618 | readPingHostsFile(char *fname) |
---|
619 | { |
---|
620 | /* Local Variables */ |
---|
621 | |
---|
622 | FILE *fp; |
---|
623 | char buf[LINE_MAX]; |
---|
624 | char *p; |
---|
625 | ping_target *list = NULL; |
---|
626 | char *addr, *name; |
---|
627 | ping_target *new; |
---|
628 | |
---|
629 | /* Make sure we in fact have a file to process */ |
---|
630 | |
---|
631 | if ((fname == NULL) || (fname[0] == '\0')) { |
---|
632 | fprintf(stderr, "%s: invalid ping host file name\n", progname); |
---|
633 | return NULL; |
---|
634 | } |
---|
635 | |
---|
636 | /* Open the file */ |
---|
637 | |
---|
638 | if ((fp = fopen(fname, "r")) == NULL) { |
---|
639 | char msg[1024]; |
---|
640 | sprintf(msg, "%s: unable to open host file %s", progname, fname); |
---|
641 | perror(msg); |
---|
642 | return NULL; |
---|
643 | } |
---|
644 | |
---|
645 | if (debug_p) |
---|
646 | fprintf (stderr, "%s: reading file %s\n", progname, fname); |
---|
647 | |
---|
648 | /* Read the file line by line */ |
---|
649 | |
---|
650 | while ((p = fgets(buf, LINE_MAX, fp)) != NULL) { |
---|
651 | |
---|
652 | /* |
---|
653 | * Parse the line skipping those that start with '#'. |
---|
654 | * The rest of the lines in the file should be in the same |
---|
655 | * format as a /etc/hosts file. We are only concerned with |
---|
656 | * the first two field, the IP address and the name |
---|
657 | */ |
---|
658 | |
---|
659 | while ((*p == ' ') || (*p == '\t')) |
---|
660 | p++; |
---|
661 | if (*p == '#') |
---|
662 | continue; |
---|
663 | |
---|
664 | /* Get the name and address */ |
---|
665 | |
---|
666 | name = addr = NULL; |
---|
667 | if ((addr = strtok(buf, " ,;\t\n")) != NULL) |
---|
668 | name = strtok(NULL, " ,;\t\n"); |
---|
669 | else |
---|
670 | continue; |
---|
671 | |
---|
672 | /* Check to see if the addr looks like an addr. If not, assume |
---|
673 | the addr is a name and there is no addr. This way, we can |
---|
674 | handle files whose lines have "xx.xx.xx.xx hostname" as their |
---|
675 | first two tokens, and also files that have a hostname as their |
---|
676 | first token (like .ssh/known_hosts and .rhosts.) |
---|
677 | */ |
---|
678 | { |
---|
679 | int i; char c; |
---|
680 | if (4 != sscanf(addr, "%d.%d.%d.%d%c", &i, &i, &i, &i, &c)) |
---|
681 | { |
---|
682 | name = addr; |
---|
683 | addr = NULL; |
---|
684 | } |
---|
685 | } |
---|
686 | |
---|
687 | /* If the name is all digits, it's not a name. */ |
---|
688 | if (name) |
---|
689 | { |
---|
690 | const char *s; |
---|
691 | for (s = name; *s; s++) |
---|
692 | if (*s < '0' || *s > '9') |
---|
693 | break; |
---|
694 | if (! *s) |
---|
695 | { |
---|
696 | if (debug_p > 1) |
---|
697 | fprintf (stderr, "%s: skipping bogus name \"%s\" (%s)\n", |
---|
698 | progname, name, addr); |
---|
699 | name = NULL; |
---|
700 | } |
---|
701 | } |
---|
702 | |
---|
703 | /* Create a new target using first the name then the address */ |
---|
704 | |
---|
705 | new = NULL; |
---|
706 | if (name != NULL) |
---|
707 | new = newHost(name); |
---|
708 | if (new == NULL && addr != NULL) |
---|
709 | new = newHost(addr); |
---|
710 | |
---|
711 | /* Add it to the list if we got one */ |
---|
712 | |
---|
713 | if (new != NULL) { |
---|
714 | new->next = list; |
---|
715 | list = new; |
---|
716 | } |
---|
717 | } |
---|
718 | |
---|
719 | /* Close the file and return the list */ |
---|
720 | |
---|
721 | fclose(fp); |
---|
722 | return list; |
---|
723 | } |
---|
724 | |
---|
725 | |
---|
726 | static ping_target * |
---|
727 | delete_duplicate_hosts (ping_target *list) |
---|
728 | { |
---|
729 | ping_target *head = list; |
---|
730 | ping_target *rest; |
---|
731 | |
---|
732 | for (rest = head; rest; rest = rest->next) |
---|
733 | { |
---|
734 | struct sockaddr_in *i1 = (struct sockaddr_in *) &(rest->address); |
---|
735 | unsigned long ip1 = i1->sin_addr.s_addr; |
---|
736 | |
---|
737 | static ping_target *rest2; |
---|
738 | for (rest2 = rest; rest2; rest2 = rest2->next) |
---|
739 | { |
---|
740 | if (rest2 && rest2->next) |
---|
741 | { |
---|
742 | struct sockaddr_in *i2 = (struct sockaddr_in *) |
---|
743 | &(rest2->next->address); |
---|
744 | unsigned long ip2 = i2->sin_addr.s_addr; |
---|
745 | |
---|
746 | if (ip1 == ip2) |
---|
747 | { |
---|
748 | if (debug_p) |
---|
749 | { |
---|
750 | fprintf (stderr, "%s: deleted duplicate: ", progname); |
---|
751 | print_host (stderr, ip2, rest2->next->name); |
---|
752 | } |
---|
753 | rest2->next = rest2->next->next; |
---|
754 | } |
---|
755 | } |
---|
756 | } |
---|
757 | } |
---|
758 | |
---|
759 | return head; |
---|
760 | } |
---|
761 | |
---|
762 | |
---|
763 | |
---|
764 | |
---|
765 | /* |
---|
766 | * Generate a list ping targets consisting of all of the entries on |
---|
767 | * the same subnet. |
---|
768 | * |
---|
769 | * Returns: |
---|
770 | * A list of all of the hosts on this net. |
---|
771 | */ |
---|
772 | |
---|
773 | static ping_target * |
---|
774 | subnetHostsList(int base, int subnet_width) |
---|
775 | { |
---|
776 | unsigned long mask; |
---|
777 | |
---|
778 | /* Local Variables */ |
---|
779 | |
---|
780 | char hostname[BUFSIZ]; |
---|
781 | char address[BUFSIZ]; |
---|
782 | struct hostent *hent; |
---|
783 | char *p; |
---|
784 | int i; |
---|
785 | ping_target *new; |
---|
786 | ping_target *list = NULL; |
---|
787 | |
---|
788 | if (subnet_width < 24) |
---|
789 | { |
---|
790 | fprintf (stderr, |
---|
791 | "%s: pinging %lu hosts is a bad idea; please use a subnet mask of 24 bits\n" |
---|
792 | " or more (255 hosts max.)\n", |
---|
793 | progname, (unsigned long) (1L << (32 - subnet_width)) - 1); |
---|
794 | exit (1); |
---|
795 | } |
---|
796 | else if (subnet_width > 30) |
---|
797 | { |
---|
798 | fprintf (stderr, "%s: a subnet of %d bits doesn't make sense:" |
---|
799 | " try \"subnet/24\" or \"subnet/29\".\n", |
---|
800 | progname, subnet_width); |
---|
801 | exit (1); |
---|
802 | } |
---|
803 | |
---|
804 | |
---|
805 | if (debug_p) |
---|
806 | fprintf (stderr, "%s: adding %d-bit subnet\n", progname, subnet_width); |
---|
807 | |
---|
808 | /* Get our hostname */ |
---|
809 | |
---|
810 | if (gethostname(hostname, BUFSIZ)) { |
---|
811 | fprintf(stderr, "%s: unable to get local hostname\n", progname); |
---|
812 | return NULL; |
---|
813 | } |
---|
814 | |
---|
815 | /* Get our IP address and convert it to a string */ |
---|
816 | |
---|
817 | if ((hent = gethostbyname(hostname)) == NULL) { |
---|
818 | fprintf(stderr, "%s: unable to lookup our IP address\n", progname); |
---|
819 | return NULL; |
---|
820 | } |
---|
821 | strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0]))); |
---|
822 | |
---|
823 | /* Construct targets for all addresses in this subnet */ |
---|
824 | |
---|
825 | mask = 0; |
---|
826 | for (i = 0; i < subnet_width; i++) |
---|
827 | mask |= (1L << (31-i)); |
---|
828 | |
---|
829 | /* If no base IP specified, assume localhost. */ |
---|
830 | if (base == 0) |
---|
831 | base = ((((unsigned char) hent->h_addr_list[0][0]) << 24) | |
---|
832 | (((unsigned char) hent->h_addr_list[0][1]) << 16) | |
---|
833 | (((unsigned char) hent->h_addr_list[0][2]) << 8) | |
---|
834 | (((unsigned char) hent->h_addr_list[0][3]))); |
---|
835 | |
---|
836 | if (base == ((127 << 24) | 1)) |
---|
837 | { |
---|
838 | fprintf (stderr, |
---|
839 | "%s: unable to determine local subnet address: \"%s\"\n" |
---|
840 | " resolves to loopback address %d.%d.%d.%d.\n", |
---|
841 | progname, hostname, |
---|
842 | (base >> 24) & 255, (base >> 16) & 255, |
---|
843 | (base >> 8) & 255, (base ) & 255); |
---|
844 | return NULL; |
---|
845 | } |
---|
846 | |
---|
847 | for (i = 255; i >= 0; i--) { |
---|
848 | int ip = (base & 0xFFFFFF00) | i; |
---|
849 | |
---|
850 | if ((ip & mask) != (base & mask)) /* not in the mask range at all */ |
---|
851 | continue; |
---|
852 | if ((ip & ~mask) == 0) /* broadcast address */ |
---|
853 | continue; |
---|
854 | if ((ip & ~mask) == ~mask) /* broadcast address */ |
---|
855 | continue; |
---|
856 | |
---|
857 | sprintf (address, "%d.%d.%d.%d", |
---|
858 | (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, (ip)&255); |
---|
859 | |
---|
860 | if (debug_p > 1) |
---|
861 | fprintf(stderr, "%s: subnet: %s (%d.%d.%d.%d & %d.%d.%d.%d / %d)\n", |
---|
862 | progname, |
---|
863 | address, |
---|
864 | (int) (base>>24)&255, |
---|
865 | (int) (base>>16)&255, |
---|
866 | (int) (base>> 8)&255, |
---|
867 | (int) (base&mask&255), |
---|
868 | (int) (mask>>24)&255, |
---|
869 | (int) (mask>>16)&255, |
---|
870 | (int) (mask>> 8)&255, |
---|
871 | (int) (mask&255), |
---|
872 | (int) subnet_width); |
---|
873 | |
---|
874 | p = address + strlen(address) + 1; |
---|
875 | sprintf(p, "%d", i); |
---|
876 | |
---|
877 | new = newHost(address); |
---|
878 | if (new != NULL) { |
---|
879 | new->next = list; |
---|
880 | list = new; |
---|
881 | } |
---|
882 | } |
---|
883 | |
---|
884 | /* Done */ |
---|
885 | |
---|
886 | return list; |
---|
887 | } |
---|
888 | |
---|
889 | /* |
---|
890 | * Initialize the ping sensor. |
---|
891 | * |
---|
892 | * Returns: |
---|
893 | * A newly allocated ping_info structure or null if an error occured. |
---|
894 | */ |
---|
895 | |
---|
896 | static ping_target *parse_mode (Bool ping_works_p); |
---|
897 | |
---|
898 | static ping_info * |
---|
899 | init_ping(void) |
---|
900 | { |
---|
901 | |
---|
902 | Bool socket_initted_p = False; |
---|
903 | |
---|
904 | /* Local Variables */ |
---|
905 | |
---|
906 | ping_info *pi = NULL; /* The new ping_info struct */ |
---|
907 | ping_target *pt; /* Used to count the targets */ |
---|
908 | |
---|
909 | /* Create the ping info structure */ |
---|
910 | |
---|
911 | if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) { |
---|
912 | fprintf(stderr, "%s: Out of memory\n", progname); |
---|
913 | goto ping_init_error; |
---|
914 | } |
---|
915 | |
---|
916 | /* Create the ICMP socket */ |
---|
917 | |
---|
918 | if ((pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) >= 0) { |
---|
919 | socket_initted_p = True; |
---|
920 | } |
---|
921 | |
---|
922 | /* Disavow privs */ |
---|
923 | |
---|
924 | setuid(getuid()); |
---|
925 | |
---|
926 | |
---|
927 | pi->pid = getpid() & 0xFFFF; |
---|
928 | pi->seq = 0; |
---|
929 | pi->timeout = get_integer_resource("pingTimeout", "PingTimeout"); |
---|
930 | |
---|
931 | /* Generate a list of targets */ |
---|
932 | |
---|
933 | pi->targets = parse_mode (socket_initted_p); |
---|
934 | pi->targets = delete_duplicate_hosts (pi->targets); |
---|
935 | |
---|
936 | |
---|
937 | if (debug_p) |
---|
938 | { |
---|
939 | ping_target *t; |
---|
940 | fprintf (stderr, "%s: Target list:\n", progname); |
---|
941 | for (t = pi->targets; t; t = t->next) |
---|
942 | { |
---|
943 | struct sockaddr_in *iaddr = (struct sockaddr_in *) &(t->address); |
---|
944 | unsigned long ip = iaddr->sin_addr.s_addr; |
---|
945 | fprintf (stderr, "%s: ", progname); |
---|
946 | print_host (stderr, ip, t->name); |
---|
947 | } |
---|
948 | } |
---|
949 | |
---|
950 | /* Make sure there is something to ping */ |
---|
951 | |
---|
952 | if (pi->targets == NULL) { |
---|
953 | goto ping_init_error; |
---|
954 | } |
---|
955 | |
---|
956 | /* Count the targets */ |
---|
957 | |
---|
958 | pt = pi->targets; |
---|
959 | pi->numtargets = 0; |
---|
960 | while (pt != NULL) { |
---|
961 | pi->numtargets++; |
---|
962 | pt = pt->next; |
---|
963 | } |
---|
964 | |
---|
965 | /* Done */ |
---|
966 | |
---|
967 | return pi; |
---|
968 | |
---|
969 | /* Handle initialization errors here */ |
---|
970 | |
---|
971 | ping_init_error: |
---|
972 | if (pi != NULL) |
---|
973 | free(pi); |
---|
974 | return NULL; |
---|
975 | } |
---|
976 | |
---|
977 | |
---|
978 | /* |
---|
979 | * Ping a host. |
---|
980 | * |
---|
981 | * Args: |
---|
982 | * pi - The ping information strcuture. |
---|
983 | * host - The name or IP address of the host to ping (in ascii). |
---|
984 | */ |
---|
985 | |
---|
986 | static void |
---|
987 | sendping(ping_info *pi, ping_target *pt) |
---|
988 | { |
---|
989 | |
---|
990 | /* Local Variables */ |
---|
991 | |
---|
992 | u_char *packet; |
---|
993 | struct ICMP *icmph; |
---|
994 | int result; |
---|
995 | |
---|
996 | /* |
---|
997 | * Note, we will send the character name of the host that we are |
---|
998 | * pinging in the packet so that we don't have to keep track of the |
---|
999 | * name or do an address lookup when it comes back. |
---|
1000 | */ |
---|
1001 | |
---|
1002 | int pcktsiz = sizeof(struct ICMP) + sizeof(struct timeval) + |
---|
1003 | strlen(pt->name) + 1; |
---|
1004 | |
---|
1005 | /* Create the ICMP packet */ |
---|
1006 | |
---|
1007 | if ((packet = (u_char *) malloc(pcktsiz)) == (void *) 0) |
---|
1008 | return; /* Out of memory */ |
---|
1009 | icmph = (struct ICMP *) packet; |
---|
1010 | ICMP_TYPE(icmph) = ICMP_ECHO; |
---|
1011 | ICMP_CODE(icmph) = 0; |
---|
1012 | ICMP_CHECKSUM(icmph) = 0; |
---|
1013 | ICMP_ID(icmph) = pi->pid; |
---|
1014 | ICMP_SEQ(icmph) = pi->seq++; |
---|
1015 | # ifdef GETTIMEOFDAY_TWO_ARGS |
---|
1016 | gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)], |
---|
1017 | (struct timezone *) 0); |
---|
1018 | # else |
---|
1019 | gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)]); |
---|
1020 | # endif |
---|
1021 | |
---|
1022 | strcpy((char *) &packet[sizeof(struct ICMP) + sizeof(struct timeval)], |
---|
1023 | pt->name); |
---|
1024 | ICMP_CHECKSUM(icmph) = checksum((u_short *)packet, pcktsiz); |
---|
1025 | |
---|
1026 | /* Send it */ |
---|
1027 | |
---|
1028 | if ((result = sendto(pi->icmpsock, packet, pcktsiz, 0, |
---|
1029 | &pt->address, sizeof(pt->address))) != pcktsiz) { |
---|
1030 | #if 0 |
---|
1031 | char errbuf[BUFSIZ]; |
---|
1032 | sprintf(errbuf, "%s: error sending ping to %s", progname, pt->name); |
---|
1033 | perror(errbuf); |
---|
1034 | #endif |
---|
1035 | } |
---|
1036 | } |
---|
1037 | |
---|
1038 | /* |
---|
1039 | * Catch a signal and do nothing. |
---|
1040 | * |
---|
1041 | * Args: |
---|
1042 | * sig - The signal that was caught. |
---|
1043 | */ |
---|
1044 | |
---|
1045 | static void |
---|
1046 | sigcatcher(int sig) |
---|
1047 | { |
---|
1048 | timer_expired = 1; |
---|
1049 | } |
---|
1050 | |
---|
1051 | /* |
---|
1052 | * Compute the checksum on a ping packet. |
---|
1053 | * |
---|
1054 | * Args: |
---|
1055 | * packet - A pointer to the packet to compute the checksum for. |
---|
1056 | * size - The size of the packet. |
---|
1057 | * |
---|
1058 | * Returns: |
---|
1059 | * The computed checksum |
---|
1060 | * |
---|
1061 | */ |
---|
1062 | |
---|
1063 | static u_short |
---|
1064 | checksum(u_short *packet, int size) |
---|
1065 | { |
---|
1066 | |
---|
1067 | /* Local Variables */ |
---|
1068 | |
---|
1069 | register int nleft = size; |
---|
1070 | register u_short *w = packet; |
---|
1071 | register int sum = 0; |
---|
1072 | u_short answer = 0; |
---|
1073 | |
---|
1074 | /* |
---|
1075 | * Our algorithm is simple, using a 32 bit accumulator (sum), we add |
---|
1076 | * sequential 16 bit words to it, and at the end, fold back all the |
---|
1077 | * carry bits from the top 16 bits into the lower 16 bits. |
---|
1078 | */ |
---|
1079 | |
---|
1080 | while (nleft > 1) { |
---|
1081 | sum += *w++; |
---|
1082 | nleft -= 2; |
---|
1083 | } |
---|
1084 | |
---|
1085 | /* mop up an odd byte, if necessary */ |
---|
1086 | |
---|
1087 | if (nleft == 1) { |
---|
1088 | *(u_char *)(&answer) = *(u_char *)w ; |
---|
1089 | *(1 + (u_char *)(&answer)) = 0; |
---|
1090 | sum += answer; |
---|
1091 | } |
---|
1092 | |
---|
1093 | /* add back carry outs from top 16 bits to low 16 bits */ |
---|
1094 | |
---|
1095 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
---|
1096 | sum += (sum >> 16); /* add carry */ |
---|
1097 | answer = ~sum; /* truncate to 16 bits */ |
---|
1098 | |
---|
1099 | /* Done */ |
---|
1100 | |
---|
1101 | return(answer); |
---|
1102 | } |
---|
1103 | |
---|
1104 | /* |
---|
1105 | * Look for ping replies. |
---|
1106 | * |
---|
1107 | * Retrieve all outstanding ping replies. |
---|
1108 | * |
---|
1109 | * Args: |
---|
1110 | * si - Information about the sonar. |
---|
1111 | * pi - Ping information. |
---|
1112 | * ttl - The time each bogie is to live on the screen |
---|
1113 | * |
---|
1114 | * Returns: |
---|
1115 | * A Bogie list of all the machines that replied. |
---|
1116 | */ |
---|
1117 | |
---|
1118 | static Bogie * |
---|
1119 | getping(sonar_info *si, ping_info *pi) |
---|
1120 | { |
---|
1121 | |
---|
1122 | /* Local Variables */ |
---|
1123 | |
---|
1124 | struct sockaddr from; |
---|
1125 | unsigned int fromlen; /* Posix says socklen_t, but that's not portable */ |
---|
1126 | int result; |
---|
1127 | u_char packet[1024]; |
---|
1128 | struct timeval now; |
---|
1129 | struct timeval *then; |
---|
1130 | struct ip *ip; |
---|
1131 | int iphdrlen; |
---|
1132 | struct ICMP *icmph; |
---|
1133 | Bogie *bl = NULL; |
---|
1134 | Bogie *new; |
---|
1135 | char *name; |
---|
1136 | struct sigaction sa; |
---|
1137 | struct itimerval it; |
---|
1138 | fd_set rfds; |
---|
1139 | struct timeval tv; |
---|
1140 | |
---|
1141 | /* Set up a signal to interupt our wait for a packet */ |
---|
1142 | |
---|
1143 | sigemptyset(&sa.sa_mask); |
---|
1144 | sa.sa_flags = 0; |
---|
1145 | sa.sa_handler = sigcatcher; |
---|
1146 | if (sigaction(SIGALRM, &sa, 0) == -1) { |
---|
1147 | char msg[1024]; |
---|
1148 | sprintf(msg, "%s: unable to trap SIGALRM", progname); |
---|
1149 | perror(msg); |
---|
1150 | exit(1); |
---|
1151 | } |
---|
1152 | |
---|
1153 | /* Set up a timer to interupt us if we don't get a packet */ |
---|
1154 | |
---|
1155 | it.it_interval.tv_sec = 0; |
---|
1156 | it.it_interval.tv_usec = 0; |
---|
1157 | it.it_value.tv_sec = 0; |
---|
1158 | it.it_value.tv_usec = pi->timeout; |
---|
1159 | timer_expired = 0; |
---|
1160 | setitimer(ITIMER_REAL, &it, NULL); |
---|
1161 | |
---|
1162 | /* Wait for a result packet */ |
---|
1163 | |
---|
1164 | fromlen = sizeof(from); |
---|
1165 | while (! timer_expired) { |
---|
1166 | tv.tv_usec=pi->timeout; |
---|
1167 | tv.tv_sec=0; |
---|
1168 | #if 0 |
---|
1169 | /* This breaks on BSD, which uses bzero() in the definition of FD_ZERO */ |
---|
1170 | FD_ZERO(&rfds); |
---|
1171 | #else |
---|
1172 | memset (&rfds, 0, sizeof(rfds)); |
---|
1173 | #endif |
---|
1174 | FD_SET(pi->icmpsock,&rfds); |
---|
1175 | /* only wait a little while, in case we raced with the timer expiration. |
---|
1176 | From Valentijn Sessink <valentyn@openoffice.nl> */ |
---|
1177 | if (select(pi->icmpsock+1, &rfds, NULL, NULL, &tv) >0) { |
---|
1178 | result = recvfrom(pi->icmpsock, packet, sizeof(packet), |
---|
1179 | 0, &from, &fromlen); |
---|
1180 | |
---|
1181 | /* Check the packet */ |
---|
1182 | |
---|
1183 | # ifdef GETTIMEOFDAY_TWO_ARGS |
---|
1184 | gettimeofday(&now, (struct timezone *) 0); |
---|
1185 | # else |
---|
1186 | gettimeofday(&now); |
---|
1187 | # endif |
---|
1188 | ip = (struct ip *) packet; |
---|
1189 | iphdrlen = IP_HDRLEN(ip) << 2; |
---|
1190 | icmph = (struct ICMP *) &packet[iphdrlen]; |
---|
1191 | |
---|
1192 | /* Was the packet a reply?? */ |
---|
1193 | |
---|
1194 | if (ICMP_TYPE(icmph) != ICMP_ECHOREPLY) { |
---|
1195 | /* Ignore anything but ICMP Replies */ |
---|
1196 | continue; /* Nope */ |
---|
1197 | } |
---|
1198 | |
---|
1199 | /* Was it for us? */ |
---|
1200 | |
---|
1201 | if (ICMP_ID(icmph) != pi->pid) { |
---|
1202 | /* Ignore packets not set from us */ |
---|
1203 | continue; /* Nope */ |
---|
1204 | } |
---|
1205 | |
---|
1206 | /* Copy the name of the bogie */ |
---|
1207 | |
---|
1208 | if ((name = |
---|
1209 | strdup((char *) &packet[iphdrlen + |
---|
1210 | + sizeof(struct ICMP) |
---|
1211 | + sizeof(struct timeval)])) == NULL) { |
---|
1212 | fprintf(stderr, "%s: Out of memory\n", progname); |
---|
1213 | return bl; |
---|
1214 | } |
---|
1215 | |
---|
1216 | /* If the name is an IP addr, try to resolve it. */ |
---|
1217 | { |
---|
1218 | int iip[4]; |
---|
1219 | char c; |
---|
1220 | if (4 == sscanf(name, " %d.%d.%d.%d %c", |
---|
1221 | &iip[0], &iip[1], &iip[2], &iip[3], &c)) |
---|
1222 | { |
---|
1223 | unsigned char ip[4]; |
---|
1224 | struct hostent *h; |
---|
1225 | ip[0] = iip[0]; ip[1] = iip[1]; ip[2] = iip[2]; ip[3] = iip[3]; |
---|
1226 | h = gethostbyaddr ((char *) ip, 4, AF_INET); |
---|
1227 | if (h && h->h_name && *h->h_name) |
---|
1228 | { |
---|
1229 | free (name); |
---|
1230 | name = strdup (h->h_name); |
---|
1231 | } |
---|
1232 | } |
---|
1233 | } |
---|
1234 | |
---|
1235 | /* Create the new Bogie and add it to the list we are building */ |
---|
1236 | |
---|
1237 | if ((new = newBogie(name, 0, si->current, si->TTL)) == NULL) |
---|
1238 | return bl; |
---|
1239 | new->next = bl; |
---|
1240 | bl = new; |
---|
1241 | |
---|
1242 | /* Compute the round trip time */ |
---|
1243 | |
---|
1244 | then = (struct timeval *) &packet[iphdrlen + |
---|
1245 | sizeof(struct ICMP)]; |
---|
1246 | new->distance = delta(then, &now) / 100; |
---|
1247 | if (new->distance == 0) |
---|
1248 | new->distance = 2; /* HACK */ |
---|
1249 | } |
---|
1250 | } |
---|
1251 | |
---|
1252 | /* Done */ |
---|
1253 | |
---|
1254 | return bl; |
---|
1255 | } |
---|
1256 | |
---|
1257 | /* |
---|
1258 | * Ping hosts. |
---|
1259 | * |
---|
1260 | * Args: |
---|
1261 | * si - Sonar Information. |
---|
1262 | * pi - Ping Information. |
---|
1263 | * |
---|
1264 | * Returns: |
---|
1265 | * A list of hosts that replied to pings or null if there were none. |
---|
1266 | */ |
---|
1267 | |
---|
1268 | static Bogie * |
---|
1269 | ping(sonar_info *si, void *vpi) |
---|
1270 | { |
---|
1271 | |
---|
1272 | /* |
---|
1273 | * This tries to distribute the targets evely around the field of the |
---|
1274 | * sonar. |
---|
1275 | */ |
---|
1276 | |
---|
1277 | ping_info *pi = (ping_info *) vpi; |
---|
1278 | static ping_target *ptr = NULL; |
---|
1279 | |
---|
1280 | int tick = si->current * -1 + 1; |
---|
1281 | if ((ptr == NULL) && (tick == 1)) |
---|
1282 | ptr = pi->targets; |
---|
1283 | |
---|
1284 | if (pi->numtargets <= 90) { |
---|
1285 | int xdrant = 90 / pi->numtargets; |
---|
1286 | if ((tick % xdrant) == 0) { |
---|
1287 | if (ptr != (ping_target *) 0) { |
---|
1288 | sendping(pi, ptr); |
---|
1289 | ptr = ptr->next; |
---|
1290 | } |
---|
1291 | } |
---|
1292 | |
---|
1293 | } else if (pi->numtargets > 90) { |
---|
1294 | if (ptr != (ping_target *) 0) { |
---|
1295 | sendping(pi, ptr); |
---|
1296 | ptr = ptr->next; |
---|
1297 | } |
---|
1298 | } |
---|
1299 | |
---|
1300 | /* Get the results */ |
---|
1301 | |
---|
1302 | return getping(si, pi); |
---|
1303 | } |
---|
1304 | |
---|
1305 | #endif /* HAVE_PING */ |
---|
1306 | |
---|
1307 | /* |
---|
1308 | * Calculate the difference between two timevals in microseconds. |
---|
1309 | * |
---|
1310 | * Args: |
---|
1311 | * then - The older timeval. |
---|
1312 | * now - The newer timeval. |
---|
1313 | * |
---|
1314 | * Returns: |
---|
1315 | * The difference between the two in microseconds. |
---|
1316 | */ |
---|
1317 | |
---|
1318 | static long |
---|
1319 | delta(struct timeval *then, struct timeval *now) |
---|
1320 | { |
---|
1321 | return (((now->tv_sec - then->tv_sec) * 1000000) + |
---|
1322 | (now->tv_usec - then->tv_usec)); |
---|
1323 | } |
---|
1324 | |
---|
1325 | /* |
---|
1326 | * Initialize the simulation mode. |
---|
1327 | */ |
---|
1328 | |
---|
1329 | static sim_info * |
---|
1330 | init_sim(void) |
---|
1331 | { |
---|
1332 | |
---|
1333 | /* Local Variables */ |
---|
1334 | |
---|
1335 | sim_info *si; |
---|
1336 | int i; |
---|
1337 | |
---|
1338 | /* Create the simulation info structure */ |
---|
1339 | |
---|
1340 | if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) { |
---|
1341 | fprintf(stderr, "%s: Out of memory\n", progname); |
---|
1342 | return NULL; |
---|
1343 | } |
---|
1344 | |
---|
1345 | /* Team A */ |
---|
1346 | |
---|
1347 | si->numA = get_integer_resource("teamACount", "TeamACount"); |
---|
1348 | if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target))) |
---|
1349 | == NULL) { |
---|
1350 | free(si); |
---|
1351 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
1352 | return NULL; |
---|
1353 | } |
---|
1354 | si->teamAID = get_string_resource("teamAName", "TeamAName"); |
---|
1355 | for (i = 0; i < si->numA; i++) { |
---|
1356 | if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4)) |
---|
1357 | == NULL) { |
---|
1358 | free(si); |
---|
1359 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
1360 | return NULL; |
---|
1361 | } |
---|
1362 | sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1); |
---|
1363 | si->teamA[i].nexttick = random() % 90; |
---|
1364 | si->teamA[i].nextdist = random() % 100; |
---|
1365 | si->teamA[i].movedonsweep = -1; |
---|
1366 | } |
---|
1367 | |
---|
1368 | /* Team B */ |
---|
1369 | |
---|
1370 | si->numB = get_integer_resource("teamBCount", "TeamBCount"); |
---|
1371 | if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target))) |
---|
1372 | == NULL) { |
---|
1373 | free(si); |
---|
1374 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
1375 | return NULL; |
---|
1376 | } |
---|
1377 | si->teamBID = get_string_resource("teamBName", "TeamBName"); |
---|
1378 | for (i = 0; i < si->numB; i++) { |
---|
1379 | if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4)) |
---|
1380 | == NULL) { |
---|
1381 | free(si); |
---|
1382 | fprintf(stderr, "%s: Out of Memory\n", progname); |
---|
1383 | return NULL; |
---|
1384 | } |
---|
1385 | sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1); |
---|
1386 | si->teamB[i].nexttick = random() % 90; |
---|
1387 | si->teamB[i].nextdist = random() % 100; |
---|
1388 | si->teamB[i].movedonsweep = -1; |
---|
1389 | } |
---|
1390 | |
---|
1391 | /* Done */ |
---|
1392 | |
---|
1393 | return si; |
---|
1394 | } |
---|
1395 | |
---|
1396 | /* |
---|
1397 | * Creates and returns a drawing mask for the scope: |
---|
1398 | * mask out anything outside of the disc. |
---|
1399 | */ |
---|
1400 | static Pixmap |
---|
1401 | scope_mask (Display *dpy, Window win, sonar_info *si) |
---|
1402 | { |
---|
1403 | XGCValues gcv; |
---|
1404 | Pixmap mask = XCreatePixmap(dpy, win, si->width, si->height, 1); |
---|
1405 | GC gc = XCreateGC (dpy, mask, 0, &gcv); |
---|
1406 | XSetFunction (dpy, gc, GXclear); |
---|
1407 | XFillRectangle (dpy, mask, gc, 0, 0, si->width, si->height); |
---|
1408 | XSetFunction (dpy, gc, GXset); |
---|
1409 | XFillArc(dpy, mask, gc, si->minx, si->miny, |
---|
1410 | si->maxx - si->minx, si->maxy - si->miny, |
---|
1411 | 0, 360 * 64); |
---|
1412 | return mask; |
---|
1413 | } |
---|
1414 | |
---|
1415 | |
---|
1416 | /* |
---|
1417 | * Initialize the Sonar. |
---|
1418 | * |
---|
1419 | * Args: |
---|
1420 | * dpy - The X display. |
---|
1421 | * win - The X window; |
---|
1422 | * |
---|
1423 | * Returns: |
---|
1424 | * A sonar_info strcuture or null if memory allocation problems occur. |
---|
1425 | */ |
---|
1426 | |
---|
1427 | static sonar_info * |
---|
1428 | init_sonar(Display *dpy, Window win) |
---|
1429 | { |
---|
1430 | |
---|
1431 | /* Local Variables */ |
---|
1432 | |
---|
1433 | XGCValues gcv; |
---|
1434 | XWindowAttributes xwa; |
---|
1435 | sonar_info *si; |
---|
1436 | XColor start, end; |
---|
1437 | int h1, h2; |
---|
1438 | double s1, s2, v1, v2; |
---|
1439 | |
---|
1440 | /* Create the Sonar information structure */ |
---|
1441 | |
---|
1442 | if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) { |
---|
1443 | fprintf(stderr, "%s: Out of memory\n", progname); |
---|
1444 | return NULL; |
---|
1445 | } |
---|
1446 | |
---|
1447 | /* Initialize the structure for the current environment */ |
---|
1448 | |
---|
1449 | si->dpy = dpy; |
---|
1450 | si->win = win; |
---|
1451 | si->visible = NULL; |
---|
1452 | XGetWindowAttributes(dpy, win, &xwa); |
---|
1453 | si->cmap = xwa.colormap; |
---|
1454 | si->width = xwa.width; |
---|
1455 | si->height = xwa.height; |
---|
1456 | si->centrex = si->width / 2; |
---|
1457 | si->centrey = si->height / 2; |
---|
1458 | si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10; |
---|
1459 | si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10; |
---|
1460 | si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10; |
---|
1461 | si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10; |
---|
1462 | si->radius = si->maxx - si->centrex; |
---|
1463 | si->current = 0; |
---|
1464 | si->sweepnum = 0; |
---|
1465 | |
---|
1466 | /* Get the font */ |
---|
1467 | |
---|
1468 | if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font"))) |
---|
1469 | == NULL) && |
---|
1470 | ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) { |
---|
1471 | fprintf(stderr, "%s: can't load an appropriate font\n", progname); |
---|
1472 | return NULL; |
---|
1473 | } |
---|
1474 | |
---|
1475 | /* Get the delay between animation frames */ |
---|
1476 | |
---|
1477 | si->delay = get_integer_resource ("delay", "Integer"); |
---|
1478 | |
---|
1479 | if (si->delay < 0) si->delay = 0; |
---|
1480 | si->TTL = get_integer_resource("ttl", "TTL"); |
---|
1481 | |
---|
1482 | /* Create the Graphics Contexts that will be used to draw things */ |
---|
1483 | |
---|
1484 | gcv.foreground = |
---|
1485 | get_pixel_resource ("sweepColor", "SweepColor", dpy, si->cmap); |
---|
1486 | si->hi = XCreateGC(dpy, win, GCForeground, &gcv); |
---|
1487 | gcv.font = si->font->fid; |
---|
1488 | si->text = XCreateGC(dpy, win, GCForeground|GCFont, &gcv); |
---|
1489 | gcv.foreground = get_pixel_resource("scopeColor", "ScopeColor", |
---|
1490 | dpy, si->cmap); |
---|
1491 | si->erase = XCreateGC (dpy, win, GCForeground, &gcv); |
---|
1492 | gcv.foreground = get_pixel_resource("gridColor", "GridColor", |
---|
1493 | dpy, si->cmap); |
---|
1494 | si->grid = XCreateGC (dpy, win, GCForeground, &gcv); |
---|
1495 | |
---|
1496 | /* Install the clip mask... */ |
---|
1497 | { |
---|
1498 | Pixmap mask = scope_mask (dpy, win, si); |
---|
1499 | XSetClipMask(dpy, si->text, mask); |
---|
1500 | XSetClipMask(dpy, si->erase, mask); |
---|
1501 | XFreePixmap (dpy, mask); /* it's been copied into the GCs */ |
---|
1502 | } |
---|
1503 | |
---|
1504 | /* Compute pixel values for fading text on the display */ |
---|
1505 | |
---|
1506 | XParseColor(dpy, si->cmap, |
---|
1507 | get_string_resource("textColor", "TextColor"), &start); |
---|
1508 | XParseColor(dpy, si->cmap, |
---|
1509 | get_string_resource("scopeColor", "ScopeColor"), &end); |
---|
1510 | |
---|
1511 | rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1); |
---|
1512 | rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2); |
---|
1513 | |
---|
1514 | si->text_steps = get_integer_resource("textSteps", "TextSteps"); |
---|
1515 | if (si->text_steps < 0 || si->text_steps > 255) |
---|
1516 | si->text_steps = 10; |
---|
1517 | |
---|
1518 | si->text_colors = (XColor *) calloc(si->text_steps, sizeof(XColor)); |
---|
1519 | make_color_ramp (dpy, si->cmap, |
---|
1520 | h1, s1, v1, |
---|
1521 | h2, s2, v2, |
---|
1522 | si->text_colors, &si->text_steps, |
---|
1523 | False, True, False); |
---|
1524 | |
---|
1525 | /* Compute the pixel values for the fading sweep */ |
---|
1526 | |
---|
1527 | XParseColor(dpy, si->cmap, |
---|
1528 | get_string_resource("sweepColor", "SweepColor"), &start); |
---|
1529 | |
---|
1530 | rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1); |
---|
1531 | |
---|
1532 | si->sweep_degrees = get_integer_resource("sweepDegrees", "Degrees"); |
---|
1533 | if (si->sweep_degrees <= 0) si->sweep_degrees = 20; |
---|
1534 | if (si->sweep_degrees > 350) si->sweep_degrees = 350; |
---|
1535 | |
---|
1536 | si->sweep_segs = get_integer_resource("sweepSegments", "SweepSegments"); |
---|
1537 | if (si->sweep_segs < 1 || si->sweep_segs > 255) |
---|
1538 | si->sweep_segs = 255; |
---|
1539 | |
---|
1540 | si->sweep_colors = (XColor *) calloc(si->sweep_segs, sizeof(XColor)); |
---|
1541 | make_color_ramp (dpy, si->cmap, |
---|
1542 | h1, s1, v1, |
---|
1543 | h2, s2, v2, |
---|
1544 | si->sweep_colors, &si->sweep_segs, |
---|
1545 | False, True, False); |
---|
1546 | |
---|
1547 | if (si->sweep_segs <= 0) |
---|
1548 | si->sweep_segs = 1; |
---|
1549 | |
---|
1550 | /* Done */ |
---|
1551 | |
---|
1552 | return si; |
---|
1553 | } |
---|
1554 | |
---|
1555 | /* |
---|
1556 | * Update the location of a simulated bogie. |
---|
1557 | */ |
---|
1558 | |
---|
1559 | static void |
---|
1560 | updateLocation(sim_target *t) |
---|
1561 | { |
---|
1562 | |
---|
1563 | int xdist, xtick; |
---|
1564 | |
---|
1565 | xtick = (int) (random() % 3) - 1; |
---|
1566 | xdist = (int) (random() % 11) - 5; |
---|
1567 | if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0)) |
---|
1568 | t->nexttick += xtick; |
---|
1569 | else |
---|
1570 | t->nexttick -= xtick; |
---|
1571 | if (((t->nextdist + xdist) < 100) && ((t->nextdist+xdist) >= 0)) |
---|
1572 | t->nextdist += xdist; |
---|
1573 | else |
---|
1574 | t->nextdist -= xdist; |
---|
1575 | } |
---|
1576 | |
---|
1577 | /* |
---|
1578 | * The simulator. This uses information in the sim_info to simulate a bunch |
---|
1579 | * of bogies flying around on the screen. |
---|
1580 | */ |
---|
1581 | |
---|
1582 | /* |
---|
1583 | * TODO: It would be cool to have the two teams chase each other around and |
---|
1584 | * shoot it out. |
---|
1585 | */ |
---|
1586 | |
---|
1587 | static Bogie * |
---|
1588 | simulator(sonar_info *si, void *vinfo) |
---|
1589 | { |
---|
1590 | |
---|
1591 | /* Local Variables */ |
---|
1592 | |
---|
1593 | int i; |
---|
1594 | Bogie *list = NULL; |
---|
1595 | Bogie *new; |
---|
1596 | sim_target *t; |
---|
1597 | sim_info *info = (sim_info *) vinfo; |
---|
1598 | |
---|
1599 | /* Check team A */ |
---|
1600 | |
---|
1601 | for (i = 0; i < info->numA; i++) { |
---|
1602 | t = &info->teamA[i]; |
---|
1603 | if ((t->movedonsweep != si->sweepnum) && |
---|
1604 | (t->nexttick == (si->current * -1))) { |
---|
1605 | new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL); |
---|
1606 | if (list != NULL) |
---|
1607 | new->next = list; |
---|
1608 | list = new; |
---|
1609 | updateLocation(t); |
---|
1610 | t->movedonsweep = si->sweepnum; |
---|
1611 | } |
---|
1612 | } |
---|
1613 | |
---|
1614 | /* Team B */ |
---|
1615 | |
---|
1616 | for (i = 0; i < info->numB; i++) { |
---|
1617 | t = &info->teamB[i]; |
---|
1618 | if ((t->movedonsweep != si->sweepnum) && |
---|
1619 | (t->nexttick == (si->current * -1))) { |
---|
1620 | new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL); |
---|
1621 | if (list != NULL) |
---|
1622 | new->next = list; |
---|
1623 | list = new; |
---|
1624 | updateLocation(t); |
---|
1625 | t->movedonsweep = si->sweepnum; |
---|
1626 | } |
---|
1627 | } |
---|
1628 | |
---|
1629 | /* Done */ |
---|
1630 | |
---|
1631 | return list; |
---|
1632 | } |
---|
1633 | |
---|
1634 | /* |
---|
1635 | * Compute the X coordinate of the label. |
---|
1636 | * |
---|
1637 | * Args: |
---|
1638 | * si - The sonar info block. |
---|
1639 | * label - The label that will be drawn. |
---|
1640 | * x - The x coordinate of the bogie. |
---|
1641 | * |
---|
1642 | * Returns: |
---|
1643 | * The x coordinate of the start of the label. |
---|
1644 | */ |
---|
1645 | |
---|
1646 | static int |
---|
1647 | computeStringX(sonar_info *si, char *label, int x) |
---|
1648 | { |
---|
1649 | |
---|
1650 | int width = XTextWidth(si->font, label, strlen(label)); |
---|
1651 | return x - (width / 2); |
---|
1652 | } |
---|
1653 | |
---|
1654 | /* |
---|
1655 | * Compute the Y coordinate of the label. |
---|
1656 | * |
---|
1657 | * Args: |
---|
1658 | * si - The sonar information. |
---|
1659 | * y - The y coordinate of the bogie. |
---|
1660 | * |
---|
1661 | * Returns: |
---|
1662 | * The y coordinate of the start of the label. |
---|
1663 | */ |
---|
1664 | |
---|
1665 | /* TODO: Add smarts to keep label in sonar screen */ |
---|
1666 | |
---|
1667 | static int |
---|
1668 | computeStringY(sonar_info *si, int y) |
---|
1669 | { |
---|
1670 | |
---|
1671 | int fheight = si->font->ascent + si->font->descent; |
---|
1672 | return y + 5 + fheight; |
---|
1673 | } |
---|
1674 | |
---|
1675 | /* |
---|
1676 | * Draw a Bogie on the radar screen. |
---|
1677 | * |
---|
1678 | * Args: |
---|
1679 | * si - Sonar Information. |
---|
1680 | * draw - A flag to indicate if the bogie should be drawn or erased. |
---|
1681 | * name - The name of the bogie. |
---|
1682 | * degrees - The number of degrees that it should apprear at. |
---|
1683 | * distance - The distance the object is from the centre. |
---|
1684 | * ttl - The time this bogie has to live. |
---|
1685 | * age - The time this bogie has been around. |
---|
1686 | */ |
---|
1687 | |
---|
1688 | static void |
---|
1689 | DrawBogie(sonar_info *si, int draw, char *name, int degrees, |
---|
1690 | int distance, int ttl, int age) |
---|
1691 | { |
---|
1692 | |
---|
1693 | /* Local Variables */ |
---|
1694 | |
---|
1695 | int x, y; |
---|
1696 | GC gc; |
---|
1697 | int ox = si->centrex; |
---|
1698 | int oy = si->centrey; |
---|
1699 | int index, delta; |
---|
1700 | |
---|
1701 | /* Compute the coordinates of the object */ |
---|
1702 | |
---|
1703 | if (distance != 0) |
---|
1704 | distance = (log((double) distance) / 10.0) * si->radius; |
---|
1705 | x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578)); |
---|
1706 | y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578)); |
---|
1707 | |
---|
1708 | /* Set up the graphics context */ |
---|
1709 | |
---|
1710 | if (draw) { |
---|
1711 | |
---|
1712 | /* Here we attempt to compute the distance into the total life of |
---|
1713 | * object that we currently are. This distance is used against |
---|
1714 | * the total lifetime to compute a fraction which is the index of |
---|
1715 | * the color to draw the bogie. |
---|
1716 | */ |
---|
1717 | |
---|
1718 | if (si->current <= degrees) |
---|
1719 | delta = (si->current - degrees) * -1; |
---|
1720 | else |
---|
1721 | delta = 90 + (degrees - si->current); |
---|
1722 | delta += (age * 90); |
---|
1723 | index = (si->text_steps - 1) * ((float) delta / (90.0 * (float) ttl)); |
---|
1724 | gc = si->text; |
---|
1725 | XSetForeground(si->dpy, gc, si->text_colors[index].pixel); |
---|
1726 | |
---|
1727 | } else |
---|
1728 | gc = si->erase; |
---|
1729 | |
---|
1730 | /* Draw (or erase) the Bogie */ |
---|
1731 | |
---|
1732 | XFillArc(si->dpy, si->win, gc, x, y, 5, 5, 0, 360 * 64); |
---|
1733 | XDrawString(si->dpy, si->win, gc, |
---|
1734 | computeStringX(si, name, x), |
---|
1735 | computeStringY(si, y), name, strlen(name)); |
---|
1736 | } |
---|
1737 | |
---|
1738 | |
---|
1739 | /* |
---|
1740 | * Draw the sonar grid. |
---|
1741 | * |
---|
1742 | * Args: |
---|
1743 | * si - Sonar information block. |
---|
1744 | */ |
---|
1745 | |
---|
1746 | static void |
---|
1747 | drawGrid(sonar_info *si) |
---|
1748 | { |
---|
1749 | |
---|
1750 | /* Local Variables */ |
---|
1751 | |
---|
1752 | int i; |
---|
1753 | int width = si->maxx - si->minx; |
---|
1754 | int height = si->maxy - si->miny; |
---|
1755 | |
---|
1756 | /* Draw the circles */ |
---|
1757 | |
---|
1758 | XDrawArc(si->dpy, si->win, si->grid, si->minx - 10, si->miny - 10, |
---|
1759 | width + 20, height + 20, 0, (360 * 64)); |
---|
1760 | |
---|
1761 | XDrawArc(si->dpy, si->win, si->grid, si->minx, si->miny, |
---|
1762 | width, height, 0, (360 * 64)); |
---|
1763 | |
---|
1764 | XDrawArc(si->dpy, si->win, si->grid, |
---|
1765 | (int) (si->minx + (.166 * width)), |
---|
1766 | (int) (si->miny + (.166 * height)), |
---|
1767 | (unsigned int) (.666 * width), (unsigned int)(.666 * height), |
---|
1768 | 0, (360 * 64)); |
---|
1769 | |
---|
1770 | XDrawArc(si->dpy, si->win, si->grid, |
---|
1771 | (int) (si->minx + (.333 * width)), |
---|
1772 | (int) (si->miny + (.333 * height)), |
---|
1773 | (unsigned int) (.333 * width), (unsigned int) (.333 * height), |
---|
1774 | 0, (360 * 64)); |
---|
1775 | |
---|
1776 | /* Draw the radial lines */ |
---|
1777 | |
---|
1778 | for (i = 0; i < 360; i += 10) |
---|
1779 | if (i % 30 == 0) |
---|
1780 | XDrawLine(si->dpy, si->win, si->grid, si->centrex, si->centrey, |
---|
1781 | (int) (si->centrex + |
---|
1782 | (si->radius + 10) * (cos((double) i / 57.29578))), |
---|
1783 | (int) (si->centrey - |
---|
1784 | (si->radius + 10)*(sin((double) i / 57.29578)))); |
---|
1785 | else |
---|
1786 | XDrawLine(si->dpy, si->win, si->grid, |
---|
1787 | (int) (si->centrex + si->radius * |
---|
1788 | (cos((double) i / 57.29578))), |
---|
1789 | (int) (si->centrey - si->radius * |
---|
1790 | (sin((double) i / 57.29578))), |
---|
1791 | (int) (si->centrex + |
---|
1792 | (si->radius + 10) * (cos((double) i / 57.29578))), |
---|
1793 | (int) (si->centrey - |
---|
1794 | (si->radius + 10) * (sin((double) i / 57.29578)))); |
---|
1795 | } |
---|
1796 | |
---|
1797 | /* |
---|
1798 | * Update the Sonar scope. |
---|
1799 | * |
---|
1800 | * Args: |
---|
1801 | * si - The Sonar information. |
---|
1802 | * bl - A list of bogies to add to the scope. |
---|
1803 | */ |
---|
1804 | |
---|
1805 | static void |
---|
1806 | Sonar(sonar_info *si, Bogie *bl) |
---|
1807 | { |
---|
1808 | |
---|
1809 | /* Local Variables */ |
---|
1810 | |
---|
1811 | Bogie *bp, *prev; |
---|
1812 | int i; |
---|
1813 | |
---|
1814 | /* Check for expired tagets and remove them from the visible list */ |
---|
1815 | |
---|
1816 | prev = NULL; |
---|
1817 | for (bp = si->visible; bp != NULL; bp = (bp ? bp->next : 0)) { |
---|
1818 | |
---|
1819 | /* |
---|
1820 | * Remove it from the visible list if it's expired or we have |
---|
1821 | * a new target with the same name. |
---|
1822 | */ |
---|
1823 | |
---|
1824 | bp->age ++; |
---|
1825 | |
---|
1826 | if (((bp->tick == si->current) && (++bp->age >= bp->ttl)) || |
---|
1827 | (findNode(bl, bp->name) != NULL)) { |
---|
1828 | DrawBogie(si, 0, bp->name, bp->tick, |
---|
1829 | bp->distance, bp->ttl, bp->age); |
---|
1830 | if (prev == NULL) |
---|
1831 | si->visible = bp->next; |
---|
1832 | else |
---|
1833 | prev->next = bp->next; |
---|
1834 | freeBogie(bp); |
---|
1835 | bp = prev; |
---|
1836 | } else |
---|
1837 | prev = bp; |
---|
1838 | } |
---|
1839 | |
---|
1840 | /* Draw the sweep */ |
---|
1841 | |
---|
1842 | { |
---|
1843 | int seg_deg = (si->sweep_degrees * 64) / si->sweep_segs; |
---|
1844 | int start_deg = si->current * 4 * 64; |
---|
1845 | if (seg_deg <= 0) seg_deg = 1; |
---|
1846 | for (i = 0; i < si->sweep_segs; i++) { |
---|
1847 | XSetForeground(si->dpy, si->hi, si->sweep_colors[i].pixel); |
---|
1848 | XFillArc(si->dpy, si->win, si->hi, si->minx, si->miny, |
---|
1849 | si->maxx - si->minx, si->maxy - si->miny, |
---|
1850 | start_deg + (i * seg_deg), |
---|
1851 | seg_deg); |
---|
1852 | } |
---|
1853 | |
---|
1854 | /* Remove the trailing wedge the sonar */ |
---|
1855 | XFillArc(si->dpy, si->win, si->erase, si->minx, si->miny, |
---|
1856 | si->maxx - si->minx, si->maxy - si->miny, |
---|
1857 | start_deg + (i * seg_deg), |
---|
1858 | (4 * 64)); |
---|
1859 | } |
---|
1860 | |
---|
1861 | /* Move the new targets to the visible list */ |
---|
1862 | |
---|
1863 | for (bp = bl; bp != (Bogie *) 0; bp = bl) { |
---|
1864 | bl = bl->next; |
---|
1865 | bp->next = si->visible; |
---|
1866 | si->visible = bp; |
---|
1867 | } |
---|
1868 | |
---|
1869 | /* Draw the visible targets */ |
---|
1870 | |
---|
1871 | for (bp = si->visible; bp != NULL; bp = bp->next) { |
---|
1872 | if (bp->age < bp->ttl) /* grins */ |
---|
1873 | DrawBogie(si, 1, bp->name, bp->tick, bp->distance, bp->ttl,bp->age); |
---|
1874 | } |
---|
1875 | |
---|
1876 | /* Redraw the grid */ |
---|
1877 | |
---|
1878 | drawGrid(si); |
---|
1879 | } |
---|
1880 | |
---|
1881 | |
---|
1882 | static ping_target * |
---|
1883 | parse_mode (Bool ping_works_p) |
---|
1884 | { |
---|
1885 | char *source = get_string_resource ("ping", "Ping"); |
---|
1886 | char *token, *end; |
---|
1887 | char dummy; |
---|
1888 | |
---|
1889 | ping_target *hostlist = 0; |
---|
1890 | |
---|
1891 | if (!source) source = strdup(""); |
---|
1892 | |
---|
1893 | if (!*source || !strcmp (source, "default")) |
---|
1894 | { |
---|
1895 | # ifdef HAVE_PING |
---|
1896 | if (ping_works_p) /* if root or setuid, ping will work. */ |
---|
1897 | source = strdup("subnet/29,/etc/hosts"); |
---|
1898 | else |
---|
1899 | # endif |
---|
1900 | source = strdup("simulation"); |
---|
1901 | } |
---|
1902 | |
---|
1903 | token = source; |
---|
1904 | end = source + strlen(source); |
---|
1905 | while (token < end) |
---|
1906 | { |
---|
1907 | char *next; |
---|
1908 | # ifdef HAVE_PING |
---|
1909 | ping_target *new; |
---|
1910 | struct stat st; |
---|
1911 | unsigned int n0=0, n1=0, n2=0, n3=0, m=0; |
---|
1912 | char d; |
---|
1913 | # endif /* HAVE_PING */ |
---|
1914 | |
---|
1915 | for (next = token; |
---|
1916 | *next && |
---|
1917 | *next != ',' && *next != ' ' && *next != '\t' && *next != '\n'; |
---|
1918 | next++) |
---|
1919 | ; |
---|
1920 | *next = 0; |
---|
1921 | |
---|
1922 | |
---|
1923 | if (debug_p) |
---|
1924 | fprintf (stderr, "%s: parsing %s\n", progname, token); |
---|
1925 | |
---|
1926 | if (!strcmp (token, "simulation")) |
---|
1927 | return 0; |
---|
1928 | |
---|
1929 | if (!ping_works_p) |
---|
1930 | { |
---|
1931 | fprintf(stderr, |
---|
1932 | "%s: this program must be setuid to root for `ping mode' to work.\n" |
---|
1933 | " Running in `simulation mode' instead.\n", |
---|
1934 | progname); |
---|
1935 | return 0; |
---|
1936 | } |
---|
1937 | |
---|
1938 | #ifdef HAVE_PING |
---|
1939 | if ((4 == sscanf (token, "%u.%u.%u/%u %c", &n0,&n1,&n2, &m,&d)) || |
---|
1940 | (5 == sscanf (token, "%u.%u.%u.%u/%u %c", &n0,&n1,&n2,&n3,&m,&d))) |
---|
1941 | { |
---|
1942 | /* subnet: A.B.C.D/M |
---|
1943 | subnet: A.B.C/M |
---|
1944 | */ |
---|
1945 | unsigned long ip = (n0 << 24) | (n1 << 16) | (n2 << 8) | n3; |
---|
1946 | new = subnetHostsList(ip, m); |
---|
1947 | } |
---|
1948 | else if (4 == sscanf (token, "%u.%u.%u.%u %c", &n0, &n1, &n2, &n3, &d)) |
---|
1949 | { |
---|
1950 | /* IP: A.B.C.D |
---|
1951 | */ |
---|
1952 | new = newHost (token); |
---|
1953 | } |
---|
1954 | else if (!strcmp (token, "subnet")) |
---|
1955 | { |
---|
1956 | new = subnetHostsList(0, 24); |
---|
1957 | } |
---|
1958 | else if (1 == sscanf (token, "subnet/%u %c", &m, &dummy)) |
---|
1959 | { |
---|
1960 | new = subnetHostsList(0, m); |
---|
1961 | } |
---|
1962 | else if (*token == '.' || *token == '/' || !stat (token, &st)) |
---|
1963 | { |
---|
1964 | /* file name |
---|
1965 | */ |
---|
1966 | new = readPingHostsFile (token); |
---|
1967 | } |
---|
1968 | else |
---|
1969 | { |
---|
1970 | /* not an existant file - must be a host name |
---|
1971 | */ |
---|
1972 | new = newHost (token); |
---|
1973 | } |
---|
1974 | |
---|
1975 | if (new) |
---|
1976 | { |
---|
1977 | ping_target *nn = new; |
---|
1978 | while (nn && nn->next) |
---|
1979 | nn = nn->next; |
---|
1980 | nn->next = hostlist; |
---|
1981 | hostlist = new; |
---|
1982 | |
---|
1983 | sensor = ping; |
---|
1984 | } |
---|
1985 | #endif /* HAVE_PING */ |
---|
1986 | |
---|
1987 | token = next + 1; |
---|
1988 | while (token < end && |
---|
1989 | (*token == ',' || *token == ' ' || |
---|
1990 | *token == '\t' || *token == '\n')) |
---|
1991 | token++; |
---|
1992 | } |
---|
1993 | |
---|
1994 | return hostlist; |
---|
1995 | } |
---|
1996 | |
---|
1997 | |
---|
1998 | |
---|
1999 | /* |
---|
2000 | * Main screen saver hack. |
---|
2001 | * |
---|
2002 | * Args: |
---|
2003 | * dpy - The X display. |
---|
2004 | * win - The X window. |
---|
2005 | */ |
---|
2006 | |
---|
2007 | void |
---|
2008 | screenhack(Display *dpy, Window win) |
---|
2009 | { |
---|
2010 | |
---|
2011 | /* Local Variables */ |
---|
2012 | |
---|
2013 | sonar_info *si; |
---|
2014 | struct timeval start, finish; |
---|
2015 | Bogie *bl; |
---|
2016 | long sleeptime; |
---|
2017 | |
---|
2018 | debug_p = get_boolean_resource ("debug", "Debug"); |
---|
2019 | |
---|
2020 | sensor = 0; |
---|
2021 | # ifdef HAVE_PING |
---|
2022 | sensor_info = (void *) init_ping(); |
---|
2023 | # else /* !HAVE_PING */ |
---|
2024 | sensor_info = 0; |
---|
2025 | parse_mode (0); /* just to check argument syntax */ |
---|
2026 | # endif /* !HAVE_PING */ |
---|
2027 | |
---|
2028 | if (sensor == 0) |
---|
2029 | { |
---|
2030 | sensor = simulator; |
---|
2031 | if ((sensor_info = (void *) init_sim()) == NULL) |
---|
2032 | exit(1); |
---|
2033 | } |
---|
2034 | |
---|
2035 | if ((si = init_sonar(dpy, win)) == (sonar_info *) 0) |
---|
2036 | exit(1); |
---|
2037 | |
---|
2038 | |
---|
2039 | /* Sonar loop */ |
---|
2040 | |
---|
2041 | while (1) { |
---|
2042 | |
---|
2043 | /* Call the sensor and display the results */ |
---|
2044 | |
---|
2045 | # ifdef GETTIMEOFDAY_TWO_ARGS |
---|
2046 | gettimeofday(&start, (struct timezone *) 0); |
---|
2047 | # else |
---|
2048 | gettimeofday(&start); |
---|
2049 | # endif |
---|
2050 | bl = sensor(si, sensor_info); |
---|
2051 | Sonar(si, bl); |
---|
2052 | |
---|
2053 | /* Set up and sleep for the next one */ |
---|
2054 | |
---|
2055 | si->current = (si->current - 1) % 90; |
---|
2056 | if (si->current == 0) |
---|
2057 | si->sweepnum++; |
---|
2058 | XSync (dpy, False); |
---|
2059 | # ifdef GETTIMEOFDAY_TWO_ARGS |
---|
2060 | gettimeofday(&finish, (struct timezone *) 0); |
---|
2061 | # else |
---|
2062 | gettimeofday(&finish); |
---|
2063 | # endif |
---|
2064 | sleeptime = si->delay - delta(&start, &finish); |
---|
2065 | screenhack_handle_events (dpy); |
---|
2066 | if (sleeptime > 0L) |
---|
2067 | usleep(sleeptime); |
---|
2068 | |
---|
2069 | } |
---|
2070 | } |
---|