/*
* click.cc -- user-level Click main program
* Eddie Kohler
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2000 Mazu Networks, Inc.
* Copyright (c) 2001 International Computer Science Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include <click/pathvars.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <click/lexer.hh>
#include <click/routerthread.hh>
#include <click/router.hh>
#include <click/error.hh>
#include <click/timer.hh>
#include <click/straccum.hh>
#include <click/clp.h>
#include <click/archive.hh>
#include <click/glue.hh>
#include <click/driver.hh>
#include <click/userutils.hh>
#include <click/confparse.hh>
#include <click/master.hh>
#include <click/simclick.h>
#include <click/handlercall.hh>
#include "elements/standard/quitwatcher.hh"
#include "elements/userlevel/controlsocket.hh"
CLICK_USING_DECLS
#define HELP_OPT 300
#define VERSION_OPT 301
#define CLICKPATH_OPT 302
#define ROUTER_OPT 303
#define QUIT_OPT 304
#define OUTPUT_OPT 305
#define HANDLER_OPT 306
#define TIME_OPT 307
#define STOP_OPT 308
#define PORT_OPT 309
#define UNIX_SOCKET_OPT 310
#define NO_WARNINGS_OPT 311
#define WARNINGS_OPT 312
#define EXPRESSION_OPT 313
//
// State for each simulated machine
//
class SimState {
public:
Router *router;
//String::Initializer crap_initializer;
//Vector<String> packages;
//String configuration_string;
//Vector<String> handlers;
SimState() {
router = NULL;
}
static SimState* simmain(simclick_sim siminst,const char* router_file);
static bool didinit_;
};
bool SimState::didinit_ = false;
static simclick_simstate* cursimclickstate = NULL;
//
// XXX
// OK, this bit of code here should work fine as long as your simulator
// isn't multithreaded. If it is, there could be multiple threads stomping
// on each other and potentially causing subtle or unsubtle problems.
//
static void setsimstate(simclick_simstate* newstate) {
cursimclickstate = newstate;
}
static simclick_simstate* getsimstate() {
return cursimclickstate;
}
static ErrorHandler *errh;
// functions for packages
static String::Initializer crap_initializer;
static String configuration_string;
#if 0
extern "C" int
click_add_element_type(const char *, Element *(*)(uintptr_t), uintptr_t)
{
// if (name)
// return lexer->add_element_type(name, e);
// else
// return lexer->add_element_type(e);
fprintf(stderr,"Hey! Need to do click_add_element_type!\n");
return 0;
}
extern "C" void
click_remove_element_type(int)
{
//lexer->remove_element_type(which);
fprintf(stderr,"Hey! Need to do click_remove_element_type!\n");
}
// global handlers for ControlSocket
enum {
GH_VERSION, GH_LIST, GH_CLASSES, GH_CONFIG,
GH_FLATCONFIG, GH_PACKAGES, GH_REQUIREMENTS
};
String
read_global_handler(Element *, void *thunk)
{
StringAccum sa;
switch (reinterpret_cast<int>(thunk)) {
case GH_VERSION:
return String(CLICK_VERSION "\n");
case GH_LIST:
return router->element_list_string();
case GH_CLASSES: {
Vector<String> v;
lexer->element_type_names(v);
for (int i = 0; i < v.size(); i++)
sa << v[i] << "\n";
return sa.take_string();
}
case GH_CONFIG:
return configuration_string;
case GH_FLATCONFIG:
return router->flat_configuration_string();
case GH_PACKAGES: {
Vector<String> p;
click_public_packages(p);
for (int i = 0; i < p.size(); i++)
sa << p[i] << "\n";
return sa.take_string();
}
case GH_REQUIREMENTS: {
const Vector<String> &v = router->requirements();
for (int i = 0; i < v.size(); i++)
sa << v[i] << "\n";
return sa.take_string();
}
default:
return "<error>\n";
}
}
static int
stop_global_handler(const String &s, Element *, void *, ErrorHandler *)
{
int n = 1;
(void) cp_integer(cp_uncomment(s), &n);
router->adjust_runcount(-n);
return 0;
}
// report handler results
static int
call_read_handler(Element *e, String handler_name, Router *r,
bool print_name, ErrorHandler *errh)
{
const Handler *rh = Router::handler(e, handler_name);
String full_name = Handler::unparse_name(e, handler_name);
if (!rh || !rh->visible())
return errh->error("no `%s' handler", full_name.c_str());
else if (!rh->read_visible())
return errh->error("`%s' is a write handler", full_name.c_str());
if (print_name)
fprintf(stdout, "%s:\n", full_name.c_str());
String result = rh->call_read(e);
fputs(result.c_str(), stdout);
if (print_name)
fputs("\n", stdout);
return 0;
}
static bool
expand_handler_elements(const String &pattern, const String &handler_name,
Vector<Element *> &elements, Router *router)
{
int nelem = router->nelements();
bool any_elements = false;
for (int i = 0; i < nelem; i++) {
const String &id = router->ename(i);
if (glob_match(id, pattern)) {
any_elements = true;
if (const Handler *h = Router::handler(router->element(i), handler_name))
if (h->read_visible())
elements.push_back(router->element(i));
}
}
return any_elements;
}
static int
call_read_handlers(Vector<String> &handlers, ErrorHandler *errh)
{
Vector<Element *> handler_elements;
Vector<String> handler_names;
bool print_names = (handlers.size() > 1);
int before = errh->nerrors();
// expand handler names
for (int i = 0; i < handlers.size(); i++) {
const char *dot = find(handlers[i], '.');
if (dot == handlers[i].end()) {
call_read_handler(0, handlers[i], router, print_names, errh);
continue;
}
String element_name = handlers[i].substring(handlers[i].begin(), dot);
String handler_name = handlers[i].substring(dot + 1, handlers[i].end());
Vector<Element *> elements;
if (Element *e = router->find(element_name))
elements.push_back(e);
else if (expand_handler_elements(element_name, handler_name, elements, router))
print_names = true;
else
errh->error("no element matching `%s'", element_name.c_str());
for (int j = 0; j < elements.size(); j++)
call_read_handler(elements[j], handler_name, router, print_names, errh);
}
return (errh->nerrors() == before ? 0 : -1);
}
#endif
// main
SimState*
SimState::simmain(simclick_sim siminst, const char *router_file)
{
if (!didinit_) {
click_static_initialize();
errh = ErrorHandler::default_handler();
didinit_ = true;
}
bool warnings = true;
SimState* newstate = new SimState();
// lex
newstate->router = click_read_router(router_file, false, errh, false);
if (!newstate->router)
exit(1);
newstate->router->master()->initialize_ns(siminst, (simclick_click)newstate);
if (newstate->router->nelements() == 0 && warnings)
errh->warning("%s: configuration has no elements", router_file);
if (errh->nerrors() > 0 || newstate->router->initialize(errh) < 0)
exit(1);
newstate->router->activate(errh);
return newstate;
}
simclick_click simclick_click_create(simclick_sim siminst,
const char* router_file,
simclick_simstate* startstate) {
setsimstate(startstate);
return SimState::simmain(siminst,router_file);
}
/*
* XXX Need to actually implement this a little more intelligenetly...
*/
void simclick_click_run(simclick_click clickinst,simclick_simstate* state) {
setsimstate(state);
//fprintf(stderr,"Hey! Need to implement simclick_click_run!\n");
// not right - mostly smoke testing for now...
Router* r = ((SimState*)clickinst)->router;
if (r) {
r->master()->thread(0)->driver();
}
else {
click_chatter("simclick_click_run: call with null router");
}
}
void simclick_click_kill(simclick_click clickinst, simclick_simstate* state) {
//fprintf(stderr,"Hey! Need to implement simclick_click_kill!\n");
setsimstate(state);
Router *r = ((SimState*)clickinst)->router;
if (r) {
delete r;
((SimState*)clickinst)->router = 0;
}
else {
click_chatter("simclick_click_kill: call with null router");
}
}
int simclick_gettimeofday(struct timeval* tv) {
simclick_simstate* sstate = getsimstate();
if (sstate) {
*tv = sstate->curtime;
}
else {
fprintf(stderr,"Hey! Called simclick_gettimeofday without simstate set!\n");
}
return 0;
}
int simclick_click_send(simclick_click clickinst,simclick_simstate* state,
int ifid,int type,const unsigned char* data,int len,
simclick_simpacketinfo* pinfo) {
setsimstate(state);
int result = 0;
Router* r = ((SimState*)clickinst)->router;
if (r) {
r->sim_incoming_packet(ifid,type,data,len,pinfo);
r->master()->thread(0)->driver();
}
else {
click_chatter("simclick_click_send: called with null router");
result = -1;
}
return result;
}
char* simclick_click_read_handler(simclick_click clickinst,
const char* elementname,
const char* handlername,
SIMCLICK_MEM_ALLOC memalloc,
void* memparam,
simclick_simstate *state) {
Router *r = ((SimState*)clickinst)->router;
if (!r) {
click_chatter("simclick_click_read_handler: call with null router");
return 0;
}
setsimstate(state);
String hdesc = String(elementname) + "." + String(handlername);
ErrorHandler *errh = ErrorHandler::default_handler();
int before = errh->nerrors();
String result = HandlerCall::call_read(hdesc, r->root_element(), errh);
if (!result && errh->nerrors() != before)
return 0;
char *rstr;
if (memalloc)
rstr = (char *) memalloc(result.length() + 1, memparam);
else
rstr = (char *) malloc(result.length() + 1);
if (rstr) {
memcpy(rstr, result.data(), result.length());
rstr[result.length()] = 0;
}
return rstr;
}
int simclick_click_write_handler(simclick_click clickinst,
const char* elementname,
const char* handlername,
const char* writestring,
simclick_simstate *state) {
Router *r = ((SimState*)clickinst)->router;
if (!r) {
click_chatter("simclick_click_write_handler: call with null router");
return -3;
}
setsimstate(state);
String hdesc = String(elementname) + "." + String(handlername);
return HandlerCall::call_write(hdesc, String(writestring), r->root_element(), ErrorHandler::default_handler());
}
syntax highlighted by Code2HTML, v. 0.9.1