Home | History | Annotate | Download | only in net
      1 // Copyright 2009 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 	"internal/poll"
      9 	"io"
     10 	"os"
     11 	"syscall"
     12 )
     13 
     14 // Network file descriptor.
     15 type netFD struct {
     16 	pfd poll.FD
     17 
     18 	// immutable until Close
     19 	net               string
     20 	n                 string
     21 	dir               string
     22 	listen, ctl, data *os.File
     23 	laddr, raddr      Addr
     24 	isStream          bool
     25 }
     26 
     27 var netdir = "/net" // default network
     28 
     29 func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
     30 	ret := &netFD{
     31 		net:    net,
     32 		n:      name,
     33 		dir:    netdir + "/" + net + "/" + name,
     34 		listen: listen,
     35 		ctl:    ctl, data: data,
     36 		laddr: laddr,
     37 		raddr: raddr,
     38 	}
     39 	ret.pfd.Destroy = ret.destroy
     40 	return ret, nil
     41 }
     42 
     43 func (fd *netFD) init() error {
     44 	// stub for future fd.pd.Init(fd)
     45 	return nil
     46 }
     47 
     48 func (fd *netFD) name() string {
     49 	var ls, rs string
     50 	if fd.laddr != nil {
     51 		ls = fd.laddr.String()
     52 	}
     53 	if fd.raddr != nil {
     54 		rs = fd.raddr.String()
     55 	}
     56 	return fd.net + ":" + ls + "->" + rs
     57 }
     58 
     59 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
     60 
     61 func (fd *netFD) destroy() {
     62 	if !fd.ok() {
     63 		return
     64 	}
     65 	err := fd.ctl.Close()
     66 	if fd.data != nil {
     67 		if err1 := fd.data.Close(); err1 != nil && err == nil {
     68 			err = err1
     69 		}
     70 	}
     71 	if fd.listen != nil {
     72 		if err1 := fd.listen.Close(); err1 != nil && err == nil {
     73 			err = err1
     74 		}
     75 	}
     76 	fd.ctl = nil
     77 	fd.data = nil
     78 	fd.listen = nil
     79 }
     80 
     81 func (fd *netFD) Read(b []byte) (n int, err error) {
     82 	if !fd.ok() || fd.data == nil {
     83 		return 0, syscall.EINVAL
     84 	}
     85 	n, err = fd.pfd.Read(fd.data.Read, b)
     86 	if fd.net == "udp" && err == io.EOF {
     87 		n = 0
     88 		err = nil
     89 	}
     90 	return
     91 }
     92 
     93 func (fd *netFD) Write(b []byte) (n int, err error) {
     94 	if !fd.ok() || fd.data == nil {
     95 		return 0, syscall.EINVAL
     96 	}
     97 	return fd.pfd.Write(fd.data.Write, b)
     98 }
     99 
    100 func (fd *netFD) closeRead() error {
    101 	if !fd.ok() {
    102 		return syscall.EINVAL
    103 	}
    104 	return syscall.EPLAN9
    105 }
    106 
    107 func (fd *netFD) closeWrite() error {
    108 	if !fd.ok() {
    109 		return syscall.EINVAL
    110 	}
    111 	return syscall.EPLAN9
    112 }
    113 
    114 func (fd *netFD) Close() error {
    115 	if err := fd.pfd.Close(); err != nil {
    116 		return err
    117 	}
    118 	if !fd.ok() {
    119 		return syscall.EINVAL
    120 	}
    121 	if fd.net == "tcp" {
    122 		// The following line is required to unblock Reads.
    123 		_, err := fd.ctl.WriteString("close")
    124 		if err != nil {
    125 			return err
    126 		}
    127 	}
    128 	err := fd.ctl.Close()
    129 	if fd.data != nil {
    130 		if err1 := fd.data.Close(); err1 != nil && err == nil {
    131 			err = err1
    132 		}
    133 	}
    134 	if fd.listen != nil {
    135 		if err1 := fd.listen.Close(); err1 != nil && err == nil {
    136 			err = err1
    137 		}
    138 	}
    139 	fd.ctl = nil
    140 	fd.data = nil
    141 	fd.listen = nil
    142 	return err
    143 }
    144 
    145 // This method is only called via Conn.
    146 func (fd *netFD) dup() (*os.File, error) {
    147 	if !fd.ok() || fd.data == nil {
    148 		return nil, syscall.EINVAL
    149 	}
    150 	return fd.file(fd.data, fd.dir+"/data")
    151 }
    152 
    153 func (l *TCPListener) dup() (*os.File, error) {
    154 	if !l.fd.ok() {
    155 		return nil, syscall.EINVAL
    156 	}
    157 	return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl")
    158 }
    159 
    160 func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
    161 	dfd, err := syscall.Dup(int(f.Fd()), -1)
    162 	if err != nil {
    163 		return nil, os.NewSyscallError("dup", err)
    164 	}
    165 	return os.NewFile(uintptr(dfd), s), nil
    166 }
    167 
    168 func setReadBuffer(fd *netFD, bytes int) error {
    169 	return syscall.EPLAN9
    170 }
    171 
    172 func setWriteBuffer(fd *netFD, bytes int) error {
    173 	return syscall.EPLAN9
    174 }
    175