file_plan9.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. package net
  5. import (
  6. "errors"
  7. "io"
  8. "os"
  9. "syscall"
  10. )
  11. func (fd *netFD) status(ln int) (string, error) {
  12. if !fd.ok() {
  13. return "", syscall.EINVAL
  14. }
  15. status, err := os.Open(fd.dir + "/status")
  16. if err != nil {
  17. return "", err
  18. }
  19. defer status.Close()
  20. buf := make([]byte, ln)
  21. n, err := io.ReadFull(status, buf[:])
  22. if err != nil {
  23. return "", err
  24. }
  25. return string(buf[:n]), nil
  26. }
  27. func newFileFD(f *os.File) (net *netFD, err error) {
  28. var ctl *os.File
  29. close := func(fd int) {
  30. if err != nil {
  31. syscall.Close(fd)
  32. }
  33. }
  34. path, err := syscall.Fd2path(int(f.Fd()))
  35. if err != nil {
  36. return nil, os.NewSyscallError("fd2path", err)
  37. }
  38. comp := splitAtBytes(path, "/")
  39. n := len(comp)
  40. if n < 3 || comp[0][0:3] != "net" {
  41. return nil, syscall.EPLAN9
  42. }
  43. name := comp[2]
  44. switch file := comp[n-1]; file {
  45. case "ctl", "clone":
  46. syscall.ForkLock.RLock()
  47. fd, err := syscall.Dup(int(f.Fd()), -1)
  48. syscall.ForkLock.RUnlock()
  49. if err != nil {
  50. return nil, os.NewSyscallError("dup", err)
  51. }
  52. defer close(fd)
  53. dir := netdir + "/" + comp[n-2]
  54. ctl = os.NewFile(uintptr(fd), dir+"/"+file)
  55. ctl.Seek(0, 0)
  56. var buf [16]byte
  57. n, err := ctl.Read(buf[:])
  58. if err != nil {
  59. return nil, err
  60. }
  61. name = string(buf[:n])
  62. default:
  63. if len(comp) < 4 {
  64. return nil, errors.New("could not find control file for connection")
  65. }
  66. dir := netdir + "/" + comp[1] + "/" + name
  67. ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0)
  68. if err != nil {
  69. return nil, err
  70. }
  71. defer close(int(ctl.Fd()))
  72. }
  73. dir := netdir + "/" + comp[1] + "/" + name
  74. laddr, err := readPlan9Addr(comp[1], dir+"/local")
  75. if err != nil {
  76. return nil, err
  77. }
  78. return newFD(comp[1], name, ctl, nil, laddr, nil)
  79. }
  80. func newFileConn(f *os.File) (c Conn, err error) {
  81. fd, err := newFileFD(f)
  82. if err != nil {
  83. return nil, err
  84. }
  85. if !fd.ok() {
  86. return nil, syscall.EINVAL
  87. }
  88. fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
  89. if err != nil {
  90. return nil, err
  91. }
  92. switch fd.laddr.(type) {
  93. case *TCPAddr:
  94. return newTCPConn(fd), nil
  95. case *UDPAddr:
  96. return newUDPConn(fd), nil
  97. }
  98. return nil, syscall.EPLAN9
  99. }
  100. func newFileListener(f *os.File) (l Listener, err error) {
  101. fd, err := newFileFD(f)
  102. if err != nil {
  103. return nil, err
  104. }
  105. switch fd.laddr.(type) {
  106. case *TCPAddr:
  107. default:
  108. return nil, syscall.EPLAN9
  109. }
  110. // check that file corresponds to a listener
  111. s, err := fd.status(len("Listen"))
  112. if err != nil {
  113. return nil, err
  114. }
  115. if s != "Listen" {
  116. return nil, errors.New("file does not represent a listener")
  117. }
  118. return &TCPListener{fd}, nil
  119. }
  120. // FileConn returns a copy of the network connection corresponding to
  121. // the open file f. It is the caller's responsibility to close f when
  122. // finished. Closing c does not affect f, and closing f does not
  123. // affect c.
  124. func FileConn(f *os.File) (c Conn, err error) {
  125. return newFileConn(f)
  126. }
  127. // FileListener returns a copy of the network listener corresponding
  128. // to the open file f. It is the caller's responsibility to close l
  129. // when finished. Closing l does not affect f, and closing f does not
  130. // affect l.
  131. func FileListener(f *os.File) (l Listener, err error) {
  132. return newFileListener(f)
  133. }
  134. // FilePacketConn returns a copy of the packet network connection
  135. // corresponding to the open file f. It is the caller's
  136. // responsibility to close f when finished. Closing c does not affect
  137. // f, and closing f does not affect c.
  138. func FilePacketConn(f *os.File) (c PacketConn, err error) {
  139. return nil, syscall.EPLAN9
  140. }