📄 icmpsendpings.cc
字号:
// -*- c-basic-offset: 4 -*-/* * icmpsendpings.{cc,hh} -- Send ICMP ping packets. * Robert Morris, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * * 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 "icmpsendpings.hh"#include <click/confparse.hh>#include <click/error.hh>#include <click/glue.hh>#include <clicknet/ip.h>#include <clicknet/icmp.h>#include <click/packet_anno.hh>#include <click/integers.hh>#include <click/handlercall.hh>#include <click/straccum.hh>#if CLICK_LINUXMODULE# include <click/cxxprotect.h>CLICK_CXX_PROTECT# include <linux/vmalloc.h>CLICK_CXX_UNPROTECT# include <click/cxxunprotect.h>#endifCLICK_DECLSICMPPingSource::ICMPPingSource() : Element(0, 1), _limit(-1), _timer(this), _receiver(0){}ICMPPingSource::~ICMPPingSource(){}voidICMPPingSource::notify_ninputs(int n){ set_ninputs(n < 1 ? 0 : 1);}intICMPPingSource::configure(Vector<String> &conf, ErrorHandler *errh){ _icmp_id = 0; _interval = 1000; _data = String(); _active = true; _verbose = true; if (cp_va_parse(conf, this, errh, cpIPAddress, "source IP address", &_src, cpIPAddress, "destination IP address", &_dst, cpKeywords, "INTERVAL", cpSecondsAsMilli, "time between pings (s)", &_interval, "IDENTIFIER", cpUnsignedShort, "ICMP echo identifier", &_icmp_id, "DATA", cpString, "payload", &_data, "LIMIT", cpInteger, "total packet count", &_limit, "ACTIVE", cpBool, "active?", &_active, "VERBOSE", cpBool, "be verbose?", &_verbose, cpEnd) < 0) return -1;#ifndef __linux__ _icmp_id = htons(_icmp_id);#endif if (_interval == 0) errh->warning("INTERVAL so small that it is zero"); return 0;}intICMPPingSource::initialize(ErrorHandler *errh){ _count = 0; _timer.initialize(this); if (_limit != 0 && _active && output_is_push(0)) _timer.schedule_after_ms(_interval); if (ninputs() == 1) {#if CLICK_LINUXMODULE _receiver = (ReceiverInfo *)vmalloc(sizeof(ReceiverInfo));#else _receiver = new ReceiverInfo;#endif if (!_receiver) return errh->error("out of memory!"); memset(_receiver, 0, sizeof(ReceiverInfo)); } return 0;}voidICMPPingSource::cleanup(CleanupStage){ if (_receiver) { if (_verbose) { PrefixErrorHandler perrh(ErrorHandler::default_handler(), declaration() + ": "); perrh.message("%s", HandlerCall::call_read(this, "summary", &perrh).c_str()); }#if CLICK_LINUXMODULE vfree(_receiver);#else delete _receiver;#endif }}Packet*ICMPPingSource::make_packet(){ WritablePacket *q = Packet::make(sizeof(click_ip) + sizeof(struct click_icmp_echo) + _data.length()); if (!q) return 0; memset(q->data(), '\0', sizeof(click_ip) + sizeof(struct click_icmp_echo)); memcpy(q->data() + sizeof(click_ip) + sizeof(struct click_icmp_echo), _data.data(), _data.length()); click_ip *nip = reinterpret_cast<click_ip *>(q->data()); nip->ip_v = 4; nip->ip_hl = sizeof(click_ip) >> 2; nip->ip_len = htons(q->length()); uint16_t ip_id = (_count % 0xFFFF) + 1; // ensure ip_id != 0 nip->ip_id = htons(ip_id); nip->ip_p = IP_PROTO_ICMP; /* icmp */ nip->ip_ttl = 200; nip->ip_src = _src; nip->ip_dst = _dst; nip->ip_sum = click_in_cksum((unsigned char *)nip, sizeof(click_ip)); click_icmp_echo *icp = (struct click_icmp_echo *) (nip + 1); icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_identifier = _icmp_id;#ifdef __linux__ icp->icmp_sequence = ip_id;#else icp->icmp_sequence = htons(ip_id);#endif icp->icmp_cksum = click_in_cksum((const unsigned char *)icp, sizeof(click_icmp_sequenced) + _data.length()); q->set_dst_ip_anno(IPAddress(_dst)); q->set_ip_header(nip, sizeof(click_ip)); q->timestamp_anno().set_now(); if (_receiver) _receiver->send_timestamp[icp->icmp_sequence] = q->timestamp_anno(); return q;}voidICMPPingSource::run_timer(){ if (Packet *q = make_packet()) { output(0).push(q); _count++; if (_count < _limit || _limit < 0) _timer.reschedule_after_ms(_interval); }}Packet*ICMPPingSource::pull(int){ Packet *p = 0; if ((_count < _limit || _limit < 0) && (p = make_packet())) _count++; return p;}voidICMPPingSource::push(int, Packet *p){ const click_ip *iph = p->ip_header(); const click_icmp_echo *icmph = reinterpret_cast<const click_icmp_echo *>(p->icmp_header()); if (iph && iph->ip_p == IP_PROTO_ICMP && p->transport_length() >= (int)sizeof(click_icmp_echo) && icmph->icmp_type == ICMP_ECHOREPLY && icmph->icmp_identifier == _icmp_id) { Timestamp *send_ts = &_receiver->send_timestamp[icmph->icmp_sequence]; if (!*send_ts) /* error */; else { if (send_ts->_subsec < 0) { _receiver->nduplicate++; send_ts->_subsec ^= 0xFFFFFFFF; } Timestamp diff = p->timestamp_anno() - *send_ts; uint32_t diffval = diff.usec1(); if (diffval < _receiver->time_min || !_receiver->nreceived) _receiver->time_min = diffval; if (diffval > _receiver->time_max || !_receiver->nreceived) _receiver->time_max = diffval; _receiver->time_sum += diffval; _receiver->time_sq_sum += ((counter_t)diffval) * diffval; _receiver->nreceived++; send_ts->_subsec ^= 0xFFFFFFFF; #ifdef __linux__ uint16_t readable_seq = icmph->icmp_sequence;#else uint16_t readable_seq = ntohs(icmph->icmp_sequence);#endif if (_verbose) click_chatter("%s: %d bytes from %s: icmp_seq=%u ttl=%u time=%d.%03d ms", declaration().c_str(), ntohs(iph->ip_len) - (iph->ip_hl << 2) - sizeof(*icmph), IPAddress(iph->ip_dst).s().c_str(), readable_seq, iph->ip_ttl, (unsigned)(diffval/1000), (unsigned)(diffval % 1000)); } } p->kill();}enum { H_ACTIVE, H_LIMIT, H_INTERVAL, H_RESET_COUNTS, H_COUNT, H_SUMMARY, H_RTT_MIN, H_RTT_AVG, H_RTT_MAX };StringICMPPingSource::read_handler(Element *e, void *thunk){ ICMPPingSource *ps = static_cast<ICMPPingSource *>(e); ReceiverInfo *ri = ps->_receiver; switch ((uintptr_t)thunk) { case H_ACTIVE: return String(ps->_active) + "\n"; case H_COUNT: return String(ps->_count) + "\n"; case H_SUMMARY: { StringAccum sa; sa << ps->_count << " packets transmitted" << ", " << (ri->nreceived - ri->nduplicate) << " received"; if (ri->nduplicate) sa << ", +" << ri->nduplicate << " duplicates"; if (ps->_count) sa << ", " << (int)(((ps->_count - ri->nreceived - ri->nduplicate) * 100) / ps->_count) << "% packet loss\n"; if (ri->nreceived) { counter_t avg = ri->time_sum / ri->nreceived; counter_t avg_sq = ri->time_sq_sum / ri->nreceived; counter_t stdev = int_sqrt(avg_sq - avg * avg); sa.snprintf(256, "rtt min/avg/max/mdev = %u.%03u/%u.%03u/%u.%03u/%u.%03u\n", ri->time_min / 1000, ri->time_min % 1000, (unsigned)(avg / 1000), (unsigned)(avg % 1000), ri->time_max / 1000, ri->time_max % 1000, (unsigned)(stdev / 1000), (unsigned)(stdev % 1000)); } return sa.take_string(); } case H_RTT_MIN: return cp_unparse_microseconds(ri->time_min) + "\n"; case H_RTT_AVG: return cp_unparse_microseconds(ri->time_sum / (ri->nreceived ? ri->nreceived : 1)) + "\n"; case H_RTT_MAX: return cp_unparse_microseconds(ri->time_max) + "\n"; default: return ""; }}intICMPPingSource::write_handler(const String &str_in, Element *e, void *thunk, ErrorHandler *errh){ String s = cp_uncomment(str_in); ICMPPingSource *ps = static_cast<ICMPPingSource *>(e); switch ((uintptr_t)thunk) { case H_ACTIVE: if (!cp_bool(s, &ps->_active)) return errh->error("'active' should be bool"); if (ps->_active && !ps->_timer.scheduled() && ps->output_is_push(0)) ps->_timer.schedule_now(); else if (!ps->_active) ps->_timer.unschedule(); return 0; case H_LIMIT: if (!cp_integer(s, &ps->_limit)) return errh->error("'limit' should be integer"); if ((ps->_count < ps->_limit || ps->_limit < 0) && ps->_active && !ps->_timer.scheduled() && ps->output_is_push(0)) ps->_timer.schedule_after_ms(ps->_interval); return 0; case H_INTERVAL: if (!cp_seconds_as_milli(s, (uint32_t *)&ps->_interval)) return errh->error("'interval' should be an interval"); return 0; case H_RESET_COUNTS: ps->_count = 0; if (ReceiverInfo *ri = ps->_receiver) memset(ri, 0, sizeof(ReceiverInfo)); if (ps->_count < ps->_limit && ps->_active && !ps->_timer.scheduled() && ps->output_is_push(0)) ps->_timer.schedule_after_ms(ps->_interval); return 0; default: return -1; }}voidICMPPingSource::add_handlers(){ add_read_handler("active", read_handler, (void *)H_ACTIVE); add_write_handler("active", write_handler, (void *)H_ACTIVE); add_read_handler("count", read_handler, (void *)H_COUNT); add_write_handler("limit", write_handler, (void *)H_LIMIT); add_write_handler("interval", write_handler, (void *)H_INTERVAL); add_write_handler("reset_counts", write_handler, (void *)H_RESET_COUNTS); if (ninputs() > 0) { add_read_handler("summary", read_handler, (void *)H_SUMMARY); add_read_handler("rtt_min", read_handler, (void *)H_RTT_MIN); add_read_handler("rtt_avg", read_handler, (void *)H_RTT_AVG); add_read_handler("rtt_max", read_handler, (void *)H_RTT_MAX); }}CLICK_ENDDECLSEXPORT_ELEMENT(ICMPPingSource ICMPPingSource-ICMPSendPings)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -