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/sock.go | |
parent | 80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff) | |
download | golang-upstream/60.tar.gz |
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/net/sock.go')
-rw-r--r-- | src/pkg/net/sock.go | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go new file mode 100644 index 000000000..821716e43 --- /dev/null +++ b/src/pkg/net/sock.go @@ -0,0 +1,166 @@ +// Copyright 2009 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. + +// Sockets + +package net + +import ( + "io" + "os" + "reflect" + "syscall" +) + +// Boolean to int. +func boolint(b bool) int { + if b { + return 1 + } + return 0 +} + +// Generic socket creation. +func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) { + // See ../syscall/exec.go for description of ForkLock. + syscall.ForkLock.RLock() + s, e := syscall.Socket(f, p, t) + if e != 0 { + syscall.ForkLock.RUnlock() + return nil, os.Errno(e) + } + syscall.CloseOnExec(s) + syscall.ForkLock.RUnlock() + + setKernelSpecificSockopt(s, f) + + if la != nil { + e = syscall.Bind(s, la) + if e != 0 { + closesocket(s) + return nil, os.Errno(e) + } + } + + if fd, err = newFD(s, f, p, net); err != nil { + closesocket(s) + return nil, err + } + + if ra != nil { + if err = fd.connect(ra); err != nil { + fd.Close() + return nil, err + } + } + + sa, _ := syscall.Getsockname(s) + laddr := toAddr(sa) + sa, _ = syscall.Getpeername(s) + raddr := toAddr(sa) + + fd.setAddr(laddr, raddr) + return fd, nil +} + +func setsockoptInt(fd *netFD, level, opt int, value int) os.Error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value)) +} + +func setsockoptNsec(fd *netFD, level, opt int, nsec int64) os.Error { + var tv = syscall.NsecToTimeval(nsec) + return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, level, opt, &tv)) +} + +func setReadBuffer(fd *netFD, bytes int) os.Error { + fd.incref() + defer fd.decref() + return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes) +} + +func setWriteBuffer(fd *netFD, bytes int) os.Error { + fd.incref() + defer fd.decref() + return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes) +} + +func setReadTimeout(fd *netFD, nsec int64) os.Error { + fd.rdeadline_delta = nsec + return nil +} + +func setWriteTimeout(fd *netFD, nsec int64) os.Error { + fd.wdeadline_delta = nsec + return nil +} + +func setTimeout(fd *netFD, nsec int64) os.Error { + if e := setReadTimeout(fd, nsec); e != nil { + return e + } + return setWriteTimeout(fd, nsec) +} + +func setReuseAddr(fd *netFD, reuse bool) os.Error { + fd.incref() + defer fd.decref() + return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)) +} + +func bindToDevice(fd *netFD, dev string) os.Error { + // TODO(rsc): call setsockopt with null-terminated string pointer + return os.EINVAL +} + +func setDontRoute(fd *netFD, dontroute bool) os.Error { + fd.incref() + defer fd.decref() + return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)) +} + +func setKeepAlive(fd *netFD, keepalive bool) os.Error { + fd.incref() + defer fd.decref() + return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)) +} + +func setNoDelay(fd *netFD, noDelay bool) os.Error { + fd.incref() + defer fd.decref() + return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)) +} + +func setLinger(fd *netFD, sec int) os.Error { + var l syscall.Linger + if sec >= 0 { + l.Onoff = 1 + l.Linger = int32(sec) + } else { + l.Onoff = 0 + l.Linger = 0 + } + fd.incref() + defer fd.decref() + e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l) + return os.NewSyscallError("setsockopt", e) +} + +type UnknownSocketError struct { + sa syscall.Sockaddr +} + +func (e *UnknownSocketError) String() string { + return "unknown socket address type " + reflect.TypeOf(e.sa).String() +} + +type writerOnly struct { + io.Writer +} + +// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't +// applicable. +func genericReadFrom(w io.Writer, r io.Reader) (n int64, err os.Error) { + // Use wrapper to hide existing r.ReadFrom from io.Copy. + return io.Copy(writerOnly{w}, r) +} |