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