diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
commit | 5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch) | |
tree | c0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/net/file.go | |
parent | 80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff) | |
download | golang-upstream/60.tar.gz |
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/net/file.go')
-rw-r--r-- | src/pkg/net/file.go | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/pkg/net/file.go b/src/pkg/net/file.go new file mode 100644 index 000000000..0e411a192 --- /dev/null +++ b/src/pkg/net/file.go @@ -0,0 +1,119 @@ +// 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 ( + "os" + "syscall" +) + +func newFileFD(f *os.File) (nfd *netFD, err os.Error) { + fd, errno := syscall.Dup(f.Fd()) + if errno != 0 { + return nil, os.NewSyscallError("dup", errno) + } + + proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) + if errno != 0 { + return nil, os.NewSyscallError("getsockopt", errno) + } + + toAddr := sockaddrToTCP + sa, _ := syscall.Getsockname(fd) + switch sa.(type) { + default: + closesocket(fd) + return nil, os.EINVAL + case *syscall.SockaddrInet4: + if proto == syscall.SOCK_DGRAM { + toAddr = sockaddrToUDP + } else if proto == syscall.SOCK_RAW { + toAddr = sockaddrToIP + } + case *syscall.SockaddrInet6: + if proto == syscall.SOCK_DGRAM { + toAddr = sockaddrToUDP + } else if proto == syscall.SOCK_RAW { + toAddr = sockaddrToIP + } + case *syscall.SockaddrUnix: + toAddr = sockaddrToUnix + if proto == syscall.SOCK_DGRAM { + toAddr = sockaddrToUnixgram + } else if proto == syscall.SOCK_SEQPACKET { + toAddr = sockaddrToUnixpacket + } + } + laddr := toAddr(sa) + sa, _ = syscall.Getpeername(fd) + raddr := toAddr(sa) + + if nfd, err = newFD(fd, 0, proto, laddr.Network()); err != nil { + return nil, err + } + nfd.setAddr(laddr, raddr) + return nfd, nil +} + +// FileConn returns a copy of the network connection corresponding to +// the open file f. It is the caller's responsibility to close f when +// finished. Closing c does not affect f, and closing f does not +// affect c. +func FileConn(f *os.File) (c Conn, err os.Error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch fd.laddr.(type) { + case *TCPAddr: + return newTCPConn(fd), nil + case *UDPAddr: + return newUDPConn(fd), nil + case *UnixAddr: + return newUnixConn(fd), nil + case *IPAddr: + return newIPConn(fd), nil + } + fd.Close() + return nil, os.EINVAL +} + +// FileListener returns a copy of the network listener corresponding +// to the open file f. It is the caller's responsibility to close l +// when finished. Closing c does not affect l, and closing l does not +// affect c. +func FileListener(f *os.File) (l Listener, err os.Error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch laddr := fd.laddr.(type) { + case *TCPAddr: + return &TCPListener{fd}, nil + case *UnixAddr: + return &UnixListener{fd, laddr.Name}, nil + } + fd.Close() + return nil, os.EINVAL +} + +// FilePacketConn returns a copy of the packet network connection +// corresponding to the open file f. It is the caller's +// responsibility to close f when finished. Closing c does not affect +// f, and closing f does not affect c. +func FilePacketConn(f *os.File) (c PacketConn, err os.Error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch fd.laddr.(type) { + case *UDPAddr: + return newUDPConn(fd), nil + case *UnixAddr: + return newUnixConn(fd), nil + } + fd.Close() + return nil, os.EINVAL +} |