Show conn-sender.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.c: This a "ping" client, which broadcasts a 'ping' packet, and
* then waits for replies from the network. This program, and the
* corresponding 'pingd' server, 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: conn-sender.c,v 1.6 2003/11/18 02:08:42 cerpa Exp $
*/
char conn_sender_c_cvsid[] = "$Id: conn-sender.c,v 1.6 2003/11/18 02:08:42 cerpa Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "emrun/emrun.h"
#include "link/link.h"
#include <string.h>
#include <libdev/logring_dev.h>
#include <libdev/command_dev.h>
#define LOGRING_SUPPORT
#define CONN_MAX_PACKET_SZ 1024 /* pkts can never be larger than this */
#define CONN_DEFAULT_PACKET_SZ 200
#define CONN_DEFAULT_SEND_DELAY 1000
#define CONN_DEFAULT_START_DELAY 3000
#define CONN_DEFAULT_TOTAL_CNT 1000
#define CONN_DEFAULT_BURST_CNT 50
#define CONN_DEFAULT_TOTAL_NODES 54
/* this is here only until this linkstats_pkt is moved to linkstats.h.
this structure is not used by this code, but the sizeof it is!
*/
typedef struct linkstats_pkt {
node_id_t src_id; /* my node ID */
uint64_t seqno; /* the sequence number of this packet */
uint8_t inner_type; /* the type of the packet once linkstats
header is stripped */
uint8_t data[0]; /* pointer to the following data packet */
} __attribute__ ((packed)) linkstats_pkt_t;
typedef struct app_state {
int total_sent;
link_context_t *link;
link_context_t *control_channel;
/* app configuration variables */
int total_cnt; /* total number of packets this node should send*/
int burst_cnt; /* number of packets that should be sent before handing
off token */
int send_delay; /* milliseconds between each packet send */
int start_delay; /* once token is received, number of milliseconds
before starting to send */
int packet_size; /* size includes link stats header, and link_header */
int total_nodes; /* how many nodes are in the experiment */
#ifdef LOGRING_SUPPORT
int token_fd;
#endif
} app_state_t;
typedef struct token_pkt {
int id;
} token_pkt_t;
/*******************************************************************/
/*
* Callback activated when we are asked to shut down by emrun.
* Compute and print summary statistics of all replies received
*/
void app_shutdown(void *data)
{
app_state_t *u = (app_state_t *) data;
if(close(u->token_fd)){
elog(LOG_ERR,"error closing the token logring");
}
elog(LOG_NOTICE, "%d packets sent",u->total_sent);
exit(0);
}
/*
* Construct a packet, and send it out over the wire, using the
* link context stored as part of our app_state.
*/
void app_send(app_state_t *u)
{
int pktsz, i;
/* Allocate a small buffer for the packet */
char buf[CONN_MAX_PACKET_SZ];
link_pkt_t *pkt = (link_pkt_t *) buf;
char *ptr = (char *)pkt->data;
elog(LOG_DEBUG(0), "in app_send");
/* initialize the link_pkt header */
memset(buf, 0, sizeof(buf));
pktsz = u->packet_size - sizeof(link_pkt_t) - sizeof(linkstats_pkt_t);
for (i = 0; i < pktsz; i++){
ptr[i] = (char)(256.0*random()/(RAND_MAX+1.0));
}
pkt->dst.id = LINK_BROADCAST;
pkt->type = PKT_TYPE_CONNTEST_DATA;
u->total_sent++;
/* now launch the packet! */
if (link_send(u->link, pkt, pktsz) < 0)
elog(LOG_ERR, "can't send on %s: %m", link_name(link_opts(u->link)));
else
elog(LOG_NOTICE, "broadcast packet %d", u->total_sent);
}
void token_send(app_state_t *u)
{
#ifdef UDPD_SUPPORT
/* Allocate a small buffer for the packet */
char buf[CONN_MAX_PACKET_SZ];
link_pkt_t *pkt = (link_pkt_t *) buf;
token_pkt_t *tpkt = (token_pkt_t *)(pkt->data);
/* send token containing id of next node to send */
int next_id = (my_node_id + 1) % u->total_nodes;
elog(LOG_DEBUG(0), "in token_send");
/* initialize the link_pkt header */
memset(buf, 0, sizeof(buf));
pkt->dst.id = LINK_BROADCAST;
pkt->type = PKT_TYPE_CONNTEST_DATA;
/* initialize the inner header */
tpkt->id = next_id;
/* now launch the packet! */
if (link_send(u->control_channel, pkt, sizeof(token_pkt_t)) < 0)
elog(LOG_ERR, "can't send on %s: %m",
link_name(link_opts(u->control_channel)));
else
elog(LOG_NOTICE, "broadcast token %d", tpkt->id);
#endif
#ifdef LOGRING_SUPPORT
/* send token containing id of next node to send */
char buf[CONN_MAX_PACKET_SZ];
int retval;
int next_id = (my_node_id + 1);
if (next_id > u->total_nodes) next_id -= u->total_nodes;
elog(LOG_NOTICE,"myid %d +1 = %d mod %d = %d",my_node_id, (my_node_id + 1),
u->total_nodes, next_id);
sprintf(buf,"%4d",next_id);
if ((retval = write(u->token_fd,buf,5))!= 5){
elog(LOG_ERR,"error writing token %d %d %s",retval, errno,strerror(errno));
exit(1);
}
elog(LOG_NOTICE, "wrote token %d", next_id);
#endif
}
/* Called every time our periodic ping timer expies. */
int app_periodic_timer(void *data, int interval, g_event_t *ev)
{
app_state_t *u = (app_state_t *) data;
elog(LOG_NOTICE, "in app_periodic timer");
app_send(u);
if ((u->total_sent % u->burst_cnt) == 0){
token_send(u);
if (u->total_sent >= u->total_cnt) app_shutdown(u);
return EVENT_DONE;
}
return EVENT_RENEW;
}
int start_timer(void *data, int interval, g_event_t *ev)
{
app_state_t *u = (app_state_t *)data;
elog(LOG_NOTICE,"starting burst...%d",u->send_delay);
g_timer_add(u->send_delay, app_periodic_timer, u, NULL,NULL);
return EVENT_DONE;
}
void start_sending(app_state_t *u)
{
elog(LOG_NOTICE,"starting to send...");
g_timer_add(u->start_delay,start_timer,u,NULL,NULL);
}
#ifdef LOGRING_SUPPORT
int new_token(gpointer data, gint fd, int fusd_condition, g_event_t *ev)
{
int retval, token;
char buf[10];
/* Get a pointer to my app state */
app_state_t *u = (app_state_t *)data;
if((retval = read(u->token_fd, &buf, 5))!=5){
elog(LOG_ERR,"problem reading token - error: %d %s",
retval,strerror(errno));
exit(1);
}
token = atoi(buf);
elog(LOG_DEBUG(0), "received token %d",token);
if (token == my_node_id){
elog(LOG_DEBUG(0), "Node %d has received token",my_node_id);
start_sending(u);
}
return EVENT_RENEW;
}
#endif
int pkt_receiver(link_pkt_t * link_pkt, ssize_t data_len, link_context_t *link)
{
/* got a packet, but do nothing */
elog(LOG_DEBUG(0),"received a packet");
free(link_pkt);
return EVENT_RENEW;
}
#ifdef UDPD_SUPPORT
int token_receiver(link_pkt_t * link_pkt, ssize_t data_len,
link_context_t *link)
{
/* Get a pointer to the data portion of the packet */
token_pkt_t *tpkt = (token_pkt_t *)(link_pkt->data);
/* Get a pointer to my app state */
app_state_t *u = (app_state_t *)(link_opts(link))->data;
elog(LOG_DEBUG(0), "in token_receiver");
if (tpkt->id == my_node_id){
start_sending(u);
}
free(link_pkt);
return EVENT_RENEW;
}
#endif
void usage(void)
{
fprintf(stderr,
/* "conn-sender release: %s\n" */
"\n"
"usage: conn-sender [-t total packets][-b burst packets]\n"
" [-p send delay][-d start delay]\n"
" [-s packet size][-n total nodes]\n"
/* ,CVSTAG */
);
exit(1);
}
int main(int argc, char *argv[])
{
int arg;
struct timeval tv;
struct timezone tz;
app_state_t u;
link_opts_t link_opts;
emrun_opts_t emrun_opts = {
shutdown: app_shutdown,
data: (void *) &u
};
memset(&u,0,sizeof(app_state_t));
u.total_cnt = CONN_DEFAULT_TOTAL_CNT;
u.burst_cnt = CONN_DEFAULT_BURST_CNT;
u.send_delay = CONN_DEFAULT_SEND_DELAY;
u.start_delay = CONN_DEFAULT_START_DELAY;
u.packet_size = CONN_DEFAULT_PACKET_SZ;
u.total_nodes = CONN_DEFAULT_TOTAL_NODES;
gettimeofday(&tv,&tz);
srandom(tv.tv_usec);
/* Generic initialization common to most software */
misc_init(&argc, argv, CVSTAG);
/************ Parse command-line arguments ***********/
opterr = 0;
while((arg = getopt(argc,argv, "ht:b:p:d:s:n:")) != EOF){
switch(arg){
case 'h':
usage();
break;
case 't':
if (!isdigit(*optarg)){
elog_g(LOG_CRIT, "invalid total message count '%s'",optarg);
exit(1);
} else {
u.total_cnt = atoi(optarg);
elog_g(LOG_NOTICE,"total_cnt set to %d",u.total_cnt);
}
break;
case 'b':
if (!isdigit(*optarg)){
elog_g(LOG_CRIT, "invalid burst count '%s'",optarg);
exit(1);
} else {
u.burst_cnt = atoi(optarg);
elog_g(LOG_NOTICE,"burst_cnt set to %d",u.burst_cnt);
}
break;
case 'p':
if (!isdigit(*optarg)){
elog_g(LOG_CRIT, "invalid send delay '%s'",optarg);
exit(1);
} else {
u.send_delay = atoi(optarg);
elog_g(LOG_NOTICE,"send_delay set to %d",u.send_delay);
}
break;
case 'd':
if (!isdigit(*optarg)){
elog_g(LOG_CRIT, "invalid start delay '%s'",optarg);
exit(1);
} else {
u.start_delay = atoi(optarg);
elog_g(LOG_NOTICE,"start_delay set to %d",u.start_delay);
}
break;
case 's':
if (!isdigit(*optarg)){
elog_g(LOG_CRIT, "invalid packet size '%s'",optarg);
exit(1);
} else {
u.packet_size = atoi(optarg);
elog_g(LOG_NOTICE,"packet_size set to %d",u.packet_size);
}
break;
case 'n':
if (!isdigit(*optarg)){
elog_g(LOG_CRIT, "invalid total nodes '%s'",optarg);
exit(1);
} else {
u.total_nodes = atoi(optarg);
elog_g(LOG_NOTICE,"total_nodes set to %d",u.total_nodes);
}
break;
default:
usage();
break;
}
}
/* advance past parsed options */
argc -= optind;
argv += optind;
/*
* Open the real link-layer device and the control channel device.
*/
elog(LOG_DEBUG(0),"assigning link_opts");
link_opts.link_index = 0;
link_opts.dev_type = LINK_DEV_DATA;
link_opts.pkt_type = PKT_TYPE_CONNTEST_DATA; /* only give us ping-type packets */
link_opts.receive = pkt_receiver; /* call this func when packets arrive */
link_opts.data = (void *) &u; /* store app_state so link callback can use it */
link_opts.q_opts.outq_len = 300;
link_opts.q_opts.inq_len = 300;
elog(LOG_DEBUG(0),"link_opts assigned");
if (link_open(&link_opts, &u.link) < 0) {
elog(LOG_CRIT, "can't open %s: %m", link_name(&link_opts));
exit(1);
}
elog_g(LOG_NOTICE, "running, using %s", link_name(&link_opts));
#ifdef UDPD_SUPPORT
link_opts.link_index = 1;
link_opts.dev_type = LINK_DEV_DATA;
link_opts.receive = token_receiver; /* call this func when packets arrive */
if (link_open(&link_opts, &u.control_channel) < 0) {
elog(LOG_CRIT, "can't open %s: %m", link_name(&link_opts));
exit(1);
}
elog_g(LOG_NOTICE, "running, using %s", link_name(&link_opts));
#endif
#ifdef LOGRING_SUPPORT
if((u.token_fd = open("/dev/logring/l1", O_RDWR))==-1){
elog(LOG_ERR,"can't open logring: %s",strerror(errno));
exit(1);
}
g_event_add(u.token_fd,FUSD_NOTIFY_INPUT,new_token,&u,NULL,NULL);
#endif
/* Try to set the POT of the radio to 56, just to demonstrate how
* POT-setting is done */
/*
POT = 56;
if (link_ioctl(u.link, LINK_SET_POT, &POT) < 0)
elog(LOG_CRIT, "warning: can't set POT: %m");
*/
/* node 1 starts things off */
if (my_node_id == 1){
g_timer_add(u.send_delay, app_periodic_timer, &u, NULL, 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