1 // 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
6 7 import (
8 "errors"
9 "net"
10 "os"
11 "syscall"
12 )
13 14 // A Conn represents a raw connection.
15 type Conn struct {
16 network string
17 c syscall.RawConn
18 }
19 20 // tcpConn is an interface implemented by net.TCPConn.
21 // It can be used for interface assertions to check if a net.Conn is a TCP connection.
22 type tcpConn interface {
23 SyscallConn() (syscall.RawConn, error)
24 SetLinger(int) error
25 }
26 27 var _ tcpConn = (*net.TCPConn)(nil)
28 29 // udpConn is an interface implemented by net.UDPConn.
30 // It can be used for interface assertions to check if a net.Conn is a UDP connection.
31 type udpConn interface {
32 SyscallConn() (syscall.RawConn, error)
33 ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
34 }
35 36 var _ udpConn = (*net.UDPConn)(nil)
37 38 // ipConn is an interface implemented by net.IPConn.
39 // It can be used for interface assertions to check if a net.Conn is an IP connection.
40 type ipConn interface {
41 SyscallConn() (syscall.RawConn, error)
42 ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *net.IPAddr, err error)
43 }
44 45 var _ ipConn = (*net.IPConn)(nil)
46 47 // NewConn returns a new raw connection.
48 func NewConn(c net.Conn) (*Conn, error) {
49 var err error
50 var cc Conn
51 switch c := c.(type) {
52 case tcpConn:
53 cc.network = "tcp"
54 cc.c, err = c.SyscallConn()
55 case udpConn:
56 cc.network = "udp"
57 cc.c, err = c.SyscallConn()
58 case ipConn:
59 cc.network = "ip"
60 cc.c, err = c.SyscallConn()
61 default:
62 return nil, errors.New("unknown connection type")
63 }
64 if err != nil {
65 return nil, err
66 }
67 return &cc, nil
68 }
69 70 func (o *Option) get(c *Conn, b []byte) (int, error) {
71 var operr error
72 var n int
73 fn := func(s uintptr) {
74 n, operr = getsockopt(s, o.Level, o.Name, b)
75 }
76 if err := c.c.Control(fn); err != nil {
77 return 0, err
78 }
79 return n, os.NewSyscallError("getsockopt", operr)
80 }
81 82 func (o *Option) set(c *Conn, b []byte) error {
83 var operr error
84 fn := func(s uintptr) {
85 operr = setsockopt(s, o.Level, o.Name, b)
86 }
87 if err := c.c.Control(fn); err != nil {
88 return err
89 }
90 return os.NewSyscallError("setsockopt", operr)
91 }
92