file_unix.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Copyright 2011 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris
  5. package net
  6. import (
  7. "os"
  8. "syscall"
  9. )
  10. func newFileFD(f *os.File) (*netFD, error) {
  11. fd, err := dupCloseOnExec(int(f.Fd()))
  12. if err != nil {
  13. return nil, os.NewSyscallError("dup", err)
  14. }
  15. if err = syscall.SetNonblock(fd, true); err != nil {
  16. closesocket(fd)
  17. return nil, err
  18. }
  19. sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
  20. if err != nil {
  21. closesocket(fd)
  22. return nil, os.NewSyscallError("getsockopt", err)
  23. }
  24. family := syscall.AF_UNSPEC
  25. toAddr := sockaddrToTCP
  26. lsa, _ := syscall.Getsockname(fd)
  27. switch lsa.(type) {
  28. default:
  29. closesocket(fd)
  30. return nil, syscall.EINVAL
  31. case *syscall.SockaddrInet4:
  32. family = syscall.AF_INET
  33. if sotype == syscall.SOCK_DGRAM {
  34. toAddr = sockaddrToUDP
  35. } else if sotype == syscall.SOCK_RAW {
  36. toAddr = sockaddrToIP
  37. }
  38. case *syscall.SockaddrInet6:
  39. family = syscall.AF_INET6
  40. if sotype == syscall.SOCK_DGRAM {
  41. toAddr = sockaddrToUDP
  42. } else if sotype == syscall.SOCK_RAW {
  43. toAddr = sockaddrToIP
  44. }
  45. case *syscall.SockaddrUnix:
  46. family = syscall.AF_UNIX
  47. toAddr = sockaddrToUnix
  48. if sotype == syscall.SOCK_DGRAM {
  49. toAddr = sockaddrToUnixgram
  50. } else if sotype == syscall.SOCK_SEQPACKET {
  51. toAddr = sockaddrToUnixpacket
  52. }
  53. }
  54. laddr := toAddr(lsa)
  55. rsa, _ := syscall.Getpeername(fd)
  56. raddr := toAddr(rsa)
  57. netfd, err := newFD(fd, family, sotype, laddr.Network())
  58. if err != nil {
  59. closesocket(fd)
  60. return nil, err
  61. }
  62. if err := netfd.init(); err != nil {
  63. netfd.Close()
  64. return nil, err
  65. }
  66. netfd.setAddr(laddr, raddr)
  67. return netfd, nil
  68. }
  69. // FileConn returns a copy of the network connection corresponding to
  70. // the open file f. It is the caller's responsibility to close f when
  71. // finished. Closing c does not affect f, and closing f does not
  72. // affect c.
  73. func FileConn(f *os.File) (c Conn, err error) {
  74. fd, err := newFileFD(f)
  75. if err != nil {
  76. return nil, err
  77. }
  78. switch fd.laddr.(type) {
  79. case *TCPAddr:
  80. return newTCPConn(fd), nil
  81. case *UDPAddr:
  82. return newUDPConn(fd), nil
  83. case *IPAddr:
  84. return newIPConn(fd), nil
  85. case *UnixAddr:
  86. return newUnixConn(fd), nil
  87. }
  88. fd.Close()
  89. return nil, syscall.EINVAL
  90. }
  91. // FileListener returns a copy of the network listener corresponding
  92. // to the open file f. It is the caller's responsibility to close l
  93. // when finished. Closing l does not affect f, and closing f does not
  94. // affect l.
  95. func FileListener(f *os.File) (l Listener, err error) {
  96. fd, err := newFileFD(f)
  97. if err != nil {
  98. return nil, err
  99. }
  100. switch laddr := fd.laddr.(type) {
  101. case *TCPAddr:
  102. return &TCPListener{fd}, nil
  103. case *UnixAddr:
  104. return &UnixListener{fd, laddr.Name}, nil
  105. }
  106. fd.Close()
  107. return nil, syscall.EINVAL
  108. }
  109. // FilePacketConn returns a copy of the packet network connection
  110. // corresponding to the open file f. It is the caller's
  111. // responsibility to close f when finished. Closing c does not affect
  112. // f, and closing f does not affect c.
  113. func FilePacketConn(f *os.File) (c PacketConn, err error) {
  114. fd, err := newFileFD(f)
  115. if err != nil {
  116. return nil, err
  117. }
  118. switch fd.laddr.(type) {
  119. case *UDPAddr:
  120. return newUDPConn(fd), nil
  121. case *IPAddr:
  122. return newIPConn(fd), nil
  123. case *UnixAddr:
  124. return newUnixConn(fd), nil
  125. }
  126. fd.Close()
  127. return nil, syscall.EINVAL
  128. }