sock_cloexec.go 2.6 KB

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