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 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 5 | package net |
| 6 | |
| 7 | import ( |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 8 | "errors" |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 9 | "os" |
Mikio Hara | 03d4c7c | 2012-02-17 10:59:30 +0900 | [diff] [blame] | 10 | "syscall" |
Brad Fitzpatrick | ef6806f | 2012-11-08 10:35:16 -0600 | [diff] [blame] | 11 | "time" |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 12 | ) |
| 13 | |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 14 | // UDPConn is the implementation of the Conn and PacketConn interfaces |
| 15 | // for UDP network connections. |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 16 | type UDPConn struct { |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 17 | conn |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 18 | } |
| 19 | |
Mikio Hara | e2c453e | 2013-03-31 16:47:54 +0900 | [diff] [blame] | 20 | func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } |
Akshat Kumar | 66b69a1 | 2013-02-19 17:11:17 -0800 | [diff] [blame] | 21 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 22 | // ReadFromUDP reads a UDP packet from c, copying the payload into b. |
| 23 | // It returns the number of bytes copied into b and the return address |
| 24 | // that was on the packet. |
| 25 | // |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 26 | // ReadFromUDP can be made to time out and return an error with |
| 27 | // Timeout() == true after a fixed time limit; see SetDeadline and |
| 28 | // SetReadDeadline. |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 29 | func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { |
Akshat Kumar | 66b69a1 | 2013-02-19 17:11:17 -0800 | [diff] [blame] | 30 | if !c.ok() || c.fd.data == nil { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 31 | return 0, nil, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 32 | } |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 33 | buf := make([]byte, udpHeaderSize+len(b)) |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 34 | m, err := c.fd.data.Read(buf) |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 35 | if err != nil { |
Mikio Hara | afd2d2b | 2015-04-21 22:53:47 +0900 | [diff] [blame] | 36 | return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 37 | } |
| 38 | if m < udpHeaderSize { |
Mikio Hara | afd2d2b | 2015-04-21 22:53:47 +0900 | [diff] [blame] | 39 | return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 40 | } |
| 41 | buf = buf[:m] |
| 42 | |
| 43 | h, buf := unmarshalUDPHeader(buf) |
| 44 | n = copy(b, buf) |
Mikio Hara | e8cf49f | 2012-11-27 00:45:42 +0900 | [diff] [blame] | 45 | return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 46 | } |
| 47 | |
Mikio Hara | 3d400db | 2012-01-29 19:11:05 +0900 | [diff] [blame] | 48 | // ReadFrom implements the PacketConn ReadFrom method. |
Anthony Martin | 253ed02 | 2012-11-30 11:41:50 -0800 | [diff] [blame] | 49 | func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 50 | if !c.ok() { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 51 | return 0, nil, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 52 | } |
| 53 | return c.ReadFromUDP(b) |
| 54 | } |
| 55 | |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 56 | // ReadMsgUDP reads a packet from c, copying the payload into b and |
Robert Griesemer | 0ad265d | 2013-03-20 16:32:37 -0700 | [diff] [blame] | 57 | // the associated out-of-band data into oob. It returns the number |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 58 | // of bytes copied into b, the number of bytes copied into oob, the |
| 59 | // flags that were set on the packet and the source address of the |
| 60 | // packet. |
| 61 | func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) { |
Mikio Hara | afd2d2b | 2015-04-21 22:53:47 +0900 | [diff] [blame] | 62 | return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | // WriteToUDP writes a UDP packet to addr via c, copying the payload |
| 66 | // from b. |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 67 | // |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 68 | // WriteToUDP can be made to time out and return an error with |
| 69 | // Timeout() == true after a fixed time limit; see SetDeadline and |
| 70 | // SetWriteDeadline. On packet-oriented connections, write timeouts |
| 71 | // are rare. |
Anthony Martin | 253ed02 | 2012-11-30 11:41:50 -0800 | [diff] [blame] | 72 | func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { |
Akshat Kumar | 66b69a1 | 2013-02-19 17:11:17 -0800 | [diff] [blame] | 73 | if !c.ok() || c.fd.data == nil { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 74 | return 0, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 75 | } |
Mikio Hara | 7917b88 | 2013-08-18 19:19:36 +0900 | [diff] [blame] | 76 | if addr == nil { |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 77 | return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} |
Mikio Hara | 7917b88 | 2013-08-18 19:19:36 +0900 | [diff] [blame] | 78 | } |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 79 | h := new(udpHeader) |
| 80 | h.raddr = addr.IP.To16() |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 81 | h.laddr = c.fd.laddr.(*UDPAddr).IP.To16() |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 82 | h.ifcaddr = IPv6zero // ignored (receive only) |
| 83 | h.rport = uint16(addr.Port) |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 84 | h.lport = uint16(c.fd.laddr.(*UDPAddr).Port) |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 85 | |
| 86 | buf := make([]byte, udpHeaderSize+len(b)) |
| 87 | i := copy(buf, h.Bytes()) |
| 88 | copy(buf[i:], b) |
Mikio Hara | 2757554 | 2015-04-21 23:15:12 +0900 | [diff] [blame] | 89 | if _, err := c.fd.data.Write(buf); err != nil { |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 90 | return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} |
Mikio Hara | 11b5f98 | 2015-04-16 11:26:44 +0900 | [diff] [blame] | 91 | } |
Mikio Hara | 2757554 | 2015-04-21 23:15:12 +0900 | [diff] [blame] | 92 | return len(b), nil |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 93 | } |
| 94 | |
Mikio Hara | 3d400db | 2012-01-29 19:11:05 +0900 | [diff] [blame] | 95 | // WriteTo implements the PacketConn WriteTo method. |
Anthony Martin | 253ed02 | 2012-11-30 11:41:50 -0800 | [diff] [blame] | 96 | func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 97 | if !c.ok() { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 98 | return 0, syscall.EINVAL |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 99 | } |
| 100 | a, ok := addr.(*UDPAddr) |
| 101 | if !ok { |
Mikio Hara | afd2d2b | 2015-04-21 22:53:47 +0900 | [diff] [blame] | 102 | return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 103 | } |
| 104 | return c.WriteToUDP(b, a) |
| 105 | } |
| 106 | |
Mikio Hara | a9a6757 | 2015-02-10 19:27:29 +0900 | [diff] [blame] | 107 | // WriteMsgUDP writes a packet to addr via c if c isn't connected, or |
| 108 | // to c's remote destination address if c is connected (in which case |
| 109 | // addr must be nil). The payload is copied from b and the associated |
| 110 | // out-of-band data is copied from oob. It returns the number of |
| 111 | // payload and out-of-band bytes written. |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 112 | func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 113 | return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 114 | } |
| 115 | |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 116 | // DialUDP connects to the remote address raddr on the network net, |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 117 | // which must be "udp", "udp4", or "udp6". If laddr is not nil, it is |
| 118 | // used as the local address for the connection. |
Anthony Martin | 253ed02 | 2012-11-30 11:41:50 -0800 | [diff] [blame] | 119 | func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) { |
Brad Fitzpatrick | ef6806f | 2012-11-08 10:35:16 -0600 | [diff] [blame] | 120 | return dialUDP(net, laddr, raddr, noDeadline) |
| 121 | } |
| 122 | |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 123 | func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) { |
Brad Fitzpatrick | ef6806f | 2012-11-08 10:35:16 -0600 | [diff] [blame] | 124 | if !deadline.IsZero() { |
| 125 | panic("net.dialUDP: deadline not implemented on Plan 9") |
| 126 | } |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 127 | switch net { |
| 128 | case "udp", "udp4", "udp6": |
| 129 | default: |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 130 | return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 131 | } |
| 132 | if raddr == nil { |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 133 | return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 134 | } |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 135 | fd, err := dialPlan9(net, laddr, raddr) |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 136 | if err != nil { |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 137 | return nil, err |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 138 | } |
Akshat Kumar | 66b69a1 | 2013-02-19 17:11:17 -0800 | [diff] [blame] | 139 | return newUDPConn(fd), nil |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | const udpHeaderSize = 16*3 + 2*2 |
| 143 | |
| 144 | type udpHeader struct { |
| 145 | raddr, laddr, ifcaddr IP |
| 146 | rport, lport uint16 |
| 147 | } |
| 148 | |
| 149 | func (h *udpHeader) Bytes() []byte { |
| 150 | b := make([]byte, udpHeaderSize) |
| 151 | i := 0 |
| 152 | i += copy(b[i:i+16], h.raddr) |
| 153 | i += copy(b[i:i+16], h.laddr) |
| 154 | i += copy(b[i:i+16], h.ifcaddr) |
| 155 | b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2 |
| 156 | b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2 |
| 157 | return b |
| 158 | } |
| 159 | |
| 160 | func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) { |
| 161 | h := new(udpHeader) |
| 162 | h.raddr, b = IP(b[:16]), b[16:] |
| 163 | h.laddr, b = IP(b[:16]), b[16:] |
| 164 | h.ifcaddr, b = IP(b[:16]), b[16:] |
| 165 | h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:] |
| 166 | h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:] |
| 167 | return h, b |
| 168 | } |
| 169 | |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 170 | // ListenUDP listens for incoming UDP packets addressed to the local |
Mikio Hara | 245dc62 | 2013-03-29 15:06:43 +0900 | [diff] [blame] | 171 | // address laddr. Net must be "udp", "udp4", or "udp6". If laddr has |
| 172 | // a port of 0, ListenUDP will choose an available port. |
| 173 | // The LocalAddr method of the returned UDPConn can be used to |
| 174 | // discover the port. The returned connection's ReadFrom and WriteTo |
Mikio Hara | d6665bc | 2012-09-26 16:11:49 +0900 | [diff] [blame] | 175 | // methods can be used to receive and send UDP packets with per-packet |
| 176 | // addressing. |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 177 | func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 178 | switch net { |
| 179 | case "udp", "udp4", "udp6": |
| 180 | default: |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 181 | return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 182 | } |
| 183 | if laddr == nil { |
Mikio Hara | 677c6e6 | 2012-11-13 12:56:28 +0900 | [diff] [blame] | 184 | laddr = &UDPAddr{} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 185 | } |
| 186 | l, err := listenPlan9(net, laddr) |
| 187 | if err != nil { |
Mikio Hara | 306afc7 | 2012-11-13 16:18:37 +0900 | [diff] [blame] | 188 | return nil, err |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 189 | } |
| 190 | _, err = l.ctl.WriteString("headers") |
| 191 | if err != nil { |
Mikio Hara | afd2d2b | 2015-04-21 22:53:47 +0900 | [diff] [blame] | 192 | return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 193 | } |
Akshat Kumar | 66b69a1 | 2013-02-19 17:11:17 -0800 | [diff] [blame] | 194 | l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0) |
| 195 | if err != nil { |
Mikio Hara | afd2d2b | 2015-04-21 22:53:47 +0900 | [diff] [blame] | 196 | return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} |
Akshat Kumar | 66b69a1 | 2013-02-19 17:11:17 -0800 | [diff] [blame] | 197 | } |
Jeff Sickel | 5212573 | 2014-01-22 22:21:53 +0100 | [diff] [blame] | 198 | fd, err := l.netFD() |
| 199 | return newUDPConn(fd), err |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 200 | } |
| 201 | |
Mikio Hara | 2f63afd | 2012-02-01 01:53:26 +0900 | [diff] [blame] | 202 | // ListenMulticastUDP listens for incoming multicast UDP packets |
Mikio Hara | 49894be | 2015-05-07 19:10:29 +0900 | [diff] [blame] | 203 | // addressed to the group address gaddr on the interface ifi. |
| 204 | // Network must be "udp", "udp4" or "udp6". |
| 205 | // ListenMulticastUDP uses the system-assigned multicast interface |
| 206 | // when ifi is nil, although this is not recommended because the |
| 207 | // assignment depends on platforms and sometimes it might require |
| 208 | // routing configuration. |
| 209 | // |
| 210 | // ListenMulticastUDP is just for convenience of simple, small |
| 211 | // applications. There are golang.org/x/net/ipv4 and |
| 212 | // golang.org/x/net/ipv6 packages for general purpose uses. |
| 213 | func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { |
Mikio Hara | 22829bd | 2015-05-30 07:33:16 +0900 | [diff] [blame] | 214 | return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: syscall.EPLAN9} |
Fazlul Shahriar | 0f7bc92 | 2011-08-17 13:28:29 -0400 | [diff] [blame] | 215 | } |