📄 khandlerproxy.cc
字号:
/* * khandlerproxy.{cc,hh} -- element forwards handlers to kernel configuration * Eddie Kohler * * Copyright (c) 2000-2001 Mazu Networks, 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 "khandlerproxy.hh"#include <click/error.hh>#include <click/router.hh>#include <click/confparse.hh>#include <click/userutils.hh>#include <click/llrpc.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>CLICK_DECLSKernelHandlerProxy::KernelHandlerProxy() : _detailed_error_message(false){}KernelHandlerProxy::~KernelHandlerProxy(){}void *KernelHandlerProxy::cast(const char *n){ if (strcmp(n, "HandlerProxy") == 0) return (HandlerProxy *)this; else if (strcmp(n, "KernelHandlerProxy") == 0) return (Element *)this; else return 0;}intKernelHandlerProxy::configure(Vector<String> &conf, ErrorHandler *errh){ _verbose = false; return cp_va_parse(conf, this, errh, cpKeywords, "VERBOSE", cpBool, "be verbose?", &_verbose, cpEnd);}voidKernelHandlerProxy::add_handlers(){ add_write_handler("*", star_write_handler, 0);}static voidcomplain_to(ErrorHandler *errh, int errcode, const String &complaint){ if (errcode >= 0) errh->set_error_code(errcode); errh->verror_text(ErrorHandler::ERR_ERROR, String(), complaint);}intKernelHandlerProxy::complain(ErrorHandler *errh, const String &hname, int errcode, const String &complaint){ if (errh) complain_to(errh, errcode, complaint); else { for (int i = 0; i < _nerr_rcvs; i++) if ((errh = _err_rcvs[i].hook(hname, _err_rcvs[i].thunk))) complain_to(errh, errcode, complaint); } return -EINVAL;}intKernelHandlerProxy::complain_about_open(ErrorHandler *errh, const String &hname, int errno_val){ const char *dot = find(hname, '.'); String k_elt = hname.substring(hname.begin(), dot); if (errno_val == ENOENT) { String try_fn = "/click/" + k_elt; if (access("/click", F_OK) < 0) complain(errh, hname, CSERR_NO_ROUTER, "No router installed"); else if (k_elt != "0" && access(try_fn.cc(), F_OK) < 0) complain(errh, hname, CSERR_NO_SUCH_ELEMENT, "No element named '" + k_elt.printable() + "'"); else complain(errh, hname, CSERR_NO_SUCH_HANDLER, "No handler named '" + hname.printable() + "'"); } else if (errno_val == EACCES) complain(errh, hname, CSERR_PERMISSION, "Permission denied for '" + hname.printable() + "'"); else complain(errh, hname, CSERR_UNSPECIFIED, "Handler '" + hname.printable() + "' error: " + String(strerror(errno_val))); return -errno_val;}intKernelHandlerProxy::check_handler_name(const String &hname, ErrorHandler *errh){ const char *dot = find(hname, '.'); if (dot == hname.begin() || dot >= hname.end() - 1) return complain(errh, hname, CSERR_SYNTAX, "Bad handler name '" + hname.printable() + "'"); // check characters for validity -- don't want to screw stuff up for (const char *s = hname.begin(); s < dot; s++) if (!isalnum(*s) && *s != '_' && *s != '/' && *s != '@') return complain(errh, hname, CSERR_SYNTAX, "Bad character in element name '" + hname.substring(hname.begin(), dot).printable() + "'"); for (const char *s = dot + 1; s < hname.end(); s++) if (*s < 32 || *s >= 127 || *s == '/') return complain(errh, hname, CSERR_SYNTAX, "Bad character in handler name '" + hname.printable() + "'"); return 0;}static Stringhandler_name_to_file_name(const String &str){ if (str[0] == '0' && str[1] == '.') return "/click/" + str.substring(2); else { const char *dot = find(str, '.'); return "/click/" + str.substring(str.begin(), dot) + "/" + str.substring(dot + 1, str.end()); }}intKernelHandlerProxy::star_write_handler(const String &str, Element *e, void *, ErrorHandler *errh){ KernelHandlerProxy *khp = static_cast<KernelHandlerProxy *>(e); if (khp->check_handler_name(str, errh) < 0) return -1; khp->set_handler(str, Handler::OP_READ | Handler::OP_WRITE, handler_hook); return Router::hindex(e, str);}intKernelHandlerProxy::check_handler(const String &hname, bool write, ErrorHandler *errh){ if (check_handler_name(hname, errh) < 0) return 0; String fn = handler_name_to_file_name(hname); if (access(fn.cc(), (write ? W_OK : R_OK)) < 0) { complain_about_open(errh, hname, errno); return 0; } // If accessible, it still might be a directory rather than a handler. struct stat buf; stat(fn.cc(), &buf); if (S_ISDIR(buf.st_mode)) { errh->set_error_code(CSERR_NO_SUCH_HANDLER); errh->error("No handler named '%#s'", hname.printable().cc()); return 0; } else { errh->message("%s handler '%s' OK", (write ? "Write" : "Read"), hname.printable().cc()); return 1; }}intKernelHandlerProxy::handler_hook(int op, String& str, Element* e, const Handler* handler, ErrorHandler* errh){ KernelHandlerProxy *khp = static_cast<KernelHandlerProxy *>(e); const String& hname = handler->name(); String fn = handler_name_to_file_name(hname); if (op == Handler::OP_READ) { errno = 0; str = file_string(fn, 0); int err = errno; if (!str && err != 0) { if (khp->_verbose) khp->complain_about_open(ErrorHandler::default_handler(), hname, err); // complain to error receivers khp->complain_about_open(0, hname, err); } return -err; } else if (op == Handler::OP_WRITE) { int fd = open(fn.c_str(), O_WRONLY | O_TRUNC); if (fd < 0) return khp->complain_about_open(errh, hname, errno); const char* s = str.begin(); const char* end = str.end(); while (s < end) { ssize_t written = write(fd, s, end - s); if (written < 0 && errno != EINTR) { close(fd); return khp->complain(errh, hname, CSERR_UNSPECIFIED, fn + ": " + String(strerror(errno))); } else if (written >= 0) s += written; } if (close(fd) < 0) { int err = errno; khp->complain(errh, hname, CSERR_HANDLER_ERROR, "Error executing kernel write handler '" + String(hname) + "'"); if (!khp->_detailed_error_message) { khp->complain(errh, hname, CSERR_HANDLER_ERROR, "(Check /click/errors for details.)"); khp->_detailed_error_message = true; } return -err; } else return 0; } else return errh->error("odd operation");}intKernelHandlerProxy::llrpc(unsigned command, void *data){ if (command == CLICK_LLRPC_PROXY) { click_llrpc_proxy_st* proxy = static_cast<click_llrpc_proxy_st*>(data); const Handler* h = static_cast<Handler*>(proxy->proxied_handler); String fn = handler_name_to_file_name(h->name()); int fd = open(fn.c_str(), O_RDONLY); int err = errno; if (fd < 0) { if (_verbose) complain_about_open(ErrorHandler::default_handler(), h->name(), err); // complain to error receivers and return return complain_about_open(0, h->name(), err); } click_chatter("about to %x on %s", proxy->proxied_command, fn.c_str()); int retval = ioctl(fd, proxy->proxied_command, proxy->proxied_data); err = errno; close(fd); return (retval >= 0 ? retval : -err); } else return Element::llrpc(command, data);}ELEMENT_REQUIRES(userlevel HandlerProxy)EXPORT_ELEMENT(KernelHandlerProxy)CLICK_ENDDECLS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -