📄 fromnlanrdump.cc
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fromnlanrdump.{cc,hh} -- element reads packets from NLANR format file * Eddie Kohler * * Copyright (c) 2002 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 "fromnlanrdump.hh"#include <click/confparse.hh>#include <click/packet_anno.hh>#include <click/router.hh>#include <click/standard/scheduleinfo.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/handlercall.hh>#include <clicknet/rfc1483.h>#include <click/userutils.hh>#include "elements/userlevel/fakepcap.hh"#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef ALLOW_MMAP# include <sys/mman.h>#endifCLICK_DECLS#define SWAPLONG(y) \ ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))#define SWAPSHORT(y) \ ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) )FromNLANRDump::FromNLANRDump() : Element(0, 1), _packet(0), _end_h(0), _task(this){}FromNLANRDump::~FromNLANRDump(){ delete _end_h;}voidFromNLANRDump::notify_noutputs(int n){ set_noutputs(n <= 1 ? 1 : 2);}intFromNLANRDump::configure(Vector<String> &conf, ErrorHandler *errh){ bool timing = false, stop = false, active = true; String format = "guess"; Timestamp first_time, first_time_off, last_time, last_time_off, interval; _sampling_prob = (1 << SAMPLING_SHIFT); _packet_filepos = 0; bool force_ip = true; if (_ff.configure_keywords(conf, 1, this, errh) < 0) return -1; if (cp_va_parse(conf, this, errh, cpFilename, "dump file name", &_ff.filename(), cpKeywords, "FORMAT", cpWord, "file format", &format, "STOP", cpBool, "stop driver when done?", &stop, "ACTIVE", cpBool, "start active?", &active, "FORCE_IP", cpBool, "ignored for compatibility", &force_ip, "START", cpTimestamp, "starting time", &first_time, "START_AFTER", cpTimestamp, "starting time offset", &first_time_off, "END", cpTimestamp, "ending time", &last_time, "END_AFTER", cpTimestamp, "ending time offset", &last_time_off, "INTERVAL", cpTimestamp, "time interval", &interval, "END_CALL", cpWriteHandlerCall, "write handler for ending time", &_end_h, "FILEPOS", cpFileOffset, "starting file position", &_packet_filepos, "SAMPLE", cpUnsignedReal2, "sampling probability", SAMPLING_SHIFT, &_sampling_prob, "TIMING", cpBool, "use original packet timing?", &timing, cpEnd) < 0) return -1; // check sampling rate if (_sampling_prob > (1 << SAMPLING_SHIFT)) { errh->warning("SAMPLE probability reduced to 1"); _sampling_prob = (1 << SAMPLING_SHIFT); } else if (_sampling_prob == 0) errh->warning("SAMPLE probability is 0; emitting no packets"); // check times _have_first_time = _have_last_time = true; _first_time_relative = _last_time_relative = _last_time_interval = false; if ((bool) first_time + (bool) first_time_off > 1) return errh->error("'START' and 'START_AFTER' are mutually exclusive"); else if (first_time) _first_time = first_time; else if (first_time_off) _first_time = first_time_off, _first_time_relative = true; else _have_first_time = false, _first_time_relative = true; if ((bool) last_time + (bool) last_time_off + (bool) interval > 1) return errh->error("'END', 'END_AFTER', and 'INTERVAL' are mutually exclusive"); else if (last_time) _last_time = last_time; else if (last_time_off) _last_time = last_time_off, _last_time_relative = true; else if (interval) _last_time = interval, _last_time_interval = true; else _have_last_time = false; if (stop && _end_h) return errh->error("'END_CALL' and 'STOP' are mutually exclusive"); else if (stop) _end_h = new HandlerCall(id() + ".stop"); else if (_have_last_time && !_end_h) _end_h = new HandlerCall(id() + ".active false"); // format format = format.lower(); if (format == "fr") _format = C_FR; else if (format == "fr+") _format = C_FRPLUS; else if (format == "tsh") _format = C_TSH; else if (format == "guess") { format = _ff.filename().lower(); if (format.substring(-3).lower() == ".gz") format = format.substring(0, format.length() - 3); else if (format.substring(-2).lower() == ".z") format = format.substring(0, format.length() - 2); else if (format.substring(-4).lower() == ".bz2") format = format.substring(0, format.length() - 4); if (format.substring(-3).lower() == ".fr") _format = C_FR; else if (format.substring(-3).lower() == ".fr+") _format = C_FRPLUS; else if (format.substring(-4).lower() == ".tsh") _format = C_TSH; else { errh->warning("cannot guess file format from filename, assuming 'tsh'"); _format = C_TSH; } } else return errh->error("bad FORMAT"); switch (_format) { case C_FR: _cell_size = FRCell::SIZE; break; case C_FRPLUS: _cell_size = FRPlusCell::SIZE; break; case C_TSH: _cell_size = TSHCell::SIZE; break; } // set other variables _have_any_times = false; _timing = timing; _active = active; return 0;}intFromNLANRDump::initialize(ErrorHandler *errh){ // check handler call, initialize Task if (_end_h && _end_h->initialize_write(this, errh) < 0) return -1; if (output_is_push(0)) ScheduleInfo::initialize_task(this, &_task, _active, errh); // open file if (_ff.initialize(errh) < 0) return -1; // try reading a packet if (read_packet(errh)) _time_offset = Timestamp::now() - _packet->timestamp_anno(); // maybe skip ahead in the file if (_packet_filepos != 0) { int result = _ff.seek(_packet_filepos, errh); _packet_filepos = 0; return result; } else return 0;}voidFromNLANRDump::cleanup(CleanupStage){ _ff.cleanup(); if (_packet) _packet->kill(); _packet = 0;}voidFromNLANRDump::set_active(bool active){ if (_active != active) { _active = active; if (active && output_is_push(0) && !_task.scheduled()) _task.reschedule(); }}voidFromNLANRDump::prepare_times(const Timestamp &tv){ if (_first_time_relative) _first_time += tv; if (_last_time_relative) _last_time += tv; else if (_last_time_interval) _last_time += _first_time; _have_any_times = true;}boolFromNLANRDump::read_packet(ErrorHandler *errh){ const TSHCell *cell; static TSHCell static_cell; Timestamp tv; Packet *p; bool more = true; _packet = 0; retry: // quit if we sampled or force_ip failed, but we are no longer active if (!more) return false; // record file position _packet_filepos = _ff.file_pos(); // read the cell cell = reinterpret_cast<const TSHCell *>(_ff.get_aligned(_cell_size, &static_cell, errh)); if (!cell) return false; // check times check_times: uint32_t usec = ntohl(cell->timestamp_usec); if (_format == C_TSH) tv = Timestamp(ntohl(cell->timestamp_sec), usec & 0xFFFFFF); else if (_format == C_FRPLUS || _format == C_FR) tv = Timestamp(ntohl(cell->timestamp_sec), usec); if (!_have_any_times) prepare_times(tv); if (_have_first_time) { if (tv < _first_time) goto retry; else _have_first_time = false; } if (_have_last_time && tv >= _last_time) { _have_last_time = false; (void) _end_h->call_write(errh); if (!_active) more = false; // The handler might have scheduled us, in which case we might crash // at fast_reschedule()! Don't want that -- make sure we are // unscheduled. _task.fast_unschedule(); // retry _last_time in case someone changed it goto check_times; } // checking sampling probability if (_sampling_prob < (1 << SAMPLING_SHIFT) && (uint32_t)(random() & ((1<<SAMPLING_SHIFT)-1)) >= _sampling_prob) goto retry; // create packet if (_format != C_FR) p = _ff.get_packet_from_data(&cell->iph, _cell_size - 8, _cell_size - 8, tv.sec(), tv.subsec(), errh); else p = 0; if (!p) return false; fake_pcap_force_ip(p, FAKE_DLT_RAW); if (p->network_header_length() != sizeof(click_ip)) { // there were ip options checked_output_push(1, p); goto retry; } if (_format == C_TSH) // set link annotation SET_PAINT_ANNO(p, usec >> 24); _packet = p; return more;}boolFromNLANRDump::run_task(){ if (!_active) return false; bool more; if (_packet || read_packet(0)) { if (_timing && _packet->timestamp_anno() > Timestamp::now() - _time_offset) { _task.fast_reschedule(); return false; } output(0).push(_packet); more = read_packet(0); } else more = false; if (more) _task.fast_reschedule(); else if (_end_h) _end_h->call_write(ErrorHandler::default_handler()); return true;}Packet *FromNLANRDump::pull(int){ if (!_active) return 0; bool more; Packet *p; if (_packet || read_packet(0)) { if (_timing && _packet->timestamp_anno() > Timestamp::now() - _time_offset) return 0; p = _packet; more = read_packet(0); } else { p = 0; more = false; } if (!more && _end_h) _end_h->call_write(ErrorHandler::default_handler()); return p;}enum { H_SAMPLING_PROB, H_ACTIVE, H_ENCAP, H_STOP, H_PACKET_FILEPOS, H_EXTEND_INTERVAL};StringFromNLANRDump::read_handler(Element *e, void *thunk){ FromNLANRDump *fd = static_cast<FromNLANRDump *>(e); switch ((intptr_t)thunk) { case H_SAMPLING_PROB: return cp_unparse_real2(fd->_sampling_prob, SAMPLING_SHIFT) + "\n"; case H_ACTIVE: return cp_unparse_bool(fd->_active) + "\n"; case H_ENCAP: return "IP\n"; case H_PACKET_FILEPOS: return String(fd->_packet_filepos) + "\n"; default: return "<error>\n"; }}intFromNLANRDump::write_handler(const String &s_in, Element *e, void *thunk, ErrorHandler *errh){ FromNLANRDump *fd = static_cast<FromNLANRDump *>(e); String s = cp_uncomment(s_in); switch ((intptr_t)thunk) { case H_ACTIVE: { bool active; if (cp_bool(s, &active)) { fd->set_active(active); return 0; } else return errh->error("'active' should be Boolean"); } case H_STOP: fd->set_active(false); fd->router()->please_stop_driver(); return 0; case H_EXTEND_INTERVAL: { Timestamp tv; if (cp_time(s, &tv)) { fd->_last_time += tv; if (fd->_end_h) fd->_have_last_time = true, fd->set_active(true); return 0; } else return errh->error("'extend_interval' takes a time interval"); } default: return -EINVAL; }}voidFromNLANRDump::add_handlers(){ add_read_handler("sampling_prob", read_handler, (void *)H_SAMPLING_PROB); add_read_handler("active", read_handler, (void *)H_ACTIVE); add_write_handler("active", write_handler, (void *)H_ACTIVE); add_read_handler("encap", read_handler, (void *)H_ENCAP); add_write_handler("stop", write_handler, (void *)H_STOP); add_read_handler("packet_filepos", read_handler, (void *)H_PACKET_FILEPOS); add_write_handler("extend_interval", write_handler, (void *)H_EXTEND_INTERVAL); _ff.add_handlers(this); if (output_is_push(0)) add_task_handlers(&_task);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel int64 FakePcap FromFile)EXPORT_ELEMENT(FromNLANRDump)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -