Home | History | Annotate | Download | only in net
      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 }
    151