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