blob: 729dea14b39368f4a420968b22197489e6c67b1a [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// Copyright 2017 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 socket provides a portable interface for socket system
6// calls.
7package socket // import "golang.org/x/net/internal/socket"
8
9import (
10 "errors"
11 "net"
12 "unsafe"
13)
14
15// An Option represents a sticky socket option.
16type Option struct {
17 Level int // level
18 Name int // name; must be equal or greater than 1
19 Len int // length of value in bytes; must be equal or greater than 1
20}
21
22// Get reads a value for the option from the kernel.
23// It returns the number of bytes written into b.
24func (o *Option) Get(c *Conn, b []byte) (int, error) {
25 if o.Name < 1 || o.Len < 1 {
26 return 0, errors.New("invalid option")
27 }
28 if len(b) < o.Len {
29 return 0, errors.New("short buffer")
30 }
31 return o.get(c, b)
32}
33
34// GetInt returns an integer value for the option.
35//
36// The Len field of Option must be either 1 or 4.
37func (o *Option) GetInt(c *Conn) (int, error) {
38 if o.Len != 1 && o.Len != 4 {
39 return 0, errors.New("invalid option")
40 }
41 var b []byte
42 var bb [4]byte
43 if o.Len == 1 {
44 b = bb[:1]
45 } else {
46 b = bb[:4]
47 }
48 n, err := o.get(c, b)
49 if err != nil {
50 return 0, err
51 }
52 if n != o.Len {
53 return 0, errors.New("invalid option length")
54 }
55 if o.Len == 1 {
56 return int(b[0]), nil
57 }
58 return int(NativeEndian.Uint32(b[:4])), nil
59}
60
61// Set writes the option and value to the kernel.
62func (o *Option) Set(c *Conn, b []byte) error {
63 if o.Name < 1 || o.Len < 1 {
64 return errors.New("invalid option")
65 }
66 if len(b) < o.Len {
67 return errors.New("short buffer")
68 }
69 return o.set(c, b)
70}
71
72// SetInt writes the option and value to the kernel.
73//
74// The Len field of Option must be either 1 or 4.
75func (o *Option) SetInt(c *Conn, v int) error {
76 if o.Len != 1 && o.Len != 4 {
77 return errors.New("invalid option")
78 }
79 var b []byte
80 if o.Len == 1 {
81 b = []byte{byte(v)}
82 } else {
83 var bb [4]byte
84 NativeEndian.PutUint32(bb[:o.Len], uint32(v))
85 b = bb[:4]
86 }
87 return o.set(c, b)
88}
89
90func controlHeaderLen() int {
91 return roundup(sizeofCmsghdr)
92}
93
94func controlMessageLen(dataLen int) int {
95 return roundup(sizeofCmsghdr) + dataLen
96}
97
98// ControlMessageSpace returns the whole length of control message.
99func ControlMessageSpace(dataLen int) int {
100 return roundup(sizeofCmsghdr) + roundup(dataLen)
101}
102
103// A ControlMessage represents the head message in a stream of control
104// messages.
105//
106// A control message comprises of a header, data and a few padding
107// fields to conform to the interface to the kernel.
108//
109// See RFC 3542 for further information.
110type ControlMessage []byte
111
112// Data returns the data field of the control message at the head on
113// w.
114func (m ControlMessage) Data(dataLen int) []byte {
115 l := controlHeaderLen()
116 if len(m) < l || len(m) < l+dataLen {
117 return nil
118 }
119 return m[l : l+dataLen]
120}
121
122// Next returns the control message at the next on w.
123//
124// Next works only for standard control messages.
125func (m ControlMessage) Next(dataLen int) ControlMessage {
126 l := ControlMessageSpace(dataLen)
127 if len(m) < l {
128 return nil
129 }
130 return m[l:]
131}
132
133// MarshalHeader marshals the header fields of the control message at
134// the head on w.
135func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
136 if len(m) < controlHeaderLen() {
137 return errors.New("short message")
138 }
139 h := (*cmsghdr)(unsafe.Pointer(&m[0]))
140 h.set(controlMessageLen(dataLen), lvl, typ)
141 return nil
142}
143
144// ParseHeader parses and returns the header fields of the control
145// message at the head on w.
146func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
147 l := controlHeaderLen()
148 if len(m) < l {
149 return 0, 0, 0, errors.New("short message")
150 }
151 h := (*cmsghdr)(unsafe.Pointer(&m[0]))
152 return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
153}
154
155// Marshal marshals the control message at the head on w, and returns
156// the next control message.
157func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
158 l := len(data)
159 if len(m) < ControlMessageSpace(l) {
160 return nil, errors.New("short message")
161 }
162 h := (*cmsghdr)(unsafe.Pointer(&m[0]))
163 h.set(controlMessageLen(l), lvl, typ)
164 if l > 0 {
165 copy(m.Data(l), data)
166 }
167 return m.Next(l), nil
168}
169
170// Parse parses w as a single or multiple control messages.
171//
172// Parse works for both standard and compatible messages.
173func (m ControlMessage) Parse() ([]ControlMessage, error) {
174 var ms []ControlMessage
175 for len(m) >= controlHeaderLen() {
176 h := (*cmsghdr)(unsafe.Pointer(&m[0]))
177 l := h.len()
178 if l <= 0 {
179 return nil, errors.New("invalid header length")
180 }
181 if uint64(l) < uint64(controlHeaderLen()) {
182 return nil, errors.New("invalid message length")
183 }
184 if uint64(l) > uint64(len(m)) {
185 return nil, errors.New("short buffer")
186 }
187 // On message reception:
188 //
189 // |<- ControlMessageSpace --------------->|
190 // |<- controlMessageLen ---------->| |
191 // |<- controlHeaderLen ->| | |
192 // +---------------+------+---------+------+
193 // | Header | PadH | Data | PadD |
194 // +---------------+------+---------+------+
195 //
196 // On compatible message reception:
197 //
198 // | ... |<- controlMessageLen ----------->|
199 // | ... |<- controlHeaderLen ->| |
200 // +-----+---------------+------+----------+
201 // | ... | Header | PadH | Data |
202 // +-----+---------------+------+----------+
203 ms = append(ms, ControlMessage(m[:l]))
204 ll := l - controlHeaderLen()
205 if len(m) >= ControlMessageSpace(ll) {
206 m = m[ControlMessageSpace(ll):]
207 } else {
208 m = m[controlMessageLen(ll):]
209 }
210 }
211 return ms, nil
212}
213
214// NewControlMessage returns a new stream of control messages.
215func NewControlMessage(dataLen []int) ControlMessage {
216 var l int
217 for i := range dataLen {
218 l += ControlMessageSpace(dataLen[i])
219 }
220 return make([]byte, l)
221}
222
223// A Message represents an IO message.
224type Message struct {
225 // When writing, the Buffers field must contain at least one
226 // byte to write.
227 // When reading, the Buffers field will always contain a byte
228 // to read.
229 Buffers [][]byte
230
231 // OOB contains protocol-specific control or miscellaneous
232 // ancillary data known as out-of-band data.
233 OOB []byte
234
235 // Addr specifies a destination address when writing.
236 // It can be nil when the underlying protocol of the raw
237 // connection uses connection-oriented communication.
238 // After a successful read, it may contain the source address
239 // on the received packet.
240 Addr net.Addr
241
242 N int // # of bytes read or written from/to Buffers
243 NN int // # of bytes read or written from/to OOB
244 Flags int // protocol-specific information on the received message
245}
246
247// RecvMsg wraps recvmsg system call.
248//
249// The provided flags is a set of platform-dependent flags, such as
250// syscall.MSG_PEEK.
251func (c *Conn) RecvMsg(m *Message, flags int) error {
252 return c.recvMsg(m, flags)
253}
254
255// SendMsg wraps sendmsg system call.
256//
257// The provided flags is a set of platform-dependent flags, such as
258// syscall.MSG_DONTROUTE.
259func (c *Conn) SendMsg(m *Message, flags int) error {
260 return c.sendMsg(m, flags)
261}
262
263// RecvMsgs wraps recvmmsg system call.
264//
265// It returns the number of processed messages.
266//
267// The provided flags is a set of platform-dependent flags, such as
268// syscall.MSG_PEEK.
269//
270// Only Linux supports this.
271func (c *Conn) RecvMsgs(ms []Message, flags int) (int, error) {
272 return c.recvMsgs(ms, flags)
273}
274
275// SendMsgs wraps sendmmsg system call.
276//
277// It returns the number of processed messages.
278//
279// The provided flags is a set of platform-dependent flags, such as
280// syscall.MSG_DONTROUTE.
281//
282// Only Linux supports this.
283func (c *Conn) SendMsgs(ms []Message, flags int) (int, error) {
284 return c.sendMsgs(ms, flags)
285}