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

📄 todevice.cc

📁 Click is a modular router toolkit. To use it you ll need to know how to compile and install the sof
💻 CC
字号:
/* * todevice.{cc,hh} -- element writes packets to network via pcap library * Douglas S. J. De Couto, Eddie Kohler, John Jannotti * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2005-2008 Regents of the University of California * * 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>#if HAVE_NET_BPF_H# include <sys/types.h># include <sys/time.h># include <net/bpf.h># define PCAP_DONT_INCLUDE_PCAP_BPF_H 1#endif#include "todevice.hh"#include <click/error.hh>#include <click/etheraddress.hh>#include <click/confparse.hh>#include <click/router.hh>#include <click/standard/scheduleinfo.hh>#include <click/packet_anno.hh>#include <click/straccum.hh>#include <stdio.h>#include <unistd.h>#if TODEVICE_BSD_DEV_BPF# include <fcntl.h># include <sys/types.h># include <sys/socket.h># include <sys/ioctl.h># include <net/if.h>#elif TODEVICE_LINUX# include <sys/socket.h># include <sys/ioctl.h># include <net/if.h># include <net/if_packet.h># include <features.h># if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1#  include <netpacket/packet.h># else#  include <linux/if_packet.h># endif#endifCLICK_DECLSToDevice::ToDevice()  : _task(this), _timer(&_task), _fd(-1), _my_fd(false),    _q(0),    _pulls(0){}ToDevice::~ToDevice(){}intToDevice::configure(Vector<String> &conf, ErrorHandler *errh){  if (cp_va_kparse(conf, this, errh,		   "DEVNAME", cpkP+cpkM, cpString, &_ifname,		   "DEBUG", 0, cpBool, &_debug,		   cpEnd) < 0)    return -1;  if (!_ifname)    return errh->error("interface not set");  return 0;}intToDevice::initialize(ErrorHandler *errh){  _timer.initialize(this);  _fd = -1;#if TODEVICE_BSD_DEV_BPF  /* pcap_open_live() doesn't open for writing. */  for (int i = 0; i < 16 && _fd < 0; i++) {    char tmp[64];    sprintf(tmp, "/dev/bpf%d", i);    _fd = open(tmp, 1);  }  if (_fd < 0)    return(errh->error("open /dev/bpf* for write: %s", strerror(errno)));  struct ifreq ifr;  strncpy(ifr.ifr_name, _ifname.c_str(), sizeof(ifr.ifr_name));  ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0;  if (ioctl(_fd, BIOCSETIF, (caddr_t)&ifr) < 0)    return errh->error("BIOCSETIF %s failed", ifr.ifr_name);# ifdef BIOCSHDRCMPLT  int yes = 1;  if (ioctl(_fd, BIOCSHDRCMPLT, (caddr_t)&yes) < 0)      errh->warning("BIOCSHDRCMPLT %s failed", ifr.ifr_name);# endif  _my_fd = true;#elif TODEVICE_LINUX || TODEVICE_PCAP  // find a FromDevice and reuse its socket if possible  for (int ei = 0; ei < router()->nelements() && _fd < 0; ei++) {    Element *e = router()->element(ei);    FromDevice *fdev = (FromDevice *)e->cast("FromDevice");    if (fdev && fdev->ifname() == _ifname && fdev->fd() >= 0) {      _fd = fdev->fd();      _my_fd = false;    }  }  if (_fd < 0) {# if TODEVICE_LINUX    _fd = FromDevice::open_packet_socket(_ifname, errh);    _my_fd = true;# else    return errh->error("ToDevice requires an initialized FromDevice on this platform") ;# endif  }  if (_fd < 0)    return -1;#else  return errh->error("ToDevice is not supported on this platform");#endif  // check for duplicate writers  void *&used = router()->force_attachment("device_writer_" + _ifname);  if (used)    return errh->error("duplicate writer for device `%s'", _ifname.c_str());  used = this;  ScheduleInfo::join_scheduler(this, &_task, errh);  _signal = Notifier::upstream_empty_signal(this, 0, &_task);  return 0;}voidToDevice::cleanup(CleanupStage){  if (_fd >= 0 && _my_fd)    close(_fd);  _fd = -1;}/* * Linux select marks datagram fd's as writeable when the socket * buffer has enough space to do a send (sock_writeable() in * sock.h). BSD select always marks datagram fd's as writeable * (bpf_poll() in sys/net/bpf.c) This function should behave * appropriately under both.  It makes use of select if it correctly * tells us when buffers are available, and it schedules a backoff * timer if buffers are not available. * --jbicket */boolToDevice::run_task(Task *){    Packet *p = _q;    _q = 0;    if (!p) {	p = input(0).pull();	_pulls++;    }    if (p) {	int retval;	const char *syscall;#if TODEVICE_WRITE	retval = ((uint32_t) write(_fd, p->data(), p->length()) == p->length() ? 0 : -1);	syscall = "write";#elif TODEVICE_SEND	retval = send(_fd, p->data(), p->length(), 0);	syscall = "send";#else	retval = 0;#endif	if (retval >= 0) {	    _backoff = 0;	    checked_output_push(0, p);	} else if (errno == ENOBUFS || errno == EAGAIN) {	    assert(!_q);	    _q = p;	    if (!_backoff) {		_backoff = 1;		add_select(_fd, SELECT_WRITE);	    } else {		_timer.schedule_after(Timestamp::make_usec(_backoff));		if (_backoff < 32768)		    _backoff *= 2;		if (_debug) {		    Timestamp now = Timestamp::now();		    click_chatter("%{element} backing off for %d at %{timestamp}\n", this, _backoff, &now);		}	    }	    return false;	} else {	    click_chatter("ToDevice(%s) %s: %s", _ifname.c_str(), syscall, strerror(errno));	    checked_output_push(1, p);	}    }    if (!p && !_signal)	return false;    _task.fast_reschedule();    return p != 0;}voidToDevice::selected(int){    _task.reschedule();    remove_select(_fd, SELECT_WRITE);}enum {H_DEBUG, H_SIGNAL, H_PULLS, H_Q};StringToDevice::read_param(Element *e, void *thunk){  ToDevice *td = (ToDevice *)e;  switch((uintptr_t) thunk) {  case H_DEBUG:      return String(td->_debug);  case H_SIGNAL:      return String(td->_signal);  case H_PULLS:      return String(td->_pulls);  case H_Q:      return String((bool) td->_q);  default:      return String();  }}intToDevice::write_param(const String &in_s, Element *e, void *vparam,		     ErrorHandler *errh){  ToDevice *td = (ToDevice *)e;  String s = cp_uncomment(in_s);  switch ((intptr_t)vparam) {  case H_DEBUG: {    bool debug;    if (!cp_bool(s, &debug))      return errh->error("debug parameter must be boolean");    td->_debug = debug;    break;  }  }  return 0;}voidToDevice::add_handlers(){  add_task_handlers(&_task);  add_read_handler("debug", read_param, (void *) H_DEBUG, Handler::CHECKBOX);  add_read_handler("pulls", read_param, (void *) H_PULLS);  add_read_handler("signal", read_param, (void *) H_SIGNAL);  add_read_handler("q", read_param, (void *) H_Q);  add_write_handler("debug", write_param, (void *) H_DEBUG);}CLICK_ENDDECLSELEMENT_REQUIRES(FromDevice userlevel)EXPORT_ELEMENT(ToDevice)

⌨️ 快捷键说明

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