~sinzui/ubuntu/vivid/juju-core/vivid-1.24.6

« back to all changes in this revision

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

  • Committer: Curtis Hovey
  • Date: 2015-09-30 14:14:54 UTC
  • mfrom: (1.1.34)
  • Revision ID: curtis@hovey.name-20150930141454-o3ldf23dzyjio6c0
Backport of 1.24.6 from wily. (LP: #1500916)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2012 The Go Authors.  All rights reserved.
2
 
// Use of this source code is governed by a BSD-style
3
 
// license that can be found in the LICENSE file.
4
 
 
5
 
package ipv4
6
 
 
7
 
import (
8
 
        "os"
9
 
        "syscall"
10
 
        "unsafe"
11
 
)
12
 
 
13
 
// Linux provides a convenient path control option IP_PKTINFO that
14
 
// contains IP_SENDSRCADDR, IP_RECVDSTADDR, IP_RECVIF and IP_SENDIF.
15
 
const pktinfo = FlagSrc | FlagDst | FlagInterface
16
 
 
17
 
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
18
 
        opt.Lock()
19
 
        defer opt.Unlock()
20
 
        if cf&FlagTTL != 0 {
21
 
                if err := setIPv4ReceiveTTL(fd, on); err != nil {
22
 
                        return err
23
 
                }
24
 
                if on {
25
 
                        opt.set(FlagTTL)
26
 
                } else {
27
 
                        opt.clear(FlagTTL)
28
 
                }
29
 
        }
30
 
        if cf&pktinfo != 0 {
31
 
                if err := setIPv4PacketInfo(fd, on); err != nil {
32
 
                        return err
33
 
                }
34
 
                if on {
35
 
                        opt.set(cf & pktinfo)
36
 
                } else {
37
 
                        opt.clear(cf & pktinfo)
38
 
                }
39
 
        }
40
 
        return nil
41
 
}
42
 
 
43
 
func newControlMessage(opt *rawOpt) (oob []byte) {
44
 
        opt.Lock()
45
 
        defer opt.Unlock()
46
 
        l, off := 0, 0
47
 
        if opt.isset(FlagTTL) {
48
 
                l += syscall.CmsgSpace(1)
49
 
        }
50
 
        if opt.isset(pktinfo) {
51
 
                l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
52
 
        }
53
 
        if l > 0 {
54
 
                oob = make([]byte, l)
55
 
                if opt.isset(FlagTTL) {
56
 
                        m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
57
 
                        m.Level = ianaProtocolIP
58
 
                        m.Type = syscall.IP_RECVTTL
59
 
                        m.SetLen(syscall.CmsgLen(1))
60
 
                        off += syscall.CmsgSpace(1)
61
 
                }
62
 
                if opt.isset(pktinfo) {
63
 
                        m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
64
 
                        m.Level = ianaProtocolIP
65
 
                        m.Type = syscall.IP_PKTINFO
66
 
                        m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
67
 
                        off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
68
 
                }
69
 
        }
70
 
        return
71
 
}
72
 
 
73
 
func parseControlMessage(b []byte) (*ControlMessage, error) {
74
 
        if len(b) == 0 {
75
 
                return nil, nil
76
 
        }
77
 
        cmsgs, err := syscall.ParseSocketControlMessage(b)
78
 
        if err != nil {
79
 
                return nil, os.NewSyscallError("parse socket control message", err)
80
 
        }
81
 
        cm := &ControlMessage{}
82
 
        for _, m := range cmsgs {
83
 
                if m.Header.Level != ianaProtocolIP {
84
 
                        continue
85
 
                }
86
 
                switch m.Header.Type {
87
 
                case syscall.IP_TTL:
88
 
                        cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
89
 
                case syscall.IP_PKTINFO:
90
 
                        pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&m.Data[0]))
91
 
                        cm.IfIndex = int(pi.Ifindex)
92
 
                        cm.Dst = pi.Addr[:]
93
 
                }
94
 
        }
95
 
        return cm, nil
96
 
}
97
 
 
98
 
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
99
 
        if cm == nil {
100
 
                return
101
 
        }
102
 
        l, off := 0, 0
103
 
        pion := false
104
 
        if cm.Src.To4() != nil || cm.IfIndex != 0 {
105
 
                pion = true
106
 
                l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
107
 
        }
108
 
        if l > 0 {
109
 
                oob = make([]byte, l)
110
 
                if pion {
111
 
                        m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
112
 
                        m.Level = ianaProtocolIP
113
 
                        m.Type = syscall.IP_PKTINFO
114
 
                        m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
115
 
                        pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
116
 
                        if ip := cm.Src.To4(); ip != nil {
117
 
                                copy(pi.Addr[:], ip)
118
 
                        }
119
 
                        if cm.IfIndex != 0 {
120
 
                                pi.Ifindex = int32(cm.IfIndex)
121
 
                        }
122
 
                        off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
123
 
                }
124
 
        }
125
 
        return
126
 
}