Code Search for Developers
 
 
  

send_ping_device.c from EmStar at Krugle


Show send_ping_device.c syntax highlighted

/*
 *
 * Copyright (c) 2003 The Regents of the University of California.  All 
 * rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Neither the name of the University nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
 

/*
 * ping-device that will actively send pings when requested through a
 * status-device. Will be used for experiments in testing the change of
 * link-state over time.
 * We want to see:
 *   - how long it takes for two different ping-frequencies to
 * converge on the same link-quality measurement 
 *   - how quickly different frequencies will react to changes in link-quality
 *   - how stable each frequency is given a stable link-quality  
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <arpa/inet.h>

#include "emrun/emrun.h"
#include "link/link.h"
#include "ping.h"
#include "libmisc/misc_time.h"

/*******************************************************************/


#define MAX_PINGS 1000
#define LONG_INTERVAL 90000
#define SHORT_INTERVAL 11000
#define CMD_DEV_NAME "ping_device/command"
#define SHORT_STATE "Short"
#define LONG_STATE "Long"
#define PKT_TYPE_PING_SHORT 45
#define PKT_TYPE_PING_LONG 46

typedef struct ping_state {
  int random_id;		/* our randomly selected ID, to
				 * differentiate our packets from any
				 * other ping processes that might be
				 * happening at the same time. */
  int last_seqno;		/* last seqno we used */
  int total_sent;		/* total pings sent */
  struct timeval time_sent;	/* time we sent the most recent ping */
  struct timeval rtt[MAX_PINGS]; /* rtts of responses we've received */
  int num_replies;		/* number of responses we've received */
  lu_context_t *link;		/* link we're using to ping on */
  int pkt_type;
} ping_state_t;

typedef struct pd_ctx {
  uint sint; /* Interval for short timer */
  uint lint; /* Interval for long timer */
  g_event_t* stimer;
  g_event_t* ltimer;
  ping_state_t ps_short;
  ping_state_t ps_long;
} pd_ctx_t;

void compute_stats(ping_state_t* p, char* state);

/*******************************************************************/

/*
 * Callback activated when we are asked to shut down by emrun.
 * Compute and print summary statistics of all replies received
 */  
void ping_shutdown(void *data)
{
  pd_ctx_t *pd = (pd_ctx_t *) data;
  ping_state_t* p;
  int j;
  char* state;

  for (j = 0; j < 2; j++)
  {
    if (j == 0) 
    {
      p = &pd->ps_short;
      state = SHORT_STATE;
    }
    else 
    {
      p = &pd->ps_long;
      state = LONG_STATE;
    }

    if (!p->num_replies) {
      elog_g(LOG_NOTICE, "%s: %d pings sent, no replies received", 
		      state, p->total_sent);
    }
    else compute_stats(p, state);
  }

  /* Now shut down */
  exit(0);
}


/*
 * Construct a ping packet, and send it out over the wire, using the
 * link context stored as part of our "ping" state.
 */
void ping_send(ping_state_t *p, int pkt_type)
{
  /* Allocate a small buffer for the packet */
  char buf[200];
  link_pkt_t *pkt = (link_pkt_t *) buf;
  ping_pkt_t *ping_pkt = (ping_pkt_t *) pkt->data;
  int this_seq = p->last_seqno + 1;

  /* initialize the outer header (the link_pkt header) */
  memset(buf, 0, sizeof(buf));
  pkt->dst.id = LINK_BROADCAST;
  pkt->type = pkt_type;

  /* and our application-layer (ping) protocol data */
  ping_pkt->cmd = PING_REQUEST;
  ping_pkt->random_id = p->random_id;
  ping_pkt->seqno = this_seq;

  /* now launch the packet! */
  if (lu_send(p->link, pkt, sizeof(ping_pkt_t)) < 0) {
    if (errno != EAGAIN)
      elog(LOG_ERR, "can't send on %s: %m", lu_name(p->link, NULL));
  }
  else {
    elog(LOG_NOTICE, "broadcast ping seqno %d", ping_pkt->seqno);
    
    /* remember what time it is, so we can calculate RTT */
    gettimeofday(&p->time_sent, NULL);
    p->last_seqno = this_seq;
    p->total_sent++;
  }
}


/* Called every time our periodic ping timer expies.  */
int ping_send_short(void *data, int interval, g_event_t *ev)
{
  pd_ctx_t* pd = (pd_ctx_t *) data;
  elog(LOG_DEBUG(1), "%s\n", SHORT_STATE);
  compute_stats(&pd->ps_short, SHORT_STATE);
  ping_send(&pd->ps_short, PKT_TYPE_PING_SHORT);
  return EVENT_RENEW;
}

