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