func listen(netw, addr string) (fd int, err error) { var ( family int socktype int protocol int sockaddr syscall.Sockaddr ) netAddr, err := ResolveAddr(netw, addr) if err != nil { return -1, err } switch netAddr.(type) { case *net.TCPAddr, *net.UDPAddr: default: return -1, ErrUnsupportedProtocol } family = sockaddrnet.NetAddrAF(netAddr) protocol = sockaddrnet.NetAddrIPPROTO(netAddr) sockaddr = sockaddrnet.NetAddrToSockaddr(netAddr) socktype = sockaddrnet.NetAddrSOCK(netAddr) if fd, err = socket(family, socktype, protocol); err != nil { return -1, err } if err = syscall.Bind(fd, sockaddr); err != nil { syscall.Close(fd) return -1, err } if protocol == syscall.IPPROTO_TCP { // by default golang/net sets TCP no delay to true. if err = setNoDelay(fd, true); err != nil { syscall.Close(fd) return -1, err } } if err = syscall.SetNonblock(fd, true); err != nil { syscall.Close(fd) return -1, err } return fd, nil }
func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { var ( fd int lfamily int rfamily int socktype int lprotocol int rprotocol int file *os.File deadline time.Time remoteSockaddr syscall.Sockaddr localSockaddr syscall.Sockaddr ) netAddr, err := ResolveAddr(netw, addr) if err != nil { return nil, err } switch netAddr.(type) { case *net.TCPAddr, *net.UDPAddr: default: return nil, ErrUnsupportedProtocol } switch { case !dialer.Deadline.IsZero(): deadline = dialer.Deadline case dialer.Timeout != 0: deadline = time.Now().Add(dialer.Timeout) } localSockaddr = sockaddrnet.NetAddrToSockaddr(dialer.LocalAddr) remoteSockaddr = sockaddrnet.NetAddrToSockaddr(netAddr) rfamily = sockaddrnet.NetAddrAF(netAddr) rprotocol = sockaddrnet.NetAddrIPPROTO(netAddr) socktype = sockaddrnet.NetAddrSOCK(netAddr) if dialer.LocalAddr != nil { switch dialer.LocalAddr.(type) { case *net.TCPAddr, *net.UDPAddr: default: return nil, ErrUnsupportedProtocol } // check family and protocols match. lfamily = sockaddrnet.NetAddrAF(dialer.LocalAddr) lprotocol = sockaddrnet.NetAddrIPPROTO(dialer.LocalAddr) if lfamily != rfamily && lprotocol != rfamily { return nil, &net.AddrError{Err: "unexpected address type", Addr: netAddr.String()} } } // look at dialTCP in http://golang.org/src/net/tcpsock_posix.go .... ! // here we just try again 3 times. for i := 0; i < 3; i++ { if !deadline.IsZero() && deadline.Before(time.Now()) { err = errTimeout break } if fd, err = socket(rfamily, socktype, rprotocol); err != nil { return nil, err } if localSockaddr != nil { if err = syscall.Bind(fd, localSockaddr); err != nil { syscall.Close(fd) return nil, err } } if err = syscall.SetNonblock(fd, true); err != nil { syscall.Close(fd) return nil, err } if err = connect(fd, remoteSockaddr, deadline); err != nil { syscall.Close(fd) continue // try again. } break } if err != nil { return nil, err } if rprotocol == syscall.IPPROTO_TCP { // by default golang/net sets TCP no delay to true. if err = setNoDelay(fd, true); err != nil { syscall.Close(fd) return nil, err } } // File Name get be nil file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid())) if c, err = net.FileConn(file); err != nil { syscall.Close(fd) return nil, err } if err = file.Close(); err != nil { syscall.Close(fd) c.Close() return nil, err } // c = wrapConnWithRemoteAddr(c, netAddr) return c, err }