github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/net/iprawsock_posix.go (about) 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. 4 5 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows 6 7 package net 8 9 import ( 10 "context" 11 "syscall" 12 ) 13 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: zoneCache.name(int(sa.ZoneId))} 20 } 21 return nil 22 } 23 24 func (a *IPAddr) family() int { 25 if a == nil || len(a.IP) <= IPv4len { 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 34 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 35 if a == nil { 36 return nil, nil 37 } 38 return ipToSockaddr(family, a.IP, 0, a.Zone) 39 } 40 41 func (a *IPAddr) toLocal(net string) sockaddr { 42 return &IPAddr{loopbackIP(net), a.Zone} 43 } 44 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: zoneCache.name(int(sa.ZoneId))} 56 } 57 return n, addr, err 58 } 59 60 func stripIPv4Header(n int, b []byte) int { 61 if len(b) < 20 { 62 return n 63 } 64 l := int(b[0]&0x0f) << 2 65 if 20 > l || l > len(b) { 66 return n 67 } 68 if b[0]>>4 != 4 { 69 return n 70 } 71 copy(b, b[l:]) 72 return n - l 73 } 74 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: zoneCache.name(int(sa.ZoneId))} 83 } 84 return 85 } 86 87 func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) { 88 if c.fd.isConnected { 89 return 0, ErrWriteToConnected 90 } 91 if addr == nil { 92 return 0, errMissingAddress 93 } 94 sa, err := addr.sockaddr(c.fd.family) 95 if err != nil { 96 return 0, err 97 } 98 return c.fd.writeTo(b, sa) 99 } 100 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 104 } 105 if addr == nil { 106 return 0, 0, errMissingAddress 107 } 108 sa, err := addr.sockaddr(c.fd.family) 109 if err != nil { 110 return 0, 0, err 111 } 112 return c.fd.writeMsg(b, oob, sa) 113 } 114 115 func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) { 116 network, proto, err := parseNetwork(ctx, netProto, true) 117 if err != nil { 118 return nil, err 119 } 120 switch network { 121 case "ip", "ip4", "ip6": 122 default: 123 return nil, UnknownNetworkError(netProto) 124 } 125 if raddr == nil { 126 return nil, errMissingAddress 127 } 128 fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial") 129 if err != nil { 130 return nil, err 131 } 132 return newIPConn(fd), nil 133 } 134 135 func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) { 136 network, proto, err := parseNetwork(ctx, netProto, true) 137 if err != nil { 138 return nil, err 139 } 140 switch network { 141 case "ip", "ip4", "ip6": 142 default: 143 return nil, UnknownNetworkError(netProto) 144 } 145 fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen") 146 if err != nil { 147 return nil, err 148 } 149 return newIPConn(fd), nil 150 }