⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 script.cc

📁 Click is a modular router toolkit. To use it you ll need to know how to compile and install the sof
💻 CC
📖 第 1 页 / 共 2 页
字号:
// -*- c-basic-offset: 4 -*-/* * script.{cc,hh} -- element provides scripting functionality * Eddie Kohler * * Copyright (c) 2001 International Computer Science Institute * Copyright (c) 2001 Mazu Networks, Inc. * Copyright (c) 2005-2008 Regents of the University of California * Copyright (c) 2008-2009 Meraki, Inc. * * 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 "script.hh"#include <click/confparse.hh>#include <click/error.hh>#include <click/router.hh>#include <click/straccum.hh>#include <click/handlercall.hh>#include <click/nameinfo.hh>#if CLICK_USERLEVEL# include <signal.h># include <click/master.hh># include <click/userutils.hh>#endifCLICK_DECLSstatic const StaticNameDB::Entry instruction_entries[] = {    { "end", Script::INSN_END },    { "error", Script::insn_error },    { "errorq", Script::insn_errorq },    { "exit", Script::INSN_EXIT },    { "goto", Script::INSN_GOTO },    { "init", Script::INSN_INIT },    { "initq", Script::insn_initq },    { "label", Script::INSN_LABEL },    { "loop", Script::INSN_LOOP_PSEUDO },    { "pause", Script::INSN_WAIT_STEP },    { "print", Script::INSN_PRINT },    { "printn", Script::INSN_PRINTN },    { "read", Script::INSN_READ },    { "readq", Script::INSN_READQ },    { "return", Script::INSN_RETURN },    { "returnq", Script::insn_returnq },    { "set", Script::INSN_SET },    { "setq", Script::insn_setq },    { "stop", Script::INSN_STOP },    { "wait", Script::INSN_WAIT_PSEUDO },    { "wait_for", Script::INSN_WAIT_TIME },    { "wait_step", Script::INSN_WAIT_STEP },    { "wait_stop", Script::INSN_WAIT_STEP },    { "wait_time", Script::INSN_WAIT_TIME },    { "write", Script::INSN_WRITE },    { "writeq", Script::INSN_WRITEQ }};#if CLICK_USERLEVELstatic const StaticNameDB::Entry signal_entries[] = {    { "ABRT", SIGABRT },    { "HUP", SIGHUP },    { "INT", SIGINT },    { "PIPE", SIGPIPE },    { "QUIT", SIGQUIT },    { "TERM", SIGTERM },    { "TSTP", SIGTSTP },    { "USR1", SIGUSR1 },    { "USR2", SIGUSR2 }};#endifstatic NameDB *dbs[2];voidScript::static_initialize(){    dbs[0] = new StaticNameDB(NameInfo::T_SCRIPT_INSN, String(), instruction_entries, sizeof(instruction_entries) / sizeof(instruction_entries[0]));    NameInfo::installdb(dbs[0], 0);#if CLICK_USERLEVEL    dbs[1] = new StaticNameDB(NameInfo::T_SIGNO, String(), signal_entries, sizeof(signal_entries) / sizeof(signal_entries[0]));    NameInfo::installdb(dbs[1], 0);#endif}voidScript::static_cleanup(){    delete dbs[0];#if CLICK_USERLEVEL    delete dbs[1];#endif}Script::Script()    : _type(type_active), _write_status(0), _timer(this), _cur_steps(0){}Script::~Script(){}voidScript::add_insn(int insn, int arg, int arg2, const String &arg3){    // first instruction must be WAIT or WAIT_STEP, so add INITIAL if    // necessary    if (_insns.size() == 0 && insn > INSN_WAIT_TIME)	add_insn(INSN_INITIAL, 0);    _insns.push_back(insn);    _args.push_back(arg);    _args2.push_back(arg2);    _args3.push_back(arg3);}intScript::find_label(const String &label) const{    for (int i = 0; i < _insns.size(); i++)	if (_insns[i] == INSN_LABEL && _args3[i] == label)	    return i;    if (label.equals("exit", 4))	return LABEL_EXIT;    if (label.equals("end", 3))	return LABEL_END;    if (label.equals("begin", 5))	return LABEL_BEGIN;    if (label.equals("error", 5))	return label_error;    return _insns.size();}intScript::find_variable(const String &name, bool add){    int i;    for (i = 0; i < _vars.size(); i += 2)	if (_vars[i] == name)	    goto found;    if (add) {	_vars.push_back(name);	_vars.push_back(String());    } found:    return i;}intScript::configure(Vector<String> &conf, ErrorHandler *errh){    String type_arg;    if (cp_va_kparse_remove_keywords	(conf, this, errh,	 "TYPE", 0, cpArgument, &type_arg,	 cpEnd) < 0)	return -1;    int before = errh->nerrors();    String type_word = cp_shift_spacevec(type_arg);    if (type_word == "ACTIVE" && !type_arg)	_type = type_active;    else if (type_word == "PASSIVE" && !type_arg)	_type = type_passive;    else if ((type_word == "PACKET" || type_word == "PUSH") && !type_arg)	_type = type_push;    else if (type_word == "PROXY" && !type_arg)	_type = type_proxy;    else if (type_word == "DRIVER" && !type_arg)	_type = type_driver;#if CLICK_USERLEVEL    else if (type_word == "SIGNAL") {	_type = type_signal;	int32_t signo;	while ((type_word = cp_shift_spacevec(type_arg))	       && NameInfo::query_int(NameInfo::T_SIGNO, this, type_word, &signo)	       && signo >= 0 && signo < 32)	    _signos.push_back(signo);	if (type_word || !_signos.size())	    return errh->error("bad signal number");    }#endif    else if (type_word)	return errh->error("bad TYPE");    if (_type == type_driver) {	if (router()->attachment("Script"))	    return errh->error("router has more than one driver script");	router()->set_attachment("Script", this);    }    if (_type == type_push && ninputs() == 0)	return errh->error("PACKET script must have inputs");    else if (_type != type_push && (ninputs() || noutputs()))	return errh->error("ports allowed only on PACKET scripts");    for (int i = 0; i < conf.size(); i++) {	String insn_name = cp_shift_spacevec(conf[i]);	int32_t insn;	if (!insn_name)		// ignore as benign	    continue;	else if (!NameInfo::query_int(NameInfo::T_SCRIPT_INSN, this, insn_name, &insn)) {	    errh->error("syntax error at '%s'", insn_name.c_str());	    continue;	}	switch (insn) {	case INSN_WAIT_PSEUDO:	    if (!conf[i])		goto wait_step;	    else		goto wait_time;	wait_step:	case INSN_WAIT_STEP: {	    unsigned n = 1;	    if (!conf[i] || cp_integer(conf[i], &n))		add_insn(INSN_WAIT_STEP, n, 0);	    else		goto syntax_error;	    break;	}	case INSN_WRITE:	case INSN_WRITEQ:	case INSN_READ:	case INSN_READQ:	case INSN_PRINT:	case INSN_PRINTN:	case INSN_GOTO:	    add_insn(insn, 0, 0, conf[i]);	    break;	case INSN_RETURN:	case insn_returnq:	    conf[i] = "_ " + conf[i];	    /* fall through */	case INSN_INIT:	case insn_initq:	case INSN_SET:	case insn_setq: {	    String word = cp_shift_spacevec(conf[i]);	    if (!word		|| ((insn == INSN_SET || insn == insn_setq) && !conf[i]))		goto syntax_error;	    add_insn(insn, find_variable(word, true), 0, conf[i]);	    break;	}	wait_time:	case INSN_WAIT_TIME:	    add_insn(INSN_WAIT_TIME, 0, 0, conf[i]);	    break;	case INSN_LABEL: {	    String word = cp_shift_spacevec(conf[i]);	    if (!word || conf[i])		goto syntax_error;	    add_insn(insn, 0, 0, word);	    break;	}	case INSN_LOOP_PSEUDO:	    insn = INSN_GOTO;	    /* fallthru */	case INSN_END:	case INSN_EXIT:	case INSN_STOP:	case insn_error:	case insn_errorq:	    if (conf[i] && insn != insn_error && insn != insn_errorq)		goto syntax_error;	    add_insn(insn, 0, 0, conf[i]);	    break;	default:	syntax_error:	    errh->error("syntax error at '%s'", insn_name.c_str());	    break;	}    }    // fix the gotos    for (int i = 0; i < _insns.size(); i++)	if (_insns[i] == INSN_GOTO && _args3[i]) {	    String word = cp_shift_spacevec(_args3[i]);	    if ((_args[i] = find_label(word)) >= _insns.size())		errh->error("no such label '%s'", word.c_str());	}    if (_insns.size() == 0 && _type == type_driver)	add_insn(INSN_WAIT_STEP, 1, 0);    add_insn(_type == type_driver ? INSN_STOP : INSN_END, 0);    return (errh->nerrors() == before ? 0 : -1);}intScript::initialize(ErrorHandler *errh){    _insn_pos = 0;    _step_count = 0;    _timer.initialize(this);    Expander expander;    expander.script = this;    expander.errh = errh;    for (int i = 0; i < _insns.size(); i++)	if (_insns[i] == INSN_INIT)	    _vars[_args[i] + 1] = cp_expand(_args3[i], expander);	else if (_insns[i] == insn_initq)	    _vars[_args[i] + 1] = cp_unquote(cp_expand(_args3[i], expander));    int insn = _insns[_insn_pos];    assert(insn <= INSN_WAIT_TIME);    if (_type == type_signal || _type == type_passive || _type == type_push	|| _type == type_proxy)	/* passive, do nothing */;    else if (insn == INSN_WAIT_TIME) {	Timestamp ts;	if (cp_time(cp_expand(_args3[_insn_pos], expander), &ts))	    _timer.schedule_after(ts);	else	    errh->error("syntax error at 'wait'");    } else if (insn == INSN_INITIAL) {	// get rid of the initial runcount so we get called right away	if (_type == type_driver)	    router()->adjust_runcount(-1);	else	    _timer.schedule_now();	_args[0] = 1;    }#if CLICK_USERLEVEL    if (_type == type_signal)	for (int i = 0; i < _signos.size(); i++)	    master()->add_signal_handler(_signos[i], router(), name() + ".run");#endif    return 0;}intScript::step(int nsteps, int step_type, int njumps, ErrorHandler *errh){    Expander expander;    expander.script = this;    expander.errh = errh;    nsteps += _step_count;    while ((nsteps - _step_count) >= 0 && _insn_pos < _insns.size()	   && njumps < max_jumps) {	// process current instruction	// increment instruction pointer now, in case we call 'goto' directly	// or indirectly	int ipos = _insn_pos++;	int insn = _insns[ipos];	switch (insn) {	case INSN_STOP:	    _step_count++;	    _insn_pos--;	    if (step_type != STEP_ROUTER)		router()->adjust_runcount(-1);	    return njumps + 1;	case INSN_WAIT_STEP:	    while (_step_count < nsteps && _args2[ipos] < _args[ipos]) {		_args2[ipos]++;		_step_count++;	    }	    if (_step_count == nsteps && _args2[ipos] < _args[ipos]) {		_insn_pos--;		goto done;	    }	    break;	case INSN_WAIT_TIME:	    if (_step_count == nsteps) {		Timestamp ts;		if (cp_time(cp_expand(_args3[ipos], expander), &ts)) {		    _timer.schedule_after(ts);		    _insn_pos--;		} else		    errh->error("syntax error at 'wait'");		goto done;	    }	    _step_count++;	    _timer.unschedule();	    break;	case INSN_INITIAL:	    if (_args[ipos]) {		_step_count++;		_args[ipos] = 0;	    }	    break;	case INSN_PRINT:	case INSN_PRINTN: {	    String text = _args3[ipos];#if CLICK_USERLEVEL || CLICK_TOOL	    FILE *f = stdout;	    if (text.length() && text[0] == '>') {		bool append = (text.length() > 1 && text[1] == '>');		text = text.substring(1 + append);		String filename = cp_shift_spacevec(text);		if (filename && filename != "-"		    && !(f = fopen(filename.c_str(), append ? "ab" : "wb"))) {		    errh->error("%s: %s", filename.c_str(), strerror(errno));		    break;		}	    }#endif	    int before = errh->nerrors();	    String result;	    if (text && (isalpha((unsigned char) text[0]) || text[0] == '@' || text[0] == '_')) {		result = cp_expand(text, expander);		result = HandlerCall::call_read(result, this, errh);	    } else		result = cp_unquote(cp_expand(text, expander, true));	    if (errh->nerrors() == before		&& (!result || result.back() != '\n')		&& insn != INSN_PRINTN)		result += "\n";#if CLICK_USERLEVEL || CLICK_TOOL	    ignore_result(fwrite(result.data(), 1, result.length(), f));	    if (f == stdout)		fflush(f);	    else		fclose(f);#else	    click_chatter("{}%s", result.c_str());#endif	    break;	}	case INSN_READ:	case INSN_READQ: {	    String arg = (insn == INSN_READ ? _args3[ipos] : cp_unquote(_args3[ipos]));	    HandlerCall hc(cp_expand(arg, expander));	    if (hc.initialize_read(this, errh) >= 0) {		ContextErrorHandler c_errh(errh, "While calling %<%s%>:", hc.unparse().c_str());		String result = hc.call_read(&c_errh);		ErrorHandler *d_errh = ErrorHandler::default_handler();		d_errh->message("%s:\n%s\n", hc.handler()->unparse_name(hc.element()).c_str(), result.c_str());	    }	    break;	}	case INSN_WRITE:	case INSN_WRITEQ: {	    String arg = (insn == INSN_WRITE ? _args3[ipos] : cp_unquote(_args3[ipos]));	    HandlerCall hc(cp_expand(arg, expander));	    if (hc.initialize_write(this, errh) >= 0) {		ContextErrorHandler c_errh(errh, "While calling %<%s%>:", hc.unparse().c_str());		_write_status = hc.call_write(&c_errh);	    }	    break;	}	case INSN_RETURN:	case insn_returnq:	case INSN_SET:	case insn_setq: {	    expander.errh = errh;	    _vars[_args[ipos] + 1] = cp_expand(_args3[ipos], expander);	    if (insn == insn_setq || insn == insn_returnq)		_vars[_args[ipos] + 1] = cp_unquote(_vars[_args[ipos] + 1]);	    if ((insn == INSN_RETURN || insn == insn_returnq)		&& _insn_pos == ipos + 1) {		_insn_pos--;		goto done;	    }	    break;	}	case INSN_GOTO: {	    // reset intervening instructions	    String cond_text = cp_expand(_args3[ipos], expander);	    bool cond;	    if (cond_text && !cp_bool(cond_text, &cond))		errh->error("bad condition '%s'", cond_text.c_str());	    else if (!cond_text || cond) {		if (_args[ipos] < 0)		    goto insn_finish;		for (int i = _args[ipos]; i < ipos; i++)		    if (_insns[i] == INSN_WAIT_STEP)			_args2[i] = 0;		_insn_pos = _args[ipos];	    }	    break;	}	case insn_error:	case insn_errorq: {	    String msg = cp_expand(_args3[ipos], expander);	    if (insn == insn_errorq)		msg = cp_unquote(msg);	    if (msg)		errh->error("%s", msg.c_str());	    /* fallthru */	}	case INSN_END:	case INSN_EXIT:	insn_finish:	    _insn_pos--;	    return njumps + 1;	}	if (_insn_pos != ipos + 1)	    njumps++;    }  done:    if (njumps >= max_jumps) {	ErrorHandler::default_handler()->error("%{element}: too many jumps, giving up", this);	_insn_pos = _insns.size();	_timer.unschedule();    }    if (step_type == STEP_ROUTER)	router()->adjust_runcount(1);    return njumps + 1;}intScript::complete_step(String *retval){    int last_insn;    if (_insn_pos < 0 || _insn_pos >= _insns.size())	last_insn = -1;    else {	last_insn = _insns[_insn_pos];	if (last_insn == INSN_GOTO) {	    if (_args[_insn_pos] == LABEL_EXIT)		last_insn = INSN_EXIT;	    else if (_args[_insn_pos] == LABEL_END)		last_insn = INSN_END;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -