- remove some warnings from the windows compile
[obnox/wireshark/wip.git] / plugins / lua / elua_dumper.c
1 /*
2  *  lua_dumper.c
3  *
4  * Ethereal's interface to the Lua Programming Language
5  *
6  * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
7  *
8  * $Id$
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
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 #include "elua.h"
30 #include <math.h>
31
32 ELUA_CLASS_DEFINE(PseudoHeader,NOP)
33 /*
34  A pseudoheader to be used to save captured frames.
35  */ 
36
37 enum lua_pseudoheader_type {
38     PHDR_NONE,
39     PHDR_ETH,
40     PHDR_X25,
41     PHDR_ISDN,
42     PHDR_ATM,
43     PHDR_ASCEND,
44     PHDR_P2P,
45     PHDR_WIFI,
46     PHDR_COSINE,
47     PHDR_IRDA,
48     PHDR_NETTL,
49     PHDR_MTP2,
50     PHDR_K12
51 };
52
53 struct lua_pseudo_header {
54     enum lua_pseudoheader_type type;
55     union wtap_pseudo_header* wph;   
56 };
57
58 ELUA_CONSTRUCTOR PseudoHeader_none(lua_State* L) {
59         /*
60          Creates a "no" pseudoheader.
61         
62         */
63     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
64     ph->type = PHDR_NONE;
65     ph->wph = NULL;
66     
67     pushPseudoHeader(L,ph);
68         
69     ELUA_RETURN(1);
70         /* A null pseudoheader */
71 }
72
73 ELUA_CONSTRUCTOR PseudoHeader_eth(lua_State* L) {
74         /*
75          Creates an ethernet pseudoheader
76          */
77
78 #define ELUA_OPTARG_PseudoHeader_eth_FCSLEN 1 /* the fcs lenght */
79         
80     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
81     ph->type = PHDR_ETH;
82     ph->wph = g_malloc(sizeof(union wtap_pseudo_header));
83     ph->wph->eth.fcs_len = luaL_optint(L,1,-1);
84     
85     pushPseudoHeader(L,ph);
86         
87         ELUA_RETURN(1); /* The ethernet pseudoheader */
88 }
89
90 ELUA_CONSTRUCTOR PseudoHeader_atm(lua_State* L) {
91         /*
92          Creates an ATM pseudoheader
93          */
94 #define ELUA_OPTARG_PseudoHeader_atm_AAL 1 /* AAL number */
95 #define ELUA_OPTARG_PseudoHeader_atm_VPI 2 /* VPI */
96 #define ELUA_OPTARG_PseudoHeader_atm_VCI 3 /* VCI */
97 #define ELUA_OPTARG_PseudoHeader_atm_CHANNEL 4 /* Channel */
98 #define ELUA_OPTARG_PseudoHeader_atm_CELLS 5 /* Number of cells in the PDU */
99 #define ELUA_OPTARG_PseudoHeader_atm_AAL5U2U 6 /* AAL5 User to User indicator */
100 #define ELUA_OPTARG_PseudoHeader_atm_AAL5LEN 7 /* AAL5 Len */
101
102     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
103     ph->type = PHDR_ATM;
104     ph->wph = g_malloc(sizeof(union wtap_pseudo_header));
105     ph->wph->atm.aal = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_AAL,5);
106     ph->wph->atm.vpi = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_VPI,1);
107     ph->wph->atm.vci = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_VCI,1);
108     ph->wph->atm.channel = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_CHANNEL,0);
109     ph->wph->atm.cells = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_CELLS,1);
110     ph->wph->atm.aal5t_u2u = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_AAL5U2U,1);
111     ph->wph->atm.aal5t_len = luaL_optint(L,ELUA_OPTARG_PseudoHeader_atm_AAL5LEN,0);
112     
113     pushPseudoHeader(L,ph);
114         ELUA_RETURN(1);
115         /* The ATM pseudoheader */
116 }
117
118 ELUA_CONSTRUCTOR PseudoHeader_mtp2(lua_State* L) {
119         /* Creates an MTP2 PseudoHeader */
120 #define ELUA_OPTARG_PseudoHeader_mtp2_SENT /* True if the packet is sent, False if received. */
121 #define ELUA_OPTARG_PseudoHeader_mtp2_ANNEXA /* True if annex A is used  */
122 #define ELUA_OPTARG_PseudoHeader_mtp2_LINKNUM /* Link Number */
123     PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header));
124     ph->type = PHDR_MTP2;
125     ph->wph = g_malloc(sizeof(union wtap_pseudo_header));
126     ph->wph->mtp2.sent = luaL_optint(L,1,0);
127     ph->wph->mtp2.annex_a_used = luaL_optint(L,2,0);
128     ph->wph->mtp2.link_number = luaL_optint(L,3,0);
129
130     pushPseudoHeader(L,ph);
131         ELUA_RETURN(1); /* The MTP2 pseudoheader */
132 }
133
134 #if 0
135 static int PseudoHeader_x25(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
136 static int PseudoHeader_isdn(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
137 static int PseudoHeader_ascend(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
138 static int PseudoHeader_wifi(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
139 static int PseudoHeader_cosine(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
140 static int PseudoHeader_irda(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
141 static int PseudoHeader_nettl(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
142 static int PseudoHeader_k12(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
143 #endif
144
145 ELUA_METHODS PseudoHeader_methods[] = {
146         ELUA_CLASS_FNREG(PseudoHeader,mtp2),
147         ELUA_CLASS_FNREG(PseudoHeader,atm),
148         ELUA_CLASS_FNREG(PseudoHeader,eth),
149         ELUA_CLASS_FNREG(PseudoHeader,none),
150         {0,0}
151 };
152
153 ELUA_META PseudoHeader_meta[] = {
154         {0,0}
155 };
156
157 int PseudoHeader_register(lua_State* L) {
158         ELUA_REGISTER_CLASS(PseudoHeader)
159     return 0;
160 }
161
162
163 ELUA_CLASS_DEFINE(Dumper,FAIL_ON_NULL("Dumper already closed"))
164
165 static GHashTable* dumper_encaps = NULL;
166 #define DUMPER_ENCAP(d) GPOINTER_TO_INT(g_hash_table_lookup(dumper_encaps,d))
167
168 ELUA_CONSTRUCTOR Dumper_new(lua_State* L) {
169         /*
170          Creates a file to write packets.
171          Dumper:new_for_current() will probably be a better choice. 
172         */
173 #define ELUA_ARG_Dumper_new_FILENAME 1 /* The name of the capture file to be created */
174 #define ELUA_OPTARG_Dumper_new_FILETYPE 3 /* The type of the file to be created */
175 #define ELUA_OPTARG_Dumper_new_ENCAP 3 /* The encapsulation to be used in the file to be created */
176     Dumper d;
177     const char* filename = luaL_checkstring(L,1);
178     int filetype = luaL_optint(L,2,WTAP_FILE_PCAP);
179     int encap  = luaL_optint(L,3,WTAP_ENCAP_ETHERNET);
180     int err = 0;
181     
182     if (! filename) return 0;
183     
184     if (!wtap_dump_can_write_encap(filetype, encap))
185         ELUA_ERROR(Dumper_new,"not every filetype handles every encap");
186     
187     d = wtap_dump_open(filename, filetype, encap,0 , FALSE, &err);
188     
189     if (! d ) {
190                 /* ELUA_ERROR("error while opening file for writing"); */
191         luaL_error(L,"error while opening `%s': %s",
192                    filename,
193                    wtap_strerror(err));
194         return 0;
195     }
196     
197     g_hash_table_insert(dumper_encaps,d,GINT_TO_POINTER(encap));
198     
199     pushDumper(L,d);
200     ELUA_RETURN(1);
201         /* The newly created Dumper object */
202 }
203
204 ELUA_METHOD Dumper_close(lua_State* L) {
205         /* Closes a dumper */
206         Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper");
207     int err;
208     
209     if (! *dp)
210                 ELUA_ERROR(Dumper_close,"Cannot operate on a closed dumper");
211
212     g_hash_table_remove(dumper_encaps,*dp);
213
214     if (!wtap_dump_close(*dp, &err)) {
215         luaL_error(L,"error closing: %s",
216                    wtap_strerror(err));
217     }
218
219         /* this way if we close a dumper any attempt to use it (for everything but GC) will yield an error */
220         dp = NULL;
221
222     return 0;
223 }
224
225 ELUA_METHOD Dumper_flush(lua_State* L) {
226         /*
227          Writes all unsaved data of a dumper to the disk.
228          */
229     Dumper d = checkDumper(L,1);
230
231     if (!d) return 0;
232     
233     wtap_dump_flush(d);
234     
235     return 0;
236 }
237
238 ELUA_METHOD Dumper_dump(lua_State* L) {
239         /*
240          Dumps an arbitrary packet.
241          Note: Dumper:dump_current() will fit best in most cases.
242          */
243 #define ELUA_ARG_Dumper_dump_TIMESTAMP 2 /* The absolute timestamp the packet will have */
244 #define ELUA_ARG_Dumper_dump_PSEUDOHEADER 3 /* The Pseudoheader to use. */
245 #define ELUA_ARG_Dumper_dump_BYTEARRAY 4 /* the data to be saved */
246
247         Dumper d = checkDumper(L,1);
248     PseudoHeader ph;
249     ByteArray ba;
250     struct wtap_pkthdr pkthdr;
251     double ts;
252     int err;
253     
254     if (!d) return 0;
255     
256     ts = luaL_checknumber(L,ELUA_ARG_Dumper_dump_TIMESTAMP);
257     ph = checkPseudoHeader(L,ELUA_ARG_Dumper_dump_PSEUDOHEADER);
258     
259     if (!ph) ELUA_ARG_ERROR(Dumper_dump,TIMESTAMP,"need a PseudoHeader");
260     
261     ba = checkByteArray(L,ELUA_ARG_Dumper_dump_BYTEARRAY);
262     
263         if (! ba) ELUA_ARG_ERROR(Dumper_dump,BYTEARRAY,"must be a ByteArray");
264     
265     pkthdr.ts.secs = (int)floor(ts);
266     pkthdr.ts.nsecs = (int)floor(ts - pkthdr.ts.secs) * 1000000000;
267     pkthdr.len  = ba->len;
268     pkthdr.caplen  = ba->len;    
269     pkthdr.pkt_encap = DUMPER_ENCAP(d);
270     
271     if (! wtap_dump(d, &pkthdr, ph->wph, ba->data, &err)) {
272         luaL_error(L,"error while dumping: %s",
273                    wtap_strerror(err));        
274     }
275     
276     return 0;
277     
278 }
279
280 ELUA_METHOD Dumper_new_for_current(lua_State* L) {
281         /*
282          Creates a capture file using the same encapsulation as the one of the cuurrent packet
283          */
284 #define ELUA_OPTARG_Dumper_new_for_current_FILETYPE 2 /* The file type. Defaults to pcap. */
285         Dumper d;
286     const char* filename = luaL_checkstring(L,1);
287     int filetype = luaL_optint(L,2,WTAP_FILE_PCAP);
288     int encap;
289     int err = 0;
290     
291     if (! lua_pinfo )
292                 ELUA_ERROR(Dumper_new_for_current,"cannot be used outside a tap or a dissector");
293     
294     encap = lua_pinfo->fd->lnk_t;
295     
296     if (!wtap_dump_can_write_encap(filetype, encap)) {
297         luaL_error(L,"Cannot write encap %s in filetype %s",
298                    wtap_encap_short_string(encap),
299                    wtap_file_type_string(filetype));
300         return 0;
301     }
302     
303     d = wtap_dump_open(filename, filetype, encap, 0 , FALSE, &err);
304
305     if (! d ) {
306         luaL_error(L,"error while opening `%s': %s",
307                    filename,
308                    wtap_strerror(err));
309         return 0;
310     }
311     
312     pushDumper(L,d);
313     ELUA_RETURN(1); /* The newly created Dumper Object */
314     
315 }
316
317 ELUA_METHOD Dumper_dump_current(lua_State* L) {
318         /*
319          Dumps the current packet as it is.
320          */
321     Dumper d = checkDumper(L,1);
322     struct wtap_pkthdr pkthdr;
323     const guchar* data;
324     tvbuff_t* data_src;
325     int err = 0;
326     
327     if (!d) return 0;
328     
329         if (! lua_pinfo ) ELUA_ERROR(Dumper_new_for_current,"cannot be used outside a tap or a dissector");
330
331     data_src = ((data_source*)(lua_pinfo->data_src->data))->tvb;
332
333     pkthdr.ts.secs = lua_pinfo->fd->abs_ts.secs;
334     pkthdr.ts.nsecs = lua_pinfo->fd->abs_ts.nsecs;
335     pkthdr.len  = tvb_reported_length(data_src);
336     pkthdr.caplen  = tvb_length(data_src);    
337     pkthdr.pkt_encap = lua_pinfo->fd->lnk_t;
338
339     data = ep_tvb_memdup(data_src,0,pkthdr.caplen);
340     
341     if (! wtap_dump(d, &pkthdr, lua_pinfo->pseudo_header, data, &err)) {
342         luaL_error(L,"error while dumping: %s",
343                    wtap_strerror(err));        
344     }
345
346     return 0;
347 }
348
349 static int Dumper__gc(lua_State* L) {
350         Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper");
351         int err;
352
353         /* If we are Garbage Collected it means the Dumper is no longer usable. Close it */ 
354         
355         if (! *dp)
356                 return 0; /* already closed, nothing to do! */
357
358         g_hash_table_remove(dumper_encaps,*dp);
359
360         if (!wtap_dump_close(*dp, &err)) {
361                 luaL_error(L,"error closing: %s",
362                                    wtap_strerror(err));
363         }
364
365         return 0;
366 }
367
368
369 ELUA_METHODS Dumper_methods[] = {
370     {"new",       Dumper_new},
371     {"new_for_current",       Dumper_new_for_current},
372     {"close",       Dumper_close},
373     {"flush",       Dumper_flush},
374     {"dump",       Dumper_dump},
375     {"dump_current",       Dumper_dump_current},
376     {0, 0}
377 };
378
379 ELUA_META Dumper_meta[] = {
380         {"__gc", Dumper__gc},
381     {0, 0}
382 };
383
384 int Dumper_register(lua_State* L) {
385     dumper_encaps = g_hash_table_new(g_direct_hash,g_direct_equal);
386     ELUA_REGISTER_CLASS(Dumper);
387     return 1;
388 }
389