]> mj.ucw.cz Git - netgrind.git/blob - netgrind/save.c
TODO: A note on IPv6
[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   asave_event(s, when, "Terminated: %s\n", flow_cause_names[cause]);
134   asave_event(s, when, "TX %Ld bytes in %Ld packets, RX %Ld bytes in %Ld packets\n",
135               f->pipe[1].stat.bytes, f->pipe[1].stat.packets,
136               f->pipe[0].stat.bytes, f->pipe[0].stat.packets);
137   asave_event(s, when, "Transferred %Ld bytes, TCP overhead %Ld bytes\n",
138               f->pipe[0].stat.bytes + f->pipe[1].stat.bytes,
139               f->stat_raw.bytes - (f->pipe[0].stat.bytes + f->pipe[1].stat.bytes));
140   fclose(s->file);
141   xfree(s);
142 }
143
144 static void asave_input(struct flow *f, int dir, struct pkt *p)
145 {
146   struct asave_state *s = f->appl_data;
147
148   if (!pkt_len(p))
149     {
150       asave_event(s, p->timestamp, "%s FIN\n", (dir ? ">>" : "<<"));
151       return;
152     }
153
154   asave_event(s, p->timestamp, (dir ? ">>> " : "<<< "));
155   uns len = pkt_len(p);
156   uns cnt = 0;
157   for (uns i=0; i<len; i++)
158     {
159       uns c = p->data[i];
160       if (c == '\n')
161         cnt = ~0U;
162       else if (c >= 0x20 && c < 0x7f || c >= 0xa0)
163         {
164           fputc(c, s->file);
165           cnt++;
166         }
167       else
168         {
169           fprintf(s->file, "<%02x>", c);
170           cnt += 4;
171         }
172       if (cnt >= asave_width+10 || (cnt == asave_width && i < len-1 && p->data[i+1] != '\n'))
173         {
174           if (c != '\n')
175             fputc('\\', s->file);
176           fputc('\n', s->file);
177           if (i < len-1)
178             asave_event(s, p->timestamp, (dir ? ">>> " : "<<< "));
179           cnt = 0;
180         }
181     }
182   if (cnt)
183     {
184       fputc('\\', s->file);
185       fputc('\n', s->file);
186     }
187   pkt_free(p);
188 }
189
190 struct appl_hooks appl_asave = {
191   .open = asave_open,
192   .input = asave_input,
193   .close = asave_close
194 };
195
196 struct summary_state {
197   u64 estab_time;
198 };
199
200 static void summary_open(struct flow *f, u64 when)
201 {
202   struct summary_state *s = xmalloc(sizeof(*s));
203   f->appl_data = s;
204   s->estab_time = when;
205 }
206
207 static void summary_close(struct flow *f, int cause, u64 when)
208 {
209   static int summary_cnt;
210   if (!summary_cnt++)
211     printf("# timestamp             source                destination              elapsed close   tx      rx  oh    KB/s\n");
212          /* 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 */
213
214   struct summary_state *s = f->appl_data;
215   u64 duration = when - s->estab_time;
216   byte src[22], dst[22];
217   byte stamp[TIMESTAMP_LEN];
218   format_timestamp(stamp, s->estab_time);
219   sprintf(src, "%d.%d.%d.%d:%d", IPQUAD(f->saddr), ntohs(f->sport));
220   sprintf(dst, "%d.%d.%d.%d:%d", IPQUAD(f->daddr), ntohs(f->dport));
221   double braw = f->stat_raw.bytes;
222   double beff = f->pipe[0].stat.bytes + f->pipe[1].stat.bytes;
223   double over = 100 * ((braw - beff) / braw);
224   double avs = duration ? ((beff / ((double)duration/1000000)) / 1024) : 1e30;
225   printf("%s %-21s %-21s %6d.%03d %s %7Ld %7Ld %3d%% ",
226          stamp, src, dst,
227          (uns)(duration/1000000), (uns)(duration%1000000)/1000, flow_cause_names_short[cause],
228          f->pipe[1].stat.bytes, f->pipe[0].stat.bytes,
229          CLAMP((int)over,0,100));
230   printf((avs < 100) ? "%6.3f" : "%6.0f", MIN(avs, 999999));
231   putchar('\n');
232   xfree(s);
233 }
234
235 struct appl_hooks appl_summary = {
236   .open = summary_open,
237   .input = sink_input,
238   .close = summary_close
239 };