Show pingd.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.
*
*/
/*
* pingd.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
*
* $Id: pingd.c,v 1.22 2005/09/08 19:05:59 girod Exp $
*/
char pingd_c_cvsid[] = "$Id: pingd.c,v 1.22 2005/09/08 19:05:59 girod Exp $";
#include <stdio.h>
#include <stdlib.h>
#include "emrun/emrun.h"
#include "link/link.h"
#include "ping.h"
/*****************************************************************/
/* Duplicate suppression is commented out because it doesnt really
* work if you restart ping, and it also assumes low numbers for
* node IDs -LDG */
#undef DUP_SUPPRESS
#ifdef DUP_SUPPRESS
#define MAX_SOURCES 60
uint16_t last_seqno[MAX_SOURCES];
#endif
/*
* 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>",
" --uses <device>: Specify device to use\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_NOTICE, "got a packet from source %s and destination %s",
print_if_id(link_pkt->src.id), print_if_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_PING) {
elog(LOG_WARNING, "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;
}
#ifdef DUP_SUPPRESS
/*
* 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 */
#endif
/*
* 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 */
if (lu_send(link, link_pkt, data_len) < 0) {
elog(LOG_WARNING, "Can't send ping reply to %s: %m",
print_if_id(link_pkt->dst.id));
}
done:
/* note, packet must be freed! */
free(link_pkt);
return EVENT_RENEW;
}
int main(int argc, char *argv[])
{
int arg;
char *uses = NULL;
emrun_opts_t emrun_opts = {
shutdown: pingd_shutdown
};
#ifdef DUP_SUPPRESS
int i;
/* init seqno state */
for (i = 0; i < MAX_SOURCES; i++)
last_seqno[i] = 0;
#endif
/* generic initialization common to all programs */
misc_init(&argc, argv, CVSTAG);
/********** Parse command-line arguments ************/
uses = link_parse_uses(&argc, argv, NULL);
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_PING /* 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