~james-page/ubuntu/raring/juju-core/1.10.0

« back to all changes in this revision

Viewing changes to src/code.google.com/p/go.net/ipv4/mockicmp_test.go

  • Committer: James Page
  • Date: 2013-04-24 15:16:56 UTC
  • mfrom: (1.1.1)
  • Revision ID: james.page@canonical.com-20130424151656-xr50npm6aq4tdeb1
Recut with -1 upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
package ipv4_test
6
6
 
7
7
import (
8
 
        "errors"
 
8
        "bytes"
9
9
        "flag"
10
10
)
11
11
 
12
12
var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
13
13
 
14
 
const (
15
 
        icmpv4EchoRequest = 8
16
 
        icmpv4EchoReply   = 0
17
 
        icmpv6EchoRequest = 128
18
 
        icmpv6EchoReply   = 129
19
 
)
20
 
 
21
 
// icmpMessage represents an ICMP message.
22
 
type icmpMessage struct {
23
 
        Type     int             // type
24
 
        Code     int             // code
25
 
        Checksum int             // checksum
26
 
        Body     icmpMessageBody // body
27
 
}
28
 
 
29
 
// icmpMessageBody represents an ICMP message body.
30
 
type icmpMessageBody interface {
31
 
        Len() int
32
 
        Marshal() ([]byte, error)
33
 
}
34
 
 
35
 
// Marshal returns the binary enconding of the ICMP echo request or
36
 
// reply message m.
37
 
func (m *icmpMessage) Marshal() ([]byte, error) {
38
 
        b := []byte{byte(m.Type), byte(m.Code), 0, 0}
39
 
        if m.Body != nil && m.Body.Len() != 0 {
40
 
                mb, err := m.Body.Marshal()
41
 
                if err != nil {
42
 
                        return nil, err
43
 
                }
44
 
                b = append(b, mb...)
45
 
        }
46
 
        switch m.Type {
47
 
        case icmpv6EchoRequest, icmpv6EchoReply:
48
 
                return b, nil
49
 
        }
50
 
        csumcv := len(b) - 1 // checksum coverage
 
14
func newICMPEchoRequest(id, seqnum, msglen int, filler []byte) []byte {
 
15
        b := newICMPInfoMessage(id, seqnum, msglen, filler)
 
16
        b[0] = 8
 
17
        // calculate ICMP checksum
 
18
        cklen := len(b)
51
19
        s := uint32(0)
52
 
        for i := 0; i < csumcv; i += 2 {
 
20
        for i := 0; i < cklen-1; i += 2 {
53
21
                s += uint32(b[i+1])<<8 | uint32(b[i])
54
22
        }
55
 
        if csumcv&1 == 0 {
56
 
                s += uint32(b[csumcv])
 
23
        if cklen&1 == 1 {
 
24
                s += uint32(b[cklen-1])
57
25
        }
58
 
        s = s>>16 + s&0xffff
59
 
        s = s + s>>16
60
 
        // Place checksum back in header; using ^= avoids the
61
 
        // assumption the checksum bytes are zero.
 
26
        s = (s >> 16) + (s & 0xffff)
 
27
        s = s + (s >> 16)
 
28
        // place checksum back in header; using ^= avoids the
 
29
        // assumption the checksum bytes are zero
62
30
        b[2] ^= byte(^s & 0xff)
63
31
        b[3] ^= byte(^s >> 8)
64
 
        return b, nil
65
 
}
66
 
 
67
 
// parseICMPMessage parses b as an ICMP message.
68
 
func parseICMPMessage(b []byte) (*icmpMessage, error) {
69
 
        msglen := len(b)
70
 
        if msglen < 4 {
71
 
                return nil, errors.New("message too short")
72
 
        }
73
 
        m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
74
 
        if msglen > 4 {
75
 
                var err error
76
 
                switch m.Type {
77
 
                case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
78
 
                        m.Body, err = parseICMPEcho(b[4:])
79
 
                        if err != nil {
80
 
                                return nil, err
81
 
                        }
82
 
                }
83
 
        }
84
 
        return m, nil
85
 
}
86
 
 
87
 
// imcpEcho represenets an ICMP echo request or reply message body.
88
 
type icmpEcho struct {
89
 
        ID   int    // identifier
90
 
        Seq  int    // sequence number
91
 
        Data []byte // data
92
 
}
93
 
 
94
 
func (p *icmpEcho) Len() int {
95
 
        if p == nil {
96
 
                return 0
97
 
        }
98
 
        return 4 + len(p.Data)
99
 
}
100
 
 
101
 
// Marshal returns the binary enconding of the ICMP echo request or
102
 
// reply message body p.
103
 
func (p *icmpEcho) Marshal() ([]byte, error) {
104
 
        b := make([]byte, 4+len(p.Data))
105
 
        b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
106
 
        b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
107
 
        copy(b[4:], p.Data)
108
 
        return b, nil
109
 
}
110
 
 
111
 
// parseICMPEcho parses b as an ICMP echo request or reply message
112
 
// body.
113
 
func parseICMPEcho(b []byte) (*icmpEcho, error) {
114
 
        bodylen := len(b)
115
 
        p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
116
 
        if bodylen > 4 {
117
 
                p.Data = make([]byte, bodylen-4)
118
 
                copy(p.Data, b[4:])
119
 
        }
120
 
        return p, nil
 
32
        return b
 
33
}
 
34
 
 
35
func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
 
36
        b := make([]byte, msglen)
 
37
        copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
 
38
        b[0] = 0                   // type
 
39
        b[1] = 0                   // code
 
40
        b[2] = 0                   // checksum
 
41
        b[3] = 0                   // checksum
 
42
        b[4] = byte(id >> 8)       // identifier
 
43
        b[5] = byte(id & 0xff)     // identifier
 
44
        b[6] = byte(seqnum >> 8)   // sequence number
 
45
        b[7] = byte(seqnum & 0xff) // sequence number
 
46
        return b
121
47
}