root/src/modules/ping_icmp.c

Revision de520024f8801f5cc271ac9301e66f7c3690558e, 22.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

Don't assert on double runs, just log an error

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #ifdef HAVE_SYS_FILIO_H
41 #include <sys/filio.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_SYSTM_H
44 #include <netinet/in_systm.h>
45 #endif
46 #include <netinet/in.h>
47 #include <netinet/ip.h>
48 #include <netinet/ip_icmp.h>
49 #include <netinet/ip6.h>
50 #include <netinet/icmp6.h>
51 #include <math.h>
52 #ifndef MAXFLOAT
53 #include <float.h>
54 #define MAXFLOAT FLT_MAX
55 #endif
56
57 #include "noit_module.h"
58 #include "noit_check.h"
59 #include "noit_check_tools.h"
60 #include "utils/noit_log.h"
61
62 #define PING_INTERVAL 2000 /* 2000ms = 2s */
63 #define PING_COUNT    5
64
65 struct check_info {
66   u_int16_t check_no;
67   u_int8_t check_seq_no;
68   u_int8_t seq;
69   int8_t expected_count;
70   float *turnaround;
71   eventer_t timeout_event;
72 };
73 struct ping_session_key {
74   void  *addr_of_check; /* ticket #288 */
75   uuid_t checkid;
76 };
77 struct ping_payload {
78   void  *addr_of_check; /* ticket #288 */
79   uuid_t checkid;
80   u_int64_t tv_sec;
81   u_int32_t tv_usec;
82   u_int16_t generation;   
83   u_int16_t check_no;
84   u_int8_t  check_pack_no;
85   u_int8_t  check_pack_cnt;
86   u_int8_t  size_bookend;
87 };
88 #define PING_PAYLOAD_LEN offsetof(struct ping_payload, size_bookend)
89 struct ping_closure {
90   noit_module_t *self;
91   noit_check_t *check;
92   void *payload;
93   int payload_len;
94   int icp_len;
95 };
96 static noit_log_stream_t nlerr = NULL;
97 static noit_log_stream_t nldeb = NULL;
98 static int in_cksum(u_short *addr, int len);
99
100 typedef struct  {
101   int ipv4_fd;
102   int ipv6_fd;
103   noit_hash_table *in_flight;
104 } ping_icmp_data_t;
105
106 static int ping_icmp_config(noit_module_t *self, noit_hash_table *options) {
107   return 0;
108 }
109 static int ping_icmp_is_complete(noit_module_t *self, noit_check_t *check) {
110   int i;
111   struct check_info *data;
112   data = (struct check_info *)check->closure;
113   for(i=0; i<data->expected_count; i++)
114     if(data->turnaround[i] < 0.0) {
115       noitL(nldeb, "ping_icmp: %s %d is still outstanding.\n",
116             check->target_ip, i);
117       return 0;
118     }
119   return 1;
120 }
121 static void ping_icmp_log_results(noit_module_t *self, noit_check_t *check) {
122   struct check_info *data;
123   double avail, min = MAXFLOAT, max = 0.0, avg = 0.0, cnt;
124   int avail_needed = 100;
125   const char *config_val = NULL;
126   int i, points = 0;
127   char human_buffer[256];
128   stats_t current;
129   struct timeval duration;
130
131   noit_check_stats_clear(check, &current);
132
133   data = (struct check_info *)check->closure;
134   for(i=0; i<data->expected_count; i++) {
135     if(data->turnaround[i] >= 0.0) {
136       points++;
137       avg += data->turnaround[i];
138       if(data->turnaround[i] > max) max = data->turnaround[i];
139       if(data->turnaround[i] < min) min = data->turnaround[i];
140     }
141   }
142   if(points == 0) {
143     min = 0.0 / 0.0;
144     max = 0.0 / 0.0;
145   }
146   cnt = data->expected_count;
147   avail = (float)points /cnt;
148   avg /= (float)points;
149
150   if(noit_hash_retr_str(check->config, "avail_needed", strlen("avail_needed"),
151                         &config_val))
152     avail_needed = atoi(config_val);
153
154   snprintf(human_buffer, sizeof(human_buffer),
155            "cnt=%d,avail=%0.0f,min=%0.4f,max=%0.4f,avg=%0.4f",
156            (int)cnt, 100.0*avail, min, max, avg);
157   noitL(nldeb, "ping_icmp(%s) [%s]\n", check->target_ip, human_buffer);
158
159   gettimeofday(&current.whence, NULL);
160   sub_timeval(current.whence, check->last_fire_time, &duration);
161   current.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;
162   current.available = (avail > 0.0) ? NP_AVAILABLE : NP_UNAVAILABLE;
163   current.state = (avail < ((float)avail_needed / 100.0)) ? NP_BAD : NP_GOOD;
164   current.status = human_buffer;
165   noit_stats_set_metric(check, &current, "count",
166                         METRIC_INT32, &data->expected_count);
167   avail *= 100.0;
168   noit_stats_set_metric(check, &current, "available", METRIC_DOUBLE, &avail);
169   noit_stats_set_metric(check, &current, "minimum",
170                         METRIC_DOUBLE, avail > 0.0 ? &min : NULL);
171   noit_stats_set_metric(check, &current, "maximum",
172                         METRIC_DOUBLE, avail > 0.0 ? &max : NULL);
173   noit_stats_set_metric(check, &current, "average",
174                         METRIC_DOUBLE, avail > 0.0 ? &avg : NULL);
175   noit_check_set_stats(check, &current);
176 }
177 static int ping_icmp_timeout(eventer_t e, int mask,
178                              void *closure, struct timeval *now) {
179   struct ping_closure *pcl = (struct ping_closure *)closure;
180   struct ping_session_key k;
181   struct check_info *data;
182   ping_icmp_data_t *ping_data;
183
184   if(!NOIT_CHECK_KILLED(pcl->check) && !NOIT_CHECK_DISABLED(pcl->check)) {
185     ping_icmp_log_results(pcl->self, pcl->check);
186   }
187   data = (struct check_info *)pcl->check->closure;
188   data->timeout_event = NULL;
189   pcl->check->flags &= ~NP_RUNNING;
190   ping_data = noit_module_get_userdata(pcl->self);
191   k.addr_of_check = pcl->check;
192   uuid_copy(k.checkid, pcl->check->checkid);
193   noit_hash_delete(ping_data->in_flight, (const char *)&k, sizeof(k),
194                    free, NULL);
195   free(pcl);
196   return 0;
197 }
198
199 static int ping_icmp_handler(eventer_t e, int mask,
200                              void *closure, struct timeval *now,
201                              u_int8_t family) {
202   noit_module_t *self = (noit_module_t *)closure;
203   ping_icmp_data_t *ping_data;
204   struct check_info *data;
205   char packet[1500];
206   int packet_len = sizeof(packet);
207   union {
208    struct sockaddr_in  in4;
209    struct sockaddr_in6 in6;
210   } from;
211   unsigned int from_len;
212   struct ping_payload *payload;
213
214   if(family != AF_INET && family != AF_INET6) return EVENTER_READ;
215
216   ping_data = noit_module_get_userdata(self);
217   while(1) {
218     struct ping_session_key k;
219     int inlen;
220     u_int8_t iphlen = 0;
221     void *vcheck;
222     noit_check_t *check;
223     struct timeval tt, whence;
224
225     from_len = sizeof(from);
226
227     inlen = recvfrom(e->fd, packet, packet_len, 0,
228                      (struct sockaddr *)&from, &from_len);
229     gettimeofday(now, NULL); /* set it, as we care about accuracy */
230
231     if(inlen < 0) {
232       if(errno == EAGAIN || errno == EINTR) break;
233       noitLT(nldeb, now, "ping_icmp recvfrom: %s\n", strerror(errno));
234       break;
235     }
236
237     if(family == AF_INET) {
238       struct icmp *icp4;
239       iphlen = ((struct ip *)packet)->ip_hl << 2;
240       if((inlen-iphlen) != sizeof(struct icmp)+PING_PAYLOAD_LEN) {
241         noitLT(nldeb, now,
242                "ping_icmp bad size: %d+%d\n", iphlen, inlen-iphlen);
243         continue;
244       }
245       icp4 = (struct icmp *)(packet + iphlen);
246       payload = (struct ping_payload *)(icp4 + 1);
247       if(icp4->icmp_type != ICMP_ECHOREPLY) {
248         noitLT(nldeb, now, "ping_icmp bad type: %d\n", icp4->icmp_type);
249         continue;
250       }
251       if(icp4->icmp_id != (((vpsized_uint)self) & 0xffff)) {
252         noitLT(nldeb, now,
253                  "ping_icmp not sent from this instance (%d:%d) vs. %lu\n",
254                  icp4->icmp_id, ntohs(icp4->icmp_seq),
255                  (unsigned long)(((vpsized_uint)self) & 0xffff));
256         continue;
257       }
258     }
259     else if(family == AF_INET6) {
260       struct icmp6_hdr *icp6 = (struct icmp6_hdr *)packet;
261       if((inlen) != sizeof(struct icmp6_hdr)+PING_PAYLOAD_LEN) {
262         noitLT(nldeb, now,
263                "ping_icmp bad size: %d+%d\n", iphlen, inlen-iphlen);
264         continue;
265       }
266       payload = (struct ping_payload *)(icp6+1);
267       if(icp6->icmp6_type != ICMP6_ECHO_REPLY) {
268         noitLT(nldeb, now, "ping_icmp bad type: %d\n", icp6->icmp6_type);
269         continue;
270       }
271       if(icp6->icmp6_id != (((vpsized_uint)self) & 0xffff)) {
272         noitLT(nldeb, now,
273                  "ping_icmp not sent from this instance (%d:%d) vs. %lu\n",
274                  icp6->icmp6_id, ntohs(icp6->icmp6_seq),
275                  (unsigned long)(((vpsized_uint)self) & 0xffff));
276         continue;
277       }
278     }
279     else {
280       /* This should be unreachable */
281       continue;
282     }
283     check = NULL;
284     k.addr_of_check = payload->addr_of_check;
285     uuid_copy(k.checkid, payload->checkid);
286     if(noit_hash_retrieve(ping_data->in_flight,
287                           (const char *)&k, sizeof(k),
288                           &vcheck))
289       check = vcheck;
290
291     /* make sure this check is from this generation! */
292     if(!check) {
293       char uuid_str[37];
294       uuid_unparse_lower(payload->checkid, uuid_str);
295       noitLT(nldeb, now,
296              "ping_icmp response for unknown check '%s'\n", uuid_str);
297       continue;
298     }
299     if((check->generation & 0xffff) != payload->generation) {
300       noitLT(nldeb, now,
301              "ping_icmp response in generation gap\n");
302       continue;
303     }
304     data = (struct check_info *)check->closure;
305
306     /* If there is no timeout_event, the check must have completed.
307      * We have nothing to do. */
308     if(!data->timeout_event) continue;
309
310     /* Sanity check the payload */
311     if(payload->check_no != data->check_no) continue;
312     if(payload->check_pack_cnt != data->expected_count) continue;
313     if(payload->check_pack_no >= data->expected_count) continue;
314
315     whence.tv_sec = payload->tv_sec;
316     whence.tv_usec = payload->tv_usec;
317     sub_timeval(*now, whence, &tt);
318     data->turnaround[payload->check_pack_no] =
319       (float)tt.tv_sec + (float)tt.tv_usec / 1000000.0;
320     if(ping_icmp_is_complete(self, check)) {
321       ping_icmp_log_results(self, check);
322       eventer_remove(data->timeout_event);
323       free(data->timeout_event->closure);
324       eventer_free(data->timeout_event);
325       data->timeout_event = NULL;
326       check->flags &= ~NP_RUNNING;
327       k.addr_of_check = check;
328       uuid_copy(k.checkid, check->checkid);
329       noit_hash_delete(ping_data->in_flight, (const char *)&k,
330                        sizeof(k), free, NULL);
331     }
332   }
333   return EVENTER_READ;
334 }
335 static int ping_icmp4_handler(eventer_t e, int mask,
336                               void *closure, struct timeval *now) {
337   return ping_icmp_handler(e, mask, closure, now, AF_INET);
338 }
339 static int ping_icmp6_handler(eventer_t e, int mask,
340                               void *closure, struct timeval *now) {
341   return ping_icmp_handler(e, mask, closure, now, AF_INET6);
342 }
343
344 static int ping_icmp_init(noit_module_t *self) {
345   socklen_t on;
346   struct protoent *proto;
347   ping_icmp_data_t *data;
348
349   data = malloc(sizeof(*data));
350   data->in_flight = calloc(1, sizeof(*data->in_flight));
351   data->ipv4_fd = data->ipv6_fd = -1;
352
353   if ((proto = getprotobyname("icmp")) == NULL) {
354     noitL(noit_error, "Couldn't find 'icmp' protocol\n");
355     return -1;
356   }
357
358   data->ipv4_fd = socket(AF_INET, SOCK_RAW, proto->p_proto);
359   if(data->ipv4_fd < 0) {
360     noitL(noit_error, "ping_icmp: socket failed: %s\n",
361           strerror(errno));
362   }
363   else {
364     socklen_t slen = sizeof(on);
365     if(getsockopt(data->ipv4_fd, SOL_SOCKET, SO_SNDBUF, &on, &slen) == 0) {
366       if(on <= 0) on = 1024;
367       while(on < (1 << 20)) {
368         on <<= 1;
369         if(setsockopt(data->ipv4_fd, SOL_SOCKET, SO_SNDBUF,
370                       &on, sizeof(on)) != 0) {
371           on >>= 1;
372           break;
373         }
374       }
375       noitL(noit_debug, "ping_icmp: send buffer set to %d\n", on);
376     }
377     else
378       noitL(noit_error, "Cannot get sndbuf size: %s\n", strerror(errno));
379
380     if(eventer_set_fd_nonblocking(data->ipv4_fd)) {
381       close(data->ipv4_fd);
382       data->ipv4_fd = -1;
383       noitL(noit_error,
384             "ping_icmp: could not set socket non-blocking: %s\n",
385             strerror(errno));
386     }
387   }
388   if(data->ipv4_fd >= 0) {
389     eventer_t newe;
390     newe = eventer_alloc();
391     newe->fd = data->ipv4_fd;
392     newe->mask = EVENTER_READ;
393     newe->callback = ping_icmp4_handler;
394     newe->closure = self;
395     eventer_add(newe);
396   }
397
398   if ((proto = getprotobyname("ipv6-icmp")) != NULL) {
399     data->ipv6_fd = socket(AF_INET6, SOCK_RAW, proto->p_proto);
400     if(data->ipv6_fd < 0) {
401       noitL(noit_error, "ping_icmp: socket failed: %s\n",
402             strerror(errno));
403     }
404     else {
405       if(eventer_set_fd_nonblocking(data->ipv6_fd)) {
406         close(data->ipv6_fd);
407         data->ipv6_fd = -1;
408         noitL(noit_error,
409               "ping_icmp: could not set socket non-blocking: %s\n",
410                  strerror(errno));
411       }
412     }
413     if(data->ipv6_fd >= 0) {
414       eventer_t newe;
415       newe = eventer_alloc();
416       newe->fd = data->ipv6_fd;
417       newe->mask = EVENTER_READ;
418       newe->callback = ping_icmp6_handler;
419       newe->closure = self;
420       eventer_add(newe);
421     }
422   }
423   else
424     noitL(noit_error, "Couldn't find 'ipv6-icmp' protocol\n");
425
426   noit_module_set_userdata(self, data);
427   return 0;
428 }
429
430 static int ping_icmp_real_send(eventer_t e, int mask,
431                                void *closure, struct timeval *now) {
432   struct ping_closure *pcl = (struct ping_closure *)closure;
433   struct ping_session_key k;
434   struct ping_payload *payload;
435   struct timeval whence;
436   ping_icmp_data_t *data;
437   void *vcheck;
438   int i;
439
440   data = noit_module_get_userdata(pcl->self);
441   payload = (struct ping_payload *)((char *)pcl->payload + pcl->icp_len);
442   k.addr_of_check = payload->addr_of_check;
443   uuid_copy(k.checkid, payload->checkid);
444
445   if(pcl->check->target_ip[0] == '\0') goto cleanup;
446
447   if(!noit_hash_retrieve(data->in_flight, (const char *)&k, sizeof(k),
448                          &vcheck)) {
449     noitLT(nldeb, now, "ping check no longer active, bailing\n");
450     goto cleanup;
451   }
452
453   noitLT(nldeb, now, "ping_icmp_real_send(%s)\n", pcl->check->target_ip);
454   gettimeofday(&whence, NULL); /* now isn't accurate enough */
455   payload->tv_sec = whence.tv_sec;
456   payload->tv_usec = whence.tv_usec;
457   if(pcl->check->target_family == AF_INET) {
458     struct sockaddr_in sin;
459     struct icmp *icp4 = (struct icmp *)pcl->payload;
460     icp4->icmp_cksum = in_cksum(pcl->payload, pcl->payload_len);
461     memset(&sin, 0, sizeof(sin));
462     sin.sin_family = AF_INET;
463     memcpy(&sin.sin_addr,
464            &pcl->check->target_addr.addr, sizeof(sin.sin_addr));
465     i = sendto(data->ipv4_fd,
466                pcl->payload, pcl->payload_len, 0,
467                (struct sockaddr *)&sin, sizeof(sin));
468   }
469   else if(pcl->check->target_family == AF_INET6) {
470     struct sockaddr_in6 sin;
471     struct icmp6_hdr *icp6 = (struct icmp6_hdr *)pcl->payload;
472     icp6->icmp6_cksum = in_cksum(pcl->payload, pcl->payload_len);
473     memset(&sin, 0, sizeof(sin));
474     sin.sin6_family = AF_INET6;
475     memcpy(&sin.sin6_addr,
476            &pcl->check->target_addr.addr6, sizeof(sin.sin6_addr));
477     i = sendto(data->ipv6_fd,
478                pcl->payload, pcl->payload_len, 0,
479                (struct sockaddr *)&sin, sizeof(sin));
480   }
481   if(i != pcl->payload_len) {
482     noitLT(nlerr, now, "Error sending ICMP packet to %s(%s): %s\n",
483              pcl->check->target, pcl->check->target_ip, strerror(errno));
484   }
485  cleanup:
486   free(pcl->payload);
487   free(pcl);
488   return 0;
489 }
490 static void ping_check_cleanup(noit_module_t *self, noit_check_t *check) {
491   struct check_info *ci = (struct check_info *)check->closure;
492   if(ci) {
493     if(ci->timeout_event) {
494       eventer_remove(ci->timeout_event);
495       free(ci->timeout_event->closure);
496       eventer_free(ci->timeout_event);
497       ci->timeout_event = NULL;
498     }
499     if(ci->turnaround) free(ci->turnaround);
500   }
501 }
502 static int ping_icmp_send(noit_module_t *self, noit_check_t *check,
503                           noit_check_t *cause) {
504   struct timeval when, p_int;
505   struct ping_payload *payload;
506   struct ping_closure *pcl;
507   struct check_info *ci = (struct check_info *)check->closure;
508   int packet_len, icp_len, i;
509   eventer_t newe;
510   const char *config_val;
511   ping_icmp_data_t *ping_data;
512   struct ping_session_key *k;
513   void *icp;
514
515   int interval = PING_INTERVAL;
516   int count = PING_COUNT;
517
518   BAIL_ON_RUNNING_CHECK(check);
519
520   if(noit_hash_retr_str(check->config, "interval", strlen("interval"),
521                         &config_val))
522     interval = atoi(config_val);
523   if(noit_hash_retr_str(check->config, "count", strlen("count"),
524                         &config_val))
525     count = atoi(config_val);
526
527   check->flags |= NP_RUNNING;
528   ping_data = noit_module_get_userdata(self);
529   k = calloc(1, sizeof(*k));
530   k->addr_of_check = check;
531   uuid_copy(k->checkid, check->checkid);
532   if(!noit_hash_store(ping_data->in_flight, (const char *)k, sizeof(*k),
533                       check)) {
534     free(k);
535   }
536   noitL(nldeb, "ping_icmp_send(%p,%s,%d,%d)\n",
537         self, check->target_ip, interval, count);
538
539   /* remove a timeout if we still have one -- we should unless someone
540    * has set a lower timeout than the period.
541    */
542   if(ci->timeout_event) {
543     eventer_remove(ci->timeout_event);
544     free(ci->timeout_event->closure);
545     eventer_free(ci->timeout_event);
546     ci->timeout_event = NULL;
547   }
548
549   gettimeofday(&when, NULL);
550   memcpy(&check->last_fire_time, &when, sizeof(when));
551
552   /* Setup some stuff used in the loop */
553   p_int.tv_sec = interval / 1000;
554   p_int.tv_usec = (interval % 1000) * 1000;
555   icp_len = (check->target_family == AF_INET6) ?
556               sizeof(struct icmp6_hdr) : sizeof(struct icmp);
557   packet_len = icp_len + PING_PAYLOAD_LEN;
558
559   /* Prep holding spots for return info */
560   ci->expected_count = count;
561   if(ci->turnaround) free(ci->turnaround);
562   ci->turnaround = malloc(count * sizeof(*ci->turnaround));
563
564   ++ci->check_no;
565   for(i=0; i<count; i++) {
566     /* Negative means we've not received a response */
567     ci->turnaround[i] = -1.0;
568
569     newe = eventer_alloc();
570     newe->callback = ping_icmp_real_send;
571     newe->mask = EVENTER_TIMER;
572     memcpy(&newe->whence, &when, sizeof(when));
573     add_timeval(when, p_int, &when); /* Next one is a bit later */
574
575     icp = calloc(1,packet_len);
576     payload = (struct ping_payload *)((char *)icp + icp_len);
577
578     if(check->target_family == AF_INET) {
579       struct icmp *icp4 = icp;
580       icp4->icmp_type = ICMP_ECHO;
581       icp4->icmp_code = 0;
582       icp4->icmp_cksum = 0;
583       icp4->icmp_seq = htons(ci->seq++);
584       icp4->icmp_id = (((vpsized_uint)self) & 0xffff);
585     }
586     else if(check->target_family == AF_INET6) {
587       struct icmp6_hdr *icp6 = icp;
588       icp6->icmp6_type = ICMP6_ECHO_REQUEST;
589       icp6->icmp6_code = 0;
590       icp6->icmp6_cksum = 0;
591       icp6->icmp6_seq = htons(ci->seq++);
592       icp6->icmp6_id = (((vpsized_uint)self) & 0xffff);
593     }
594
595     payload->addr_of_check = check;
596     uuid_copy(payload->checkid, check->checkid);
597     payload->generation = check->generation & 0xffff;
598     payload->check_no = ci->check_no;
599     payload->check_pack_no = i;
600     payload->check_pack_cnt = count;
601
602     pcl = calloc(1, sizeof(*pcl));
603     pcl->self = self;
604     pcl->check = check;
605     pcl->payload = icp;
606     pcl->payload_len = packet_len;
607     pcl->icp_len = icp_len;
608
609     newe->closure = pcl;
610     eventer_add(newe);
611   }
612   newe = eventer_alloc();
613   newe->mask = EVENTER_TIMER;
614   gettimeofday(&when, NULL);
615   p_int.tv_sec = check->timeout / 1000;
616   p_int.tv_usec = (check->timeout % 1000) * 1000;
617   add_timeval(when, p_int, &newe->whence);
618   pcl = calloc(1, sizeof(*pcl));
619   pcl->self = self;
620   pcl->check = check;
621   newe->closure = pcl;
622   newe->callback = ping_icmp_timeout;
623   eventer_add(newe);
624   ci->timeout_event = newe;
625
626   return 0;
627 }
628 static int ping_icmp_initiate_check(noit_module_t *self, noit_check_t *check,
629                                     int once, noit_check_t *cause) {
630   if(!check->closure) check->closure = calloc(1, sizeof(struct check_info));
631   INITIATE_CHECK(ping_icmp_send, self, check, cause);
632   return 0;
633 }
634
635 /*
636  *      I N _ C K S U M
637  *          This is from Mike Muuss's Public Domain code.
638  * Checksum routine for Internet Protocol family headers (C Version)
639  *
640  */
641 static int in_cksum(u_short *addr, int len)
642 {
643   register int nleft = len;
644   register u_short *w = addr;
645   register u_short answer;
646   register int sum = 0;
647
648   /*
649    *  Our algorithm is simple, using a 32 bit accumulator (sum),
650    *  we add sequential 16 bit words to it, and at the end, fold
651    *  back all the carry bits from the top 16 bits into the lower
652    *  16 bits.
653    */
654   while( nleft > 1 )  {
655     sum += *w++;
656     nleft -= 2;
657   }
658
659   /* mop up an odd byte, if necessary */
660   if( nleft == 1 ) {
661     u_short  u = 0;
662
663     *(u_char *)(&u) = *(u_char *)w ;
664     sum += u;
665   }
666
667   /*
668    * add back carry outs from top 16 bits to low 16 bits
669    */
670   sum = (sum >> 16) + (sum & 0xffff);  /* add hi 16 to low 16 */
671   sum += (sum >> 16);      /* add carry */
672   answer = ~sum;        /* truncate to 16 bits */
673   return (answer);
674 }
675
676 static int ping_icmp_onload(noit_image_t *self) {
677   nlerr = noit_log_stream_find("error/ping_icmp");
678   nldeb = noit_log_stream_find("debug/ping_icmp");
679   if(!nlerr) nlerr = noit_stderr;
680   if(!nldeb) nldeb = noit_debug;
681   eventer_name_callback("ping_icmp/timeout", ping_icmp_timeout);
682   eventer_name_callback("ping_icmp/handler", ping_icmp4_handler);
683   eventer_name_callback("ping_icmp6/handler", ping_icmp6_handler);
684   eventer_name_callback("ping_icmp/send", ping_icmp_real_send);
685   return 0;
686 }
687 #include "ping_icmp.xmlh"
688 noit_module_t ping_icmp = {
689   {
690     NOIT_MODULE_MAGIC,
691     NOIT_MODULE_ABI_VERSION,
692     "ping_icmp",
693     "ICMP based host availability detection",
694     ping_icmp_xml_description,
695     ping_icmp_onload
696   },
697   ping_icmp_config,
698   ping_icmp_init,
699   ping_icmp_initiate_check,
700   ping_check_cleanup
701 };
702
Note: See TracBrowser for help on using the browser.