...

Source file src/net/file_plan9.go

     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: fd}, nil
   131	}
   132	
   133	func filePacketConn(f *os.File) (PacketConn, error) {
   134		return nil, syscall.EPLAN9
   135	}
   136	

View as plain text