123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- // 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 (
- "errors"
- "net"
- "unsafe"
- )
-
- // 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(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
- NativeEndian.PutUint32(bb[:o.Len], uint32(v))
- b = bb[:4]
- }
- return o.set(c, b)
- }
-
- func controlHeaderLen() int {
- return roundup(sizeofCmsghdr)
- }
-
- func controlMessageLen(dataLen int) int {
- return roundup(sizeofCmsghdr) + dataLen
- }
-
- // ControlMessageSpace returns the whole length of control message.
- func ControlMessageSpace(dataLen int) int {
- return roundup(sizeofCmsghdr) + roundup(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
- // w.
- 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 w.
- //
- // 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 w.
- 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 w.
- 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 w, 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 w 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)
- }
|