From a56b7174bc4d39064e5fb8d22953963f224315db Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 7 Feb 2008 14:59:44 +0000 Subject: [PATCH] Resolve IP addresses to hostnames Cap the rate at which to generate packets from hosts Reduce the number of GL calls in rendering packets A lot of other changes --- source/host.cpp | 94 ++++++++++++++-- source/host.h | 29 +++-- source/netvis.cpp | 258 +++++++++++++++++++++++++++++++++++--------- source/netvis.h | 26 ++++- source/packet.cpp | 65 ++++++----- source/packet.h | 9 +- source/resolver.cpp | 75 +++++++++++++ source/resolver.h | 43 ++++++++ source/vector2.h | 7 ++ 9 files changed, 509 insertions(+), 97 deletions(-) create mode 100644 source/resolver.cpp create mode 100644 source/resolver.h diff --git a/source/host.cpp b/source/host.cpp index be24f05..e5eafc8 100644 --- a/source/host.cpp +++ b/source/host.cpp @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #include #include #include @@ -14,11 +21,48 @@ using namespace Msp; Host::Host(NetVis &nv, unsigned a): netvis(nv), - addr(a) + addr(a), + local(false), + active(true), + activity(0), + throttle(0) { in_addr ina; ina.s_addr=htonl(addr); name=inet_ntoa(ina); + short_name=name; +} + +void Host::set_name(const string &n) +{ + name=n; + + if(local) + { + unsigned dot=name.find('.'); + short_name=name.substr(0, dot); + } + else + { + unsigned dot=name.size(); + for(unsigned i=0; (dot>0 && dot!=string::npos); ++i) + { + unsigned prev=name.rfind('.', dot-1); + if(prev+151) + break; + dot=prev; + } + + if(dot==string::npos) + short_name=name; + else + short_name="..."+name.substr(dot+1); + } +} + +void Host::set_local(bool l) +{ + local=l; } void Host::set_position(const Vector2 &p) @@ -26,19 +70,36 @@ void Host::set_position(const Vector2 &p) pos=p; } -void Host::add_connection(Connection &) +void Host::set_active(bool a) +{ + active=a; +} + +void Host::add_activity(unsigned bytes) { + activity+=bytes*0.06935; } -Connection *Host::get_connection(Host &) +float Host::send_packet() { - return 0; + float ret=throttle; + if(throttle<1) + throttle+=0.025; + return ret; } void Host::tick(const Msp::Time::TimeDelta &td) { float dt=td/Msp::Time::sec; + activity*=pow(0.933f, dt); + throttle-=dt; + if(throttle<0) + throttle=0; + + if(!active) + return; + const map &hosts=netvis.get_hosts(); float fx=-pos.x*0.1; float fy=-pos.y*0.1; @@ -57,8 +118,8 @@ void Host::tick(const Msp::Time::TimeDelta &td) for(unsigned j=32; (j-- && !((addr^other_addr)>>j));) ++matching_bits; - float nearness=24-min(matching_bits, 24U); - float f=10000.0*(1.0/(60+nearness*15)-1.0/d); + float optimal_dist=100+(24-min(matching_bits, 24U))*12; + float f=5000.0*(1.0/optimal_dist-1.0/d); fx+=dx/d*f; fy+=dy/d*f; @@ -73,23 +134,36 @@ void Host::tick(const Msp::Time::TimeDelta &td) void Host::render() const { + if(!active) + return; + GL::push_matrix(); GL::translate(static_cast(pos.x), static_cast(pos.y), 0); GL::Immediate imm((GL::COLOR4_UBYTE, GL::VERTEX2)); imm.begin(GL::QUADS); - imm.color(1.0f, 1.0f, 1.0f, 1.0f); + imm.color(1.0f, 1.0f, 1.0f, max(min(static_cast(activity/10000), 1.0f), 0.2f)); imm.vertex(-5, -5); imm.vertex(5, -5); imm.vertex(5, 5); imm.vertex(-5, 5); imm.end(); + GL::pop_matrix(); +} + +void Host::render_label() const +{ + if(!active) + return; + const GL::Font &font=netvis.get_font(); - GL::translate(-static_cast(font.get_string_width(name)*5), 6, 0); + + GL::push_matrix(); + GL::translate(static_cast(pos.x)-static_cast(font.get_string_width(short_name)*5), static_cast(pos.y)+6, 0); GL::scale_uniform(10); - font.draw_string(name); - GL::Texture::unbind(); + + font.draw_string(short_name); GL::pop_matrix(); } diff --git a/source/host.h b/source/host.h index 60dc547..2910ad6 100644 --- a/source/host.h +++ b/source/host.h @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #ifndef HOST_H_ #define HOST_H_ @@ -6,7 +13,6 @@ #include #include "vector2.h" -class Connection; class NetVis; class Host @@ -15,23 +21,32 @@ private: NetVis &netvis; unsigned addr; std::string name; + std::string short_name; + bool local; Vector2 pos; - bool visible; - std::map connections; + bool active; + float activity; + float throttle; public: Host(NetVis &, unsigned); - void set_position(const Vector2 &); unsigned get_address() const { return addr; } + void set_name(const std::string &); const std::string &get_name() const { return name; } + void set_local(bool); + + void set_position(const Vector2 &); const Vector2 &get_position() const { return pos; } - bool get_visible() const { return visible; } - void add_connection(Connection &); - Connection *get_connection(Host &); + void set_active(bool); + bool get_active() const { return active; } + void add_activity(unsigned); + float get_activity() const { return activity; } + float send_packet(); void tick(const Msp::Time::TimeDelta &); void render() const; + void render_label() const; }; #endif diff --git a/source/netvis.cpp b/source/netvis.cpp index 711788b..e49c28e 100644 --- a/source/netvis.cpp +++ b/source/netvis.cpp @@ -1,9 +1,18 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #include +#include #include #include #include #include #include +#include #include #include #include @@ -11,16 +20,23 @@ #include #include #include +#include #include #include "host.h" #include "netvis.h" #include "packet.h" +#include "resolver.h" using namespace std; using namespace Msp; -NetVis::NetVis(int /*argc*/, char **argv) +NetVis::NetVis(int argc, char **argv): + draw_labels(true), + blend(true), + frames(0) { + if(argc<2) + throw UsageError("No interface given"); iface=argv[1]; } @@ -34,10 +50,16 @@ int NetVis::main() if(pcap_setnonblock(pcap, true, err)==-1) throw Exception(err); + pcap_lookupnet(iface.c_str(), &localnet, &localnet_mask, err); + localnet=ntohl(localnet); + localnet_mask=ntohl(localnet_mask); + dpy=new Graphics::Display; wnd=new Graphics::Window(*dpy, 1024, 768); glc=new Graphics::GLContext(*wnd); wnd->set_title("NetVis"); + wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &NetVis::exit), 0)); + wnd->signal_key_press.connect(sigc::mem_fun(this, &NetVis::key_press)); wnd->show(); GL::enable(GL_BLEND); @@ -49,83 +71,191 @@ int NetVis::main() DataFile::load(*font_tex, "dejavu-10.tex"); font->set_texture(*font_tex); + catch_signal(SIGINT); + + resolver=new Resolver; + + //set_loop_mode(TICK_BUSY); + Application::main(); + delete resolver; + delete glc; delete wnd; delete dpy; + cout<tick(); - - pcap_dispatch(pcap, -1, &capture_handler, reinterpret_cast(this)); - - glClear(GL_COLOR_BUFFER_BIT); + if(tick_t>fps_t+Msp::Time::sec) + { + fps=frames/((tick_t-fps_t)/Msp::Time::sec); + fps_t=tick_t; + frames=0; + } - GL::matrix_mode(GL::PROJECTION); - GL::load_identity(); - GL::ortho_centered(1024, 768); - GL::matrix_mode(GL::MODELVIEW); - GL::load_identity(); + dpy->tick(); - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) { - i->second->tick(dt); - i->second->render(); + Debug::ProfilingScope s(profiler, "capture"); + while(pcap_dispatch(pcap, -1, &capture_handler, reinterpret_cast(this))>0); } - for(list::iterator i=packets.begin(); i!=packets.end();) + { - (*i)->tick(dt); - (*i)->render(); - if((*i)->get_stale()) + Debug::ProfilingScope s(profiler, "tick"); + + resolver->tick(); + + float min_activity=1e7f; + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + { + i->second->tick(dt); + min_activity=min(min_activity, i->second->get_activity()); + } + for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end(); ++i) + i->second->tick(dt); + + for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end();) { - delete *i; - i=packets.erase(i); + if(i->second->get_activity()>min_activity) + { + i->second->set_active(true); + hosts.insert(*i); + disabled_hosts.erase(i++); + } + else + ++i; + } + if(hosts.size()>20) + { + list activity; + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + activity.push_back(i->second->get_activity()); + activity.sort(); + + list::iterator j=activity.begin(); + advance(j, activity.size()-20); + float limit=*j; + + for(map::iterator i=hosts.begin(); i!=hosts.end();) + { + if(i->second->get_activity()second->set_active(false); + disabled_hosts.insert(*i); + hosts.erase(i++); + } + else + ++i; + } + } + + for(list::iterator i=packets.begin(); i!=packets.end();) + { + (*i)->tick(dt); + if((*i)->get_stale()) + { + delete *i; + i=packets.erase(i); + } + else + ++i; } - else - ++i; } - GL::translate(-500, 360, 0); - for(map::iterator i=port_colors.begin(); i!=port_colors.end(); ++i) { - GL::Color &color=i->second; + Debug::ProfilingScope s(profiler, "render"); + glClear(GL_COLOR_BUFFER_BIT); - GL::push_matrix(); + GL::matrix_mode(GL::PROJECTION); + GL::load_identity(); + GL::ortho_centered(1024, 768); + GL::matrix_mode(GL::MODELVIEW); + GL::load_identity(); - GL::Immediate imm((GL::COLOR4_UBYTE,GL::VERTEX2)); - imm.begin(GL::QUADS); - imm.color(color.r, color.g, color.b, color.a); - for(float x=0; x<0.5; x+=0.2) + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + i->second->render(); + if(draw_labels) { - imm.vertex(x+0, 0); - imm.vertex(x+10, 0); - imm.vertex(x+10, 10); - imm.vertex(x+0, 10); + glColor4f(1.0, 1.0, 1.0, 1.0); + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + i->second->render_label(); + GL::Texture::unbind(); } + GL::Immediate imm((GL::COLOR4_UBYTE, GL::VERTEX2)); + imm.begin(GL::QUADS); + for(list::iterator i=packets.begin(); i!=packets.end(); ++i) + (*i)->render(imm); imm.end(); - GL::translate(15, 1, 0); + GL::push_matrix(); + GL::translate(-500, 360, 0); + unsigned n=0; + for(map::iterator i=port_colors.begin(); (i!=port_colors.end() && n<20); ++i, ++n) + { + GL::Color &color=i->second; + + imm.begin(GL::QUADS); + imm.color(color.r, color.g, color.b, color.a); + for(unsigned x=0; x<=4; x+=2) + { + imm.vertex(x+0, 0); + imm.vertex(x+10, 0); + imm.vertex(x+10, 10); + imm.vertex(x+0, 10); + } + imm.end(); + + GL::translate(0, -12, 0); + } + GL::pop_matrix(); + + GL::push_matrix(); + if(draw_labels) + { + GL::push_matrix(); + GL::translate(-484, 361, 0); + GL::scale_uniform(10); + glColor4f(1.0, 1.0, 1.0, 1.0); + n=0; + for(map::iterator i=port_colors.begin(); (i!=port_colors.end() && n<20); ++i, ++n) + { + font->draw_string(format("%d", i->first)); + + GL::translate(0, -1.2, 0); + } + GL::pop_matrix(); + GL::Texture::unbind(); + } + GL::pop_matrix(); + + GL::push_matrix(); + GL::translate(-500, -360, 0); GL::scale_uniform(10); - glColor4f(1.0, 1.0, 1.0, 1.0); - font->draw_string(format("%d", i->first)); + font->draw_string(format("%d hosts", hosts.size()+disabled_hosts.size())); + GL::translate(0, -1.2, 0); + font->draw_string(format("%.2f fps", fps)); + GL::pop_matrix(); GL::Texture::unbind(); - GL::pop_matrix(); - GL::translate(0, -12, 0); + glc->swap_buffers(); } - glc->swap_buffers(); + ++frames; } Host &NetVis::get_host(unsigned a) @@ -134,8 +264,15 @@ Host &NetVis::get_host(unsigned a) if(i!=hosts.end()) return *i->second; + i=disabled_hosts.find(a); + if(i!=disabled_hosts.end()) + return *i->second; + Host *host=new Host(*this, a); - host->set_position(Vector2(rand()*30.0/RAND_MAX-15.0, rand()*20.0/RAND_MAX-10.0)); + if((a&localnet_mask)==localnet) + host->set_local(true); + resolver->push(host); + host->set_position(Vector2(rand()*400.0/RAND_MAX-200.0, rand()*400.0/RAND_MAX-200.0)); hosts[a]=host; return *host; } @@ -159,6 +296,17 @@ GL::Color &NetVis::get_port_color(unsigned port) return port_colors[port]=color; } +void NetVis::key_press(unsigned key, unsigned, wchar_t) +{ + if(key==46) + draw_labels=!draw_labels; + else if(key==56) + { + blend=!blend; + GL::set(GL_BLEND, blend); + } +} + void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *, const unsigned char *data) { NetVis *self=reinterpret_cast(user); @@ -168,8 +316,7 @@ void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *, const uns { const iphdr *ip=reinterpret_cast(eth+1); - //cout<<"IP packet of "<len<<'/'<tot_len)<<" bytes\n"; - + unsigned size=ntohs(ip->tot_len); unsigned port=0; if(ip->protocol==IPPROTO_TCP) { @@ -185,8 +332,23 @@ void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *, const uns Host *dhost=0; if((ntohl(ip->daddr)&0xFF)!=0xFF) dhost=&self->get_host(ntohl(ip->daddr)); - self->packets.push_back(new Packet(shost, dhost, self->get_port_color(port), ntohs(ip->tot_len))); + + float throttle=shost.send_packet(); + if(throttle<1) + { + self->packets.push_back(new Packet(shost, dhost, self->get_port_color(port), size)); + self->packets.back()->tick(-throttle*Msp::Time::sec); + } + + shost.add_activity(size); + if(dhost) + dhost->add_activity(size); } } +void NetVis::sighandler(int) +{ + exit(0); +} + Application::RegApp NetVis::reg; diff --git a/source/netvis.h b/source/netvis.h index daec1cf..9e8661e 100644 --- a/source/netvis.h +++ b/source/netvis.h @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #ifndef NETVIS_H_ #define NETVIS_H_ @@ -5,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -12,8 +20,9 @@ #include #include -class Packet; class Host; +class Packet; +class Resolver; class NetVis: public Msp::Application { @@ -22,13 +31,23 @@ private: pcap_t *pcap; std::list packets; std::map hosts; + std::map disabled_hosts; Msp::Graphics::Display *dpy; Msp::Graphics::Window *wnd; Msp::Graphics::GLContext *glc; - Msp::Time::TimeStamp last_tick; + Msp::Time::TimeStamp tick_t; std::map port_colors; Msp::GL::Font *font; Msp::GL::Texture2D *font_tex; + Msp::Debug::Profiler profiler; + bool draw_labels; + bool blend; + Resolver *resolver; + unsigned localnet; + unsigned localnet_mask; + Msp::Time::TimeStamp fps_t; + unsigned frames; + float fps; public: NetVis(int, char **); @@ -39,9 +58,12 @@ private: virtual void tick(); Host &get_host(unsigned); Msp::GL::Color &get_port_color(unsigned); + void key_press(unsigned, unsigned, wchar_t); static void capture_handler(unsigned char *, const pcap_pkthdr *, const unsigned char *); + void sighandler(int); + static Application::RegApp reg; }; diff --git a/source/packet.cpp b/source/packet.cpp index 491e807..512144a 100644 --- a/source/packet.cpp +++ b/source/packet.cpp @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #include #include #include @@ -13,11 +20,10 @@ Packet::Packet(const Host &s, const Host *d, const GL::Color &c, unsigned i): dest(d), color(c), x(0), - size(cbrt(i)), - angle(rand()*180.0/RAND_MAX), - rspeed(rand()*180.0/RAND_MAX-90.0) -{ -} + size(cbrt(i)*1.5), + angle(rand()*M_PI*2/RAND_MAX), + rspeed(rand()*M_PI/RAND_MAX-M_PI/2) +{ } void Packet::tick(const Time::TimeDelta &dt) { @@ -27,46 +33,47 @@ void Packet::tick(const Time::TimeDelta &dt) x=1; angle+=rspeed*f; if(angle<0) - angle+=360; - if(angle>=360) - angle-=360; + angle+=M_PI*2; + if(angle>=M_PI*2) + angle-=M_PI; } -void Packet::render() const +void Packet::render(GL::PrimitiveBuilder &bld) const { - GL::push_matrix(); + if(x<0) + return; + if(!src.get_active() || (dest && !dest->get_active())) + return; const Vector2 &spos=src.get_position(); if(dest) { const Vector2 &dpos=dest->get_position(); - GL::translate(spos.x*(1-x)+dpos.x*x, spos.y*(1-x)+dpos.y*x, 0); - GL::rotate(angle, 0, 0, 1); + Vector2 pos(spos.x*(1-x)+dpos.x*x, spos.y*(1-x)+dpos.y*x); + Vector2 corner(cos(angle)*size, sin(angle)*size); - GL::Immediate imm((GL::COLOR4_UBYTE,GL::VERTEX2)); - imm.begin(GL::QUADS); - imm.color(color.r, color.g, color.b, color.a); - imm.vertex(-size, -size); - imm.vertex(size, -size); - imm.vertex(size, size); - imm.vertex(-size, size); - imm.end(); + if(bld.get_type()!=GL::QUADS) + { + bld.end(); + bld.begin(GL::QUADS); + } + bld.color(color.r, color.g, color.b, color.a); + bld.vertex(pos.x+corner.x, pos.y+corner.y); + bld.vertex(pos.x-corner.y, pos.y+corner.x); + bld.vertex(pos.x-corner.x, pos.y-corner.y); + bld.vertex(pos.x+corner.y, pos.y-corner.x); } else { - GL::translate(spos.x, spos.y, 0); - GL::Immediate imm((GL::COLOR4_UBYTE,GL::VERTEX2)); - imm.begin(GL::TRIANGLE_FAN); - imm.color(color.r, color.g, color.b, color.a*(1-x)); - imm.vertex(0, 0); + bld.end(); + bld.begin(GL::TRIANGLE_FAN); + bld.color(color.r, color.g, color.b, color.a*(1-x)); + bld.vertex(spos.x, spos.y); for(unsigned i=0; i<=24; ++i) { float a=i*M_PI/12; - imm.vertex(cos(a)*x*200, sin(a)*x*200); + bld.vertex(spos.x+cos(a)*x*200, spos.y+sin(a)*x*200); } - imm.end(); } - - GL::pop_matrix(); } diff --git a/source/packet.h b/source/packet.h index cfeb2df..18e7e43 100644 --- a/source/packet.h +++ b/source/packet.h @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #ifndef PACKET_H_ #define PACKET_H_ @@ -21,7 +28,7 @@ public: Packet(const Host &, const Host *, const Msp::GL::Color &, unsigned); bool get_stale() const { return x>=1; } void tick(const Msp::Time::TimeDelta &); - void render() const; + void render(Msp::GL::PrimitiveBuilder &) const; }; #endif diff --git a/source/resolver.cpp b/source/resolver.cpp new file mode 100644 index 0000000..1a0b99f --- /dev/null +++ b/source/resolver.cpp @@ -0,0 +1,75 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + +#include +#include +#include +#include +#include "host.h" +#include "resolver.h" + +using namespace std; +using namespace Msp; + +Resolver::Resolver(): + done(false) +{ + launch(); +} + +Resolver::~Resolver() +{ + done=true; + join(); +} + +void Resolver::push(Host *h) +{ + MutexLock l_(mutex); + + in_queue.push_back(h); +} + +void Resolver::tick() +{ + MutexLock l_(mutex); + + for(list::iterator i=out_queue.begin(); i!=out_queue.end(); ++i) + i->host->set_name(i->name); + out_queue.clear(); +} + +void Resolver::main() +{ + while(!done) + { + while(1) + { + Host *host; + { + MutexLock l_(mutex); + if(in_queue.empty()) + break; + host=in_queue.front(); + in_queue.erase(in_queue.begin()); + } + + sockaddr_in addr; + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=htonl(host->get_address()); + char buf[128]; + int err=getnameinfo(reinterpret_cast(&addr), sizeof(addr), buf, sizeof(buf), 0, 0, NI_NOFQDN|NI_NAMEREQD); + if(err==0) + { + MutexLock l_(mutex); + out_queue.push_back(Result(host, buf)); + } + } + + Time::sleep(Time::sec); + } +} diff --git a/source/resolver.h b/source/resolver.h new file mode 100644 index 0000000..fb9dd10 --- /dev/null +++ b/source/resolver.h @@ -0,0 +1,43 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + +#ifndef RESOLVER_H_ +#define RESOLVER_H_ + +#include +#include +#include + +class Host; + +class Resolver: public Msp::Thread +{ +private: + struct Result + { + Host *host; + std::string name; + + Result(Host *h, const std::string &n): host(h), name(n) { } + }; + + std::list in_queue; + std::list out_queue; + Msp::Mutex mutex; + bool done; + +public: + Resolver(); + ~Resolver(); + + void push(Host *); + void tick(); +private: + void main(); +}; + +#endif diff --git a/source/vector2.h b/source/vector2.h index 0ff927c..8ece3b2 100644 --- a/source/vector2.h +++ b/source/vector2.h @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of NetVis +Copyright @ 2008 Mikko Rasa, Mikkosoft Productions +Distributed unter the GPL +*/ + #ifndef VECTOR2_H_ #define VECTOR2_H_ -- 2.43.0