~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
cvs/emstar/routing/geo-linkstate/glsping.c


  1 /*
  2  *
  3  * Copyright (c) 2003 The Regents of the University of California.  All 
  4  * rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions
  8  * are met:
  9  *
 10  * - Redistributions of source code must retain the above copyright
 11  *   notice, this list of conditions and the following disclaimer.
 12  *
 13  * - Neither the name of the University nor the names of its
 14  *   contributors may be used to endorse or promote products derived
 15  *   from this software without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 20  * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  *
 29  */
 30  
 31 
 32 /*
 33  * ping.c: This a "ping" client, which broadcasts a 'ping' packet, and
 34  * then waits for replies from the network.  This program, and the
 35  * corresponding 'pingd' server, serve as a useful example for various
 36  * tasks:
 37  *
 38  *   - How to create an application-layer protocol format
 39  *   - How to send packets to the network
 40  *   - How to wait for and react to packets that come from the network
 41  *   - How to filter incoming packets
 42  *
 43  * $Id: glsping.c,v 1.3 2003-07-11 22:30:01 cerpa Exp $
 44  */
 45 
 46 char ping_c_cvsid[] = "$Id: glsping.c,v 1.3 2003-07-11 22:30:01 cerpa Exp $";
 47 
 48 #include <stdio.h>
 49 #include <stdlib.h>
 50 #include <sys/time.h>
 51 #include <arpa/inet.h>
 52 
 53 #include "emrun/emrun.h"
 54 #include "link/link.h"
 55 #include "glsping.h"
 56 
 57 
 58 /*******************************************************************/
 59 
 60 
 61 #define MAX_PINGS 1000
 62 
 63 typedef struct ping_state {
 64   int random_id;                /* our randomly selected ID, to
 65                                  * differentiate our packets from any
 66                                  * other ping processes that might be
 67                                  * happening at the same time. */
 68   int last_seqno;               /* last seqno we used */
 69   int total_sent;               /* total pings sent */
 70   struct timeval time_sent;     /* time we sent the most recent ping */
 71   struct timeval rtt[MAX_PINGS]; /* rtts of responses we've received */
 72   int num_replies;              /* number of responses we've received */
 73 
 74   loc_t dst_loc;              /* destination location */
 75 
 76   link_context_t *link;         /* link we're using to ping on */
 77 } ping_state_t;
 78 
 79 
 80 /*******************************************************************/
 81 
 82 /*
 83  * Callback activated when we are asked to shut down by emrun.
 84  * Compute and print summary statistics of all replies received
 85  */  
 86 void ping_shutdown(void *data)
 87 {
 88   ping_state_t *p = (ping_state_t *) data;
 89   struct timeval min, max, sum;
 90   int i;
 91 
 92   if (!p->num_replies) {
 93     elog_g(LOG_NOTICE, "%d pings sent, no replies received", p->total_sent);
 94     goto done;
 95   }
 96 
 97   min = max = sum = p->rtt[0];
 98 
 99   /* This loop finds the min and max RTTs, sums all the RTTs for
100    * average, and counts how many replies we received. */
101   for (i = 1; i < p->num_replies; i++) {
102 
103     /* misc_tv_* are convenience functions for doing computations on a
104      * struct timeval found in libmisc */
105     if (misc_tv_offset_neg(&p->rtt[i], &min) < 0)
106       min = p->rtt[i];
107     if (misc_tv_offset_neg(&p->rtt[i], &max) > 0)
108       max = p->rtt[i];
109 
110     misc_tv_add(&sum, &p->rtt[i]);
111   }
112 
113   /* compute average from the sum */
114   elog_g(LOG_NOTICE, "%d pings sent, %d replies received, "
115          "min/avg/max rtt %.1f/%.1f/%.1f ms",
116          p->total_sent, p->num_replies,
117          misc_tv_msec_f(&min),
118 
119          ((float) sum.tv_sec + (sum.tv_usec / MILLION_F)) * 1000.0 /
120          p->num_replies,
121 
122          misc_tv_msec_f(&max));
123 
124   /* Now shut down */
125  done:
126   exit(0);
127 }
128 
129 
130 /*
131  * Construct a ping packet, and send it out over the wire, using the
132  * link context stored as part of our "ping" state.
133  */
134 void ping_send(ping_state_t *p, loc_t *dst_loc)
135 {
136   /* Allocate a small buffer for the packet */
137   char buf[200];
138   link_pkt_t *pkt = (link_pkt_t *) buf;
139   ping_pkt_t *ping_pkt = (ping_pkt_t *) pkt->data;
140 
141   /* initialize the outer header (the link_pkt header) */
142   memset(buf, 0, sizeof(buf));
143   pkt->dst.id = LINK_BROADCAST;
144   pkt->type = PKT_TYPE_PING;
145 
146   /* and our application-layer (ping) protocol data */
147   ping_pkt->cmd = PING_REQUEST;
148   ping_pkt->random_id = p->random_id;
149   ping_pkt->seqno = ++(p->last_seqno);
150 
151   /* remember what time it is, so we can calculate RTT */
152   p->total_sent++;
153   gettimeofday(&p->time_sent, NULL);
154 
155   /* set the destination geo location */
156   pkt->dst.loc.x = dst_loc->x;
157   pkt->dst.loc.y = dst_loc->y;
158 
159   /* now launch the packet! */
160   if (link_send(p->link, pkt, sizeof(ping_pkt_t)) < 0)
161     elog(LOG_ERR, "can't send on %s: %m", link_name(link_opts(p->link)));
162   else
163     elog(LOG_NOTICE, "broadcast ping seqno %d", ping_pkt->seqno);
164 }
165 
166 
167 /* Called every time our periodic ping timer expies.  */
168 int ping_periodic_timer(void *data, int interval, g_event_t *ev)
169 {
170   ping_state_t *p = (ping_state_t *) data;
171 
172   ping_send(p, &p->dst_loc);
173 
174   return EVENT_RENEW;
175 }
176 
177 
178 /*
179  * This callback is called whenever a packet arrives on the link we
180  * opened.  "pkt" is a pointer to a link_pkt_t header followed by
181  * data_len bytes of data.  (data_len is the length of the data
182  * following the header; it doesn't include the size of the link_pkt_t
183  * header itself.)  "link" is a pointer to the link that the packet
184  * was received on, and can be used for sending a reply packet (we
185  * don't send reply packets from the receiver callback here, but see
186  * pingd for an example where we do.)
187  */
188 int ping_receiver(link_pkt_t *link_pkt, ssize_t data_len, link_context_t *link)
189 {
190   /* Get a pointer to the data portion of the packet */
191   ping_pkt_t *ping_pkt = (ping_pkt_t *) link_pkt->data;
192 
193   /* We stored a pointer to the 'ping_state' struct as the "data"
194    * field of link_opts in main().  Now, we retrieve that pointer. */
195   ping_state_t *p = (ping_state_t *) (link_opts(link))->data;
196 
197 
198   elog (LOG_NOTICE, "Ping received packet");
199 
200   /*
201    * Make sure the packet has the right packet type.  Since we
202    * specified the desired packet type when we registered to receive
203    * packets, this test should never fail.
204    */
205   if (link_pkt->type != PKT_TYPE_PING) {
206     elog(LOG_WARNING, "got a packet not meant for us - filter failed!");
207     goto done;
208   }
209 
210   /*
211    * Make sure the data portion of the packet is exactly the right
212    * size (i.e., the size of our "ping" application-layer protocol
213    * frame.
214    */
215   if (data_len != sizeof(ping_pkt_t)) {
216     elog(LOG_ERR, "got a short ping packet (%d bytes)!", data_len);
217     goto done;
218   }
219 
220   /* We now know that the data pointed to by ping_pkt is valid */
221 
222   /*
223    * Ignore everything but ping replies (i.e. ignore requests that
224    * other ping clients might be sending.)
225    */
226   if (ping_pkt->cmd != PING_REPLY) {
227     elog(LOG_DEBUG(2), "got non-reply packet - dropping");
228     goto done;
229   }
230 
231   /*
232    * Ignore replies not meant for us (based on the random ID), or that
233    * are arriving late for the previous request
234    */
235   if (ping_pkt->random_id != p->random_id ||
236       ping_pkt->seqno != p->last_seqno) {
237     elog(LOG_DEBUG(2), "dropping old or not-for-us reply packet");
238     goto done;
239   }
240 
241   /*
242    * compute the roundtrip time, by subtracting the time the reply
243    * arrived from the time the original ping was sent.
244    */
245   misc_tv_sub(&link_pkt->rcv_time, &p->time_sent);
246   p->rtt[p->num_replies++] = link_pkt->rcv_time;
247 
248   elog(LOG_NOTICE, "got reply %d from node %d, iface %s, rtt %.2f ms",
249        p->num_replies,
250        ping_pkt->node_id,
251        print_if_id(link_pkt->src.id),
252        misc_tv_msec_f(&link_pkt->rcv_time));
253 
254   if (p->num_replies >= MAX_PINGS) {
255     elog(LOG_ALERT, "max pings exceeded; shutting down");
256     ping_shutdown(p);
257   }
258 
259  done:
260   /* note, packet must be freed! */
261   free(link_pkt);
262   return EVENT_RENEW;
263 }
264 
265 
266 
267 int main(int argc, char *argv[])
268 {
269   ping_state_t ping_state;
270   int period = 1000;
271 
272   link_opts_t link_opts = {
273     link_index: LINK_INDEX_AUTO, /* use any available link */
274     pkt_type: PKT_TYPE_PING,     /* only give us ping-type packets */
275     receive: ping_receiver,      /* call this func when packets arrive */
276     data: (void *) &ping_state   /* store ping_state so link callback
277                                     can use it */
278   };
279 
280   emrun_opts_t emrun_opts = {
281     shutdown: ping_shutdown,
282     data: (void *) &ping_state
283   };
284 
285   /* Generic initialization common to most software */
286   misc_init(&argc, argv, CVSTAG);
287 
288   /* 
289    * Pick our random ID (a 14 bit number, from the definition of the
290    * ping packet in ping.h
291    */
292   memset(&ping_state, 0, sizeof(ping_state));
293   ping_state.random_id = random_range(1, (1 << 13));
294 
295   /*
296    * If the user provided a "gls" argument, open the flooding device
297    * instead of the normal data device.  Also, send pings more slowly.
298    */
299   if (argc>1 && !strcmp(argv[1], "gls")) {
300     link_opts.dev_type = LINK_DEV_GLS;
301     ping_state.dst_loc.x = atof(argv[2]);
302     ping_state.dst_loc.y = atof(argv[3]);
303     period *= 10;
304   }
305 
306   /*
307    * Open the link-layer device.  The options struct tells it we want
308    * the ping_receiver function to be called every time a packet of
309    * type PKT_TYPE_PING arrives.
310    *
311    * If the link-opening succeeds, the link struct is returned to us
312    * using the 2nd argument (i.e., written to ping_state.link)
313    */
314   if (link_open(&link_opts, &ping_state.link) < 0) {
315     elog(LOG_CRIT, "can't open %s: %m", link_name(&link_opts));
316     exit(1);
317   }
318 
319   elog_g(LOG_NOTICE, "running, using %s", link_name(&link_opts));
320 
321   /* Send an initial ping */
322   ping_send(&ping_state, &ping_state.dst_loc);
323 
324   /* And set a timer to send one every second */
325   g_timer_add(period, ping_periodic_timer, &ping_state, NULL, NULL);
326 
327   /*
328    * Start the event loop running - it should never exit (the shutdown
329    * handler is called when the program is supposed to stop)
330    */
331   emrun_init(&emrun_opts); /* this should be the last initialization */
332   g_main();
333   elog_g(LOG_CRIT, "event loop terminated abnormally!");
334   return 0;
335 }
336 
337 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.