int ping_send_long(void *data, int interval, g_event_t *ev)
{
  pd_ctx_t* pd = (pd_ctx_t *) data;
  struct timeval tv;
  gettimeofday(&tv, NULL);
  elog(LOG_DEBUG(1), "%s: time called %s\n", LONG_STATE, misc_tv_to_str(&tv));
  compute_stats(&pd->ps_long, LONG_STATE);
  ping_send(&pd->ps_long, PKT_TYPE_PING_LONG);
  return EVENT_RENEW;
}

/*
 * This callback is called whenever a packet arrives on the link we
 * opened.  "pkt" is a pointer to a link_pkt_t header followed by
 * data_len bytes of data.  (data_len is the length of the data
 * following the header; it doesn't include the size of the link_pkt_t
 * header itself.)  "link" is a pointer to the link that the packet
 * was received on, and can be used for sending a reply packet (we
 * don't send reply packets from the receiver callback here, but see
 * pingd for an example where we do.)
 */
int ping_receiver(lu_context_t *link, link_pkt_t *link_pkt, ssize_t data_len)
{
  /* Get a pointer to the data portion of the packet */
  ping_pkt_t *ping_pkt = (ping_pkt_t *) link_pkt->data;

  /* We stored a pointer to the 'ping_state' struct as the "data"
   * field of link_opts in main().  Now, we retrieve that pointer. */
  ping_state_t *p = (ping_state_t *) lu_data(link);

  if (link_pkt->type != p->pkt_type) {
    elog(LOG_ERR, "RECEIVED INCORRECT pkt-type %d, expecting %d\n", 
		    link_pkt->type, p->pkt_type);
  }

  /*
   * Make sure the data portion of the packet is exactly the right
   * size (i.e., the size of our "ping" application-layer protocol
   * frame.
   */
  if (data_len != sizeof(ping_pkt_t)) {
    elog(LOG_ERR, "got a short ping packet (%d bytes)!", data_len);
    goto done;
  }

  /* We now know that the data pointed to by ping_pkt is valid */

  /*
   * Ignore everything but ping replies (i.e. ignore requests that
   * other ping clients might be sending.)
   */
  if (ping_pkt->cmd != PING_REPLY) {
    elog(LOG_DEBUG(2), "got non-reply packet - dropping");
    goto done;
  }

  /*
   * Ignore replies not meant for us (based on the random ID), or that
   * are arriving late for the previous request
   */
  if (ping_pkt->random_id != p->random_id ||
      ping_pkt->seqno != p->last_seqno) {
    elog(LOG_DEBUG(2), "dropping old or not-for-us reply packet");
    goto done;
  }

  /*
   * compute the roundtrip time, by subtracting the time the reply
   * arrived from the time the original ping was sent.
   */
  misc_tv_sub(&link_pkt->rcv_time, &p->time_sent);
  p->rtt[p->num_replies++] = link_pkt->rcv_time;

  elog(LOG_NOTICE, "got reply %d from node %d, iface %s, rtt %.2f ms, %d hops away",
       p->num_replies,
       ping_pkt->node_id,
       print_if_id(link_pkt->src.id),
       misc_tv_msec_f(&link_pkt->rcv_time),
       PING_MAX_HOPS - link_pkt->max_hops + 1);

  if (p->num_replies >= MAX_PINGS) {
    elog(LOG_ALERT, "max pings exceeded; shutting down");
    ping_shutdown(p);
  }

 done:
  /* note, packet must be freed! */
  free(link_pkt);
  return EVENT_RENEW;
}


void usage(char *name)
{
  misc_print_usage
    (name, "-l <long-device> -s <short-device> [-f] [-t <linterval>] [-r <sinterval>]",
     "  --l/suses <device>: Specify device for long/short-intervals to use\n"
     "  --flood: send pings as fast as possible\n"
     "  --l[t]/sint[r]: interval for long/short period (ms)\n"
     );
  exit(1);
}

