file_plan9.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. fd, err := syscall.Dup(int(f.Fd()), -1)
  47. if err != nil {
  48. return nil, os.NewSyscallError("dup", err)
  49. }
  50. defer close(fd)
  51. dir := netdir + "/" + comp[n-2]
  52. ctl = os.NewFile(uintptr(fd), dir+"/"+file)
  53. ctl.Seek(0, io.SeekStart)
  54. var buf [16]byte
  55. n, err := ctl.Read(buf[:])
  56. if err != nil {
  57. return nil, err
  58. }
  59. name = string(buf[:n])
  60. default:
  61. if len(comp) < 4 {
  62. return nil, errors.New("could not find control file for connection")
  63. }
  64. dir := netdir + "/" + comp[1] + "/" + name
  65. ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0)
  66. if err != nil {
  67. return nil, err
  68. }
  69. defer close(int(ctl.Fd()))
  70. }
  71. dir := netdir + "/" + comp[1] + "/" + name
  72. laddr, err := readPlan9Addr(comp[1], dir+"/local")
  73. if err != nil {
  74. return nil, err
  75. }
  76. return newFD(comp[1], name, nil, ctl, nil, laddr, nil)
  77. }
  78. func fileConn(f *os.File) (Conn, error) {
  79. fd, err := newFileFD(f)
  80. if err != nil {
  81. return nil, err
  82. }
  83. if !fd.ok() {
  84. return nil, syscall.EINVAL
  85. }
  86. fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
  87. if err != nil {
  88. return nil, err
  89. }
  90. switch fd.laddr.(type) {
  91. case *TCPAddr:
  92. return newTCPConn(fd), nil
  93. case *UDPAddr:
  94. return newUDPConn(fd), nil
  95. }
  96. return nil, syscall.EPLAN9
  97. }
  98. func fileListener(f *os.File) (Listener, error) {
  99. fd, err := newFileFD(f)
  100. if err != nil {
  101. return nil, err
  102. }
  103. switch fd.laddr.(type) {
  104. case *TCPAddr:
  105. default:
  106. return nil, syscall.EPLAN9
  107. }
  108. // check that file corresponds to a listener
  109. s, err := fd.status(len("Listen"))
  110. if err != nil {
  111. return nil, err
  112. }
  113. if s != "Listen" {
  114. return nil, errors.New("file does not represent a listener")
  115. }
  116. return &TCPListener{fd: fd}, nil
  117. }
  118. func filePacketConn(f *os.File) (PacketConn, error) {
  119. return nil, syscall.EPLAN9
  120. }