added support for string type
[govpp.git] / vendor / github.com / google / gopacket / pcapgo / write.go
1 // Copyright 2012 Google, Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree.
6
7 // Package pcapgo provides some native PCAP support, not requiring
8 // C libpcap to be installed.
9 package pcapgo
10
11 import (
12         "encoding/binary"
13         "fmt"
14         "io"
15         "time"
16
17         "github.com/google/gopacket"
18         "github.com/google/gopacket/layers"
19 )
20
21 // Writer wraps an underlying io.Writer to write packet data in PCAP
22 // format.  See http://wiki.wireshark.org/Development/LibpcapFileFormat
23 // for information on the file format.
24 //
25 // For those that care, we currently write v2.4 files with nanosecond
26 // timestamp resolution and little-endian encoding.
27 type Writer struct {
28         w io.Writer
29 }
30
31 const magicMicroseconds = 0xA1B2C3D4
32 const versionMajor = 2
33 const versionMinor = 4
34
35 // NewWriter returns a new writer object, for writing packet data out
36 // to the given writer.  If this is a new empty writer (as opposed to
37 // an append), you must call WriteFileHeader before WritePacket.
38 //
39 //  // Write a new file:
40 //  f, _ := os.Create("/tmp/file.pcap")
41 //  w := pcapgo.NewWriter(f)
42 //  w.WriteFileHeader(65536, layers.LinkTypeEthernet)  // new file, must do this.
43 //  w.WritePacket(gopacket.CaptureInfo{...}, data1)
44 //  f.Close()
45 //  // Append to existing file (must have same snaplen and linktype)
46 //  f2, _ := os.OpenFile("/tmp/file.pcap", os.O_APPEND, 0700)
47 //  w2 := pcapgo.NewWriter(f2)
48 //  // no need for file header, it's already written.
49 //  w2.WritePacket(gopacket.CaptureInfo{...}, data2)
50 //  f2.Close()
51 func NewWriter(w io.Writer) *Writer {
52         return &Writer{w: w}
53 }
54
55 // WriteFileHeader writes a file header out to the writer.
56 // This must be called exactly once per output.
57 func (w *Writer) WriteFileHeader(snaplen uint32, linktype layers.LinkType) error {
58         var buf [24]byte
59         binary.LittleEndian.PutUint32(buf[0:4], magicMicroseconds)
60         binary.LittleEndian.PutUint16(buf[4:6], versionMajor)
61         binary.LittleEndian.PutUint16(buf[6:8], versionMinor)
62         // bytes 8:12 stay 0 (timezone = UTC)
63         // bytes 12:16 stay 0 (sigfigs is always set to zero, according to
64         //   http://wiki.wireshark.org/Development/LibpcapFileFormat
65         binary.LittleEndian.PutUint32(buf[16:20], snaplen)
66         binary.LittleEndian.PutUint32(buf[20:24], uint32(linktype))
67         _, err := w.w.Write(buf[:])
68         return err
69 }
70
71 const nanosPerMicro = 1000
72
73 func (w *Writer) writePacketHeader(ci gopacket.CaptureInfo) error {
74         var buf [16]byte
75
76         t := ci.Timestamp
77         if t.IsZero() {
78                 t = time.Now()
79         }
80         secs := t.Unix()
81         usecs := t.Nanosecond() / nanosPerMicro
82         binary.LittleEndian.PutUint32(buf[0:4], uint32(secs))
83         binary.LittleEndian.PutUint32(buf[4:8], uint32(usecs))
84         binary.LittleEndian.PutUint32(buf[8:12], uint32(ci.CaptureLength))
85         binary.LittleEndian.PutUint32(buf[12:16], uint32(ci.Length))
86         _, err := w.w.Write(buf[:])
87         return err
88 }
89
90 // WritePacket writes the given packet data out to the file.
91 func (w *Writer) WritePacket(ci gopacket.CaptureInfo, data []byte) error {
92         if ci.CaptureLength != len(data) {
93                 return fmt.Errorf("capture length %d does not match data length %d", ci.CaptureLength, len(data))
94         }
95         if ci.CaptureLength > ci.Length {
96                 return fmt.Errorf("invalid capture info %+v:  capture length > length", ci)
97         }
98         if err := w.writePacketHeader(ci); err != nil {
99                 return fmt.Errorf("error writing packet header: %v", err)
100         }
101         _, err := w.w.Write(data)
102         return err
103 }