]> git.tdb.fi Git - netvis.git/blob - source/netvis.cpp
Delete history on exit
[netvis.git] / source / netvis.cpp
1 /* $Id$
2
3 This file is part of NetVis
4 Copyright @ 2008 Mikko Rasa, Mikkosoft Productions
5 Distributed unter the GPL
6 */
7
8 #include <limits>
9 #include <cstdlib>
10 #include <cmath>
11 #include <signal.h>
12 #include <netinet/ether.h>
13 #include <netinet/ip.h>
14 #include <netinet/tcp.h>
15 #include <netinet/udp.h>
16 #include <msp/core/except.h>
17 #include <msp/debug/profilingscope.h>
18 #include <msp/gl/blend.h>
19 #include <msp/gl/framebuffer.h>
20 #include <msp/gl/immediate.h>
21 #include <msp/gl/matrix.h>
22 #include <msp/gl/misc.h>
23 #include <msp/gl/projection.h>
24 #include <msp/gl/texture2d.h>
25 #include <msp/gl/transform.h>
26 #include <msp/strings/formatter.h>
27 #include <msp/time/units.h>
28 #include <msp/time/utils.h>
29 #include "history.h"
30 #include "host.h"
31 #include "netvis.h"
32 #include "packet.h"
33 #include "port.h"
34 #include "resolver.h"
35
36 using namespace std;
37 using namespace Msp;
38
39 NetVis::NetVis(int argc, char **argv):
40         pcap(0),
41         resolver(0),
42         wnd(0),
43         font(0),
44         max_hosts(1000),
45         max_visible_hosts(30),
46         frames(0)
47 {
48         if(argc<2)
49                 throw UsageError("No interface given");
50         iface = argv[1];
51
52         char err[1024];
53         pcap = pcap_open_live(iface.c_str(), 128, true, 0, err);
54         if(!pcap)
55                 throw Exception(err);
56
57         if(pcap_setnonblock(pcap, true, err)==-1)
58                 throw Exception(err);
59
60         pcap_lookupnet(iface.c_str(), &localnet, &localnet_mask, err);
61         localnet = ntohl(localnet);
62         localnet_mask = ntohl(localnet_mask);
63
64         resolver = new Resolver;
65
66         wnd = new Graphics::SimpleGLWindow(1024, 768);
67         wnd->set_title("NetVis");
68         wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &NetVis::exit), 0));
69         wnd->show();
70
71         GL::enable(GL::BLEND);
72         GL::blend_func(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);
73
74         font = new GL::Font;
75         DataFile::load(*font, "dejavu-10.font");
76
77         history = new History(*this, 301, 100);
78
79         catch_signal(SIGINT);
80 }
81
82 NetVis::~NetVis()
83 {
84         delete history;
85         delete resolver;
86
87         delete font;
88         delete wnd;
89
90         pcap_close(pcap);
91         for(map<unsigned, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
92                 delete i->second;
93         for(map<unsigned, Host *>::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end(); ++i)
94                 delete i->second;
95         for(map<unsigned, Port *>::iterator i=ports.begin(); i!=ports.end(); ++i)
96                 delete i->second;
97         for(list<Packet *>::iterator i=packets.begin(); i!=packets.end(); ++i)
98                 delete *i;
99 }
100
101 void NetVis::tick()
102 {
103         Msp::Time::TimeStamp t = Msp::Time::now();
104         Msp::Time::TimeDelta dt;
105         if(tick_t)
106                 dt = t-tick_t;
107         tick_t = t;
108
109         if(tick_t>fps_t+Msp::Time::sec)
110         {
111                 fps = frames/((tick_t-fps_t)/Msp::Time::sec);
112                 fps_t = tick_t;
113                 frames = 0;
114         }
115
116         wnd->get_display().tick();
117
118         while(pcap_dispatch(pcap, -1, &capture_handler, reinterpret_cast<unsigned char *>(this))>0) ;
119
120         resolver->tick();
121         history->tick(tick_t);
122
123
124         float min_activity = numeric_limits<float>::max();
125         for(map<unsigned, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
126         {
127                 i->second->tick(dt);
128                 min_activity = min(min_activity, i->second->get_activity());
129         }
130         float del_limit = pow(10, 6-0.1*static_cast<int>(max_hosts-hosts.size()-disabled_hosts.size()));
131         for(map<unsigned, Host *>::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end();)
132         {
133                 i->second->tick(dt);
134
135                 if(i->second->get_activity()>min_activity)
136                 {
137                         i->second->set_active(true);
138                         hosts.insert(*i);
139                         for(unsigned j=0; j<100; ++j)
140                                 i->second->tick(100*Time::msec);
141                         disabled_hosts.erase(i++);
142                 }
143                 else if(i->second->get_activity()<del_limit)
144                 {
145                         resolver->cancel(i->second);
146                         delete i->second;
147                         disabled_hosts.erase(i++);
148                 }
149                 else
150                         ++i;
151         }
152
153         if(hosts.size()>max_visible_hosts)
154         {
155                 list<float> activity;
156                 for(map<unsigned, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
157                         activity.push_back(i->second->get_activity());
158                 activity.sort();
159
160                 list<float>::iterator j = activity.begin();
161                 advance(j, activity.size()-max_visible_hosts);
162                 float limit = *j;
163
164                 for(map<unsigned, Host *>::iterator i=hosts.begin(); i!=hosts.end();)
165                 {
166                         if(i->second->get_activity()<limit)
167                         {
168                                 i->second->set_active(false);
169                                 disabled_hosts.insert(*i);
170                                 hosts.erase(i++);
171                         }
172                         else
173                                 ++i;
174                 }
175         }
176
177         for(map<unsigned, Port *>::iterator i=ports.begin(); i!=ports.end();)
178         {
179                 i->second->tick(dt);
180
181                 if(!i->second->is_registered() && i->second->get_activity()<0.1)
182                 {
183                         delete i->second;
184                         ports.erase(i++);
185                 }
186                 else
187                         ++i;
188         }
189
190         for(list<Packet *>::iterator i=packets.begin(); i!=packets.end();)
191         {
192                 (*i)->tick(dt);
193                 if((*i)->get_stale())
194                 {
195                         delete *i;
196                         i = packets.erase(i);
197                 }
198                 else
199                         ++i;
200         }
201
202         render();
203         wnd->swap_buffers();
204
205         ++frames;
206 }
207
208 void NetVis::render()
209 {
210         GL::clear(GL::COLOR_BUFFER_BIT);
211
212         GL::matrix_mode(GL::PROJECTION);
213         GL::load_identity();
214         GL::ortho_centered(1024, 768);
215         GL::matrix_mode(GL::MODELVIEW);
216         GL::load_identity();
217
218         for(map<unsigned, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
219                 i->second->render();
220         {
221                 GL::Immediate imm((GL::COLOR4_UBYTE, GL::VERTEX2));
222                 imm.begin(GL::QUADS);
223                 for(list<Packet *>::iterator i=packets.begin(); i!=packets.end(); ++i)
224                         (*i)->render(imm);
225                 imm.end();
226         }
227
228         GL::push_matrix();
229         GL::translate(-500, 360, 0);
230         unsigned n = 0;
231         for(map<unsigned, Port *>::iterator i=ports.begin(); (i!=ports.end() && n<50); ++i)
232         {
233                 float act = i->second->get_activity();
234                 if((i->second->is_registered() && act>1) || act>200)
235                 {
236                         i->second->render();
237                         GL::translate(0, -12, 0);
238                         ++n;
239                 }
240         }
241         GL::pop_matrix();
242
243         GL::push_matrix();
244         GL::translate(-500, -348, 0);
245         GL::scale_uniform(10);
246         font->draw_string(format("%d hosts", hosts.size()+disabled_hosts.size()));
247         GL::translate(0, -1.2, 0);
248         font->draw_string(format("%d ports", ports.size()));
249         GL::translate(0, -1.2, 0);
250         font->draw_string(format("%.2f fps", fps));
251         GL::Texture::unbind();
252         GL::pop_matrix();
253
254         GL::push_matrix();
255         GL::translate(170, -370, 0);
256         history->render();
257         GL::pop_matrix();
258 }
259
260 Host &NetVis::get_host(unsigned a)
261 {
262         map<unsigned, Host *>::iterator i = hosts.find(a);
263         if(i!=hosts.end())
264                 return *i->second;
265
266         i = disabled_hosts.find(a);
267         if(i!=disabled_hosts.end())
268                 return *i->second;
269
270         Host *host = new Host(*this, a);
271         if((a&localnet_mask)==localnet)
272                 host->set_local(true);
273         resolver->push(host);
274         host->set_position(Vector2(rand()*400.0/RAND_MAX-200.0, rand()*400.0/RAND_MAX-200.0));
275         for(unsigned j=0; j<100; ++j)
276                 host->tick(100*Time::msec);
277         hosts[a] = host;
278         return *host;
279 }
280
281 Port &NetVis::get_port(unsigned number)
282 {
283         map<unsigned, Port *>::iterator i = ports.find(number);
284         if(i!=ports.end())
285                 return *i->second;
286         Port *port = new Port(*this, number);
287         ports[number] = port;
288         return *port;
289 }
290
291 void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *, const unsigned char *data)
292 {
293         NetVis *self = reinterpret_cast<NetVis *>(user);
294
295         const ethhdr *eth = reinterpret_cast<const ethhdr *>(data);
296         if(ntohs(eth->h_proto)==ETH_P_IP)
297         {
298                 const iphdr *ip = reinterpret_cast<const iphdr *>(eth+1);
299
300                 unsigned size = ntohs(ip->tot_len);
301
302                 Port *sport = 0;
303                 Port *dport = 0;
304                 if(ip->protocol==IPPROTO_TCP)
305                 {
306                         const tcphdr *tcp = reinterpret_cast<const tcphdr *>(ip+1);
307                         sport = &self->get_port(ntohs(tcp->source));
308                         dport = &self->get_port(ntohs(tcp->dest));
309                 }
310                 else if(ip->protocol==IPPROTO_UDP)
311                 {
312                         const udphdr *udp = reinterpret_cast<const udphdr *>(ip+1);
313                         sport = &self->get_port(ntohs(udp->source));
314                         dport = &self->get_port(ntohs(udp->dest));
315                 }
316
317                 Port *port = 0;
318                 if(sport && dport)
319                 {
320                         if(sport->is_registered()!=dport->is_registered())
321                         {
322                                 if(sport->is_registered())
323                                         port = sport;
324                                 else
325                                         port = dport;
326                         }
327                         else if(sport->get_number()<dport->get_number())
328                                 port = sport;
329                         else
330                                 port = dport;
331                 }
332                 else
333                         port = &self->get_port(0);
334
335                 Host &shost = self->get_host(ntohl(ip->saddr));
336                 Host *dhost = 0;
337                 if((ntohl(ip->daddr)&0xFF)!=0xFF)
338                         dhost = &self->get_host(ntohl(ip->daddr));
339
340                 float throttle = shost.send_packet();
341                 if(throttle<1)
342                 {
343                         self->packets.push_back(new Packet(shost, dhost, port->get_color(), size));
344                         self->packets.back()->tick(-throttle*Msp::Time::sec);
345                 }
346
347                 shost.add_activity(size);
348                 if(dhost)
349                         dhost->add_activity(size);
350
351                 if(sport)
352                         sport->add_activity(size);
353                 if(dport)
354                         dport->add_activity(size);
355
356                 if((ntohl(ip->saddr)&self->localnet_mask)==self->localnet)
357                         self->history->activity(0, size);
358                 else if((ntohl(ip->daddr)&self->localnet_mask)==self->localnet)
359                         self->history->activity(size, 0);
360         }
361 }
362
363 void NetVis::sighandler(int)
364 {
365         exit(0);
366 }
367
368 Application::RegApp<NetVis> NetVis::reg;