// 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, defaultTCPKeepAlive, testHookSetKeepAlive), 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: fd}, nil } func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.EPLAN9 }