Add a inflateEnd() call to free up the stream in the re-init block.
[obnox/wireshark/wip.git] / epan / wslua / wslua_dumper.c
1 /*
2  *  wslua_dumper.c
3  *
4  * Wireshark's interface to the Lua Programming Language
5  *
6  * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 /* WSLUA_MODULE Dumper saving capture files */
30
31 #include "wslua.h"
32 #include <math.h>
33
34 WSLUA_CLASS_DEFINE(PseudoHeader,NOP,NOP);
35 /*
36  A pseudoheader to be used to save captured frames.
37  */ 
38
39 enum lua_pseudoheader_type {
40     PHDR_NONE,
41     PHDR_ETH,
42     PHDR_X25,
43     PHDR_ISDN,
44     PHDR_ATM,
45     PHDR_ASCEND,
46     PHDR_P2P,
47     PHDR_WIFI,
48     PHDR_COSINE,
49     PHDR_IRDA,
50     PHDR_NETTL,
51     PHDR_MTP2,
52     PHDR_K12
53 };
54
55 struct lua_pseudo_header {
56     enum lua_pseudoheader_type type;
57     union wtap_pseudo_header* wph;   
58 };
59
60 WSLUA_CONSTRUCTOR PseudoHeader_none(lua_State* L) {
61         /*
62          Creates a "no" pseudoheader.
63         
64         */
65     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
66     ph->type = PHDR_NONE;
67     ph->wph = NULL;
68     
69     pushPseudoHeader(L,ph);
70         
71     WSLUA_RETURN(1);
72         /* A null pseudoheader */
73 }
74
75 WSLUA_CONSTRUCTOR PseudoHeader_eth(lua_State* L) {
76         /*
77          Creates an ethernet pseudoheader
78          */
79
80 #define WSLUA_OPTARG_PseudoHeader_eth_FCSLEN 1 /* the fcs length */
81         
82     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
83     ph->type = PHDR_ETH;
84     ph->wph = g_malloc(sizeof(union wtap_pseudo_header));
85     ph->wph->eth.fcs_len = luaL_optint(L,1,-1);
86     
87     pushPseudoHeader(L,ph);
88         
89         WSLUA_RETURN(1); /* The ethernet pseudoheader */
90 }
91
92 WSLUA_CONSTRUCTOR PseudoHeader_atm(lua_State* L) {
93         /*
94          Creates an ATM pseudoheader
95          */
96 #define WSLUA_OPTARG_PseudoHeader_atm_AAL 1 /* AAL number */
97 #define WSLUA_OPTARG_PseudoHeader_atm_VPI 2 /* VPI */
98 #define WSLUA_OPTARG_PseudoHeader_atm_VCI 3 /* VCI */
99 #define WSLUA_OPTARG_PseudoHeader_atm_CHANNEL 4 /* Channel */
100 #define WSLUA_OPTARG_PseudoHeader_atm_CELLS 5 /* Number of cells in the PDU */
101 #define WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U 6 /* AAL5 User to User indicator */
102 #define WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN 7 /* AAL5 Len */
103
104     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
105     ph->type = PHDR_ATM;
106     ph->wph = g_malloc(sizeof(union wtap_pseudo_header));
107     ph->wph->atm.aal = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL,5);
108     ph->wph->atm.vpi = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_VPI,1);
109     ph->wph->atm.vci = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_VCI,1);
110     ph->wph->atm.channel = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_CHANNEL,0);
111     ph->wph->atm.cells = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_CELLS,1);
112     ph->wph->atm.aal5t_u2u = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U,1);
113     ph->wph->atm.aal5t_len = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN,0);
114     
115     pushPseudoHeader(L,ph);
116         WSLUA_RETURN(1);
117         /* The ATM pseudoheader */
118 }
119
120 WSLUA_CONSTRUCTOR PseudoHeader_mtp2(lua_State* L) {
121         /* Creates an MTP2 PseudoHeader */
122 #define WSLUA_OPTARG_PseudoHeader_mtp2_SENT 1 /* True if the packet is sent, False if received. */
123 #define WSLUA_OPTARG_PseudoHeader_mtp2_ANNEXA 2 /* True if annex A is used  */
124 #define WSLUA_OPTARG_PseudoHeader_mtp2_LINKNUM 3 /* Link Number */
125     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
126     ph->type = PHDR_MTP2;
127     ph->wph = g_malloc(sizeof(union wtap_pseudo_header));
128     ph->wph->mtp2.sent = luaL_optint(L,1,0);
129     ph->wph->mtp2.annex_a_used = luaL_optint(L,2,0);
130     ph->wph->mtp2.link_number = luaL_optint(L,3,0);
131
132     pushPseudoHeader(L,ph);
133         WSLUA_RETURN(1); /* The MTP2 pseudoheader */
134 }
135
136 #if 0
137 static int PseudoHeader_x25(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
138 static int PseudoHeader_isdn(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
139 static int PseudoHeader_ascend(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
140 static int PseudoHeader_wifi(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
141 static int PseudoHeader_cosine(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
142 static int PseudoHeader_irda(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
143 static int PseudoHeader_nettl(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
144 static int PseudoHeader_k12(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
145 #endif
146
147 WSLUA_METHODS PseudoHeader_methods[] = {
148         WSLUA_CLASS_FNREG(PseudoHeader,mtp2),
149         WSLUA_CLASS_FNREG(PseudoHeader,atm),
150         WSLUA_CLASS_FNREG(PseudoHeader,eth),
151         WSLUA_CLASS_FNREG(PseudoHeader,none),
152         {0,0}
153 };
154
155 WSLUA_META PseudoHeader_meta[] = {
156         {0,0}
157 };
158
159 int PseudoHeader_register(lua_State* L) {
160         WSLUA_REGISTER_CLASS(PseudoHeader)
161     return 0;
162 }
163
164
165 WSLUA_CLASS_DEFINE(Dumper,FAIL_ON_NULL("Dumper already closed"),NOP);
166
167 static GHashTable* dumper_encaps = NULL;
168 #define DUMPER_ENCAP(d) GPOINTER_TO_INT(g_hash_table_lookup(dumper_encaps,d))
169
170 static const char* cross_plat_fname(const char* fname) {
171         static char fname_clean[256];
172         char* f;
173
174         strncpy(fname_clean,fname,256);
175
176         for(f = fname_clean; *f; f++) {
177                 switch(*f) {
178                         case '/': case '\\':
179                                 *f = *(G_DIR_SEPARATOR_S);
180                                 break;
181                         default:
182                                 break;
183                 }
184         }
185         
186         return fname_clean;
187 }
188
189 WSLUA_CONSTRUCTOR Dumper_new(lua_State* L) {
190         /*
191          Creates a file to write packets.
192          Dumper:new_for_current() will probably be a better choice. 
193         */
194 #define WSLUA_ARG_Dumper_new_FILENAME 1 /* The name of the capture file to be created */
195 #define WSLUA_OPTARG_Dumper_new_FILETYPE 2 /* The type of the file to be created */
196 #define WSLUA_OPTARG_Dumper_new_ENCAP 3 /* The encapsulation to be used in the file to be created */
197     Dumper d;
198     const char* fname = luaL_checkstring(L,1);
199     int filetype = luaL_optint(L,2,WTAP_FILE_PCAP);
200     int encap  = luaL_optint(L,3,WTAP_ENCAP_ETHERNET);
201     int err = 0;
202     const char* filename;
203         
204     if (! fname) return 0;
205     
206         filename = cross_plat_fname(fname);
207                 
208     if (!wtap_dump_can_write_encap(filetype, encap))
209         WSLUA_ERROR(Dumper_new,"not every filetype handles every encap");
210     
211     d = wtap_dump_open(filename, filetype, encap,0 , FALSE, &err);
212     
213     if (! d ) {
214                 /* WSLUA_ERROR("error while opening file for writing"); */
215         luaL_error(L,"error while opening `%s': %s",
216                    filename,
217                    wtap_strerror(err));
218         return 0;
219     }
220     
221     g_hash_table_insert(dumper_encaps,d,GINT_TO_POINTER(encap));
222     
223     pushDumper(L,d);
224     WSLUA_RETURN(1);
225         /* The newly created Dumper object */
226 }
227
228 WSLUA_METHOD Dumper_close(lua_State* L) {
229         /* Closes a dumper */
230         Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper");
231     int err;
232     
233     if (! *dp)
234                 WSLUA_ERROR(Dumper_close,"Cannot operate on a closed dumper");
235
236     g_hash_table_remove(dumper_encaps,*dp);
237
238     if (!wtap_dump_close(*dp, &err)) {
239         luaL_error(L,"error closing: %s",
240                    wtap_strerror(err));
241     }
242
243         /* this way if we close a dumper any attempt to use it (for everything but GC) will yield an error */
244         dp = NULL;
245
246     return 0;
247 }
248
249 WSLUA_METHOD Dumper_flush(lua_State* L) {
250         /*
251          Writes all unsaved data of a dumper to the disk.
252          */
253     Dumper d = checkDumper(L,1);
254
255     if (!d) return 0;
256     
257     wtap_dump_flush(d);
258     
259     return 0;
260 }
261
262 WSLUA_METHOD Dumper_dump(lua_State* L) {
263         /*
264          Dumps an arbitrary packet.
265          Note: Dumper:dump_current() will fit best in most cases.
266          */
267 #define WSLUA_ARG_Dumper_dump_TIMESTAMP 2 /* The absolute timestamp the packet will have */
268 #define WSLUA_ARG_Dumper_dump_PSEUDOHEADER 3 /* The Pseudoheader to use. */
269 #define WSLUA_ARG_Dumper_dump_BYTEARRAY 4 /* the data to be saved */
270
271         Dumper d = checkDumper(L,1);
272     PseudoHeader ph;
273     ByteArray ba;
274     struct wtap_pkthdr pkthdr;
275     double ts;
276     int err;
277     
278     if (!d) return 0;
279     
280     ts = luaL_checknumber(L,WSLUA_ARG_Dumper_dump_TIMESTAMP);
281     ph = checkPseudoHeader(L,WSLUA_ARG_Dumper_dump_PSEUDOHEADER);
282     
283     if (!ph) WSLUA_ARG_ERROR(Dumper_dump,TIMESTAMP,"need a PseudoHeader");
284     
285     ba = checkByteArray(L,WSLUA_ARG_Dumper_dump_BYTEARRAY);
286     
287         if (! ba) WSLUA_ARG_ERROR(Dumper_dump,BYTEARRAY,"must be a ByteArray");
288     
289         pkthdr.ts.secs = (unsigned)floor(ts);
290         pkthdr.ts.nsecs = (unsigned)floor((ts - (double)pkthdr.ts.secs) * 1000000000);
291
292     pkthdr.len  = ba->len;
293     pkthdr.caplen  = ba->len;    
294     pkthdr.pkt_encap = DUMPER_ENCAP(d);
295     
296     if (! wtap_dump(d, &pkthdr, ph->wph, ba->data, &err)) {
297         luaL_error(L,"error while dumping: %s",
298                    wtap_strerror(err));        
299     }
300     
301     return 0;
302     
303 }
304
305 WSLUA_METHOD Dumper_new_for_current(lua_State* L) {
306         /*
307          Creates a capture file using the same encapsulation as the one of the cuurrent packet
308          */
309 #define WSLUA_OPTARG_Dumper_new_for_current_FILETYPE 2 /* The file type. Defaults to pcap. */
310         Dumper d;
311     const char* fname = luaL_checkstring(L,1);
312     int filetype = luaL_optint(L,2,WTAP_FILE_PCAP);
313     int encap;
314     int err = 0;
315         const char* filename;
316         
317     if (! fname) return 0;
318     
319         filename = cross_plat_fname(fname);
320         
321     if (! lua_pinfo )
322                 WSLUA_ERROR(Dumper_new_for_current,"cannot be used outside a tap or a dissector");
323     
324     encap = lua_pinfo->fd->lnk_t;
325     
326     if (!wtap_dump_can_write_encap(filetype, encap)) {
327         luaL_error(L,"Cannot write encap %s in filetype %s",
328                    wtap_encap_short_string(encap),
329                    wtap_file_type_string(filetype));
330         return 0;
331     }
332     
333     d = wtap_dump_open(filename, filetype, encap, 0 , FALSE, &err);
334
335     if (! d ) {
336         luaL_error(L,"error while opening `%s': %s",
337                    filename,
338                    wtap_strerror(err));
339         return 0;
340     }
341     
342     pushDumper(L,d);
343     WSLUA_RETURN(1); /* The newly created Dumper Object */
344     
345 }
346
347 WSLUA_METHOD Dumper_dump_current(lua_State* L) {
348         /*
349          Dumps the current packet as it is.
350          */
351     Dumper d = checkDumper(L,1);
352     struct wtap_pkthdr pkthdr;
353     const guchar* data;
354     tvbuff_t* data_src;
355     int err = 0;
356     
357     if (!d) return 0;
358     
359         if (! lua_pinfo ) WSLUA_ERROR(Dumper_new_for_current,"cannot be used outside a tap or a dissector");
360
361     data_src = ((data_source*)(lua_pinfo->data_src->data))->tvb;
362
363     pkthdr.ts.secs = lua_pinfo->fd->abs_ts.secs;
364     pkthdr.ts.nsecs = lua_pinfo->fd->abs_ts.nsecs;
365     pkthdr.len  = tvb_reported_length(data_src);
366     pkthdr.caplen  = tvb_length(data_src);    
367     pkthdr.pkt_encap = lua_pinfo->fd->lnk_t;
368
369     data = ep_tvb_memdup(data_src,0,pkthdr.caplen);
370     
371     if (! wtap_dump(d, &pkthdr, lua_pinfo->pseudo_header, data, &err)) {
372         luaL_error(L,"error while dumping: %s",
373                    wtap_strerror(err));        
374     }
375
376     return 0;
377 }
378
379 static int Dumper__gc(lua_State* L) {
380         Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper");
381         int err;
382
383         /* If we are Garbage Collected it means the Dumper is no longer usable. Close it */ 
384         
385         if (! *dp)
386                 return 0; /* already closed, nothing to do! */
387
388         g_hash_table_remove(dumper_encaps,*dp);
389
390         if (!wtap_dump_close(*dp, &err)) {
391                 luaL_error(L,"error closing: %s",
392                                    wtap_strerror(err));
393         }
394
395         return 0;
396 }
397
398
399 WSLUA_METHODS Dumper_methods[] = {
400     {"new",       Dumper_new},
401     {"new_for_current",       Dumper_new_for_current},
402     {"close",       Dumper_close},
403     {"flush",       Dumper_flush},
404     {"dump",       Dumper_dump},
405     {"dump_current",       Dumper_dump_current},
406     {0, 0}
407 };
408
409 WSLUA_META Dumper_meta[] = {
410         {"__gc", Dumper__gc},
411     {0, 0}
412 };
413
414 int Dumper_register(lua_State* L) {
415     dumper_encaps = g_hash_table_new(g_direct_hash,g_direct_equal);
416     WSLUA_REGISTER_CLASS(Dumper);
417     return 1;
418 }
419