file_read() can return -1; don't just blindly add it to a previous
[obnox/wireshark/wip.git] / wiretap / 5views.c
1 /* 5views.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <errno.h>
27 #include <string.h>
28 #include <time.h>
29
30 #include "wtap-int.h"
31 #include "file_wrappers.h"
32 #include "buffer.h"
33 #include "5views.h"
34
35
36 typedef struct
37 {
38         guint32 Signature;
39         guint32 Size;           /* Total size of Header in bytes (included Signature) */
40         guint32 Version;        /* Identify version and so the format of this record */
41         guint32 DataSize;       /* Total size of data included in the Info Record (except the header size) */
42         guint32 FileType;       /* Type of the file */
43         guint32 Reserved[3];    /* Reserved for future use */
44 }t_5VW_Info_Header;
45
46 typedef struct
47 {
48         guint32 Type;   /* Id of the attribute */
49         guint16 Size;   /* Size of the data part of the attribute (not including header size) */
50         guint16 Nb;     /* Number of elements */
51 }t_5VW_Attributes_Header;
52
53
54 #define CST_5VW_INFO_HEADER_KEY         0xAAAAAAAAU             /* signature */
55
56 #define CST_5VW_INFO_RECORD_VERSION     0x00010000U             /* version */
57
58 #define CST_5VW_DECALE_FILE_TYPE        24
59 #define CST_5VW_SECTION_CAPTURES        0x08U
60 #define CST_5VW_CAPTURES_FILE           (CST_5VW_SECTION_CAPTURES << CST_5VW_DECALE_FILE_TYPE)          /* 0x08000000 */
61 #define CST_5VW_FLAT_FILE               0x10000000U
62 #define CST_5VW_CAPTURE_FILEID          (CST_5VW_FLAT_FILE | CST_5VW_CAPTURES_FILE)
63 #define CST_5VW_FAMILY_CAP_ETH          0x01U
64 #define CST_5VW_FAMILY_CAP_WAN          0x02U
65 #define CST_5VW_DECALE_FILE_FAMILY      12
66 #define CST_5VW_CAP_ETH                 (CST_5VW_FAMILY_CAP_ETH << CST_5VW_DECALE_FILE_FAMILY)  /* 0x00001000 */
67 #define CST_5VW_CAP_WAN                 (CST_5VW_FAMILY_CAP_WAN << CST_5VW_DECALE_FILE_FAMILY)  /* 0x00002000 */
68 #define CST_5VW_CAPTURE_ETH_FILEID      (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_ETH)
69 #define CST_5VW_CAPTURE_WAN_FILEID      (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_WAN)
70
71 #define CST_5VW_CAPTURE_FILE_TYPE_MASK  0xFF000000U
72
73 #define CST_5VW_FRAME_RECORD            0x00000000U
74 #define CST_5VW_RECORDS_HEADER_KEY      0x3333EEEEU
75
76 typedef struct
77 {
78         t_5VW_Info_Header       Info_Header;
79         t_5VW_Attributes_Header HeaderDateCreation;
80         guint32                 Time;
81         t_5VW_Attributes_Header HeaderNbFrames;
82         guint32                 TramesStockeesInFile;
83 }t_5VW_Capture_Header;
84
85 typedef struct
86 {
87         guint32 Key;                    /* 0x3333EEEE */
88         guint16 HeaderSize;             /* Actual size of this header in bytes (32) */
89         guint16 HeaderType;             /* Exact type of this header (0x4000) */
90         guint32 RecType;                /* Type of record */
91         guint32 RecSubType;             /* Subtype of record */
92         guint32 RecSize;                /* Size of one record */
93         guint32 RecNb;                  /* Number of records */
94         guint32 Utc;
95         guint32 NanoSecondes;
96         guint32 RecInfo;                /* Info about Alarm / Event / Frame captured */
97 }t_5VW_TimeStamped_Header;
98
99
100 #define CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES   0x20000000U
101 #define CST_5VW_IA_DATE_CREATION                0x80000007U     /* Struct t_Attrib_Date_Create */
102 #define CST_5VW_TIMESTAMPED_HEADER_TYPE         0x4000U
103 #define CST_5VW_CAPTURES_RECORD         (CST_5VW_SECTION_CAPTURES << 28)        /* 0x80000000 */
104 #define CST_5VW_SYSTEM_RECORD           0x00000000U
105
106 static gboolean _5views_read(wtap *wth, int *err, gchar **err_info,
107     gint64 *data_offset);
108 static gboolean _5views_read_rec_data(FILE_T fh, guchar *pd, int length,
109     int *err, gchar **err_info);
110 static int _5views_read_header(wtap *wth, FILE_T fh,
111     t_5VW_TimeStamped_Header  *hdr, int *err, gchar **err_info);
112 static gboolean _5views_seek_read(wtap *wth, gint64 seek_off,
113     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
114     int *err, gchar **err_info);
115
116
117 static gboolean _5views_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
118                                                          const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
119 static gboolean _5views_dump_close(wtap_dumper *wdh, int *err);
120
121
122 int _5views_open(wtap *wth, int *err, gchar **err_info)
123 {
124         int bytes_read;
125         t_5VW_Capture_Header Capture_Header;
126         int encap = WTAP_ENCAP_UNKNOWN;
127
128         errno = WTAP_ERR_CANT_READ;
129         bytes_read = file_read(&Capture_Header.Info_Header, sizeof(t_5VW_Info_Header), wth->fh);
130         if (bytes_read != sizeof(t_5VW_Info_Header)) {
131                 *err = file_error(wth->fh, err_info);
132                 if (*err != 0)
133                         return -1;
134                 return 0;
135         }
136
137         wth->data_offset+=bytes_read;
138
139         /*      Check whether that's 5Views format or not */
140         if(Capture_Header.Info_Header.Signature != CST_5VW_INFO_HEADER_KEY)
141         {
142                 return 0;
143         }
144
145         /* Check Version */
146         Capture_Header.Info_Header.Version =
147             pletohl(&Capture_Header.Info_Header.Version);
148         switch (Capture_Header.Info_Header.Version) {
149
150         case CST_5VW_INFO_RECORD_VERSION:
151                 break;
152
153         default:
154                 *err = WTAP_ERR_UNSUPPORTED;
155                 *err_info = g_strdup_printf("5views: header version %u unsupported", Capture_Header.Info_Header.Version);
156                 return -1;
157         }
158
159         /* Check File Type */
160         Capture_Header.Info_Header.FileType =
161             pletohl(&Capture_Header.Info_Header.FileType);
162         if((Capture_Header.Info_Header.FileType & CST_5VW_CAPTURE_FILE_TYPE_MASK) != CST_5VW_CAPTURE_FILEID)
163         {
164                 *err = WTAP_ERR_UNSUPPORTED;
165                 *err_info = g_strdup_printf("5views: file is not a capture file (filetype is %u)", Capture_Header.Info_Header.Version);
166                 return -1;
167         }
168
169         /* Check possible Encap */
170         switch (Capture_Header.Info_Header.FileType) {
171         case CST_5VW_CAPTURE_ETH_FILEID:
172                 encap = WTAP_ENCAP_ETHERNET;
173                 break;
174 /*      case CST_5VW_CAPTURE_WAN_FILEID:
175                 break;
176 */
177         default:
178                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
179                 *err_info = g_strdup_printf("5views: network type %u unknown or unsupported",
180                     Capture_Header.Info_Header.FileType);
181                 return -1;
182         }
183
184         /* read the remaining header information */
185         bytes_read = file_read(&Capture_Header.HeaderDateCreation, sizeof (t_5VW_Capture_Header) - sizeof(t_5VW_Info_Header), wth->fh);
186         if (bytes_read != sizeof (t_5VW_Capture_Header)- sizeof(t_5VW_Info_Header) ) {
187                 *err = file_error(wth->fh, err_info);
188                 if (*err != 0)
189                         return -1;
190                 return 0;
191         }
192         wth->data_offset+=bytes_read;
193
194         /* This is a 5views capture file */
195         wth->file_type = WTAP_FILE_5VIEWS;
196         wth->subtype_read = _5views_read;
197         wth->subtype_seek_read = _5views_seek_read;
198         wth->file_encap = encap;
199         wth->snapshot_length = 0;       /* not available in header */
200         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
201
202         return 1;
203 }
204
205 /* Read the next packet */
206 static gboolean
207 _5views_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
208 {
209         t_5VW_TimeStamped_Header TimeStamped_Header;
210         int     bytes_read;
211         guint packet_size;
212         guint orig_size;
213
214         do
215         {
216                 bytes_read = _5views_read_header(wth, wth->fh, &TimeStamped_Header, err, err_info);
217                 if (bytes_read == -1) {
218                         /*
219                          * We failed to read the header.
220                          */
221                         return FALSE;
222                 }
223                 wth->data_offset += bytes_read;
224
225                 TimeStamped_Header.Key = pletohl(&TimeStamped_Header.Key);
226                 if(TimeStamped_Header.Key != CST_5VW_RECORDS_HEADER_KEY)
227                         return FALSE;
228
229                 TimeStamped_Header.RecSubType =
230                     pletohl(&TimeStamped_Header.RecSubType);
231                 TimeStamped_Header.RecSize =
232                     pletohl(&TimeStamped_Header.RecSize);
233                 if(TimeStamped_Header.RecSubType != CST_5VW_FRAME_RECORD) {
234                         if (file_seek(wth->fh, TimeStamped_Header.RecSize, SEEK_CUR, err) == -1)
235                                 return FALSE;
236                         wth->data_offset += TimeStamped_Header.RecSize;
237                 } else
238                         break;
239         } while (1);
240
241         packet_size = TimeStamped_Header.RecSize;
242         orig_size = TimeStamped_Header.RecSize;
243
244         *data_offset = wth->data_offset;
245
246         buffer_assure_space(wth->frame_buffer, packet_size);
247         if (!_5views_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
248             packet_size, err, err_info))
249                 return FALSE;   /* Read error */
250
251         wth->data_offset += packet_size;
252         TimeStamped_Header.Utc = pletohl(&TimeStamped_Header.Utc);
253         TimeStamped_Header.NanoSecondes =
254             pletohl(&TimeStamped_Header.NanoSecondes);
255         wth->phdr.ts.secs = TimeStamped_Header.Utc;
256         wth->phdr.ts.nsecs = TimeStamped_Header.NanoSecondes;
257         wth->phdr.caplen = packet_size;
258         wth->phdr.len = orig_size;
259
260         switch (wth->file_encap) {
261
262         case WTAP_ENCAP_ETHERNET:
263                 /* We assume there's no FCS in this frame. */
264                 wth->pseudo_header.eth.fcs_len = 0;
265                 break;
266         }
267
268         return TRUE;
269 }
270
271
272
273 static gboolean
274 _5views_read_rec_data(FILE_T fh, guchar *pd, int length, int *err,
275    gchar **err_info)
276 {
277         int     bytes_read;
278
279         errno = WTAP_ERR_CANT_READ;
280         bytes_read = file_read(pd, length, fh);
281
282         if (bytes_read != length) {
283                 *err = file_error(fh, err_info);
284                 if (*err == 0)
285                         *err = WTAP_ERR_SHORT_READ;
286                 return FALSE;
287         }
288         return TRUE;
289 }
290
291
292 /* Read the header of the next packet; if "silent" is TRUE, don't complain
293    to the console, as we're testing to see if the file appears to be of a
294    particular type.
295
296    Return -1 on an error, or the number of bytes of header read on success. */
297 static int
298 _5views_read_header(wtap *wth _U_, FILE_T fh, t_5VW_TimeStamped_Header  *hdr,   int *err, gchar **err_info)
299 {
300         int     bytes_read, bytes_to_read;
301
302         bytes_to_read = sizeof(t_5VW_TimeStamped_Header);
303
304         /* Read record header. */
305         bytes_read = file_read(hdr, bytes_to_read, fh);
306         if (bytes_read != bytes_to_read) {
307                 *err = file_error(fh, err_info);
308                 if (*err == 0 && bytes_read != 0) {
309                         *err = WTAP_ERR_SHORT_READ;
310                 }
311                 return -1;
312         }
313
314         return bytes_read;
315 }
316
317 static gboolean
318 _5views_seek_read(wtap *wth, gint64 seek_off,
319     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
320     int *err, gchar **err_info)
321 {
322         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
323                 return FALSE;
324         /*
325          * Read the packet data.
326          */
327         if (!_5views_read_rec_data(wth->random_fh, pd, length, err, err_info))
328                 return FALSE;
329
330         switch (wth->file_encap) {
331
332         case WTAP_ENCAP_ETHERNET:
333                 /* We assume there's no FCS in this frame. */
334                 pseudo_header->eth.fcs_len = 0;
335                 break;
336         }
337
338         return TRUE;
339 }
340
341
342
343 typedef struct {
344         guint32 nframes;
345 } _5views_dump_t;
346
347 static const int wtap_encap[] = {
348         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
349         CST_5VW_CAPTURE_ETH_FILEID,             /* WTAP_ENCAP_ETHERNET -> Ehernet Ethernet */
350         -1,             /* WTAP_ENCAP_TOKEN_RING -> unsupported */
351         -1,             /* WTAP_ENCAP_SLIP -> unsupported */
352         -1,             /* WTAP_ENCAP_PPP -> unsupported */
353         -1,             /* WTAP_ENCAP_FDDI -> unsupported */
354         -1,             /* WTAP_ENCAP_FDDI_BITSWAPPED -> unsupported */
355         -1,             /* WTAP_ENCAP_RAW_IP -> unsupported */
356         -1,             /* WTAP_ENCAP_ARCNET -> unsupported */
357         -1,             /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
358         -1,             /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
359         -1,             /* WTAP_ENCAP_LAPB -> unsupported */
360         -1,             /* WTAP_ENCAP_ATM_PDUS -> unsupported */
361         -1              /* WTAP_ENCAP_NULL -> unsupported */
362 };
363 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
364
365 /* Returns 0 if we could write the specified encapsulation type,
366    an error indication otherwise. */
367 int _5views_dump_can_write_encap(int encap)
368 {
369         /* Per-packet encapsulations aren't supported. */
370         if (encap == WTAP_ENCAP_PER_PACKET)
371                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
372
373         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
374                 return WTAP_ERR_UNSUPPORTED_ENCAP;
375
376         return 0;
377 }
378
379 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
380    failure */
381 gboolean _5views_dump_open(wtap_dumper *wdh, int *err)
382 {
383         _5views_dump_t *_5views;
384
385         /* We can't fill in all the fields in the file header, as we
386            haven't yet written any packets.  As we'll have to rewrite
387            the header when we've written out all the packets, we just
388            skip over the header for now. */
389         if (fseek(wdh->fh, sizeof(t_5VW_Capture_Header), SEEK_SET) == -1) {
390                 *err = errno;
391                 return FALSE;
392         }
393
394         /* This is a 5Views file */
395         wdh->subtype_write = _5views_dump;
396         wdh->subtype_close = _5views_dump_close;
397         _5views = (_5views_dump_t *)g_malloc(sizeof(_5views_dump_t));
398         wdh->priv = (void *)_5views;
399         _5views->nframes = 0;
400
401         return TRUE;
402 }
403
404 /* Write a record for a packet to a dump file.
405    Returns TRUE on success, FALSE on failure. */
406 static gboolean _5views_dump(wtap_dumper *wdh,
407         const struct wtap_pkthdr *phdr,
408         const union wtap_pseudo_header *pseudo_header _U_,
409         const guchar *pd, int *err)
410 {
411         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
412         static t_5VW_TimeStamped_Header HeaderFrame;
413
414         /* Frame Header */
415         /* constant fields */
416         HeaderFrame.Key = htolel(CST_5VW_RECORDS_HEADER_KEY);
417         HeaderFrame.HeaderSize = htoles(sizeof(t_5VW_TimeStamped_Header));
418         HeaderFrame.HeaderType = htoles(CST_5VW_TIMESTAMPED_HEADER_TYPE);
419         HeaderFrame.RecType = htolel(CST_5VW_CAPTURES_RECORD | CST_5VW_SYSTEM_RECORD);
420         HeaderFrame.RecSubType = htolel(CST_5VW_FRAME_RECORD);
421         HeaderFrame.RecNb = htolel(1);
422
423         /* record-dependant fields */
424         HeaderFrame.Utc = htolel(phdr->ts.secs);
425         HeaderFrame.NanoSecondes = htolel(phdr->ts.nsecs);
426         HeaderFrame.RecSize = htolel(phdr->len);
427         HeaderFrame.RecInfo = htolel(0);
428
429         /* write the record header */
430         if (!wtap_dump_file_write(wdh, &HeaderFrame,
431             sizeof(t_5VW_TimeStamped_Header), err))
432                 return FALSE;
433
434         /* write the data */
435         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
436                 return FALSE;
437
438         _5views->nframes ++;
439
440         return TRUE;
441 }
442
443 static gboolean _5views_dump_close(wtap_dumper *wdh, int *err)
444 {
445         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
446         t_5VW_Capture_Header file_hdr;
447
448         if (fseek(wdh->fh, 0, SEEK_SET) == -1) {
449                 *err = errno;
450                 return FALSE;
451         }
452
453         /* fill in the Info_Header */
454         file_hdr.Info_Header.Signature = htolel(CST_5VW_INFO_HEADER_KEY);
455         file_hdr.Info_Header.Size = htolel(sizeof(t_5VW_Info_Header));  /* Total size of Header in bytes (included Signature) */
456         file_hdr.Info_Header.Version = htolel(CST_5VW_INFO_RECORD_VERSION); /* Identify version and so the format of this record */
457         file_hdr.Info_Header.DataSize = htolel(sizeof(t_5VW_Attributes_Header)
458                                         + sizeof(guint32)
459                                         + sizeof(t_5VW_Attributes_Header)
460                                         + sizeof(guint32));
461                                         /* Total size of data included in the Info Record (except the header size) */
462         file_hdr.Info_Header.FileType = htolel(wtap_encap[wdh->encap]); /* Type of the file */
463         file_hdr.Info_Header.Reserved[0] = 0;   /* Reserved for future use */
464         file_hdr.Info_Header.Reserved[1] = 0;   /* Reserved for future use */
465         file_hdr.Info_Header.Reserved[2] = 0;   /* Reserved for future use */
466
467         /* fill in the HeaderDateCreation */
468         file_hdr.HeaderDateCreation.Type = htolel(CST_5VW_IA_DATE_CREATION);    /* Id of the attribute */
469         file_hdr.HeaderDateCreation.Size = htoles(sizeof(guint32));     /* Size of the data part of the attribute (not including header size) */
470         file_hdr.HeaderDateCreation.Nb = htoles(1);                     /* Number of elements */
471
472         /* fill in the Time field */
473 #ifdef _WIN32
474         _tzset();
475 #endif
476         file_hdr.Time = htolel(time(NULL));
477
478         /* fill in the Time field */
479         file_hdr.HeaderNbFrames.Type = htolel(CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES);   /* Id of the attribute */
480         file_hdr.HeaderNbFrames.Size = htoles(sizeof(guint32)); /* Size of the data part of the attribute (not including header size) */
481         file_hdr.HeaderNbFrames.Nb = htoles(1);                 /* Number of elements */
482
483         /* fill in the number of frames saved */
484         file_hdr.TramesStockeesInFile = htolel(_5views->nframes);
485
486         /* Write the file header. */
487         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof(t_5VW_Capture_Header),
488             err))
489                 return FALSE;
490
491         return TRUE;
492 }