Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 1 | // Copyright 2009 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 | |
Dave Cheney | 7c8280c | 2014-02-25 09:47:42 -0500 | [diff] [blame] | 5 | // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows |
Russ Cox | 2715956 | 2011-09-15 16:48:57 -0400 | [diff] [blame] | 6 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 7 | package net |
| 8 | |
Brad Fitzpatrick | ef6806f | 2012-11-08 10:35:16 -0600 | [diff] [blame] | 9 | import ( |
| 10 | "syscall" |
| 11 | "time" |
| 12 | ) |
Mikio Hara | 974fa75 | 2012-01-27 01:31:42 +0900 | [diff] [blame] | 13 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 14 | func sockaddrToUDP(sa syscall.Sockaddr) Addr { |
| 15 | switch sa := sa.(type) { |
| 16 | case *syscall.SockaddrInet4: |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 17 | return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 18 | case *syscall.SockaddrInet6: |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 19 | return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 20 | } |
| 21 | return nil |
| 22 | } |
| 23 | |
| 24 | func (a *UDPAddr) family() int { |
Mikio Hara | 80f79ad | 2011-08-24 13:59:33 -0400 | [diff] [blame] | 25 | if a == nil || len(a.IP) <= IPv4len { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 26 | return syscall.AF_INET |
| 27 | } |
| 28 | if a.IP.To4() != nil { |
| 29 | return syscall.AF_INET |
| 30 | } |
| 31 | return syscall.AF_INET6 |
| 32 | } |
| 33 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 34 | func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) { |
Mikio Hara | 8a7def2 | 2013-08-03 13:32:22 +0900 | [diff] [blame] | 35 | if a == nil { |
| 36 | return nil, nil |
| 37 | } |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 38 | return ipToSockaddr(family, a.IP, a.Port, a.Zone) |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 39 | } |
| 40 | |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 41 | // UDPConn is the implementation of the Conn and PacketConn interfaces |
| 42 | // for UDP network connections. |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 43 | type UDPConn struct { |
Dave Cheney | f72c828 | 2012-04-27 22:17:08 +1000 | [diff] [blame] | 44 | conn |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 45 | } |
| 46 | |
Dave Cheney | f72c828 | 2012-04-27 22:17:08 +1000 | [diff] [blame] | 47 | func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 48 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 49 | // ReadFromUDP reads a UDP packet from c, copying the payload into b. |
| 50 | // It returns the number of bytes copied into b and the return address |
| 51 | // that was on the packet. |
| 52 | // |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 53 | // ReadFromUDP can be made to time out and return an error with |
| 54 | // Timeout() == true after a fixed time limit; see SetDeadline and |
| 55 | // SetReadDeadline. |
Mikio Hara | ec11444 | 2015-04-16 23:10:56 +0900 | [diff] [blame] | 56 | func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 57 | if !c.ok() { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 58 | return 0, nil, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 59 | } |
Mikio Hara | ec11444 | 2015-04-16 23:10:56 +0900 | [diff] [blame] | 60 | var addr *UDPAddr |
Ian Lance Taylor | 7d299d0 | 2014-04-02 17:06:51 -0700 | [diff] [blame] | 61 | n, sa, err := c.fd.readFrom(b) |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 62 | switch sa := sa.(type) { |
| 63 | case *syscall.SockaddrInet4: |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 64 | addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 65 | case *syscall.SockaddrInet6: |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 66 | addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 67 | } |
Mikio Hara | ec11444 | 2015-04-16 23:10:56 +0900 | [diff] [blame] | 68 | if err != nil { |
| 69 | err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err} |
| 70 | } |
| 71 | return n, addr, err |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 72 | } |
| 73 | |
Mikio Hara | 3d400db | 2012-01-29 19:11:05 +0900 | [diff] [blame] | 74 | // ReadFrom implements the PacketConn ReadFrom method. |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 75 | func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 76 | if !c.ok() { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 77 | return 0, nil, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 78 | } |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 79 | n, addr, err := c.ReadFromUDP(b) |
Paul Marks | a5dec38 | 2015-04-01 15:17:09 -0700 | [diff] [blame] | 80 | if addr == nil { |
| 81 | return n, nil, err |
| 82 | } |
| 83 | return n, addr, err |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 84 | } |
| 85 | |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 86 | // ReadMsgUDP reads a packet from c, copying the payload into b and |
Robert Griesemer | 0ad265d | 2013-03-20 16:32:37 -0700 | [diff] [blame] | 87 | // the associated out-of-band data into oob. It returns the number |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 88 | // of bytes copied into b, the number of bytes copied into oob, the |
| 89 | // flags that were set on the packet and the source address of the |
| 90 | // packet. |
| 91 | func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) { |
| 92 | if !c.ok() { |
| 93 | return 0, 0, 0, nil, syscall.EINVAL |
| 94 | } |
| 95 | var sa syscall.Sockaddr |
Ian Lance Taylor | 7d299d0 | 2014-04-02 17:06:51 -0700 | [diff] [blame] | 96 | n, oobn, flags, sa, err = c.fd.readMsg(b, oob) |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 97 | switch sa := sa.(type) { |
| 98 | case *syscall.SockaddrInet4: |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 99 | addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port} |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 100 | case *syscall.SockaddrInet6: |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 101 | addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))} |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 102 | } |
Mikio Hara | ec11444 | 2015-04-16 23:10:56 +0900 | [diff] [blame] | 103 | if err != nil { |
| 104 | err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err} |
| 105 | } |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 106 | return |
| 107 | } |
| 108 | |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 109 | // WriteToUDP writes a UDP packet to addr via c, copying the payload |
| 110 | // from b. |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 111 | // |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 112 | // WriteToUDP can be made to time out and return an error with |
| 113 | // Timeout() == true after a fixed time limit; see SetDeadline and |
| 114 | // SetWriteDeadline. On packet-oriented connections, write timeouts |
| 115 | // are rare. |
Mikio Hara | 77cb895 | 2012-01-24 02:59:43 +0900 | [diff] [blame] | 116 | func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 117 | if !c.ok() { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 118 | return 0, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 119 | } |
Mikio Hara | 974fa75 | 2012-01-27 01:31:42 +0900 | [diff] [blame] | 120 | if c.fd.isConnected { |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 121 | return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} |
Mikio Hara | 974fa75 | 2012-01-27 01:31:42 +0900 | [diff] [blame] | 122 | } |
Mikio Hara | 7917b88 | 2013-08-18 19:19:36 +0900 | [diff] [blame] | 123 | if addr == nil { |
| 124 | return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} |
| 125 | } |
Mikio Hara | 77cb895 | 2012-01-24 02:59:43 +0900 | [diff] [blame] | 126 | sa, err := addr.sockaddr(c.fd.family) |
| 127 | if err != nil { |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 128 | return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: err} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 129 | } |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 130 | n, err := c.fd.writeTo(b, sa) |
| 131 | if err != nil { |
| 132 | err = &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: err} |
| 133 | } |
| 134 | return n, err |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 135 | } |
| 136 | |
Mikio Hara | 3d400db | 2012-01-29 19:11:05 +0900 | [diff] [blame] | 137 | // WriteTo implements the PacketConn WriteTo method. |
Mikio Hara | 77cb895 | 2012-01-24 02:59:43 +0900 | [diff] [blame] | 138 | func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 139 | if !c.ok() { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 140 | return 0, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 141 | } |
| 142 | a, ok := addr.(*UDPAddr) |
| 143 | if !ok { |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 144 | return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: syscall.EINVAL} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 145 | } |
| 146 | return c.WriteToUDP(b, a) |
| 147 | } |
| 148 | |
Nicolas S. Dade | 263405e | 2015-02-04 18:05:53 -0800 | [diff] [blame] | 149 | // WriteMsgUDP writes a packet to addr via c if c isn't connected, or |
| 150 | // to c's remote destination address if c is connected (in which case |
| 151 | // addr must be nil). The payload is copied from b and the associated |
| 152 | // out-of-band data is copied from oob. It returns the number of |
| 153 | // payload and out-of-band bytes written. |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 154 | func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { |
| 155 | if !c.ok() { |
| 156 | return 0, 0, syscall.EINVAL |
| 157 | } |
Nicolas S. Dade | 263405e | 2015-02-04 18:05:53 -0800 | [diff] [blame] | 158 | if c.fd.isConnected && addr != nil { |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 159 | return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 160 | } |
Nicolas S. Dade | 263405e | 2015-02-04 18:05:53 -0800 | [diff] [blame] | 161 | if !c.fd.isConnected && addr == nil { |
Mikio Hara | 7917b88 | 2013-08-18 19:19:36 +0900 | [diff] [blame] | 162 | return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} |
| 163 | } |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 164 | var sa syscall.Sockaddr |
| 165 | sa, err = addr.sockaddr(c.fd.family) |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 166 | if err != nil { |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 167 | return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: err} |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 168 | } |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 169 | n, oobn, err = c.fd.writeMsg(b, oob, sa) |
| 170 | if err != nil { |
| 171 | err = &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: err} |
| 172 | } |
| 173 | return |
Mikio Hara | 4b9e841 | 2012-09-25 06:57:32 +0900 | [diff] [blame] | 174 | } |
| 175 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 176 | // DialUDP connects to the remote address raddr on the network net, |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 177 | // which must be "udp", "udp4", or "udp6". If laddr is not nil, it is |
| 178 | // used as the local address for the connection. |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 179 | func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 180 | switch net { |
| 181 | case "udp", "udp4", "udp6": |
| 182 | default: |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 183 | return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 184 | } |
| 185 | if raddr == nil { |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 186 | return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 187 | } |
Mikio Hara | 3b961bf | 2013-08-22 10:33:06 +0900 | [diff] [blame] | 188 | return dialUDP(net, laddr, raddr, noDeadline) |
| 189 | } |
| 190 | |
| 191 | func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) { |
Mikio Hara | 5c055e7 | 2014-08-05 06:10:46 +0900 | [diff] [blame] | 192 | fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial") |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 193 | if err != nil { |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 194 | return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 195 | } |
| 196 | return newUDPConn(fd), nil |
| 197 | } |
| 198 | |
Mikio Hara | 245dc62 | 2013-03-29 15:06:43 +0900 | [diff] [blame] | 199 | // ListenUDP listens for incoming UDP packets addressed to the local |
| 200 | // address laddr. Net must be "udp", "udp4", or "udp6". If laddr has |
| 201 | // a port of 0, ListenUDP will choose an available port. |
| 202 | // The LocalAddr method of the returned UDPConn can be used to |
| 203 | // discover the port. The returned connection's ReadFrom and WriteTo |
| 204 | // methods can be used to receive and send UDP packets with per-packet |
| 205 | // addressing. |
Mikio Hara | 77cb895 | 2012-01-24 02:59:43 +0900 | [diff] [blame] | 206 | func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 207 | switch net { |
| 208 | case "udp", "udp4", "udp6": |
| 209 | default: |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 210 | return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 211 | } |
| 212 | if laddr == nil { |
Mikio Hara | 677c6e6 | 2012-11-13 12:56:28 +0900 | [diff] [blame] | 213 | laddr = &UDPAddr{} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 214 | } |
Mikio Hara | 5c055e7 | 2014-08-05 06:10:46 +0900 | [diff] [blame] | 215 | fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen") |
Mikio Hara | 77cb895 | 2012-01-24 02:59:43 +0900 | [diff] [blame] | 216 | if err != nil { |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 217 | return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 218 | } |
| 219 | return newUDPConn(fd), nil |
| 220 | } |
| 221 | |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 222 | // ListenMulticastUDP listens for incoming multicast UDP packets |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 223 | // addressed to the group address gaddr on ifi, which specifies the |
| 224 | // interface to join. ListenMulticastUDP uses default multicast |
| 225 | // interface if ifi is nil. |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 226 | func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { |
| 227 | switch net { |
| 228 | case "udp", "udp4", "udp6": |
| 229 | default: |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 230 | return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: UnknownNetworkError(net)} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 231 | } |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 232 | if gaddr == nil || gaddr.IP == nil { |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 233 | return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 234 | } |
Mikio Hara | 5c055e7 | 2014-08-05 06:10:46 +0900 | [diff] [blame] | 235 | fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen") |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 236 | if err != nil { |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 237 | return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: err} |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 238 | } |
| 239 | c := newUDPConn(fd) |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 240 | if ip4 := gaddr.IP.To4(); ip4 != nil { |
| 241 | if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 242 | c.Close() |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 243 | return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: ip4}, Err: err} |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 244 | } |
| 245 | } else { |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 246 | if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 247 | c.Close() |
Mikio Hara | e4bb139 | 2013-08-28 19:51:02 +0900 | [diff] [blame] | 248 | return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: gaddr.IP}, Err: err} |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 249 | } |
| 250 | } |
| 251 | return c, nil |
Mikio Hara | fca5082 | 2011-08-18 12:22:02 -0400 | [diff] [blame] | 252 | } |
| 253 | |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 254 | func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error { |
| 255 | if ifi != nil { |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 256 | if err := setIPv4MulticastInterface(c.fd, ifi); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 257 | return err |
| 258 | } |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 259 | } |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 260 | if err := setIPv4MulticastLoopback(c.fd, false); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 261 | return err |
Mikio Hara | fca5082 | 2011-08-18 12:22:02 -0400 | [diff] [blame] | 262 | } |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 263 | if err := joinIPv4Group(c.fd, ifi, ip); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 264 | return err |
| 265 | } |
| 266 | return nil |
| 267 | } |
| 268 | |
| 269 | func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error { |
| 270 | if ifi != nil { |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 271 | if err := setIPv6MulticastInterface(c.fd, ifi); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 272 | return err |
| 273 | } |
| 274 | } |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 275 | if err := setIPv6MulticastLoopback(c.fd, false); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 276 | return err |
| 277 | } |
Mikio Hara | 6d725e9 | 2013-01-15 08:53:12 +0900 | [diff] [blame] | 278 | if err := joinIPv6Group(c.fd, ifi, ip); err != nil { |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 279 | return err |
| 280 | } |
| 281 | return nil |
Mikio Hara | fca5082 | 2011-08-18 12:22:02 -0400 | [diff] [blame] | 282 | } |