]> mj.ucw.cz Git - netgrind.git/blob - netgrind/save.c
4a0be0da0df6022ef7bef02c8408ddf8d36e5943
[netgrind.git] / netgrind / save.c
1 /*
2  *      Netgrind -- Saving to Files
3  *
4  *      (c) 2003 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "netgrind/pkt.h"
12 #include "netgrind/netgrind.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <time.h>
18 #include <netinet/in.h>
19
20 byte *save_dir;
21
22 void format_timestamp(byte *buf, u64 time)
23 {
24   struct tm *tm;
25   time_t t = time / 1000000;
26   tm = localtime(&t);
27   ASSERT(tm);
28   int len = strftime(buf, TIMESTAMP_LEN, "%Y-%m-%d %H:%M:%S", tm);
29   ASSERT(len);
30   sprintf(buf+len, ".%03d", (uns)(time%1000000)/1000);
31 }
32
33 void sink_open(struct flow *f UNUSED, u64 when UNUSED)
34 {
35 }
36
37 void sink_close(struct flow *f UNUSED, int cause UNUSED, u64 when UNUSED)
38 {
39 }
40
41 void sink_input(struct flow *f UNUSED, int dir UNUSED, struct pkt *p)
42 {
43   pkt_free(p);
44 }
45
46 struct appl_hooks appl_sink = {
47   .open = sink_open,
48   .input = sink_input,
49   .close = sink_close
50 };
51
52 struct save_state {
53   FILE *file[2];
54 };
55
56 static void save_open(struct flow *f, u64 when UNUSED)
57 {
58   struct save_state *s = xmalloc(sizeof(*s));
59   static uns save_counter;
60   for (uns dir=0; dir<2; dir++)
61     {
62       byte name[256];
63       sprintf(name, "%s/%06u-%d.%d.%d.%d:%d-%d.%d.%d.%d:%d-%c", save_dir, save_counter,
64               IPQUAD(f->saddr), ntohs(f->sport), IPQUAD(f->daddr), ntohs(f->dport),
65               'A' + dir);
66       if (!(s->file[dir] = fopen(name, "w")))
67         die("Unable to create %s: %m", name);
68     }
69   f->appl_data = s;
70   save_counter++;
71 }
72
73 static void save_close(struct flow *f, int cause UNUSED, u64 when UNUSED)
74 {
75   struct save_state *s = f->appl_data;
76   fclose(s->file[0]);
77   fclose(s->file[1]);
78   xfree(s);
79 }
80
81 static void save_input(struct flow *f, int dir, struct pkt *p)
82 {
83   struct save_state *s = f->appl_data;
84   fwrite(p->data, pkt_len(p), 1, s->file[dir]);
85   pkt_free(p);
86 }
87
88 struct appl_hooks appl_save = {
89   .open = save_open,
90   .input = save_input,
91   .close = save_close
92 };
93
94 uns asave_width = 80;
95
96 struct asave_state {
97   FILE *file;
98   u64 start_time;
99 };
100
101 static void asave_event(struct asave_state *s, u64 time, byte *msg, ...)
102 {
103   va_list args;
104
105   va_start(args, msg);
106   time -= s->start_time;
107   fprintf(s->file, "%04d.%03d ", (int)(time/1000000), (int)(time%1000000)/1000);
108   vfprintf(s->file, msg, args);
109   va_end(args);
110 }
111
112 static void asave_open(struct flow *f, u64 when)
113 {
114   struct asave_state *s = xmalloc(sizeof(*s));
115   byte name[256], stamp[TIMESTAMP_LEN];
116   static uns asave_counter;
117   sprintf(name, "%s/%06u-%d.%d.%d.%d:%d-%d.%d.%d.%d:%d", save_dir, asave_counter++,
118           IPQUAD(f->saddr), ntohs(f->sport),
119           IPQUAD(f->daddr), ntohs(f->dport));
120   if (!(s->file = fopen(name, "w")))
121     die("Unable to create %s: %m", name);
122   f->appl_data = s;
123   s->start_time = when;
124   asave_event(s, when, "Connection: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n",
125               IPQUAD(f->saddr), ntohs(f->sport), IPQUAD(f->daddr), ntohs(f->dport));
126   format_timestamp(stamp, when);
127   asave_event(s, when, "Initiated on: %s\n", stamp);
128 }
129
130 static void asave_close(struct flow *f, int cause, u64 when)
131 {
132   struct asave_state *s = f->appl_data;
133   static byte *close_reasons[] = { "Close", "Connection reset", "Timeout", "Doomsday", "Corrupted" };
134   asave_event(s, when, "Terminated: %s\n", close_reasons[cause]);
135   asave_event(s, when, "TX %Ld bytes in %Ld packets, RX %Ld bytes in %Ld packets\n",
136               f->pipe[1].stat.bytes, f->pipe[1].stat.packets,
137               f->pipe[0].stat.bytes, f->pipe[0].stat.packets);
138   asave_event(s, when, "Transferred %Ld bytes, TCP overhead %Ld bytes\n",
139               f->pipe[0].stat.bytes + f->pipe[1].stat.bytes,
140               f->stat_raw.bytes - (f->pipe[0].stat.bytes + f->pipe[1].stat.bytes));
141   fclose(s->file);
142   xfree(s);
143 }
144
145 static void asave_input(struct flow *f, int dir, struct pkt *p)
146 {
147   struct asave_state *s = f->appl_data;
148   asave_event(s, p->timestamp, (dir ? ">>> " : "<<< "));
149   uns len = pkt_len(p);
150   uns cnt = 0;
151   for (uns i=0; i<len; i++)
152     {
153       uns c = p->data[i];
154       if (c == '\n')
155         cnt = ~0U;
156       else if (c >= 0x20 && c < 0x7f || c >= 0xa0)
157         {
158           fputc(c, s->file);
159           cnt++;
160         }
161       else
162         {
163           fprintf(s->file, "<%02x>", c);
164           cnt += 4;
165         }
166       if (cnt >= asave_width+10 || (cnt == asave_width && i < len-1 && p->data[i+1] != '\n'))
167         {
168           if (c != '\n')
169             fputc('\\', s->file);
170           fputc('\n', s->file);
171           if (i < len-1)
172             asave_event(s, p->timestamp, (dir ? ">>> " : "<<< "));
173           cnt = 0;
174         }
175     }
176   if (cnt)
177     {
178       fputc('\\', s->file);
179       fputc('\n', s->file);
180     }
181   pkt_free(p);
182 }
183
184 struct appl_hooks appl_asave = {
185   .open = asave_open,
186   .input = asave_input,
187   .close = asave_close
188 };
189
190 struct summary_state {
191   u64 estab_time;
192 };
193
194 static void summary_open(struct flow *f, u64 when)
195 {
196   struct summary_state *s = xmalloc(sizeof(*s));
197   f->appl_data = s;
198   s->estab_time = when;
199 }
200
201 static void summary_close(struct flow *f, int cause, u64 when)
202 {
203   static int summary_cnt;
204   if (!summary_cnt++)
205     printf("# timestamp             source                destination              elapsed close   tx      rx  oh    KB/s\n");
206          /* 2003-06-06 22:38:34.076 81.27.194.19:1165     195.113.31.123:22          1.604 OK    1991   12656  11%  8.914 */
207
208   struct summary_state *s = f->appl_data;
209   u64 duration = when - s->estab_time;
210   byte src[22], dst[22];
211   byte stamp[TIMESTAMP_LEN];
212   static byte *sum_causes[] = { "OK", "RE", "TO", "DD", "CO" };
213   format_timestamp(stamp, s->estab_time);
214   sprintf(src, "%d.%d.%d.%d:%d", IPQUAD(f->saddr), ntohs(f->sport));
215   sprintf(dst, "%d.%d.%d.%d:%d", IPQUAD(f->daddr), ntohs(f->dport));
216   double braw = f->stat_raw.bytes;
217   double beff = f->pipe[0].stat.bytes + f->pipe[1].stat.bytes;
218   double over = 100 * ((braw - beff) / braw);
219   double avs = duration ? ((beff / ((double)duration/1000000)) / 1024) : 1e30;
220   printf("%s %-21s %-21s %6d.%03d %s %7Ld %7Ld %3d%% ",
221          stamp, src, dst,
222          (uns)(duration/1000000), (uns)(duration%1000000)/1000, sum_causes[cause],
223          f->pipe[1].stat.bytes, f->pipe[0].stat.bytes,
224          CLAMP((int)over,0,100));
225   printf((avs < 100) ? "%6.3f" : "%6.0f", MIN(avs, 999999));
226   putchar('\n');
227   xfree(s);
228 }
229
230 struct appl_hooks appl_summary = {
231   .open = summary_open,
232   .input = sink_input,
233   .close = summary_close
234 };