2017-07-18 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / libgo / go / net / iprawsock_posix.go
blob16e65dcc2a864c0047595c39d72497a734e4debb
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 aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
7 package net
9 import (
10 "context"
11 "syscall"
14 func sockaddrToIP(sa syscall.Sockaddr) Addr {
15 switch sa := sa.(type) {
16 case *syscall.SockaddrInet4:
17 return &IPAddr{IP: sa.Addr[0:]}
18 case *syscall.SockaddrInet6:
19 return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
21 return nil
24 func (a *IPAddr) family() int {
25 if a == nil || len(a.IP) <= IPv4len {
26 return syscall.AF_INET
28 if a.IP.To4() != nil {
29 return syscall.AF_INET
31 return syscall.AF_INET6
34 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
35 if a == nil {
36 return nil, nil
38 return ipToSockaddr(family, a.IP, 0, a.Zone)
41 func (a *IPAddr) toLocal(net string) sockaddr {
42 return &IPAddr{loopbackIP(net), a.Zone}
45 func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
46 // TODO(cw,rsc): consider using readv if we know the family
47 // type to avoid the header trim/copy
48 var addr *IPAddr
49 n, sa, err := c.fd.readFrom(b)
50 switch sa := sa.(type) {
51 case *syscall.SockaddrInet4:
52 addr = &IPAddr{IP: sa.Addr[0:]}
53 n = stripIPv4Header(n, b)
54 case *syscall.SockaddrInet6:
55 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
57 return n, addr, err
60 func stripIPv4Header(n int, b []byte) int {
61 if len(b) < 20 {
62 return n
64 l := int(b[0]&0x0f) << 2
65 if 20 > l || l > len(b) {
66 return n
68 if b[0]>>4 != 4 {
69 return n
71 copy(b, b[l:])
72 return n - l
75 func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
76 var sa syscall.Sockaddr
77 n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
78 switch sa := sa.(type) {
79 case *syscall.SockaddrInet4:
80 addr = &IPAddr{IP: sa.Addr[0:]}
81 case *syscall.SockaddrInet6:
82 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
84 return
87 func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
88 if c.fd.isConnected {
89 return 0, ErrWriteToConnected
91 if addr == nil {
92 return 0, errMissingAddress
94 sa, err := addr.sockaddr(c.fd.family)
95 if err != nil {
96 return 0, err
98 return c.fd.writeTo(b, sa)
101 func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
102 if c.fd.isConnected {
103 return 0, 0, ErrWriteToConnected
105 if addr == nil {
106 return 0, 0, errMissingAddress
108 sa, err := addr.sockaddr(c.fd.family)
109 if err != nil {
110 return 0, 0, err
112 return c.fd.writeMsg(b, oob, sa)
115 func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
116 network, proto, err := parseNetwork(ctx, netProto)
117 if err != nil {
118 return nil, err
120 switch network {
121 case "ip", "ip4", "ip6":
122 default:
123 return nil, UnknownNetworkError(netProto)
125 if raddr == nil {
126 return nil, errMissingAddress
128 fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial")
129 if err != nil {
130 return nil, err
132 return newIPConn(fd), nil
135 func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) {
136 network, proto, err := parseNetwork(ctx, netProto)
137 if err != nil {
138 return nil, err
140 switch network {
141 case "ip", "ip4", "ip6":
142 default:
143 return nil, UnknownNetworkError(netProto)
145 fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen")
146 if err != nil {
147 return nil, err
149 return newIPConn(fd), nil