mirror of
https://github.com/golang/go
synced 2024-11-25 05:07:56 -07:00
net: introduce net.Error interface
Adds two more methods, Timeout and Temporary. Implemented by os.Errno too. The intent is to make the checks for os.EAGAIN a little less clunky. It should also let us clean up a bug that Mike Solomon pointed out: if a network server gets an "out of file descriptors" error from Accept, the listener should not stop. It will be able to check this because that error would have Temporary() == true. Also clean up some underscore names. Fixes #442. R=r CC=golang-dev, msolo https://golang.org/cl/957045
This commit is contained in:
parent
cd5191fd30
commit
47a0533411
@ -23,9 +23,10 @@ import (
|
|||||||
|
|
||||||
// DNSError represents a DNS lookup error.
|
// DNSError represents a DNS lookup error.
|
||||||
type DNSError struct {
|
type DNSError struct {
|
||||||
Error string // description of the error
|
Error string // description of the error
|
||||||
Name string // name looked for
|
Name string // name looked for
|
||||||
Server string // server used
|
Server string // server used
|
||||||
|
IsTimeout bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DNSError) String() string {
|
func (e *DNSError) String() string {
|
||||||
@ -37,23 +38,26 @@ func (e *DNSError) String() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *DNSError) Timeout() bool { return e.IsTimeout }
|
||||||
|
func (e *DNSError) Temporary() bool { return e.IsTimeout }
|
||||||
|
|
||||||
const noSuchHost = "no such host"
|
const noSuchHost = "no such host"
|
||||||
|
|
||||||
// Send a request on the connection and hope for a reply.
|
// Send a request on the connection and hope for a reply.
|
||||||
// Up to cfg.attempts attempts.
|
// Up to cfg.attempts attempts.
|
||||||
func _Exchange(cfg *_DNS_Config, c Conn, name string) (m *_DNS_Msg, err os.Error) {
|
func exchange(cfg *dnsConfig, c Conn, name string) (*dnsMsg, os.Error) {
|
||||||
if len(name) >= 256 {
|
if len(name) >= 256 {
|
||||||
return nil, &DNSError{"name too long", name, ""}
|
return nil, &DNSError{Error: "name too long", Name: name}
|
||||||
}
|
}
|
||||||
out := new(_DNS_Msg)
|
out := new(dnsMsg)
|
||||||
out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
|
out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
|
||||||
out.question = []_DNS_Question{
|
out.question = []dnsQuestion{
|
||||||
_DNS_Question{name, _DNS_TypeA, _DNS_ClassINET},
|
dnsQuestion{name, dnsTypeA, dnsClassINET},
|
||||||
}
|
}
|
||||||
out.recursion_desired = true
|
out.recursion_desired = true
|
||||||
msg, ok := out.Pack()
|
msg, ok := out.Pack()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &DNSError{"internal error - cannot pack message", name, ""}
|
return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
for attempt := 0; attempt < cfg.attempts; attempt++ {
|
for attempt := 0; attempt < cfg.attempts; attempt++ {
|
||||||
@ -66,15 +70,14 @@ func _Exchange(cfg *_DNS_Config, c Conn, name string) (m *_DNS_Msg, err os.Error
|
|||||||
|
|
||||||
buf := make([]byte, 2000) // More than enough.
|
buf := make([]byte, 2000) // More than enough.
|
||||||
n, err = c.Read(buf)
|
n, err = c.Read(buf)
|
||||||
if isEAGAIN(err) {
|
|
||||||
err = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if e, ok := err.(Error); ok && e.Timeout() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf = buf[0:n]
|
buf = buf[0:n]
|
||||||
in := new(_DNS_Msg)
|
in := new(dnsMsg)
|
||||||
if !in.Unpack(buf) || in.id != out.id {
|
if !in.Unpack(buf) || in.id != out.id {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -84,24 +87,24 @@ func _Exchange(cfg *_DNS_Config, c Conn, name string) (m *_DNS_Msg, err os.Error
|
|||||||
if a := c.RemoteAddr(); a != nil {
|
if a := c.RemoteAddr(); a != nil {
|
||||||
server = a.String()
|
server = a.String()
|
||||||
}
|
}
|
||||||
return nil, &DNSError{"no answer from server", name, server}
|
return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Find answer for name in dns message.
|
// Find answer for name in dns message.
|
||||||
// On return, if err == nil, addrs != nil.
|
// On return, if err == nil, addrs != nil.
|
||||||
func answer(name, server string, dns *_DNS_Msg) (addrs []string, err *DNSError) {
|
func answer(name, server string, dns *dnsMsg) (addrs []string, err os.Error) {
|
||||||
addrs = make([]string, 0, len(dns.answer))
|
addrs = make([]string, 0, len(dns.answer))
|
||||||
|
|
||||||
if dns.rcode == _DNS_RcodeNameError && dns.recursion_available {
|
if dns.rcode == dnsRcodeNameError && dns.recursion_available {
|
||||||
return nil, &DNSError{noSuchHost, name, ""}
|
return nil, &DNSError{Error: noSuchHost, Name: name}
|
||||||
}
|
}
|
||||||
if dns.rcode != _DNS_RcodeSuccess {
|
if dns.rcode != dnsRcodeSuccess {
|
||||||
// None of the error codes make sense
|
// None of the error codes make sense
|
||||||
// for the query we sent. If we didn't get
|
// for the query we sent. If we didn't get
|
||||||
// a name error and we didn't get success,
|
// a name error and we didn't get success,
|
||||||
// the server is behaving incorrectly.
|
// the server is behaving incorrectly.
|
||||||
return nil, &DNSError{"server misbehaving", name, server}
|
return nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for the name.
|
// Look for the name.
|
||||||
@ -115,34 +118,34 @@ Cname:
|
|||||||
for i := 0; i < len(dns.answer); i++ {
|
for i := 0; i < len(dns.answer); i++ {
|
||||||
rr := dns.answer[i]
|
rr := dns.answer[i]
|
||||||
h := rr.Header()
|
h := rr.Header()
|
||||||
if h.Class == _DNS_ClassINET && h.Name == name {
|
if h.Class == dnsClassINET && h.Name == name {
|
||||||
switch h.Rrtype {
|
switch h.Rrtype {
|
||||||
case _DNS_TypeA:
|
case dnsTypeA:
|
||||||
n := len(addrs)
|
n := len(addrs)
|
||||||
a := rr.(*_DNS_RR_A).A
|
a := rr.(*dnsRR_A).A
|
||||||
addrs = addrs[0 : n+1]
|
addrs = addrs[0 : n+1]
|
||||||
addrs[n] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String()
|
addrs[n] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String()
|
||||||
case _DNS_TypeCNAME:
|
case dnsTypeCNAME:
|
||||||
// redirect to cname
|
// redirect to cname
|
||||||
name = rr.(*_DNS_RR_CNAME).Cname
|
name = rr.(*dnsRR_CNAME).Cname
|
||||||
continue Cname
|
continue Cname
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(addrs) == 0 {
|
if len(addrs) == 0 {
|
||||||
return nil, &DNSError{noSuchHost, name, server}
|
return nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
|
||||||
}
|
}
|
||||||
return addrs, nil
|
return addrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &DNSError{"too many redirects", name, server}
|
return nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a lookup for a single name, which must be rooted
|
// Do a lookup for a single name, which must be rooted
|
||||||
// (otherwise answer will not find the answers).
|
// (otherwise answer will not find the answers).
|
||||||
func tryOneName(cfg *_DNS_Config, name string) (addrs []string, err os.Error) {
|
func tryOneName(cfg *dnsConfig, name string) (addrs []string, err os.Error) {
|
||||||
if len(cfg.servers) == 0 {
|
if len(cfg.servers) == 0 {
|
||||||
return nil, &DNSError{"no DNS servers", name, ""}
|
return nil, &DNSError{Error: "no DNS servers", Name: name}
|
||||||
}
|
}
|
||||||
for i := 0; i < len(cfg.servers); i++ {
|
for i := 0; i < len(cfg.servers); i++ {
|
||||||
// Calling Dial here is scary -- we have to be sure
|
// Calling Dial here is scary -- we have to be sure
|
||||||
@ -157,30 +160,24 @@ func tryOneName(cfg *_DNS_Config, name string) (addrs []string, err os.Error) {
|
|||||||
err = cerr
|
err = cerr
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msg, merr := _Exchange(cfg, c, name)
|
msg, merr := exchange(cfg, c, name)
|
||||||
c.Close()
|
c.Close()
|
||||||
if merr != nil {
|
if merr != nil {
|
||||||
err = merr
|
err = merr
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var dnserr *DNSError
|
addrs, err = answer(name, server, msg)
|
||||||
addrs, dnserr = answer(name, server, msg)
|
if err == nil || err.(*DNSError).Error == noSuchHost {
|
||||||
if dnserr != nil {
|
|
||||||
err = dnserr
|
|
||||||
} else {
|
|
||||||
err = nil // nil os.Error, not nil *DNSError
|
|
||||||
}
|
|
||||||
if dnserr == nil || dnserr.Error == noSuchHost {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg *_DNS_Config
|
var cfg *dnsConfig
|
||||||
var dnserr os.Error
|
var dnserr os.Error
|
||||||
|
|
||||||
func loadConfig() { cfg, dnserr = _DNS_ReadConfig() }
|
func loadConfig() { cfg, dnserr = dnsReadConfig() }
|
||||||
|
|
||||||
func isDomainName(s string) bool {
|
func isDomainName(s string) bool {
|
||||||
// Requirements on DNS name:
|
// Requirements on DNS name:
|
||||||
@ -231,7 +228,7 @@ func isDomainName(s string) bool {
|
|||||||
// host's addresses.
|
// host's addresses.
|
||||||
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
|
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
|
||||||
if !isDomainName(name) {
|
if !isDomainName(name) {
|
||||||
return name, nil, &DNSError{"invalid domain name", name, ""}
|
return name, nil, &DNSError{Error: "invalid domain name", Name: name}
|
||||||
}
|
}
|
||||||
once.Do(loadConfig)
|
once.Do(loadConfig)
|
||||||
if dnserr != nil || cfg == nil {
|
if dnserr != nil || cfg == nil {
|
||||||
|
@ -8,7 +8,7 @@ package net
|
|||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
type _DNS_Config struct {
|
type dnsConfig struct {
|
||||||
servers []string // servers to use
|
servers []string // servers to use
|
||||||
search []string // suffixes to append to local name
|
search []string // suffixes to append to local name
|
||||||
ndots int // number of dots in name to trigger absolute lookup
|
ndots int // number of dots in name to trigger absolute lookup
|
||||||
@ -17,18 +17,30 @@ type _DNS_Config struct {
|
|||||||
rotate bool // round robin among servers
|
rotate bool // round robin among servers
|
||||||
}
|
}
|
||||||
|
|
||||||
var _DNS_configError os.Error
|
var dnsconfigError os.Error
|
||||||
|
|
||||||
|
type DNSConfigError struct {
|
||||||
|
Error os.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DNSConfigError) String() string {
|
||||||
|
return "error reading DNS config: " + e.Error.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DNSConfigError) Timeout() bool { return false }
|
||||||
|
func (e *DNSConfigError) Temporary() bool { return false }
|
||||||
|
|
||||||
|
|
||||||
// See resolv.conf(5) on a Linux machine.
|
// See resolv.conf(5) on a Linux machine.
|
||||||
// TODO(rsc): Supposed to call uname() and chop the beginning
|
// TODO(rsc): Supposed to call uname() and chop the beginning
|
||||||
// of the host name to get the default search domain.
|
// of the host name to get the default search domain.
|
||||||
// We assume it's in resolv.conf anyway.
|
// We assume it's in resolv.conf anyway.
|
||||||
func _DNS_ReadConfig() (*_DNS_Config, os.Error) {
|
func dnsReadConfig() (*dnsConfig, os.Error) {
|
||||||
file, err := open("/etc/resolv.conf")
|
file, err := open("/etc/resolv.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, &DNSConfigError{err}
|
||||||
}
|
}
|
||||||
conf := new(_DNS_Config)
|
conf := new(dnsConfig)
|
||||||
conf.servers = make([]string, 3)[0:0] // small, but the standard limit
|
conf.servers = make([]string, 3)[0:0] // small, but the standard limit
|
||||||
conf.search = make([]string, 0)
|
conf.search = make([]string, 0)
|
||||||
conf.ndots = 1
|
conf.ndots = 1
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
// A few of the structure elements have string tags to aid the
|
// A few of the structure elements have string tags to aid the
|
||||||
// generic pack/unpack routines.
|
// generic pack/unpack routines.
|
||||||
//
|
//
|
||||||
// TODO(rsc) There are enough names defined in this file that they're all
|
// TODO(rsc): There are enough names defined in this file that they're all
|
||||||
// prefixed with _DNS_. Perhaps put this in its own package later.
|
// prefixed with dns. Perhaps put this in its own package later.
|
||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
@ -33,55 +33,55 @@ import (
|
|||||||
|
|
||||||
// Wire constants.
|
// Wire constants.
|
||||||
const (
|
const (
|
||||||
// valid _DNS_RR_Header.Rrtype and _DNS_Question.qtype
|
// valid dnsRR_Header.Rrtype and dnsQuestion.qtype
|
||||||
_DNS_TypeA = 1
|
dnsTypeA = 1
|
||||||
_DNS_TypeNS = 2
|
dnsTypeNS = 2
|
||||||
_DNS_TypeMD = 3
|
dnsTypeMD = 3
|
||||||
_DNS_TypeMF = 4
|
dnsTypeMF = 4
|
||||||
_DNS_TypeCNAME = 5
|
dnsTypeCNAME = 5
|
||||||
_DNS_TypeSOA = 6
|
dnsTypeSOA = 6
|
||||||
_DNS_TypeMB = 7
|
dnsTypeMB = 7
|
||||||
_DNS_TypeMG = 8
|
dnsTypeMG = 8
|
||||||
_DNS_TypeMR = 9
|
dnsTypeMR = 9
|
||||||
_DNS_TypeNULL = 10
|
dnsTypeNULL = 10
|
||||||
_DNS_TypeWKS = 11
|
dnsTypeWKS = 11
|
||||||
_DNS_TypePTR = 12
|
dnsTypePTR = 12
|
||||||
_DNS_TypeHINFO = 13
|
dnsTypeHINFO = 13
|
||||||
_DNS_TypeMINFO = 14
|
dnsTypeMINFO = 14
|
||||||
_DNS_TypeMX = 15
|
dnsTypeMX = 15
|
||||||
_DNS_TypeTXT = 16
|
dnsTypeTXT = 16
|
||||||
|
|
||||||
// valid _DNS_Question.qtype only
|
// valid dnsQuestion.qtype only
|
||||||
_DNS_TypeAXFR = 252
|
dnsTypeAXFR = 252
|
||||||
_DNS_TypeMAILB = 253
|
dnsTypeMAILB = 253
|
||||||
_DNS_TypeMAILA = 254
|
dnsTypeMAILA = 254
|
||||||
_DNS_TypeALL = 255
|
dnsTypeALL = 255
|
||||||
|
|
||||||
// valid _DNS_Question.qclass
|
// valid dnsQuestion.qclass
|
||||||
_DNS_ClassINET = 1
|
dnsClassINET = 1
|
||||||
_DNS_ClassCSNET = 2
|
dnsClassCSNET = 2
|
||||||
_DNS_ClassCHAOS = 3
|
dnsClassCHAOS = 3
|
||||||
_DNS_ClassHESIOD = 4
|
dnsClassHESIOD = 4
|
||||||
_DNS_ClassANY = 255
|
dnsClassANY = 255
|
||||||
|
|
||||||
// _DNS_Msg.rcode
|
// dnsMsg.rcode
|
||||||
_DNS_RcodeSuccess = 0
|
dnsRcodeSuccess = 0
|
||||||
_DNS_RcodeFormatError = 1
|
dnsRcodeFormatError = 1
|
||||||
_DNS_RcodeServerFailure = 2
|
dnsRcodeServerFailure = 2
|
||||||
_DNS_RcodeNameError = 3
|
dnsRcodeNameError = 3
|
||||||
_DNS_RcodeNotImplemented = 4
|
dnsRcodeNotImplemented = 4
|
||||||
_DNS_RcodeRefused = 5
|
dnsRcodeRefused = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// The wire format for the DNS packet header.
|
// The wire format for the DNS packet header.
|
||||||
type __DNS_Header struct {
|
type dnsHeader struct {
|
||||||
Id uint16
|
Id uint16
|
||||||
Bits uint16
|
Bits uint16
|
||||||
Qdcount, Ancount, Nscount, Arcount uint16
|
Qdcount, Ancount, Nscount, Arcount uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// __DNS_Header.Bits
|
// dnsHeader.Bits
|
||||||
_QR = 1 << 15 // query/response (response=1)
|
_QR = 1 << 15 // query/response (response=1)
|
||||||
_AA = 1 << 10 // authoritative
|
_AA = 1 << 10 // authoritative
|
||||||
_TC = 1 << 9 // truncated
|
_TC = 1 << 9 // truncated
|
||||||
@ -90,7 +90,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DNS queries.
|
// DNS queries.
|
||||||
type _DNS_Question struct {
|
type dnsQuestion struct {
|
||||||
Name string "domain-name" // "domain-name" specifies encoding; see packers below
|
Name string "domain-name" // "domain-name" specifies encoding; see packers below
|
||||||
Qtype uint16
|
Qtype uint16
|
||||||
Qclass uint16
|
Qclass uint16
|
||||||
@ -99,7 +99,7 @@ type _DNS_Question struct {
|
|||||||
// DNS responses (resource records).
|
// DNS responses (resource records).
|
||||||
// There are many types of messages,
|
// There are many types of messages,
|
||||||
// but they all share the same header.
|
// but they all share the same header.
|
||||||
type _DNS_RR_Header struct {
|
type dnsRR_Header struct {
|
||||||
Name string "domain-name"
|
Name string "domain-name"
|
||||||
Rrtype uint16
|
Rrtype uint16
|
||||||
Class uint16
|
Class uint16
|
||||||
@ -107,103 +107,103 @@ type _DNS_RR_Header struct {
|
|||||||
Rdlength uint16 // length of data after header
|
Rdlength uint16 // length of data after header
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *_DNS_RR_Header) Header() *_DNS_RR_Header {
|
func (h *dnsRR_Header) Header() *dnsRR_Header {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR interface {
|
type dnsRR interface {
|
||||||
Header() *_DNS_RR_Header
|
Header() *dnsRR_Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Specific DNS RR formats for each query type.
|
// Specific DNS RR formats for each query type.
|
||||||
|
|
||||||
type _DNS_RR_CNAME struct {
|
type dnsRR_CNAME struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Cname string "domain-name"
|
Cname string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_CNAME) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_HINFO struct {
|
type dnsRR_HINFO struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Cpu string
|
Cpu string
|
||||||
Os string
|
Os string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_HINFO) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_MB struct {
|
type dnsRR_MB struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Mb string "domain-name"
|
Mb string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_MB) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_MB) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_MG struct {
|
type dnsRR_MG struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Mg string "domain-name"
|
Mg string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_MG) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_MG) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_MINFO struct {
|
type dnsRR_MINFO struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Rmail string "domain-name"
|
Rmail string "domain-name"
|
||||||
Email string "domain-name"
|
Email string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_MINFO) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_MR struct {
|
type dnsRR_MR struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Mr string "domain-name"
|
Mr string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_MR) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_MR) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_MX struct {
|
type dnsRR_MX struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Pref uint16
|
Pref uint16
|
||||||
Mx string "domain-name"
|
Mx string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_MX) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_MX) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_NS struct {
|
type dnsRR_NS struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Ns string "domain-name"
|
Ns string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_NS) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_NS) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_PTR struct {
|
type dnsRR_PTR struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Ptr string "domain-name"
|
Ptr string "domain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_PTR) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_PTR) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_SOA struct {
|
type dnsRR_SOA struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Ns string "domain-name"
|
Ns string "domain-name"
|
||||||
Mbox string "domain-name"
|
Mbox string "domain-name"
|
||||||
Serial uint32
|
Serial uint32
|
||||||
@ -213,25 +213,25 @@ type _DNS_RR_SOA struct {
|
|||||||
Minttl uint32
|
Minttl uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_SOA) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_SOA) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_TXT struct {
|
type dnsRR_TXT struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
Txt string // not domain name
|
Txt string // not domain name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_TXT) Header() *_DNS_RR_Header {
|
func (rr *dnsRR_TXT) Header() *dnsRR_Header {
|
||||||
return &rr.Hdr
|
return &rr.Hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_RR_A struct {
|
type dnsRR_A struct {
|
||||||
Hdr _DNS_RR_Header
|
Hdr dnsRR_Header
|
||||||
A uint32 "ipv4"
|
A uint32 "ipv4"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *_DNS_RR_A) Header() *_DNS_RR_Header { return &rr.Hdr }
|
func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr }
|
||||||
|
|
||||||
|
|
||||||
// Packing and unpacking.
|
// Packing and unpacking.
|
||||||
@ -243,19 +243,19 @@ func (rr *_DNS_RR_A) Header() *_DNS_RR_Header { return &rr.Hdr }
|
|||||||
// packing sequence.
|
// packing sequence.
|
||||||
|
|
||||||
// Map of constructors for each RR wire type.
|
// Map of constructors for each RR wire type.
|
||||||
var rr_mk = map[int]func() _DNS_RR{
|
var rr_mk = map[int]func() dnsRR{
|
||||||
_DNS_TypeCNAME: func() _DNS_RR { return new(_DNS_RR_CNAME) },
|
dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
|
||||||
_DNS_TypeHINFO: func() _DNS_RR { return new(_DNS_RR_HINFO) },
|
dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
|
||||||
_DNS_TypeMB: func() _DNS_RR { return new(_DNS_RR_MB) },
|
dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
|
||||||
_DNS_TypeMG: func() _DNS_RR { return new(_DNS_RR_MG) },
|
dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
|
||||||
_DNS_TypeMINFO: func() _DNS_RR { return new(_DNS_RR_MINFO) },
|
dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
|
||||||
_DNS_TypeMR: func() _DNS_RR { return new(_DNS_RR_MR) },
|
dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
|
||||||
_DNS_TypeMX: func() _DNS_RR { return new(_DNS_RR_MX) },
|
dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
|
||||||
_DNS_TypeNS: func() _DNS_RR { return new(_DNS_RR_NS) },
|
dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
|
||||||
_DNS_TypePTR: func() _DNS_RR { return new(_DNS_RR_PTR) },
|
dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
|
||||||
_DNS_TypeSOA: func() _DNS_RR { return new(_DNS_RR_SOA) },
|
dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
|
||||||
_DNS_TypeTXT: func() _DNS_RR { return new(_DNS_RR_TXT) },
|
dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
|
||||||
_DNS_TypeA: func() _DNS_RR { return new(_DNS_RR_A) },
|
dnsTypeA: func() dnsRR { return new(dnsRR_A) },
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack a domain name s into msg[off:].
|
// Pack a domain name s into msg[off:].
|
||||||
@ -522,7 +522,7 @@ func printStructValue(val *reflect.StructValue) string {
|
|||||||
func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
|
func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
|
||||||
|
|
||||||
// Resource record packer.
|
// Resource record packer.
|
||||||
func packRR(rr _DNS_RR, msg []byte, off int) (off2 int, ok bool) {
|
func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
|
||||||
var off1 int
|
var off1 int
|
||||||
// pack twice, once to find end of header
|
// pack twice, once to find end of header
|
||||||
// and again to find end of packet.
|
// and again to find end of packet.
|
||||||
@ -541,9 +541,9 @@ func packRR(rr _DNS_RR, msg []byte, off int) (off2 int, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resource record unpacker.
|
// Resource record unpacker.
|
||||||
func unpackRR(msg []byte, off int) (rr _DNS_RR, off1 int, ok bool) {
|
func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
|
||||||
// unpack just the header, to find the rr type and length
|
// unpack just the header, to find the rr type and length
|
||||||
var h _DNS_RR_Header
|
var h dnsRR_Header
|
||||||
off0 := off
|
off0 := off
|
||||||
if off, ok = unpackStruct(&h, msg, off); !ok {
|
if off, ok = unpackStruct(&h, msg, off); !ok {
|
||||||
return nil, len(msg), false
|
return nil, len(msg), false
|
||||||
@ -568,7 +568,7 @@ func unpackRR(msg []byte, off int) (rr _DNS_RR, off1 int, ok bool) {
|
|||||||
|
|
||||||
// A manually-unpacked version of (id, bits).
|
// A manually-unpacked version of (id, bits).
|
||||||
// This is in its own struct for easy printing.
|
// This is in its own struct for easy printing.
|
||||||
type __DNS_Msg_Top struct {
|
type dnsMsgHdr struct {
|
||||||
id uint16
|
id uint16
|
||||||
response bool
|
response bool
|
||||||
opcode int
|
opcode int
|
||||||
@ -579,19 +579,19 @@ type __DNS_Msg_Top struct {
|
|||||||
rcode int
|
rcode int
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNS_Msg struct {
|
type dnsMsg struct {
|
||||||
__DNS_Msg_Top
|
dnsMsgHdr
|
||||||
question []_DNS_Question
|
question []dnsQuestion
|
||||||
answer []_DNS_RR
|
answer []dnsRR
|
||||||
ns []_DNS_RR
|
ns []dnsRR
|
||||||
extra []_DNS_RR
|
extra []dnsRR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (dns *_DNS_Msg) Pack() (msg []byte, ok bool) {
|
func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
|
||||||
var dh __DNS_Header
|
var dh dnsHeader
|
||||||
|
|
||||||
// Convert convenient _DNS_Msg into wire-like __DNS_Header.
|
// Convert convenient dnsMsg into wire-like dnsHeader.
|
||||||
dh.Id = dns.id
|
dh.Id = dns.id
|
||||||
dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
|
dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
|
||||||
if dns.recursion_available {
|
if dns.recursion_available {
|
||||||
@ -647,9 +647,9 @@ func (dns *_DNS_Msg) Pack() (msg []byte, ok bool) {
|
|||||||
return msg[0:off], true
|
return msg[0:off], true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dns *_DNS_Msg) Unpack(msg []byte) bool {
|
func (dns *dnsMsg) Unpack(msg []byte) bool {
|
||||||
// Header.
|
// Header.
|
||||||
var dh __DNS_Header
|
var dh dnsHeader
|
||||||
off := 0
|
off := 0
|
||||||
var ok bool
|
var ok bool
|
||||||
if off, ok = unpackStruct(&dh, msg, off); !ok {
|
if off, ok = unpackStruct(&dh, msg, off); !ok {
|
||||||
@ -665,10 +665,10 @@ func (dns *_DNS_Msg) Unpack(msg []byte) bool {
|
|||||||
dns.rcode = int(dh.Bits & 0xF)
|
dns.rcode = int(dh.Bits & 0xF)
|
||||||
|
|
||||||
// Arrays.
|
// Arrays.
|
||||||
dns.question = make([]_DNS_Question, dh.Qdcount)
|
dns.question = make([]dnsQuestion, dh.Qdcount)
|
||||||
dns.answer = make([]_DNS_RR, dh.Ancount)
|
dns.answer = make([]dnsRR, dh.Ancount)
|
||||||
dns.ns = make([]_DNS_RR, dh.Nscount)
|
dns.ns = make([]dnsRR, dh.Nscount)
|
||||||
dns.extra = make([]_DNS_RR, dh.Arcount)
|
dns.extra = make([]dnsRR, dh.Arcount)
|
||||||
|
|
||||||
for i := 0; i < len(dns.question); i++ {
|
for i := 0; i < len(dns.question); i++ {
|
||||||
off, ok = unpackStruct(&dns.question[i], msg, off)
|
off, ok = unpackStruct(&dns.question[i], msg, off)
|
||||||
@ -691,8 +691,8 @@ func (dns *_DNS_Msg) Unpack(msg []byte) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dns *_DNS_Msg) String() string {
|
func (dns *dnsMsg) String() string {
|
||||||
s := "DNS: " + printStruct(&dns.__DNS_Msg_Top) + "\n"
|
s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
|
||||||
if len(dns.question) > 0 {
|
if len(dns.question) > 0 {
|
||||||
s += "-- Questions\n"
|
s += "-- Questions\n"
|
||||||
for i := 0; i < len(dns.question); i++ {
|
for i := 0; i < len(dns.question); i++ {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"once"
|
"once"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@ -44,6 +45,12 @@ type netFD struct {
|
|||||||
ncr, ncw int
|
ncr, ncw int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InvalidConnError struct{}
|
||||||
|
|
||||||
|
func (e *InvalidConnError) String() string { return "invalid net.Conn" }
|
||||||
|
func (e *InvalidConnError) Temporary() bool { return false }
|
||||||
|
func (e *InvalidConnError) Timeout() bool { return false }
|
||||||
|
|
||||||
// A pollServer helps FDs determine when to retry a non-blocking
|
// A pollServer helps FDs determine when to retry a non-blocking
|
||||||
// read or write after they get EAGAIN. When an FD needs to wait,
|
// read or write after they get EAGAIN. When an FD needs to wait,
|
||||||
// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
|
// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
|
||||||
@ -342,13 +349,6 @@ func (fd *netFD) decref() {
|
|||||||
fd.sysmu.Unlock()
|
fd.sysmu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEAGAIN(e os.Error) bool {
|
|
||||||
if e1, ok := e.(*os.PathError); ok {
|
|
||||||
return e1.Error == os.EAGAIN
|
|
||||||
}
|
|
||||||
return e == os.EAGAIN
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fd *netFD) Close() os.Error {
|
func (fd *netFD) Close() os.Error {
|
||||||
if fd == nil || fd.sysfile == nil {
|
if fd == nil || fd.sysfile == nil {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -374,17 +374,24 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) {
|
|||||||
} else {
|
} else {
|
||||||
fd.rdeadline = 0
|
fd.rdeadline = 0
|
||||||
}
|
}
|
||||||
|
var oserr os.Error
|
||||||
for {
|
for {
|
||||||
n, err = fd.sysfile.Read(p)
|
var errno int
|
||||||
if isEAGAIN(err) && fd.rdeadline >= 0 {
|
n, errno = syscall.Read(fd.sysfile.Fd(), p)
|
||||||
|
if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
|
||||||
pollserver.WaitRead(fd)
|
pollserver.WaitRead(fd)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if errno != 0 {
|
||||||
|
n = 0
|
||||||
|
oserr = os.Errno(errno)
|
||||||
|
} else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
|
||||||
|
err = os.EOF
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if fd.proto == syscall.SOCK_DGRAM && err == os.EOF {
|
if oserr != nil {
|
||||||
// 0 in datagram protocol just means 0-length packet
|
err = &OpError{"read", fd.net, fd.raddr, oserr}
|
||||||
err = nil
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -402,6 +409,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
|
|||||||
} else {
|
} else {
|
||||||
fd.rdeadline = 0
|
fd.rdeadline = 0
|
||||||
}
|
}
|
||||||
|
var oserr os.Error
|
||||||
for {
|
for {
|
||||||
var errno int
|
var errno int
|
||||||
n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
|
n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
|
||||||
@ -411,10 +419,13 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
|
|||||||
}
|
}
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
n = 0
|
n = 0
|
||||||
err = &os.PathError{"recvfrom", fd.sysfile.Name(), os.Errno(errno)}
|
oserr = os.Errno(errno)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if oserr != nil {
|
||||||
|
err = &OpError{"read", fd.net, fd.laddr, oserr}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,25 +442,32 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) {
|
|||||||
} else {
|
} else {
|
||||||
fd.wdeadline = 0
|
fd.wdeadline = 0
|
||||||
}
|
}
|
||||||
err = nil
|
|
||||||
nn := 0
|
nn := 0
|
||||||
first := true // force at least one Write, to send 0-length datagram packets
|
var oserr os.Error
|
||||||
for nn < len(p) || first {
|
for {
|
||||||
first = false
|
n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
|
||||||
n, err = fd.sysfile.Write(p[nn:])
|
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
nn += n
|
nn += n
|
||||||
}
|
}
|
||||||
if nn == len(p) {
|
if nn == len(p) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if isEAGAIN(err) && fd.wdeadline >= 0 {
|
if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
|
||||||
pollserver.WaitWrite(fd)
|
pollserver.WaitWrite(fd)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n == 0 || err != nil {
|
if errno != 0 {
|
||||||
|
n = 0
|
||||||
|
oserr = os.Errno(errno)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if n == 0 {
|
||||||
|
oserr = io.ErrUnexpectedEOF
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if oserr != nil {
|
||||||
|
err = &OpError{"write", fd.net, fd.raddr, oserr}
|
||||||
}
|
}
|
||||||
return nn, err
|
return nn, err
|
||||||
}
|
}
|
||||||
@ -467,7 +485,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
|
|||||||
} else {
|
} else {
|
||||||
fd.wdeadline = 0
|
fd.wdeadline = 0
|
||||||
}
|
}
|
||||||
err = nil
|
var oserr os.Error
|
||||||
for {
|
for {
|
||||||
errno := syscall.Sendto(fd.sysfd, p, 0, sa)
|
errno := syscall.Sendto(fd.sysfd, p, 0, sa)
|
||||||
if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
|
if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
|
||||||
@ -475,12 +493,14 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
err = &os.PathError{"sendto", fd.sysfile.Name(), os.Errno(errno)}
|
oserr = os.Errno(errno)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err == nil {
|
if oserr == nil {
|
||||||
n = len(p)
|
n = len(p)
|
||||||
|
} else {
|
||||||
|
err = &OpError{"write", fd.net, fd.raddr, oserr}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ type sockaddr interface {
|
|||||||
func internetSocket(net string, laddr, raddr sockaddr, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
|
func internetSocket(net string, laddr, raddr sockaddr, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
|
||||||
// Figure out IP version.
|
// Figure out IP version.
|
||||||
// If network has a suffix like "tcp4", obey it.
|
// If network has a suffix like "tcp4", obey it.
|
||||||
|
var oserr os.Error
|
||||||
family := syscall.AF_INET6
|
family := syscall.AF_INET6
|
||||||
switch net[len(net)-1] {
|
switch net[len(net)-1] {
|
||||||
case '4':
|
case '4':
|
||||||
@ -67,16 +68,16 @@ func internetSocket(net string, laddr, raddr sockaddr, proto int, mode string, t
|
|||||||
|
|
||||||
var la, ra syscall.Sockaddr
|
var la, ra syscall.Sockaddr
|
||||||
if laddr != nil {
|
if laddr != nil {
|
||||||
if la, err = laddr.sockaddr(family); err != nil {
|
if la, oserr = laddr.sockaddr(family); err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if raddr != nil {
|
if raddr != nil {
|
||||||
if ra, err = raddr.sockaddr(family); err != nil {
|
if ra, oserr = raddr.sockaddr(family); err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fd, err = socket(net, family, proto, 0, la, ra, toAddr)
|
fd, oserr = socket(net, family, proto, 0, la, ra, toAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
@ -87,7 +88,7 @@ Error:
|
|||||||
if mode == "listen" {
|
if mode == "listen" {
|
||||||
addr = laddr
|
addr = laddr
|
||||||
}
|
}
|
||||||
return nil, &OpError{mode, net, addr, err}
|
return nil, &OpError{mode, net, addr, oserr}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
|
func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
|
||||||
@ -109,6 +110,13 @@ func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InvalidAddrError string
|
||||||
|
|
||||||
|
func (e InvalidAddrError) String() string { return string(e) }
|
||||||
|
func (e InvalidAddrError) Timeout() bool { return false }
|
||||||
|
func (e InvalidAddrError) Temporary() bool { return false }
|
||||||
|
|
||||||
|
|
||||||
func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
|
func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
|
||||||
switch family {
|
switch family {
|
||||||
case syscall.AF_INET:
|
case syscall.AF_INET:
|
||||||
@ -116,7 +124,7 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
|
|||||||
ip = IPv4zero
|
ip = IPv4zero
|
||||||
}
|
}
|
||||||
if ip = ip.To4(); ip == nil {
|
if ip = ip.To4(); ip == nil {
|
||||||
return nil, os.EINVAL
|
return nil, InvalidAddrError("non-IPv4 address")
|
||||||
}
|
}
|
||||||
s := new(syscall.SockaddrInet4)
|
s := new(syscall.SockaddrInet4)
|
||||||
for i := 0; i < IPv4len; i++ {
|
for i := 0; i < IPv4len; i++ {
|
||||||
@ -135,7 +143,7 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
|
|||||||
ip = IPzero
|
ip = IPzero
|
||||||
}
|
}
|
||||||
if ip = ip.To16(); ip == nil {
|
if ip = ip.To16(); ip == nil {
|
||||||
return nil, os.EINVAL
|
return nil, InvalidAddrError("non-IPv6 address")
|
||||||
}
|
}
|
||||||
s := new(syscall.SockaddrInet6)
|
s := new(syscall.SockaddrInet6)
|
||||||
for i := 0; i < IPv6len; i++ {
|
for i := 0; i < IPv6len; i++ {
|
||||||
@ -144,7 +152,7 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
|
|||||||
s.Port = port
|
s.Port = port
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
return nil, os.EINVAL
|
return nil, InvalidAddrError("unexpected socket family")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split "host:port" into "host" and "port".
|
// Split "host:port" into "host" and "port".
|
||||||
|
@ -22,16 +22,17 @@ type Addr interface {
|
|||||||
// Conn is a generic stream-oriented network connection.
|
// Conn is a generic stream-oriented network connection.
|
||||||
type Conn interface {
|
type Conn interface {
|
||||||
// Read reads data from the connection.
|
// Read reads data from the connection.
|
||||||
// Read can be made to time out and return err == os.EAGAIN
|
// Read can be made to time out and return a net.Error with Timeout() == true
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
||||||
Read(b []byte) (n int, err os.Error)
|
Read(b []byte) (n int, err os.Error)
|
||||||
|
|
||||||
// Write writes data to the connection.
|
// Write writes data to the connection.
|
||||||
// Write can be made to time out and return err == os.EAGAIN
|
// Write can be made to time out and return a net.Error with Timeout() == true
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
// after a fixed time limit; see SetTimeout and SetWriteTimeout.
|
||||||
Write(b []byte) (n int, err os.Error)
|
Write(b []byte) (n int, err os.Error)
|
||||||
|
|
||||||
// Close closes the connection.
|
// Close closes the connection.
|
||||||
|
// The error returned is an os.Error to satisfy io.Closer;
|
||||||
Close() os.Error
|
Close() os.Error
|
||||||
|
|
||||||
// LocalAddr returns the local network address.
|
// LocalAddr returns the local network address.
|
||||||
@ -45,35 +46,45 @@ type Conn interface {
|
|||||||
SetTimeout(nsec int64) os.Error
|
SetTimeout(nsec int64) os.Error
|
||||||
|
|
||||||
// SetReadTimeout sets the time (in nanoseconds) that
|
// SetReadTimeout sets the time (in nanoseconds) that
|
||||||
// Read will wait for data before returning os.EAGAIN.
|
// Read will wait for data before returning an error with Timeout() == true.
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
// Setting nsec == 0 (the default) disables the deadline.
|
||||||
SetReadTimeout(nsec int64) os.Error
|
SetReadTimeout(nsec int64) os.Error
|
||||||
|
|
||||||
// SetWriteTimeout sets the time (in nanoseconds) that
|
// SetWriteTimeout sets the time (in nanoseconds) that
|
||||||
// Write will wait to send its data before returning os.EAGAIN.
|
// Write will wait to send its data before returning an error with Timeout() == true.
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
// Setting nsec == 0 (the default) disables the deadline.
|
||||||
// Even if write times out, it may return n > 0, indicating that
|
// Even if write times out, it may return n > 0, indicating that
|
||||||
// some of the data was successfully written.
|
// some of the data was successfully written.
|
||||||
SetWriteTimeout(nsec int64) os.Error
|
SetWriteTimeout(nsec int64) os.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An Error represents a network error.
|
||||||
|
type Error interface {
|
||||||
|
os.Error
|
||||||
|
Timeout() bool // Is the error a timeout?
|
||||||
|
Temporary() bool // Is the error temporary?
|
||||||
|
}
|
||||||
|
|
||||||
// PacketConn is a generic packet-oriented network connection.
|
// PacketConn is a generic packet-oriented network connection.
|
||||||
type PacketConn interface {
|
type PacketConn interface {
|
||||||
// ReadFrom reads a packet from the connection,
|
// ReadFrom reads a packet from the connection,
|
||||||
// copying the payload into b. It returns the number of
|
// copying the payload into b. It returns the number of
|
||||||
// bytes copied into b and the return address that
|
// bytes copied into b and the return address that
|
||||||
// was on the packet.
|
// was on the packet.
|
||||||
// ReadFrom can be made to time out and return err == os.EAGAIN
|
// ReadFrom can be made to time out and return
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
// an error with Timeout() == true after a fixed time limit;
|
||||||
|
// see SetTimeout and SetReadTimeout.
|
||||||
ReadFrom(b []byte) (n int, addr Addr, err os.Error)
|
ReadFrom(b []byte) (n int, addr Addr, err os.Error)
|
||||||
|
|
||||||
// WriteTo writes a packet with payload b to addr.
|
// WriteTo writes a packet with payload b to addr.
|
||||||
// WriteTo can be made to time out and return err == os.EAGAIN
|
// WriteTo can be made to time out and return
|
||||||
// after a fixed time limit; see SetTimeout and SetWriteTimeout.
|
// an error with Timeout() == true after a fixed time limit;
|
||||||
|
// see SetTimeout and SetWriteTimeout.
|
||||||
// On packet-oriented connections, write timeouts are rare.
|
// On packet-oriented connections, write timeouts are rare.
|
||||||
WriteTo(b []byte, addr Addr) (n int, err os.Error)
|
WriteTo(b []byte, addr Addr) (n int, err os.Error)
|
||||||
|
|
||||||
// Close closes the connection.
|
// Close closes the connection.
|
||||||
|
// The error returned is an os.Error to satisfy io.Closer;
|
||||||
Close() os.Error
|
Close() os.Error
|
||||||
|
|
||||||
// LocalAddr returns the local network address.
|
// LocalAddr returns the local network address.
|
||||||
@ -84,12 +95,12 @@ type PacketConn interface {
|
|||||||
SetTimeout(nsec int64) os.Error
|
SetTimeout(nsec int64) os.Error
|
||||||
|
|
||||||
// SetReadTimeout sets the time (in nanoseconds) that
|
// SetReadTimeout sets the time (in nanoseconds) that
|
||||||
// Read will wait for data before returning os.EAGAIN.
|
// Read will wait for data before returning an error with Timeout() == true.
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
// Setting nsec == 0 (the default) disables the deadline.
|
||||||
SetReadTimeout(nsec int64) os.Error
|
SetReadTimeout(nsec int64) os.Error
|
||||||
|
|
||||||
// SetWriteTimeout sets the time (in nanoseconds) that
|
// SetWriteTimeout sets the time (in nanoseconds) that
|
||||||
// Write will wait to send its data before returning os.EAGAIN.
|
// Write will wait to send its data before returning an error with Timeout() == true.
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
// Setting nsec == 0 (the default) disables the deadline.
|
||||||
// Even if write times out, it may return n > 0, indicating that
|
// Even if write times out, it may return n > 0, indicating that
|
||||||
// some of the data was successfully written.
|
// some of the data was successfully written.
|
||||||
@ -97,11 +108,16 @@ type PacketConn interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A Listener is a generic network listener for stream-oriented protocols.
|
// A Listener is a generic network listener for stream-oriented protocols.
|
||||||
// Accept waits for the next connection and Close closes the connection.
|
|
||||||
type Listener interface {
|
type Listener interface {
|
||||||
|
// Accept waits for and returns the next connection to the listener.
|
||||||
Accept() (c Conn, err os.Error)
|
Accept() (c Conn, err os.Error)
|
||||||
|
|
||||||
|
// Close closes the listener.
|
||||||
|
// The error returned is an os.Error to satisfy io.Closer;
|
||||||
Close() os.Error
|
Close() os.Error
|
||||||
Addr() Addr // Listener's network address
|
|
||||||
|
// Addr returns the listener's network address.
|
||||||
|
Addr() Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the remote address raddr on the network net.
|
// Dial connects to the remote address raddr on the network net.
|
||||||
@ -266,6 +282,24 @@ func (e *OpError) String() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type temporary interface {
|
||||||
|
Temporary() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *OpError) Temporary() bool {
|
||||||
|
t, ok := e.Error.(temporary)
|
||||||
|
return ok && t.Temporary()
|
||||||
|
}
|
||||||
|
|
||||||
|
type timeout interface {
|
||||||
|
Timeout() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *OpError) Timeout() bool {
|
||||||
|
t, ok := e.Error.(timeout)
|
||||||
|
return ok && t.Timeout()
|
||||||
|
}
|
||||||
|
|
||||||
type AddrError struct {
|
type AddrError struct {
|
||||||
Error string
|
Error string
|
||||||
Addr string
|
Addr string
|
||||||
@ -279,6 +313,16 @@ func (e *AddrError) String() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *AddrError) Temporary() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *AddrError) Timeout() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type UnknownNetworkError string
|
type UnknownNetworkError string
|
||||||
|
|
||||||
func (e UnknownNetworkError) String() string { return "unknown network " + string(e) }
|
func (e UnknownNetworkError) String() string { return "unknown network " + string(e) }
|
||||||
|
func (e UnknownNetworkError) Temporary() bool { return false }
|
||||||
|
func (e UnknownNetworkError) Timeout() bool { return false }
|
||||||
|
@ -69,14 +69,14 @@ func connect(t *testing.T, network, addr string, isEmpty bool) {
|
|||||||
}
|
}
|
||||||
var b1 [100]byte
|
var b1 [100]byte
|
||||||
|
|
||||||
n, err := fd.Write(b)
|
n, err1 := fd.Write(b)
|
||||||
if n != len(b) {
|
if n != len(b) {
|
||||||
t.Fatalf("fd.Write(%q) = %d, %v", b, n, err)
|
t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err = fd.Read(&b1)
|
n, err1 = fd.Read(&b1)
|
||||||
if n != len(b) || err != nil {
|
if n != len(b) || err1 != nil {
|
||||||
t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err, len(b))
|
t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
|
||||||
}
|
}
|
||||||
fd.Close()
|
fd.Close()
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ func runPacket(t *testing.T, network, addr string, listening chan<- string, done
|
|||||||
var buf [1000]byte
|
var buf [1000]byte
|
||||||
for {
|
for {
|
||||||
n, addr, err := c.ReadFrom(&buf)
|
n, addr, err := c.ReadFrom(&buf)
|
||||||
if isEAGAIN(err) {
|
if e, ok := err.(Error); ok && e.Timeout() {
|
||||||
if done <- 1 {
|
if done <- 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,7 @@ func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
|
|||||||
|
|
||||||
// Implementation of the Conn interface - see Conn for documentation.
|
// Implementation of the Conn interface - see Conn for documentation.
|
||||||
|
|
||||||
// Read reads data from the TCP connection.
|
// Read implements the net.Conn Read method.
|
||||||
//
|
|
||||||
// Read can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
|
func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -92,10 +89,7 @@ func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
|
|||||||
return c.fd.Read(b)
|
return c.fd.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes data to the TCP connection.
|
// Write implements the net.Conn Write method.
|
||||||
//
|
|
||||||
// Write can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
|
func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -129,8 +123,7 @@ func (c *TCPConn) RemoteAddr() Addr {
|
|||||||
return c.fd.raddr
|
return c.fd.raddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTimeout sets the read and write deadlines associated
|
// SetTimeout implements the net.Conn SetTimeout method.
|
||||||
// with the connection.
|
|
||||||
func (c *TCPConn) SetTimeout(nsec int64) os.Error {
|
func (c *TCPConn) SetTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -138,9 +131,7 @@ func (c *TCPConn) SetTimeout(nsec int64) os.Error {
|
|||||||
return setTimeout(c.fd, nsec)
|
return setTimeout(c.fd, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReadTimeout sets the time (in nanoseconds) that
|
// SetReadTimeout implements the net.Conn SetReadTimeout method.
|
||||||
// Read will wait for data before returning os.EAGAIN.
|
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
|
||||||
func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
|
func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -148,11 +139,7 @@ func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
|
|||||||
return setReadTimeout(c.fd, nsec)
|
return setReadTimeout(c.fd, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWriteTimeout sets the time (in nanoseconds) that
|
// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
|
||||||
// Write will wait to send its data before returning os.EAGAIN.
|
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
|
||||||
// Even if write times out, it may return n > 0, indicating that
|
|
||||||
// some of the data was successfully written.
|
|
||||||
func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
|
func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
|
@ -32,8 +32,8 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
|
|||||||
if readFrom {
|
if readFrom {
|
||||||
what = "ReadFrom"
|
what = "ReadFrom"
|
||||||
}
|
}
|
||||||
if n != 0 || !isEAGAIN(err1) {
|
if n != 0 || err1 == nil || !err1.(Error).Timeout() {
|
||||||
t.Errorf("fd.%s on %s %s did not return 0, EAGAIN: %v, %v", what, network, addr, n, err1)
|
t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
|
||||||
}
|
}
|
||||||
if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
|
if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
|
||||||
t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
|
t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
|
||||||
|
@ -77,12 +77,7 @@ func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
|
|||||||
|
|
||||||
// Implementation of the Conn interface - see Conn for documentation.
|
// Implementation of the Conn interface - see Conn for documentation.
|
||||||
|
|
||||||
// Read reads data from a single UDP packet on the connection.
|
// Read implements the net.Conn Read method.
|
||||||
// If the slice b is smaller than the arriving packet,
|
|
||||||
// the excess packet data may be discarded.
|
|
||||||
//
|
|
||||||
// Read can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
|
func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -90,10 +85,7 @@ func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
|
|||||||
return c.fd.Read(b)
|
return c.fd.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes data to the connection as a single UDP packet.
|
// Write implements the net.Conn Write method.
|
||||||
//
|
|
||||||
// Write can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
|
func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -127,8 +119,7 @@ func (c *UDPConn) RemoteAddr() Addr {
|
|||||||
return c.fd.raddr
|
return c.fd.raddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTimeout sets the read and write deadlines associated
|
// SetTimeout implements the net.Conn SetTimeout method.
|
||||||
// with the connection.
|
|
||||||
func (c *UDPConn) SetTimeout(nsec int64) os.Error {
|
func (c *UDPConn) SetTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -136,9 +127,7 @@ func (c *UDPConn) SetTimeout(nsec int64) os.Error {
|
|||||||
return setTimeout(c.fd, nsec)
|
return setTimeout(c.fd, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReadTimeout sets the time (in nanoseconds) that
|
// SetReadTimeout implements the net.Conn SetReadTimeout method.
|
||||||
// Read will wait for data before returning os.EAGAIN.
|
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
|
||||||
func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
|
func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -146,11 +135,7 @@ func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
|
|||||||
return setReadTimeout(c.fd, nsec)
|
return setReadTimeout(c.fd, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWriteTimeout sets the time (in nanoseconds) that
|
// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
|
||||||
// Write will wait to send its data before returning os.EAGAIN.
|
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
|
||||||
// Even if write times out, it may return n > 0, indicating that
|
|
||||||
// some of the data was successfully written.
|
|
||||||
func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
|
func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -182,7 +167,7 @@ func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
|
|||||||
// It returns the number of bytes copied into b and the return address
|
// It returns the number of bytes copied into b and the return address
|
||||||
// that was on the packet.
|
// that was on the packet.
|
||||||
//
|
//
|
||||||
// ReadFromUDP can be made to time out and return err == os.EAGAIN
|
// ReadFromUDP can be made to time out and return an error with Timeout() == true
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
||||||
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
|
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
@ -198,12 +183,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFrom reads a UDP packet from c, copying the payload into b.
|
// ReadFrom implements the net.PacketConn ReadFrom method.
|
||||||
// It returns the number of bytes copied into b and the return address
|
|
||||||
// that was on the packet.
|
|
||||||
//
|
|
||||||
// ReadFrom can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
|
func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, nil, os.EINVAL
|
return 0, nil, os.EINVAL
|
||||||
@ -214,25 +194,22 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
|
|||||||
|
|
||||||
// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
|
// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
|
||||||
//
|
//
|
||||||
// WriteToUDP can be made to time out and return err == os.EAGAIN
|
// WriteToUDP can be made to time out and return
|
||||||
// after a fixed time limit; see SetTimeout and SetWriteTimeout.
|
// an error with Timeout() == true after a fixed time limit;
|
||||||
// On packet-oriented connections such as UDP, write timeouts are rare.
|
// see SetTimeout and SetWriteTimeout.
|
||||||
|
// On packet-oriented connections, write timeouts are rare.
|
||||||
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
|
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
}
|
}
|
||||||
sa, err := addr.sockaddr(c.fd.family)
|
sa, err1 := addr.sockaddr(c.fd.family)
|
||||||
if err != nil {
|
if err1 != nil {
|
||||||
return 0, err
|
return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
|
||||||
}
|
}
|
||||||
return c.fd.WriteTo(b, sa)
|
return c.fd.WriteTo(b, sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo writes a UDP packet with payload b to addr via c.
|
// WriteTo implements the net.PacketConn WriteTo method.
|
||||||
//
|
|
||||||
// WriteTo can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetWriteTimeout.
|
|
||||||
// On packet-oriented connections such as UDP, write timeouts are rare.
|
|
||||||
func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
|
func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
|
@ -34,7 +34,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
|
|||||||
if raddr != nil {
|
if raddr != nil {
|
||||||
ra = &syscall.SockaddrUnix{Name: raddr.Name}
|
ra = &syscall.SockaddrUnix{Name: raddr.Name}
|
||||||
} else if proto != syscall.SOCK_DGRAM || laddr == nil {
|
} else if proto != syscall.SOCK_DGRAM || laddr == nil {
|
||||||
return nil, &OpError{mode, net, nil, errMissingAddress}
|
return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "listen":
|
case "listen":
|
||||||
@ -43,7 +43,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
|
|||||||
}
|
}
|
||||||
la = &syscall.SockaddrUnix{Name: laddr.Name}
|
la = &syscall.SockaddrUnix{Name: laddr.Name}
|
||||||
if raddr != nil {
|
if raddr != nil {
|
||||||
return nil, &OpError{mode, net, raddr, &AddrError{"unexpected remote address", raddr.String()}}
|
return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,8 +51,8 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
|
|||||||
if proto != syscall.SOCK_STREAM {
|
if proto != syscall.SOCK_STREAM {
|
||||||
f = sockaddrToUnixgram
|
f = sockaddrToUnixgram
|
||||||
}
|
}
|
||||||
fd, err = socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
|
fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
|
||||||
if err != nil {
|
if oserr != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
return fd, nil
|
return fd, nil
|
||||||
@ -62,7 +62,7 @@ Error:
|
|||||||
if mode == "listen" {
|
if mode == "listen" {
|
||||||
addr = laddr
|
addr = laddr
|
||||||
}
|
}
|
||||||
return nil, &OpError{mode, net, addr, err}
|
return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnixAddr represents the address of a Unix domain socket end point.
|
// UnixAddr represents the address of a Unix domain socket end point.
|
||||||
@ -133,10 +133,7 @@ func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
|
|||||||
|
|
||||||
// Implementation of the Conn interface - see Conn for documentation.
|
// Implementation of the Conn interface - see Conn for documentation.
|
||||||
|
|
||||||
// Read reads data from the Unix domain connection.
|
// Read implements the net.Conn Read method.
|
||||||
//
|
|
||||||
// Read can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
|
func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -144,10 +141,7 @@ func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
|
|||||||
return c.fd.Read(b)
|
return c.fd.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes data to the Unix domain connection.
|
// Write implements the net.Conn Write method.
|
||||||
//
|
|
||||||
// Write can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
|
func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -184,8 +178,7 @@ func (c *UnixConn) RemoteAddr() Addr {
|
|||||||
return c.fd.raddr
|
return c.fd.raddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTimeout sets the read and write deadlines associated
|
// SetTimeout implements the net.Conn SetTimeout method.
|
||||||
// with the connection.
|
|
||||||
func (c *UnixConn) SetTimeout(nsec int64) os.Error {
|
func (c *UnixConn) SetTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -193,9 +186,7 @@ func (c *UnixConn) SetTimeout(nsec int64) os.Error {
|
|||||||
return setTimeout(c.fd, nsec)
|
return setTimeout(c.fd, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReadTimeout sets the time (in nanoseconds) that
|
// SetReadTimeout implements the net.Conn SetReadTimeout method.
|
||||||
// Read will wait for data before returning os.EAGAIN.
|
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
|
||||||
func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
|
func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -203,11 +194,7 @@ func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
|
|||||||
return setReadTimeout(c.fd, nsec)
|
return setReadTimeout(c.fd, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWriteTimeout sets the time (in nanoseconds) that
|
// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
|
||||||
// Write will wait to send its data before returning os.EAGAIN.
|
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
|
||||||
// Even if write times out, it may return n > 0, indicating that
|
|
||||||
// some of the data was successfully written.
|
|
||||||
func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
|
func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return os.EINVAL
|
return os.EINVAL
|
||||||
@ -237,8 +224,9 @@ func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
|
|||||||
// It returns the number of bytes copied into b and the return address
|
// It returns the number of bytes copied into b and the return address
|
||||||
// that was on the packet.
|
// that was on the packet.
|
||||||
//
|
//
|
||||||
// ReadFromUnix can be made to time out and return err == os.EAGAIN
|
// ReadFromUnix can be made to time out and return
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
// an error with Timeout() == true after a fixed time limit;
|
||||||
|
// see SetTimeout and SetReadTimeout.
|
||||||
func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
|
func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, nil, os.EINVAL
|
return 0, nil, os.EINVAL
|
||||||
@ -251,12 +239,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFrom reads a packet from c, copying the payload into b.
|
// ReadFrom implements the net.PacketConn ReadFrom method.
|
||||||
// It returns the number of bytes copied into b and the return address
|
|
||||||
// that was on the packet.
|
|
||||||
//
|
|
||||||
// ReadFrom can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetReadTimeout.
|
|
||||||
func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
|
func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, nil, os.EINVAL
|
return 0, nil, os.EINVAL
|
||||||
@ -267,9 +250,10 @@ func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
|
|||||||
|
|
||||||
// WriteToUnix writes a packet to addr via c, copying the payload from b.
|
// WriteToUnix writes a packet to addr via c, copying the payload from b.
|
||||||
//
|
//
|
||||||
// WriteToUnix can be made to time out and return err == os.EAGAIN
|
// WriteToUnix can be made to time out and return
|
||||||
// after a fixed time limit; see SetTimeout and SetWriteTimeout.
|
// an error with Timeout() == true after a fixed time limit;
|
||||||
// On packet-oriented connections such as UDP, write timeouts are rare.
|
// see SetTimeout and SetWriteTimeout.
|
||||||
|
// On packet-oriented connections, write timeouts are rare.
|
||||||
func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
|
func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -281,11 +265,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
|
|||||||
return c.fd.WriteTo(b, sa)
|
return c.fd.WriteTo(b, sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo writes a packet to addr via c, copying the payload from b.
|
// WriteTo implements the net.PacketConn WriteTo method.
|
||||||
//
|
|
||||||
// WriteTo can be made to time out and return err == os.EAGAIN
|
|
||||||
// after a fixed time limit; see SetTimeout and SetWriteTimeout.
|
|
||||||
// On packet-oriented connections such as UDP, write timeouts are rare.
|
|
||||||
func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
|
func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -325,17 +305,14 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
|
|||||||
if laddr != nil {
|
if laddr != nil {
|
||||||
laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own copy
|
laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own copy
|
||||||
}
|
}
|
||||||
fd, e := unixSocket(net, laddr, nil, "listen")
|
fd, err := unixSocket(net, laddr, nil, "listen")
|
||||||
if e != nil {
|
if err != nil {
|
||||||
if pe, ok := e.(*os.PathError); ok {
|
return nil, err
|
||||||
e = pe.Error
|
|
||||||
}
|
|
||||||
return nil, e
|
|
||||||
}
|
}
|
||||||
e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
|
e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
|
||||||
if e1 != 0 {
|
if e1 != 0 {
|
||||||
syscall.Close(fd.sysfd)
|
syscall.Close(fd.sysfd)
|
||||||
return nil, &OpError{"listen", "unix", laddr, os.Errno(e1)}
|
return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
|
||||||
}
|
}
|
||||||
return &UnixListener{fd, laddr.Name}, nil
|
return &UnixListener{fd, laddr.Name}, nil
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@ type Error interface {
|
|||||||
// Error.
|
// Error.
|
||||||
type ErrorString string
|
type ErrorString string
|
||||||
|
|
||||||
func (e ErrorString) String() string { return string(e) }
|
func (e ErrorString) String() string { return string(e) }
|
||||||
|
func (e ErrorString) Temporary() bool { return false }
|
||||||
|
func (e ErrorString) Timeout() bool { return false }
|
||||||
|
|
||||||
// Note: If the name of the function NewError changes,
|
// Note: If the name of the function NewError changes,
|
||||||
// pkg/go/doc/doc.go should be adjusted since it hardwires
|
// pkg/go/doc/doc.go should be adjusted since it hardwires
|
||||||
@ -30,6 +32,14 @@ type Errno int64
|
|||||||
|
|
||||||
func (e Errno) String() string { return syscall.Errstr(int(e)) }
|
func (e Errno) String() string { return syscall.Errstr(int(e)) }
|
||||||
|
|
||||||
|
func (e Errno) Temporary() bool {
|
||||||
|
return e == Errno(syscall.EINTR) || e.Timeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Errno) Timeout() bool {
|
||||||
|
return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK)
|
||||||
|
}
|
||||||
|
|
||||||
// Commonly known Unix errors.
|
// Commonly known Unix errors.
|
||||||
var (
|
var (
|
||||||
EPERM Error = Errno(syscall.EPERM)
|
EPERM Error = Errno(syscall.EPERM)
|
||||||
|
Loading…
Reference in New Issue
Block a user