| // Copyright 2017 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Package socket provides a portable interface for socket system | |
| // calls. | |
| package socket // import "golang.org/x/net/internal/socket" | |
| import ( | |
| "encoding/binary" | |
| "errors" | |
| "net" | |
| "runtime" | |
| "unsafe" | |
| ) | |
| var errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH) | |
| // An Option represents a sticky socket option. | |
| type Option struct { | |
| Level int // level | |
| Name int // name; must be equal or greater than 1 | |
| Len int // length of value in bytes; must be equal or greater than 1 | |
| } | |
| // Get reads a value for the option from the kernel. | |
| // It returns the number of bytes written into b. | |
| func (o *Option) Get(c *Conn, b []byte) (int, error) { | |
| if o.Name < 1 || o.Len < 1 { | |
| return 0, errors.New("invalid option") | |
| } | |
| if len(b) < o.Len { | |
| return 0, errors.New("short buffer") | |
| } | |
| return o.get(c, b) | |
| } | |
| // GetInt returns an integer value for the option. | |
| // | |
| // The Len field of Option must be either 1 or 4. | |
| func (o *Option) GetInt(c *Conn) (int, error) { | |
| if o.Len != 1 && o.Len != 4 { | |
| return 0, errors.New("invalid option") | |
| } | |
| var b []byte | |
| var bb [4]byte | |
| if o.Len == 1 { | |
| b = bb[:1] | |
| } else { | |
| b = bb[:4] | |
| } | |
| n, err := o.get(c, b) | |
| if err != nil { | |
| return 0, err | |
| } | |
| if n != o.Len { | |
| return 0, errors.New("invalid option length") | |
| } | |
| if o.Len == 1 { | |
| return int(b[0]), nil | |
| } | |
| return int(binary.NativeEndian.Uint32(b[:4])), nil | |
| } | |
| // Set writes the option and value to the kernel. | |
| func (o *Option) Set(c *Conn, b []byte) error { | |
| if o.Name < 1 || o.Len < 1 { | |
| return errors.New("invalid option") | |
| } | |
| if len(b) < o.Len { | |
| return errors.New("short buffer") | |
| } | |
| return o.set(c, b) | |
| } | |
| // SetInt writes the option and value to the kernel. | |
| // | |
| // The Len field of Option must be either 1 or 4. | |
| func (o *Option) SetInt(c *Conn, v int) error { | |
| if o.Len != 1 && o.Len != 4 { | |
| return errors.New("invalid option") | |
| } | |
| var b []byte | |
| if o.Len == 1 { | |
| b = []byte{byte(v)} | |
| } else { | |
| var bb [4]byte | |
| binary.NativeEndian.PutUint32(bb[:o.Len], uint32(v)) | |
| b = bb[:4] | |
| } | |
| return o.set(c, b) | |
| } | |
| // ControlMessageSpace returns the whole length of control message. | |
| func ControlMessageSpace(dataLen int) int { | |
| return controlMessageSpace(dataLen) | |
| } | |
| // A ControlMessage represents the head message in a stream of control | |
| // messages. | |
| // | |
| // A control message comprises of a header, data and a few padding | |
| // fields to conform to the interface to the kernel. | |
| // | |
| // See RFC 3542 for further information. | |
| type ControlMessage []byte | |
| // Data returns the data field of the control message at the head on | |
| // m. | |
| func (m ControlMessage) Data(dataLen int) []byte { | |
| l := controlHeaderLen() | |
| if len(m) < l || len(m) < l+dataLen { | |
| return nil | |
| } | |
| return m[l : l+dataLen] | |
| } | |
| // Next returns the control message at the next on m. | |
| // | |
| // Next works only for standard control messages. | |
| func (m ControlMessage) Next(dataLen int) ControlMessage { | |
| l := ControlMessageSpace(dataLen) | |
| if len(m) < l { | |
| return nil | |
| } | |
| return m[l:] | |
| } | |
| // MarshalHeader marshals the header fields of the control message at | |
| // the head on m. | |
| func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error { | |
| if len(m) < controlHeaderLen() { | |
| return errors.New("short message") | |
| } | |
| h := (*cmsghdr)(unsafe.Pointer(&m[0])) | |
| h.set(controlMessageLen(dataLen), lvl, typ) | |
| return nil | |
| } | |
| // ParseHeader parses and returns the header fields of the control | |
| // message at the head on m. | |
| func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) { | |
| l := controlHeaderLen() | |
| if len(m) < l { | |
| return 0, 0, 0, errors.New("short message") | |
| } | |
| h := (*cmsghdr)(unsafe.Pointer(&m[0])) | |
| return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil | |
| } | |
| // Marshal marshals the control message at the head on m, and returns | |
| // the next control message. | |
| func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) { | |
| l := len(data) | |
| if len(m) < ControlMessageSpace(l) { | |
| return nil, errors.New("short message") | |
| } | |
| h := (*cmsghdr)(unsafe.Pointer(&m[0])) | |
| h.set(controlMessageLen(l), lvl, typ) | |
| if l > 0 { | |
| copy(m.Data(l), data) | |
| } | |
| return m.Next(l), nil | |
| } | |
| // Parse parses m as a single or multiple control messages. | |
| // | |
| // Parse works for both standard and compatible messages. | |
| func (m ControlMessage) Parse() ([]ControlMessage, error) { | |
| var ms []ControlMessage | |
| for len(m) >= controlHeaderLen() { | |
| h := (*cmsghdr)(unsafe.Pointer(&m[0])) | |
| l := h.len() | |
| if l <= 0 { | |
| return nil, errors.New("invalid header length") | |
| } | |
| if uint64(l) < uint64(controlHeaderLen()) { | |
| return nil, errors.New("invalid message length") | |
| } | |
| if uint64(l) > uint64(len(m)) { | |
| return nil, errors.New("short buffer") | |
| } | |
| // On message reception: | |
| // | |
| // |<- ControlMessageSpace --------------->| | |
| // |<- controlMessageLen ---------->| | | |
| // |<- controlHeaderLen ->| | | | |
| // +---------------+------+---------+------+ | |
| // | Header | PadH | Data | PadD | | |
| // +---------------+------+---------+------+ | |
| // | |
| // On compatible message reception: | |
| // | |
| // | ... |<- controlMessageLen ----------->| | |
| // | ... |<- controlHeaderLen ->| | | |
| // +-----+---------------+------+----------+ | |
| // | ... | Header | PadH | Data | | |
| // +-----+---------------+------+----------+ | |
| ms = append(ms, ControlMessage(m[:l])) | |
| ll := l - controlHeaderLen() | |
| if len(m) >= ControlMessageSpace(ll) { | |
| m = m[ControlMessageSpace(ll):] | |
| } else { | |
| m = m[controlMessageLen(ll):] | |
| } | |
| } | |
| return ms, nil | |
| } | |
| // NewControlMessage returns a new stream of control messages. | |
| func NewControlMessage(dataLen []int) ControlMessage { | |
| var l int | |
| for i := range dataLen { | |
| l += ControlMessageSpace(dataLen[i]) | |
| } | |
| return make([]byte, l) | |
| } | |
| // A Message represents an IO message. | |
| type Message struct { | |
| // When writing, the Buffers field must contain at least one | |
| // byte to write. | |
| // When reading, the Buffers field will always contain a byte | |
| // to read. | |
| Buffers [][]byte | |
| // OOB contains protocol-specific control or miscellaneous | |
| // ancillary data known as out-of-band data. | |
| OOB []byte | |
| // Addr specifies a destination address when writing. | |
| // It can be nil when the underlying protocol of the raw | |
| // connection uses connection-oriented communication. | |
| // After a successful read, it may contain the source address | |
| // on the received packet. | |
| Addr net.Addr | |
| N int // # of bytes read or written from/to Buffers | |
| NN int // # of bytes read or written from/to OOB | |
| Flags int // protocol-specific information on the received message | |
| } | |
| // RecvMsg wraps recvmsg system call. | |
| // | |
| // The provided flags is a set of platform-dependent flags, such as | |
| // syscall.MSG_PEEK. | |
| func (c *Conn) RecvMsg(m *Message, flags int) error { | |
| return c.recvMsg(m, flags) | |
| } | |
| // SendMsg wraps sendmsg system call. | |
| // | |
| // The provided flags is a set of platform-dependent flags, such as | |
| // syscall.MSG_DONTROUTE. | |
| func (c *Conn) SendMsg(m *Message, flags int) error { | |
| return c.sendMsg(m, flags) | |
| } | |
| // RecvMsgs wraps recvmmsg system call. | |
| // | |
| // It returns the number of processed messages. | |
| // | |
| // The provided flags is a set of platform-dependent flags, such as | |
| // syscall.MSG_PEEK. | |
| // | |
| // Only Linux supports this. | |
| func (c *Conn) RecvMsgs(ms []Message, flags int) (int, error) { | |
| return c.recvMsgs(ms, flags) | |
| } | |
| // SendMsgs wraps sendmmsg system call. | |
| // | |
| // It returns the number of processed messages. | |
| // | |
| // The provided flags is a set of platform-dependent flags, such as | |
| // syscall.MSG_DONTROUTE. | |
| // | |
| // Only Linux supports this. | |
| func (c *Conn) SendMsgs(ms []Message, flags int) (int, error) { | |
| return c.sendMsgs(ms, flags) | |
| } |