int ping_command(char* cmd, size_t size, void* data)
{
  pd_ctx_t* pd = (pd_ctx_t *)data;
  uint sint = 0;
  uint lint = 0;

  parser_state_t ps = {
    input: (void *) cmd,
    input_len: size + 1
  };

  if (!pd) return EVENT_DONE;
  elog(LOG_DEBUG(1),"string = %s\n", cmd);

  /* Parse command string */
  while(misc_parse_next_kvp(&ps) >= 0) 
  {
    if (strcmp(ps.key, "sint") == 0) 
    {
      sint = (uint) atoi(ps.value);
      elog(LOG_DEBUG(1), "Changing sint val from %d to %d\n", pd->sint, sint);
      pd->sint = sint;
    }
    if (strcmp(ps.key, "lint") == 0) 
    {
      lint = (uint) atoi(ps.value);
      elog(LOG_DEBUG(1), "Changing lint val from %d to %d\n", pd->lint, lint);
      pd->lint = lint;
    }
  }

  /* Set timer if we get correct command */
  elog(LOG_DEBUG(1), "sint = %d, list = %d\n", sint, lint);
  if (!pd->stimer) return EVENT_DONE;
  if (!pd->ltimer) return EVENT_DONE;
  if (sint > 0) 
  {
    if (pd->stimer) g_timer_resched(pd->stimer, sint);
    else g_timer_add(sint, ping_send_short, pd, NULL, &pd->stimer);
    elog(LOG_DEBUG(1), "Reprogrammed short timer with int %d\n", sint);
  }
  if (lint > 0) 
  {
    if (pd->ltimer) g_timer_resched(pd->ltimer, lint);
    else g_timer_add(lint, ping_send_long, pd, NULL, &pd->ltimer);
    elog(LOG_DEBUG(1), "Reprogrammed long timer with int %d\n", lint);
  }
  elog(LOG_DEBUG(1), "done with command\n");
  return EVENT_RENEW;
}

char* ping_usage(void* data)
{
  static char buf[200];
  sprintf(buf, "usage: write lint=<int [ms]>:sint=<int [ms]> to specify interval for long/short pings\n");
  return buf;
}

int main(int argc, char *argv[])
{
  pd_ctx_t pd = {
    lint:LONG_INTERVAL,
    sint:SHORT_INTERVAL,
  };

  char *luses = NULL;
  char *suses = NULL;

  emrun_opts_t emrun_opts = {
    shutdown: ping_shutdown,
    data: (void *) &pd
  };

  cmd_dev_opts_t c_opts = {
    device: {
      devname: CMD_DEV_NAME,
      device_info: &pd,
    },
    command: ping_command,
    usage: ping_usage
  };

  /* Generic initialization common to most software */
  misc_init(&argc, argv, CVSTAG);
  
  if (!g_command_dev(&c_opts, NULL))
  {
    elog(LOG_ERR, "UNable to create command device: %s!\n", c_opts.device.devname);
  }

  /* get the --uses arg */
  if (!(suses = misc_parse_out_option(&argc, argv, "suses", 's')))
  {
    elog(LOG_CRIT, "Please specify a link to use for the short-interval!\n");
    usage(argv[0]);
  }
  if (!(luses = misc_parse_out_option(&argc, argv, "luses", 'l')))
  {
    elog(LOG_CRIT, "Please specify a link to use for the long-interval!\n");
    usage(argv[0]);
  }

  if (misc_parse_option_as_uint(&argc, argv, "lint", 't', &pd.lint))
  {
    elog(LOG_DEBUG(1), "have long-int spec: %d\n", pd.lint);
    elog(LOG_CRIT, "have long-int spec: %d\n", pd.lint);
  }
  if (misc_parse_option_as_uint(&argc, argv, "sint", 'r', &pd.sint))
  {
    elog(LOG_DEBUG(1), "have short-int spec: %d\n", pd.sint);
    elog(LOG_CRIT, "have short-int spec: %d\n", pd.sint);
  }
  elog(LOG_DEBUG(1), "long-int = %d, short-int = %d\n", pd.lint, pd.sint);

  /* add'l args? */
  if (misc_args_remain(&argc, argv)) {
    elog(LOG_CRIT, "Additional unparsed arguments!");
    usage(argv[0]);
  }

  /* 
   * Pick our random ID (a 14 bit number, from the definition of the
   * ping packet in ping.h
   */
  memset(&pd, 0, sizeof(pd_ctx_t));
  pd.ps_short.random_id = random_range(1, (1 << 13));
  pd.ps_long.random_id = random_range(1, (1 << 13));

  /*
   * Open the link-layer device.  The options struct tells it we want
   * the ping_receiver function to be called every time a packet of
   * type PKT_TYPE_PING arrives.
   *
   * If the link-opening succeeds, the link struct is returned to us
   * using the 2nd argument (i.e., written to pd.ps_short.link)
   */
  {
    lu_opts_t lu_opts = {
      opts: {
	name: suses,
	data: &pd.ps_short,
	pkt_type: PKT_TYPE_PING_SHORT /* only give us ping-type packets */
      },
      receive: ping_receiver	 /* call this func when packets arrive */
    };
    
    /* Open state for short-interval ping-device */
    pd.ps_short.pkt_type = PKT_TYPE_PING_SHORT;
    if (lu_open(&lu_opts, &pd.ps_short.link) < 0) {
      elog(LOG_CRIT, "can't open %s: %m", link_name(&lu_opts.opts, NULL));
      exit(1);
    }

    /* Open state for long-interval ping-device */
    lu_opts.opts.data = &pd.ps_long;
    lu_opts.opts.name = luses;
    lu_opts.opts.pkt_type = PKT_TYPE_PING_LONG;
    pd.ps_long.pkt_type = PKT_TYPE_PING_LONG;
    if (lu_open(&lu_opts, &pd.ps_long.link) < 0) {
      elog(LOG_CRIT, "can't open %s: %m", link_name(&lu_opts.opts, NULL));
      exit(1);
    }
    elog_g(LOG_NOTICE, "running, using short:%s and long:%s", 
	lu_name(pd.ps_short.link, NULL),
	lu_name(pd.ps_long.link, NULL));
  }

  /* And set a timer to send one every second */
  g_timer_add(SHORT_INTERVAL, ping_send_short, &pd, NULL, &pd.stimer);
  g_timer_add(LONG_INTERVAL, ping_send_long, &pd, NULL, &pd.ltimer);

  /*
   * Start the event loop running - it should never exit (the shutdown
   * handler is called when the program is supposed to stop)
   */
  emrun_init(&emrun_opts); /* this should be the last initialization */
  g_main();
  elog_g(LOG_CRIT, "event loop terminated abnormally!");
  return 0;
}

