receive_ping_device.c from EmStar at Krugle
Show receive_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.
*
*/
/*
* receive_ping_device.c: This a "ping" daemon, which waits for ping-type network
* packets. Whenever one is received, pingd sends a reply back to the
* sender. This program, and the corresponding 'ping' client, serve
* as a useful example for various tasks:
*
* - How to create an application-layer protocol format
* - How to send packets to the network
* - How to wait for and react to packets that come from the network
* - How to filter incoming packets
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "emrun/emrun.h"
#include "link/link.h"
#include "ping.h"
/*****************************************************************/
#define MAX_SOURCES 60
uint16_t last_seqno[MAX_SOURCES];
int pkt_type = PKT_TYPE_PING;
/*
* Simple callback activated when we are asked to shut down by emrun
*/
void pingd_shutdown(void *data)
{
elog(LOG_NOTICE, "ping daemon shutting down");
exit(0);
}
static void usage(char *name)
{
misc_print_usage
(name, "-U <device> -p <pkt-type>",
" --uses <device>: Specify device to use\n -p <45=short/46=long>\n"
);
exit(1);
}
/*
* 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.
*/
int pingd_receiver(lu_context_t *link, link_pkt_t *link_pkt,
ssize_t data_len)
{
ping_pkt_t *ping_pkt = (ping_pkt_t *) link_pkt->data;
elog(LOG_CRIT, "got a packet from source %d and destination %d",
link_pkt->src.id, link_pkt->dst.id);
/*
* Make sure the packet has the right packet type. Since we
* specified the desired packet type when we registered to receive
* packets, this test should never fail.
*/
if (link_pkt->type != pkt_type) {
elog(LOG_WARNING, "WARN got a packet not meant for us - filter failed!");
goto done;
}
/*
* 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, not %d)!",
data_len, sizeof(ping_pkt_t));
goto done;
}
/* We now know that the data pointed to by ping_pkt is valid */
elog(LOG_DEBUG(50), "got a ping packet: cmd: %u, random_id: %u,"
"seqno: %u, node id: %u", ping_pkt->cmd, ping_pkt->random_id,
ping_pkt->seqno, ping_pkt->node_id);
/*
* Ignore everything but ping requests. Note that we might get
* PING_REPLY packets, e.g. if another process on this same
* interface is acting as a ping client and getting their
* responses.
*/
if (ping_pkt->cmd != PING_REQUEST) {
elog(LOG_DEBUG(2), "got non-request packet - dropping");
goto done;
}
/*
* Verify that we haven't recieve this packet yet (we can receive
* duplicates if using hbh and acks are lost)
*/
if (ping_pkt->seqno <= last_seqno[ping_pkt->node_id])
goto done; /* we ignore the duplicate */
else
last_seqno[ping_pkt->node_id] = ping_pkt->seqno; /* update state */
/*
* Now, we turn the packet around and send it back out again.
*/
/* Fill in our node ID (this is not the same as interface ID) */
ping_pkt->node_id = my_node_id;
/* Destination link interface ID is the packet's source */
link_pkt->dst.id = link_pkt->src.id;
/* Source link interface ID is our id */
link_pkt->src.id = my_node_id;
/* Set the maximum number of hops, in case we're using a routed
* interface */
link_pkt->max_hops = PING_MAX_HOPS;
/* Change cmd from request to reply; seqno stays the same */
ping_pkt->cmd = PING_REPLY;
elog(LOG_DEBUG(1), "Got a ping packet on %s - replying",
lu_name(link, NULL));
/* Now send it out on the interface we received it from */
lu_send(link, link_pkt, data_len);
done:
/* note, packet must be freed! */
free(link_pkt);
return EVENT_RENEW;
}
int main(int argc, char *argv[])
{
int arg, i;
char *uses = NULL;
emrun_opts_t emrun_opts = {
shutdown: pingd_shutdown
};
/* init seqno state */
for (i = 0; i < MAX_SOURCES; i++)
last_seqno[i] = 0;
/* generic initialization common to all programs */
misc_init(&argc, argv, CVSTAG);
/********** Parse command-line arguments ************/
uses = link_parse_uses(&argc, argv, NULL);
if (misc_parse_option_as_uint(&argc, argv, "", 'p', &pkt_type))
{
elog(LOG_DEBUG(1), "pkt-type %d\n", pkt_type);
}
elog(LOG_DEBUG(1), "now pkt-type %d\n", pkt_type);
opterr = 0;
while ((arg = getopt(argc, argv, "hs")) != EOF) {
switch (arg) {
default:
case '?':
elog_g(LOG_CRIT, "invalid option '-%c' (use -h for help)", optopt);
case 'h':
usage(argv[0]);
break;
}
}
/* add'l args? */
if (misc_args_remain(&argc, argv)) {
elog(LOG_CRIT, "Additional unparsed arguments!");
usage(argv[0]);
}
/* advance past parsed options */
argc -= optind;
argv += optind;
/* If no link interfaces were explicitly given with --uses argument, fail */
if (uses == NULL) {
elog(LOG_CRIT, "Please specify a --uses argument!");
exit(1);
}
/*
* Pingd is a "link user". We use lu_open() to 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.
*
* Note, we are passing NULL as the 2nd argument since we don't need
* to save the link reference in this case. See the 'ping' program
* for an example where we do use it.
*/
{
lu_opts_t lu_opts = {
opts: {
name: uses,
pkt_type: pkt_type /* only give us ping-type packets */
},
receive: pingd_receiver /* call this func when packets arrive */
};
if (lu_open(&lu_opts, NULL) < 0) {
elog(LOG_CRIT, "can't open %s: %m", link_name(&(lu_opts.opts), NULL));
exit(1);
} else {
elog(LOG_NOTICE, "listening to %s", link_name(&(lu_opts.opts), NULL));
}
}
/*
* 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;
}
See more files for this project here