1 // Copyright 2010 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.
5 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
14 // BUG(mikio): On every POSIX platform, reads from the "ip4" network
15 // using the ReadFrom or ReadFromIP method might not return a complete
16 // IPv4 packet, including its header, even if there is space
17 // available. This can occur even in cases where Read or ReadMsgIP
18 // could return a complete packet. For this reason, it is recommended
19 // that you do not uses these methods if it is important to receive a
22 // The Go 1 compatibility guidelines make it impossible for us to
23 // change the behavior of these methods; use Read or ReadMsgIP
26 func sockaddrToIP(sa syscall
.Sockaddr
) Addr
{
27 switch sa
:= sa
.(type) {
28 case *syscall
.SockaddrInet4
:
29 return &IPAddr
{IP
: sa
.Addr
[0:]}
30 case *syscall
.SockaddrInet6
:
31 return &IPAddr
{IP
: sa
.Addr
[0:], Zone
: zoneToString(int(sa
.ZoneId
))}
36 func (a
*IPAddr
) family() int {
37 if a
== nil ||
len(a
.IP
) <= IPv4len
{
38 return syscall
.AF_INET
40 if a
.IP
.To4() != nil {
41 return syscall
.AF_INET
43 return syscall
.AF_INET6
46 func (a
*IPAddr
) isWildcard() bool {
47 if a
== nil || a
.IP
== nil {
50 return a
.IP
.IsUnspecified()
53 func (a
*IPAddr
) sockaddr(family
int) (syscall
.Sockaddr
, error
) {
57 return ipToSockaddr(family
, a
.IP
, 0, a
.Zone
)
60 // IPConn is the implementation of the Conn and PacketConn interfaces
61 // for IP network connections.
66 func newIPConn(fd
*netFD
) *IPConn
{ return &IPConn
{conn
{fd
}} }
68 // ReadFromIP reads an IP packet from c, copying the payload into b.
69 // It returns the number of bytes copied into b and the return address
70 // that was on the packet.
72 // ReadFromIP can be made to time out and return an error with
73 // Timeout() == true after a fixed time limit; see SetDeadline and
75 func (c
*IPConn
) ReadFromIP(b
[]byte) (int, *IPAddr
, error
) {
77 return 0, nil, syscall
.EINVAL
79 // TODO(cw,rsc): consider using readv if we know the family
80 // type to avoid the header trim/copy
82 n
, sa
, err
:= c
.fd
.readFrom(b
)
83 switch sa
:= sa
.(type) {
84 case *syscall
.SockaddrInet4
:
85 addr
= &IPAddr
{IP
: sa
.Addr
[0:]}
86 if len(b
) >= IPv4len
{ // discard ipv4 header
87 hsize
:= (int(b
[0]) & 0xf) * 4
91 case *syscall
.SockaddrInet6
:
92 addr
= &IPAddr
{IP
: sa
.Addr
[0:], Zone
: zoneToString(int(sa
.ZoneId
))}
97 // ReadFrom implements the PacketConn ReadFrom method.
98 func (c
*IPConn
) ReadFrom(b
[]byte) (int, Addr
, error
) {
100 return 0, nil, syscall
.EINVAL
102 n
, addr
, err
:= c
.ReadFromIP(b
)
103 return n
, addr
.toAddr(), err
106 // ReadMsgIP reads a packet from c, copying the payload into b and the
107 // associated out-of-band data into oob. It returns the number of
108 // bytes copied into b, the number of bytes copied into oob, the flags
109 // that were set on the packet and the source address of the packet.
110 func (c
*IPConn
) ReadMsgIP(b
, oob
[]byte) (n
, oobn
, flags
int, addr
*IPAddr
, err error
) {
112 return 0, 0, 0, nil, syscall
.EINVAL
114 var sa syscall
.Sockaddr
115 n
, oobn
, flags
, sa
, err
= c
.fd
.readMsg(b
, oob
)
116 switch sa
:= sa
.(type) {
117 case *syscall
.SockaddrInet4
:
118 addr
= &IPAddr
{IP
: sa
.Addr
[0:]}
119 case *syscall
.SockaddrInet6
:
120 addr
= &IPAddr
{IP
: sa
.Addr
[0:], Zone
: zoneToString(int(sa
.ZoneId
))}
125 // WriteToIP writes an IP packet to addr via c, copying the payload
128 // WriteToIP can be made to time out and return an error with
129 // Timeout() == true after a fixed time limit; see SetDeadline and
130 // SetWriteDeadline. On packet-oriented connections, write timeouts
132 func (c
*IPConn
) WriteToIP(b
[]byte, addr
*IPAddr
) (int, error
) {
134 return 0, syscall
.EINVAL
136 if c
.fd
.isConnected
{
137 return 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: addr
, Err
: ErrWriteToConnected
}
140 return 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: nil, Err
: errMissingAddress
}
142 sa
, err
:= addr
.sockaddr(c
.fd
.family
)
144 return 0, &OpError
{"write", c
.fd
.net
, addr
, err
}
146 return c
.fd
.writeTo(b
, sa
)
149 // WriteTo implements the PacketConn WriteTo method.
150 func (c
*IPConn
) WriteTo(b
[]byte, addr Addr
) (int, error
) {
152 return 0, syscall
.EINVAL
154 a
, ok
:= addr
.(*IPAddr
)
156 return 0, &OpError
{"write", c
.fd
.net
, addr
, syscall
.EINVAL
}
158 return c
.WriteToIP(b
, a
)
161 // WriteMsgIP writes a packet to addr via c, copying the payload from
162 // b and the associated out-of-band data from oob. It returns the
163 // number of payload and out-of-band bytes written.
164 func (c
*IPConn
) WriteMsgIP(b
, oob
[]byte, addr
*IPAddr
) (n
, oobn
int, err error
) {
166 return 0, 0, syscall
.EINVAL
168 if c
.fd
.isConnected
{
169 return 0, 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: addr
, Err
: ErrWriteToConnected
}
172 return 0, 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: nil, Err
: errMissingAddress
}
174 sa
, err
:= addr
.sockaddr(c
.fd
.family
)
176 return 0, 0, &OpError
{"write", c
.fd
.net
, addr
, err
}
178 return c
.fd
.writeMsg(b
, oob
, sa
)
181 // DialIP connects to the remote address raddr on the network protocol
182 // netProto, which must be "ip", "ip4", or "ip6" followed by a colon
183 // and a protocol number or name.
184 func DialIP(netProto
string, laddr
, raddr
*IPAddr
) (*IPConn
, error
) {
185 return dialIP(netProto
, laddr
, raddr
, noDeadline
)
188 func dialIP(netProto
string, laddr
, raddr
*IPAddr
, deadline time
.Time
) (*IPConn
, error
) {
189 net
, proto
, err
:= parseNetwork(netProto
)
191 return nil, &OpError
{Op
: "dial", Net
: netProto
, Addr
: raddr
, Err
: err
}
194 case "ip", "ip4", "ip6":
196 return nil, &OpError
{Op
: "dial", Net
: netProto
, Addr
: raddr
, Err
: UnknownNetworkError(netProto
)}
199 return nil, &OpError
{Op
: "dial", Net
: netProto
, Addr
: nil, Err
: errMissingAddress
}
201 fd
, err
:= internetSocket(net
, laddr
, raddr
, deadline
, syscall
.SOCK_RAW
, proto
, "dial", sockaddrToIP
)
203 return nil, &OpError
{Op
: "dial", Net
: netProto
, Addr
: raddr
, Err
: err
}
205 return newIPConn(fd
), nil
208 // ListenIP listens for incoming IP packets addressed to the local
209 // address laddr. The returned connection's ReadFrom and WriteTo
210 // methods can be used to receive and send IP packets with per-packet
212 func ListenIP(netProto
string, laddr
*IPAddr
) (*IPConn
, error
) {
213 net
, proto
, err
:= parseNetwork(netProto
)
215 return nil, &OpError
{Op
: "dial", Net
: netProto
, Addr
: laddr
, Err
: err
}
218 case "ip", "ip4", "ip6":
220 return nil, &OpError
{Op
: "listen", Net
: netProto
, Addr
: laddr
, Err
: UnknownNetworkError(netProto
)}
222 fd
, err
:= internetSocket(net
, laddr
, nil, noDeadline
, syscall
.SOCK_RAW
, proto
, "listen", sockaddrToIP
)
224 return nil, &OpError
{Op
: "listen", Net
: netProto
, Addr
: laddr
, Err
: err
}
226 return newIPConn(fd
), nil