/*** LOCAL FUNCS ***/
void compute_stats(ping_state_t* p, char* state)
{
  struct timeval min, max, sum;
  int i;

  min = max = sum = p->rtt[0];
  /* This loop finds the min and max RTTs, sums all the RTTs for
   * average, and counts how many replies we received. */
  for (i = 1; i < p->num_replies; i++) {

    /* misc_tv_* are convenience functions for doing computations on a
     * struct timeval found in libmisc */
    if (misc_tv_offset_neg(&p->rtt[i], &min) < 0)
      min = p->rtt[i];
    if (misc_tv_offset_neg(&p->rtt[i], &max) > 0)
      max = p->rtt[i];

    misc_tv_add(&sum, &p->rtt[i]);
  }

  /* compute average from the sum */
  elog(LOG_NOTICE, "%s: %d pings sent, %d replies received"
       "min/avg/max rtt %.1f/%.1f/%.1f ms",  state,
       p->total_sent, p->num_replies, 
       misc_tv_msec_f(&min),
       ((float) sum.tv_sec + (sum.tv_usec / MILLION_F)) * 1000.0 /
       p->num_replies,
       misc_tv_msec_f(&max));
  if (p->total_sent > 0) elog(LOG_NOTICE, "%% received: %d%%\n", 
		  100 * p->num_replies/p->total_sent);
}




See more files for this project here

EmStar

EmStar is a software system for developing and deploying wireless sensor networks involving Linux-based platforms. As the wireless sensor network community has attempted to deploy more complex designs---large-scale, long-lived systems that need self-organization and adaptivity---a number of difficult software design issues have arisen. Advances in software design have not kept pace with the capabilities of hardware. This is because designing for an adaptive, efficient, and useful sensor network has turned out to be surprisingly complex and difficult. EmStar is a Linux-based software framework, whose goal is to dramatically reduce this complexity, enabling work to be shared and reused, and simplifying and speeding the design of new sensor network applications.

Project homepage: http://cvs.cens.ucla.edu/emstar/
Programming language(s): C,Shell Script
License: other

  link_quality
  pd.run
  ping-flood.run
  ping-flood.sim
  ping-ls-udp.run
  ping.c
  ping.h
  ping_device.sim
  ping_device_rcvr.run
  ping_device_sndr.run
  pingd.c
  pingd.run
  pingd.sim
  receive_ping_device.c
  send_ping_device.c
  test.run
  test.sim
  test_mote.run
  test_mote.sim