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

📄 toipflowdumps.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
📖 第 1 页 / 共 2 页
字号:
// -*- c-basic-offset: 4 -*-/* * toipflowdumps.{cc,hh} -- creates separate trace files for each flow * 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 "toipflowdumps.hh"#include <click/confparse.hh>#include <click/error.hh>#include <click/packet_anno.hh>#include <click/router.hh>#include <click/standard/scheduleinfo.hh>#include <clicknet/udp.h>#include <clicknet/icmp.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#include <fcntl.h>#include "elements/analysis/ipsumdumpinfo.hh"CLICK_DECLS#ifdef i386# define PUT4(p, d)	*reinterpret_cast<uint32_t *>((p)) = htonl((d))#else# define PUT4(p, d)	do { (p)[0] = (d)>>24; (p)[1] = (d)>>16; (p)[2] = (d)>>8; (p)[3] = (d); } while (0)#endif#define PUT1(p, d)	((p)[0] = (d))ToIPFlowDumps::Flow::Flow(const Packet *p, const String &filename,			  bool absolute_time, bool absolute_seq, bool binary,			  bool ip_id, int tcp_opt, bool tcp_window)    : _next(0),      _flowid(p), _ip_p(p->ip_header()->ip_p),      _aggregate(AGGREGATE_ANNO(p)), _packet_count(0), _note_count(0),      _filename(filename), _outputted(false), _binary(binary),      _tcp_opt(tcp_opt), _npkt(0), _nnote(0){    // use the encapsulated IP header for ICMP errors    if (_ip_p == IP_PROTO_ICMP) {	const click_icmp *icmph = p->icmp_header();	// should assert some things here	const click_ip *embedded_iph = reinterpret_cast<const click_ip *>(icmph + 1);	_flowid = IPFlowID(embedded_iph);	_ip_p = embedded_iph->ip_p;    }    if (PAINT_ANNO(p) & 1)	// reverse _flowid	_flowid = _flowid.rev();        _have_first_seq[0] = _have_first_seq[1] = absolute_seq;    _first_seq[0] = _first_seq[1] = 0;    if (absolute_time)	_first_timestamp = Timestamp();    else			// make first packet have timestamp .000001	_first_timestamp = p->timestamp_anno() - Timestamp::epsilon();    if (ip_id)	_ip_ids = new uint16_t[NPKT];    else	_ip_ids = 0;    if (tcp_window && _ip_p == IP_PROTO_TCP)	_tcp_windows = new uint16_t[NPKT];    else	_tcp_windows = 0;        // sanity checks    assert(_aggregate && (_ip_p == IP_PROTO_TCP || _ip_p == IP_PROTO_UDP));}ToIPFlowDumps::Flow::~Flow(){    delete[] _ip_ids;    delete[] _tcp_windows;}intToIPFlowDumps::Flow::create_directories(const String &n, ErrorHandler *errh){    int slash = n.find_right('/');    if (slash <= 0)	return 0;    String component = n.substring(0, slash);    if (access(component.cc(), F_OK) >= 0)	return 0;    else if (create_directories(component, errh) < 0)	return -1;    else if (mkdir(component.cc(), 0777) < 0)	return errh->error("making directory %s: %s", component.cc(), strerror(errno));    else	return 0;}voidToIPFlowDumps::Flow::output_binary(StringAccum &sa){    union {	uint32_t u[8];	uint16_t us[16];	char c[32];    } buf;    int pi = 0, ni = 0;    const uint16_t *opt = reinterpret_cast<const uint16_t *>(_opt_info.data());    const uint16_t *end_opt = opt + (_opt_info.length() / 2);        while (pi < _npkt || ni < _nnote)	if (ni >= _nnote || _note[ni].before_pkt > pi) {	    int pos;	    buf.u[1] = ntohl(_pkt[pi].timestamp.sec());#if HAVE_NANOTIMESTAMP	    buf.u[2] = ntohl(_pkt[pi].timestamp.nsec());#else	    buf.u[2] = ntohl(_pkt[pi].timestamp.usec());#endif	    if (_ip_p == IP_PROTO_TCP) {		buf.u[3] = ntohl(_pkt[pi].th_seq);		buf.u[4] = ntohl(_pkt[pi].payload_len);		buf.u[5] = ntohl(_pkt[pi].th_ack);		pos = 24;	    } else {		buf.u[3] = ntohl(_pkt[pi].payload_len);		pos = 16;	    }	    if (_ip_ids)		buf.us[pos>>1] = _ip_ids[pi], pos += 2;	    if (_tcp_windows)		buf.us[pos>>1] = _tcp_windows[pi], pos += 2;	    if (_ip_p == IP_PROTO_TCP)		buf.c[pos++] = _pkt[pi].th_flags;	    buf.c[pos++] = _pkt[pi].direction;	    	    buf.u[0] = ntohl(pos);	    sa.append(&buf.c[0], pos);	    // handle TCP options specially	    if (opt < end_opt && opt[0] == pi) {		int original_pos = sa.length() - pos;		IPSummaryDump::unparse_tcp_opt_binary(sa, reinterpret_cast<const uint8_t *>(opt + 2), opt[1], _tcp_opt);		PUT4(sa.data() + original_pos, sa.length() - original_pos);		opt += 2 + (opt[1] / 2);	    }	    pi++;	} else {	    int len = (ni == _nnote - 1 ? _note_text.length() : _note[ni+1].pos) - _note[ni].pos;	    int record_len = (4 + len + 2);	    buf.u[0] = ntohl(record_len | 0x80000000U);	    buf.c[4] = '#';	    sa.append(&buf.c[0], 5);	    sa.append(_note_text.data() + _note[ni].pos, len);	    sa.append("\n", 1);	    ni++;	}}intToIPFlowDumps::Flow::output(ErrorHandler *errh){    static StringAccum sa;        int fd;    if (_filename == "-")	fd = STDOUT_FILENO;    else if (_outputted)	fd = open(_filename.cc(), O_WRONLY | O_APPEND);    else if (create_directories(_filename, errh) < 0)	return -1;    else	fd = open(_filename.cc(), O_WRONLY | O_CREAT | O_TRUNC, 0666);    if (fd < 0)	return errh->error("%s: %s", _filename.cc(), strerror(errno));    // make a guess about how much data we'll need    sa.clear();    sa.reserve(_npkt * (_binary ? 28 : 40) + _note_text.length() + _nnote * 8 + _opt_info.length() + 16);        if (!_outputted) {	sa << "!IPSummaryDump 1.2\n!flowid "	   << _flowid.saddr() << ' ' << ntohs(_flowid.sport()) << ' '	   << _flowid.daddr() << ' ' << ntohs(_flowid.dport()) << ' '	   << (_ip_p == IP_PROTO_TCP ? 'T' : 'U')	   << "\n!aggregate " << _aggregate << '\n';#if HAVE_NANOTIMESTAMP	sa << "!data ntimestamp";#else	sa << "!data timestamp";#endif	if (_binary) {	    if (_ip_p == IP_PROTO_TCP)		sa << " tcp_seq payload_len tcp_ack";	    else		sa << " payload_len";	    if (_ip_ids)		sa << " ip_id";	    if (_tcp_windows)		sa << " tcp_window";	    if (_ip_p == IP_PROTO_TCP)		sa << " tcp_flags";	    sa << " direction";	    if (_ip_p == IP_PROTO_TCP) {		if (_tcp_opt & IPSummaryDump::DO_TCPOPT_TIMESTAMP)		    sa << " tcp_opt";		else		    sa << " tcp_ntopt";	    }	} else {	    sa << " direction";	    if (_ip_ids)		sa << " ip_id";	    if (_ip_p == IP_PROTO_TCP) {		sa << " tcp_flags tcp_seq payload_len tcp_ack";		if (_tcp_opt & IPSummaryDump::DO_TCPOPT_TIMESTAMP)		    sa << " tcp_opt";		else		    sa << " tcp_ntopt";	    } else		sa << " payload_len";	}	sa << '\n';		if (_have_first_seq[0] && _first_seq[0] && _ip_p == IP_PROTO_TCP)	    sa << "!firstseq > " << _first_seq[0] << '\n';	if (_have_first_seq[1] && _first_seq[1] && _ip_p == IP_PROTO_TCP)	    sa << "!firstseq < " << _first_seq[1] << '\n';	if (_first_timestamp)	    sa << "!firsttime " << _first_timestamp << '\n';	if (_binary)	    sa << "!binary\n";    }    if (_binary)	output_binary(sa);    else {	int pi = 0, ni = 0;	const uint16_t *opt = reinterpret_cast<const uint16_t *>(_opt_info.data());	const uint16_t *end_opt = opt + (_opt_info.length() / 2);		while (pi < _npkt || ni < _nnote)	    if (ni >= _nnote || _note[ni].before_pkt > pi) {		int direction = _pkt[pi].direction;		sa << _pkt[pi].timestamp << ' '		   << (direction == 0 ? '>' : '<') << ' ';		if (_ip_ids)		    sa << _ip_ids[pi] << ' ';				if (_ip_p == IP_PROTO_TCP) {		    int flags = _pkt[pi].th_flags;		    if (flags == TH_ACK)			sa << 'A';		    else if (flags == (TH_ACK | TH_PUSH))			sa << 'P' << 'A';		    else if (flags == 0)			sa << '.';		    else			for (int flag = 0; flag < 7; flag++)			    if (flags & (1 << flag))				sa << IPSummaryDump::tcp_flags_word[flag];		    sa << ' ' << _pkt[pi].th_seq		       << ' ' << _pkt[pi].payload_len		       << ' ' << _pkt[pi].th_ack;		    if (_tcp_windows)			sa << ' ' << ntohs(_tcp_windows[pi]);		    		    if (opt < end_opt && opt[0] == pi) {			sa << ' ';			IPSummaryDump::unparse_tcp_opt(sa, reinterpret_cast<const uint8_t *>(opt + 2), opt[1], _tcp_opt);			opt += 2 + (opt[1] / 2);		    }		    		    sa << '\n';		} else		    sa << _pkt[pi].payload_len << '\n';		pi++;	    } else {		int len = (ni == _nnote - 1 ? _note_text.length() : _note[ni+1].pos) - _note[ni].pos;		sa << '#';		sa.append(_note_text.data() + _note[ni].pos, len);		sa << '\n';		ni++;	    }    }    _npkt = 0;    _opt_info.clear();        _note_text.clear();    _nnote = 0;    // actually write data    int pos = 0;    while (pos < sa.length()) {	int written = write(fd, sa.data() + pos, sa.length() - pos);	if (written < 0 && errno != EINTR) {	    errh->error("%s: %s", _filename.cc(), strerror(errno));	    break;	}	pos += written;    }        if (fd != STDOUT_FILENO)	close(fd);    _outputted = true;    return 0;}inline voidToIPFlowDumps::Flow::unlink(ErrorHandler *errh){    if (_outputted && ::unlink(_filename.cc()) < 0)	errh->error("%s: %s", _filename.cc(), strerror(errno));}voidToIPFlowDumps::Flow::store_opt(const click_tcp *tcph, int direction){    const uint8_t *opt = reinterpret_cast<const uint8_t *>(tcph + 1);    const uint8_t *end_opt = opt + ((tcph->th_off << 2) - sizeof(click_tcp));    bool any = false;    int original_len = _opt_info.length();    char *data;        while (opt < end_opt)	switch (*opt) {	  case TCPOPT_EOL:	    goto done;	  case TCPOPT_NOP:	    opt++;	    break;	  case TCPOPT_MAXSEG:	    if (opt[1] != TCPOLEN_MAXSEG || opt + opt[1] > end_opt)		goto bad_opt;	    else		goto good_opt;	  case TCPOPT_WSCALE:	    if (opt[1] != TCPOLEN_WSCALE || opt + opt[1] > end_opt)		goto bad_opt;	    else		goto good_opt;	  case TCPOPT_SACK_PERMITTED:	    if (opt[1] != TCPOLEN_SACK_PERMITTED || opt + opt[1] > end_opt)		goto bad_opt;	    else		goto good_opt;	  case TCPOPT_TIMESTAMP:	    if (opt[1] != TCPOLEN_TIMESTAMP || opt + opt[1] > end_opt)		goto bad_opt;	    else if (_tcp_opt & IPSummaryDump::DO_TCPOPT_TIMESTAMP)		goto good_opt;	    else		goto ignore_opt;	  good_opt:	    if (!any && (data = _opt_info.extend(4)))		*(reinterpret_cast<uint16_t *>(data)) = _npkt;	    if ((data = _opt_info.extend(opt[1])))		memcpy(data, opt, opt[1]);	    opt += opt[1];	    any = true;	    break;	  case TCPOPT_SACK:	    if (opt[1] % 8 != 2 || opt + opt[1] > end_opt)		goto bad_opt;	    if (!any && (data = _opt_info.extend(4)))		*(reinterpret_cast<uint16_t *>(data)) = _npkt;	    if ((data = _opt_info.extend(opt[1]))) {		// argh... must renumber sequence numbers in sack blocks 		memcpy(data, opt, 2);		const uint8_t *end_sack_opt = opt + opt[1];		for (opt += 2, data += 2; opt < end_sack_opt; opt += 8, data += 8) {		    uint32_t buf[2];		    memcpy(buf, opt, 8);		    if (!_have_first_seq[!direction]) {			_first_seq[!direction] = ntohl(buf[0]);			_have_first_seq[!direction] = true;		    }		    buf[0] = htonl(ntohl(buf[0]) - _first_seq[!direction]);		    buf[1] = htonl(ntohl(buf[1]) - _first_seq[!direction]);		    memcpy(data, buf, 8);		}	    } else		opt += opt[1];	    any = true;	    break;	  default:	    if (opt[1] == 0 || opt + opt[1] > end_opt)		goto bad_opt;	    else		goto ignore_opt;	  ignore_opt:	    opt += opt[1];	    break;	}  done:    if (any) {	if (_opt_info.length() & 1)	    _opt_info.append('\0');	*(reinterpret_cast<uint16_t *>(_opt_info.data() + original_len) + 1) = _opt_info.length() - original_len - 4;    }    return;      bad_opt:    _opt_info.set_length(original_len);}intToIPFlowDumps::Flow::add_pkt(const Packet *p, ErrorHandler *errh){    // ICMP errors are handled as notes, not packets    if (PAINT_ANNO(p) >= 2) {	assert(p->ip_header()->ip_p == IP_PROTO_ICMP);	StringAccum sa;	sa << p->timestamp_anno() << ' ' << (PAINT_ANNO(p) & 1 ? '>' : '<') << " ICMP_error";	// this doesn't count as a note, really; it is a packet	_note_count--;	if (_packet_count < 0xFFFFFFFFU)	    _packet_count++;	return add_note(sa.take_string(), errh);    }        if (_npkt >= NPKT && output(errh) < 0)	return -1;        int direction = (PAINT_ANNO(p) & 1);    const click_ip *iph = p->ip_header();    assert(iph->ip_p == _ip_p);        _pkt[_npkt].timestamp = p->timestamp_anno() - _first_timestamp;    _pkt[_npkt].direction = direction;    if (_ip_ids)	_ip_ids[_npkt] = iph->ip_id;    if (_ip_p == IP_PROTO_TCP) {	const click_tcp *tcph = p->tcp_header();	

⌨️ 快捷键说明

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