Home | History | Annotate | Download | only in net
      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