github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/net/sock_cloexec.go (about)

     1  // Copyright 2013 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  // This file implements sysSocket and accept for platforms that
     6  // provide a fast path for setting SetNonblock and CloseOnExec.
     7  
     8  // +build freebsd linux
     9  
    10  package net
    11  
    12  import "syscall"
    13  
    14  // Wrapper around the socket system call that marks the returned file
    15  // descriptor as nonblocking and close-on-exec.
    16  func sysSocket(family, sotype, proto int) (int, error) {
    17  	s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
    18  	// On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were
    19  	// introduced in 2.6.27 kernel and on FreeBSD both flags were
    20  	// introduced in 10 kernel. If we get an EINVAL error on Linux
    21  	// or EPROTONOSUPPORT error on FreeBSD, fall back to using
    22  	// socket without them.
    23  	if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) {
    24  		return s, err
    25  	}
    26  
    27  	// See ../syscall/exec_unix.go for description of ForkLock.
    28  	syscall.ForkLock.RLock()
    29  	s, err = syscall.Socket(family, sotype, proto)
    30  	if err == nil {
    31  		syscall.CloseOnExec(s)
    32  	}
    33  	syscall.ForkLock.RUnlock()
    34  	if err != nil {
    35  		return -1, err
    36  	}
    37  	if err = syscall.SetNonblock(s, true); err != nil {
    38  		syscall.Close(s)
    39  		return -1, err
    40  	}
    41  	return s, nil
    42  }
    43  
    44  // Wrapper around the accept system call that marks the returned file
    45  // descriptor as nonblocking and close-on-exec.
    46  func accept(s int) (int, syscall.Sockaddr, error) {
    47  	ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
    48  	// On Linux the accept4 system call was introduced in 2.6.28
    49  	// kernel and on FreeBSD it was introduced in 10 kernel. If we
    50  	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
    51  	// error on Linux, fall back to using accept.
    52  	switch err {
    53  	default: // nil and errors other than the ones listed
    54  		return ns, sa, err
    55  	case syscall.ENOSYS: // syscall missing
    56  	case syscall.EINVAL: // some Linux use this instead of ENOSYS
    57  	case syscall.EACCES: // some Linux use this instead of ENOSYS
    58  	case syscall.EFAULT: // some Linux use this instead of ENOSYS
    59  	}
    60  
    61  	// See ../syscall/exec_unix.go for description of ForkLock.
    62  	// It is probably okay to hold the lock across syscall.Accept
    63  	// because we have put fd.sysfd into non-blocking mode.
    64  	// However, a call to the File method will put it back into
    65  	// blocking mode. We can't take that risk, so no use of ForkLock here.
    66  	ns, sa, err = syscall.Accept(s)
    67  	if err == nil {
    68  		syscall.CloseOnExec(ns)
    69  	}
    70  	if err != nil {
    71  		return -1, nil, err
    72  	}
    73  	if err = syscall.SetNonblock(ns, true); err != nil {
    74  		syscall.Close(ns)
    75  		return -1, nil, err
    76  	}
    77  	return ns, sa, nil
    78  }