📄 agent.cc.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1990-1997 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /usr/src/mash/repository/vint/ns-2/agent.cc,v 1.55 1999/03/13 03:52:38 haoboy Exp $ (LBL)";
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "agent.h"
#include "ip.h"
#include "flags.h"
#include "address.h"
#include "app.h"
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
static class AgentClass : public TclClass {
public:
AgentClass() : TclClass("Agent") {}
TclObject* create(int, const char*const*) {
return (new Agent(PT_NTYPE));
}
} class_agent;
int Agent::uidcnt_; /* running unique id */
Agent::Agent(packet_t pkttype) :
size_(0), type_(pkttype),
channel_(0), traceName_(NULL),
oldValueList_(NULL), app_(0)
{
off_ip_ = hdr_ip::offset();
#if defined(TCLCL_CLASSINSTVAR)
#else /* ! TCLCL_CLASSINSTVAR */
/*
* the following is a workaround to allow
* older scripts that use "class_" instead of
* flowid to work -K
*/
bind("class_", (int*)&fid_);
// memset(pending_, 0, sizeof(pending_));
// this is really an IP agent, so set up
// for generating the appropriate IP fields...
bind("addr_", (int*)&addr_);
bind("dst_", (int*)&dst_);
bind("fid_", (int*)&fid_);
bind("prio_", (int*)&prio_);
bind("flags_", (int*)&flags_);
bind("ttl_", &defttl_);
#ifdef OFF_HDR
bind("off_ip_", &off_ip_);
#endif
#endif /* TCLCL_CLASSINSTVAR */
#ifdef VIKI
bind_time("local_deadline_increment",&local_deadline_increment);
bind("egress_node",&egress_node);
#endif
//begin archanakrishna
bind("ingressnodeofpacket_", (int*)&ingressnodeofpacket_);
bind("egressnodeofpacket_", (int*)&egressnodeofpacket_);
bind("classofpacket_", &classofpacket_);
//end archanakrishna
}
#if defined(TCLCL_CLASSINSTVAR)
void
Agent::delay_bind_init_all()
{
delay_bind_init_one("addr_");
delay_bind_init_one("dst_");
delay_bind_init_one("fid_");
delay_bind_init_one("prio_");
delay_bind_init_one("flags_");
delay_bind_init_one("ttl_");
delay_bind_init_one("class_");
#ifdef OFF_HDR
delay_bind_init_one("off_ip_");
#endif
Connector::delay_bind_init_all();
}
int
Agent::delay_bind_dispatch(const char *varName, const char *localName)
{
DELAY_BIND_DISPATCH(varName, localName, "addr_", delay_bind, (int*)&addr_);
DELAY_BIND_DISPATCH(varName, localName, "dst_", delay_bind, (int*)&dst_);
DELAY_BIND_DISPATCH(varName, localName, "fid_", delay_bind, (int*)&fid_);
DELAY_BIND_DISPATCH(varName, localName, "prio_", delay_bind, (int*)&prio_);
DELAY_BIND_DISPATCH(varName, localName, "flags_", delay_bind, (int*)&flags_);
DELAY_BIND_DISPATCH(varName, localName, "ttl_", delay_bind, &defttl_);
DELAY_BIND_DISPATCH(varName, localName, "off_ip_", delay_bind, &off_ip_);
DELAY_BIND_DISPATCH(varName, localName, "class_", delay_bind, (int*)&fid_);
return Connector::delay_bind_dispatch(varName, localName);
}
#endif /* TCLCL_CLASSINSTVAR */
Agent::~Agent()
{
if (oldValueList_ != NULL) {
OldValue *p;
while (oldValueList_ != NULL) {
oldValueList_ = oldValueList_->next_;
delete p;
p = oldValueList_;
}
}
}
int Agent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "delete-agent-trace") == 0) {
if ((traceName_ == 0) || (channel_ == 0))
return (TCL_OK);
deleteAgentTrace();
return (TCL_OK);
} else if (strcmp(argv[1], "show-monitor") == 0) {
if ((traceName_ == 0) || (channel_ == 0))
return (TCL_OK);
monitorAgentTrace();
return (TCL_OK);
} else if (strcmp(argv[1], "close") == 0) {
close();
return (TCL_OK);
} else if (strcmp(argv[1], "listen") == 0) {
listen();
return (TCL_OK);
} else if (strcmp(argv[1], "dump-namtracedvars") == 0) {
enum_tracedVars();
return (TCL_OK);
}
}
else if (argc == 3) {
if (strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
if (channel_ == 0) {
tcl.resultf("trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
} else if (strcmp(argv[1], "add-agent-trace") == 0) {
// we need to write nam traces and set agent trace name
if (channel_ == 0) {
tcl.resultf("agent %s: no trace file attached", name_);
return (TCL_OK);
}
addAgentTrace(argv[2]);
return (TCL_OK);
} else if (strcmp(argv[1], "connect") == 0) {
connect((nsaddr_t)atoi(argv[2]));
return (TCL_OK);
} else if (strcmp(argv[1], "send") == 0) {
sendmsg(atoi(argv[2]));
return (TCL_OK);
} else if (strcmp(argv[1], "set_pkttype") == 0) {
set_pkttype(packet_t(atoi(argv[2])));
return (TCL_OK);
}
}
else if (argc == 4) {
if (strcmp(argv[1], "sendmsg") == 0) {
sendmsg(atoi(argv[2]), argv[3]);
return (TCL_OK);
}
}
else if (argc == 5) {
if (strcmp(argv[1], "sendto") == 0) {
sendto(atoi(argv[2]), argv[3], (nsaddr_t)atoi(argv[4]));
return (TCL_OK);
}
}
if (strcmp(argv[1], "tracevar") == 0) {
// wrapper of TclObject's trace command, because some tcl
// agents (e.g. srm) uses it.
const char* args[4];
char tmp[6];
strcpy(tmp, "trace");
args[0] = argv[0];
args[1] = tmp;
args[2] = argv[2];
if (argc > 3)
args[3] = argv[3];
return (Connector::command(argc, args));
}
return (Connector::command(argc, argv));
}
void Agent::flushAVar(TracedVar *v)
{
char wrk[256], value[128];
int n;
// XXX we need to keep track of old values. What's the best way?
v->value(value);
if (strcmp(value, "") == 0)
// no value, because no writes has occurred to this var
return;
sprintf(wrk, "f -t %.17f -s %d -d %d -n %s -a %s -o %s -T v -x",
Scheduler::instance().clock(),
addr_ >> (Address::instance().NodeShift_[1]),
dst_ >> (Address::instance().NodeShift_[1]),
v->name(),
traceName_,
value);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(channel_, wrk, n+1);
}
void Agent::deleteAgentTrace()
{
char wrk[256];
// XXX we don't know InstVar outside of Tcl! Is there any
// tracedvars hidden in InstVar? If so, shall we have a tclclInt.h?
TracedVar* var = tracedvar_;
for ( ; var != 0; var = var->next_)
flushAVar(var);
// we need to flush all var values to trace file,
// so nam can do backtracing
sprintf(wrk, "a -t %.17f -s %d -d %d -n %s -x",
Scheduler::instance().clock(),
addr_ >> (Address::instance().NodeShift_[1]),
dst_ >> (Address::instance().NodeShift_[1]),
traceName_);
if (traceName_ != NULL)
delete[] traceName_;
traceName_ = NULL;
}
OldValue* Agent::lookupOldValue(TracedVar *v)
{
OldValue *p = oldValueList_;
while ((p != NULL) && (p->var_ != v))
p = p->next_;
return p;
}
void Agent::insertOldValue(TracedVar *v, const char *value)
{
OldValue *p = new OldValue;
assert(p != NULL);
strncpy(p->val_, value, min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
p->var_ = v;
p->next_ = NULL;
if (oldValueList_ == NULL)
oldValueList_ = p;
else {
p->next_ = oldValueList_;
oldValueList_ = p;
}
}
// callback from traced variable updates
void Agent::trace(TracedVar* v)
{
if (channel_ == 0)
return;
char wrk[256], value[128];
int n;
// XXX we need to keep track of old values. What's the best way?
v->value(value);
// XXX hack: how do I know ns has not started yet?
// if there's nothing in value, return
Tcl::instance().eval("[Simulator instance] is-started");
if (Tcl::instance().result()[0] == '0')
// Simulator not started, do nothing
return;
OldValue *ov = lookupOldValue(v);
if (ov != NULL) {
sprintf(wrk,
"f -t %.17f -s %d -d %d -n %s -a %s -v %s -o %s -T v",
Scheduler::instance().clock(),
addr_ >> (Address::instance().NodeShift_[1]),
dst_ >> (Address::instance().NodeShift_[1]),
v->name(),
traceName_,
value,
ov->val_);
strncpy(ov->val_,
value,
min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
} else {
// if there is value, insert it into old value list
sprintf(wrk, "f -t %.17f -s %d -d %d -n %s -a %s -v %s -T v",
Scheduler::instance().clock(),
addr_ >> (Address::instance().NodeShift_[1]),
dst_ >> (Address::instance().NodeShift_[1]),
v->name(),
traceName_,
value);
insertOldValue(v, value);
}
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(channel_, wrk, n+1);
}
void Agent::monitorAgentTrace()
{
char wrk[256];
int n;
double curTime = (&Scheduler::instance() == NULL ? 0 :
Scheduler::instance().clock());
sprintf(wrk, "v -t %.17f monitor_agent %d %s",
curTime,
addr_ >> (Address::instance().NodeShift_[1]),
traceName_);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
if (channel_)
(void)Tcl_Write(channel_, wrk, n+1);
}
void Agent::addAgentTrace(const char *name)
{
char wrk[256];
int n;
double curTime = (&Scheduler::instance() == NULL ? 0 :
Scheduler::instance().clock());
sprintf(wrk, "a -t %.17f -s %d -d %d -n %s",
curTime,
addr_ >> (Address::instance().NodeShift_[1]),
dst_ >> (Address::instance().NodeShift_[1]),
name);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
if (channel_)
(void)Tcl_Write(channel_, wrk, n+1);
// keep agent trace name
if (traceName_ != NULL)
delete[] traceName_;
traceName_ = new char[strlen(name)+1];
strcpy(traceName_, name);
}
void Agent::timeout(int)
{
}
/*
* Callback to application to notify the reception of a number of bytes
*/
void Agent::recvBytes(int nbytes)
{
if (app_)
app_->recv(nbytes);
}
/*
* Callback to application to notify the termination of a connection
*/
void Agent::idle()
{
if (app_)
app_->resume();
}
/*
* Assign application pointer for callback purposes
*/
void Agent::attachApp(Application *app)
{
app_ = app;
}
void Agent::close()
{
}
void Agent::listen()
{
}
/*
* This function is a placeholder in case applications want to dynamically
* connect to agents (presently, must be done at configuration time).
*/
void Agent::connect(nsaddr_t /*dst*/)
{
/*
dst_ = dst;
*/
}
/*
* Place holders for sending application data
*/
void Agent::sendmsg(int /*sz*/, const AppData* /*data*/, const char* /*flags*/)
{
fprintf(stderr,
"Agent::sendmsg(int, const AppData*, const char*) not implemented\n");
abort();
}
void Agent::sendto(int /*sz*/, const AppData* /*data*/, const char* /*flags*/)
{
fprintf(stderr,
"Agent::sendmsg(int, const AppData*, const char*) not implemented\n");
abort();
}
void Agent::sendmsg(int /*nbytes*/, const char* /*flags*/)
{
}
/*
* This function is a placeholder in case applications want to dynamically
* connect to agents (presently, must be done at configuration time).
*/
void Agent::sendto(int /*nbytes*/, const char /*flags*/[], nsaddr_t /*dst*/)
{
/*
dst_ = dst;
sendmsg(nbytes, flags);
*/
}
void Agent::recv(Packet* p, Handler*)
{
if (app_)
app_->recv(hdr_cmn::access(p)->size());
/*
* didn't expect packet (or we're a null agent?)
*/
Packet::free(p);
}
/*
* initpkt: fill in all the generic fields of a pkt
*/
void
Agent::initpkt(Packet* p) const
{
hdr_cmn* ch = hdr_cmn::access(p);
ch->uid() = uidcnt_++;
ch->ptype() = type_;
ch->size() = size_;
ch->timestamp() = Scheduler::instance().clock();
ch->iface() = UNKN_IFACE.value(); // from packet.h (agent is local)
ch->direction() = 0;
ch->ref_count() = 0; /* reference count */
ch->error() = 0; /* pkt not corrupt to start with */
//begin archanakrishna
ch->pktingressnode() = ingressnodeofpacket_;
ch->pktegressnode() = egressnodeofpacket_;
ch->classofpacket() = classofpacket_;
//end archanakrishna
hdr_ip* iph = hdr_ip::access(p);
iph->src() = addr_;
iph->dst() = dst_;
iph->flowid() = fid_;
iph->prio() = prio_;
iph->ttl() = defttl_;
hdr_flags* hf = hdr_flags::access(p);
hf->ecn_capable_ = 0;
hf->ecn_ = 0;
hf->eln_ = 0;
hf->ecn_to_echo_ = 0;
hf->fs_ = 0;
hf->no_ts_ = 0;
hf->pri_ = 0;
hf->cong_action_ = 0;
}
/*
* allocate a packet and fill in all the generic fields
*/
Packet*
Agent::allocpkt() const
{
Packet* p = Packet::alloc();
initpkt(p);
p->local_deadline_increment=local_deadline_increment;
p->egress_node=egress_node;
return (p);
}
/* allocate a packet and fill in all the generic fields and allocate
* a buffer of n bytes for data
*/
Packet*
Agent::allocpkt(int n) const
{
Packet* p = allocpkt();
p->local_deadline_increment=local_deadline_increment;
p->egress_node=egress_node;
if (n > 0)
p->allocdata(n);
return(p);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -