|  | // Copyright 2011 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package net | 
|  |  | 
|  | import ( | 
|  | "errors" | 
|  | "io" | 
|  | "os" | 
|  | "syscall" | 
|  | ) | 
|  |  | 
|  | func (fd *netFD) status(ln int) (string, error) { | 
|  | if !fd.ok() { | 
|  | return "", syscall.EINVAL | 
|  | } | 
|  |  | 
|  | status, err := os.Open(fd.dir + "/status") | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  | defer status.Close() | 
|  | buf := make([]byte, ln) | 
|  | n, err := io.ReadFull(status, buf[:]) | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  | return string(buf[:n]), nil | 
|  | } | 
|  |  | 
|  | func newFileFD(f *os.File) (net *netFD, err error) { | 
|  | var ctl *os.File | 
|  | close := func(fd int) { | 
|  | if err != nil { | 
|  | syscall.Close(fd) | 
|  | } | 
|  | } | 
|  |  | 
|  | path, err := syscall.Fd2path(int(f.Fd())) | 
|  | if err != nil { | 
|  | return nil, os.NewSyscallError("fd2path", err) | 
|  | } | 
|  | comp := splitAtBytes(path, "/") | 
|  | n := len(comp) | 
|  | if n < 3 || comp[0][0:3] != "net" { | 
|  | return nil, syscall.EPLAN9 | 
|  | } | 
|  |  | 
|  | name := comp[2] | 
|  | switch file := comp[n-1]; file { | 
|  | case "ctl", "clone": | 
|  | fd, err := syscall.Dup(int(f.Fd()), -1) | 
|  | if err != nil { | 
|  | return nil, os.NewSyscallError("dup", err) | 
|  | } | 
|  | defer close(fd) | 
|  |  | 
|  | dir := netdir + "/" + comp[n-2] | 
|  | ctl = os.NewFile(uintptr(fd), dir+"/"+file) | 
|  | ctl.Seek(0, io.SeekStart) | 
|  | var buf [16]byte | 
|  | n, err := ctl.Read(buf[:]) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | name = string(buf[:n]) | 
|  | default: | 
|  | if len(comp) < 4 { | 
|  | return nil, errors.New("could not find control file for connection") | 
|  | } | 
|  | dir := netdir + "/" + comp[1] + "/" + name | 
|  | ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | defer close(int(ctl.Fd())) | 
|  | } | 
|  | dir := netdir + "/" + comp[1] + "/" + name | 
|  | laddr, err := readPlan9Addr(comp[1], dir+"/local") | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | return newFD(comp[1], name, nil, ctl, nil, laddr, nil) | 
|  | } | 
|  |  | 
|  | func fileConn(f *os.File) (Conn, error) { | 
|  | fd, err := newFileFD(f) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | if !fd.ok() { | 
|  | return nil, syscall.EINVAL | 
|  | } | 
|  |  | 
|  | fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | switch fd.laddr.(type) { | 
|  | case *TCPAddr: | 
|  | return newTCPConn(fd), nil | 
|  | case *UDPAddr: | 
|  | return newUDPConn(fd), nil | 
|  | } | 
|  | return nil, syscall.EPLAN9 | 
|  | } | 
|  |  | 
|  | func fileListener(f *os.File) (Listener, error) { | 
|  | fd, err := newFileFD(f) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | switch fd.laddr.(type) { | 
|  | case *TCPAddr: | 
|  | default: | 
|  | return nil, syscall.EPLAN9 | 
|  | } | 
|  |  | 
|  | // check that file corresponds to a listener | 
|  | s, err := fd.status(len("Listen")) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | if s != "Listen" { | 
|  | return nil, errors.New("file does not represent a listener") | 
|  | } | 
|  |  | 
|  | return &TCPListener{fd}, nil | 
|  | } | 
|  |  | 
|  | func filePacketConn(f *os.File) (PacketConn, error) { | 
|  | return nil, syscall.EPLAN9 | 
|  | } |