Commit f72f4169 by Ian Lance Taylor

Update to current Go library.

From-SVN: r171732
parent f2034d06
...@@ -6,12 +6,14 @@ ...@@ -6,12 +6,14 @@
package main package main
import ( import "os"
"net"
) // Issue 481: closures and var declarations
// with multiple variables assigned from one
// function call.
func main() { func main() {
var listen, _ = net.Listen("tcp", "127.0.0.1:0") var listen, _ = Listen("tcp", "127.0.0.1:0")
go func() { go func() {
for { for {
...@@ -20,6 +22,31 @@ func main() { ...@@ -20,6 +22,31 @@ func main() {
} }
}() }()
var conn, _ = net.Dial("tcp", "", listen.Addr().String()) var conn, _ = Dial("tcp", "", listen.Addr().String())
_ = conn _ = conn
} }
// Simulated net interface to exercise bug
// without involving a real network.
type T chan int
var global T
func Listen(x, y string) (T, string) {
global = make(chan int)
return global, y
}
func (t T) Addr() os.Error {
return os.ErrorString("stringer")
}
func (t T) Accept() (int, string) {
return <-t, ""
}
func Dial(x, y, z string) (int, string) {
global <- 1
return 0, ""
}
31d7feb9281b 342e3b11f21a
The first line of this file holds the Mercurial revision number of the The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -657,6 +657,7 @@ endif # !LIBGO_IS_LINUX ...@@ -657,6 +657,7 @@ endif # !LIBGO_IS_LINUX
endif # !LIBGO_IS_RTEMS endif # !LIBGO_IS_RTEMS
go_net_files = \ go_net_files = \
go/net/cgo_stub.go \
go/net/dial.go \ go/net/dial.go \
go/net/dnsclient.go \ go/net/dnsclient.go \
go/net/dnsconfig.go \ go/net/dnsconfig.go \
...@@ -664,10 +665,12 @@ go_net_files = \ ...@@ -664,10 +665,12 @@ go_net_files = \
$(go_net_newpollserver_file) \ $(go_net_newpollserver_file) \
go/net/fd.go \ go/net/fd.go \
$(go_net_fd_os_file) \ $(go_net_fd_os_file) \
go/net/file.go \
go/net/hosts.go \ go/net/hosts.go \
go/net/ip.go \ go/net/ip.go \
go/net/iprawsock.go \ go/net/iprawsock.go \
go/net/ipsock.go \ go/net/ipsock.go \
go/net/lookup.go \
go/net/net.go \ go/net/net.go \
go/net/parse.go \ go/net/parse.go \
go/net/pipe.go \ go/net/pipe.go \
...@@ -1095,6 +1098,7 @@ go_go_ast_files = \ ...@@ -1095,6 +1098,7 @@ go_go_ast_files = \
go/go/ast/ast.go \ go/go/ast/ast.go \
go/go/ast/filter.go \ go/go/ast/filter.go \
go/go/ast/print.go \ go/go/ast/print.go \
go/go/ast/resolve.go \
go/go/ast/scope.go \ go/go/ast/scope.go \
go/go/ast/walk.go go/go/ast/walk.go
go_go_doc_files = \ go_go_doc_files = \
...@@ -2327,8 +2331,8 @@ exp/eval/check: $(CHECK_DEPS) ...@@ -2327,8 +2331,8 @@ exp/eval/check: $(CHECK_DEPS)
$(CHECK) $(CHECK)
.PHONY: exp/eval/check .PHONY: exp/eval/check
go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/token.gox io.gox os.gox \ go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/scanner.gox go/token.gox \
reflect.gox unicode.gox utf8.gox io.gox os.gox reflect.gox unicode.gox utf8.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
go/ast/check: $(CHECK_DEPS) go/ast/check: $(CHECK_DEPS)
@$(MKDIR_P) go/ast @$(MKDIR_P) go/ast
......
...@@ -1039,6 +1039,7 @@ go_mime_files = \ ...@@ -1039,6 +1039,7 @@ go_mime_files = \
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go @LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go @LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
go_net_files = \ go_net_files = \
go/net/cgo_stub.go \
go/net/dial.go \ go/net/dial.go \
go/net/dnsclient.go \ go/net/dnsclient.go \
go/net/dnsconfig.go \ go/net/dnsconfig.go \
...@@ -1046,10 +1047,12 @@ go_net_files = \ ...@@ -1046,10 +1047,12 @@ go_net_files = \
$(go_net_newpollserver_file) \ $(go_net_newpollserver_file) \
go/net/fd.go \ go/net/fd.go \
$(go_net_fd_os_file) \ $(go_net_fd_os_file) \
go/net/file.go \
go/net/hosts.go \ go/net/hosts.go \
go/net/ip.go \ go/net/ip.go \
go/net/iprawsock.go \ go/net/iprawsock.go \
go/net/ipsock.go \ go/net/ipsock.go \
go/net/lookup.go \
go/net/net.go \ go/net/net.go \
go/net/parse.go \ go/net/parse.go \
go/net/pipe.go \ go/net/pipe.go \
...@@ -1483,6 +1486,7 @@ go_go_ast_files = \ ...@@ -1483,6 +1486,7 @@ go_go_ast_files = \
go/go/ast/ast.go \ go/go/ast/ast.go \
go/go/ast/filter.go \ go/go/ast/filter.go \
go/go/ast/print.go \ go/go/ast/print.go \
go/go/ast/resolve.go \
go/go/ast/scope.go \ go/go/ast/scope.go \
go/go/ast/walk.go go/go/ast/walk.go
...@@ -4747,8 +4751,8 @@ exp/eval/check: $(CHECK_DEPS) ...@@ -4747,8 +4751,8 @@ exp/eval/check: $(CHECK_DEPS)
$(CHECK) $(CHECK)
.PHONY: exp/eval/check .PHONY: exp/eval/check
go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/token.gox io.gox os.gox \ go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/scanner.gox go/token.gox \
reflect.gox unicode.gox utf8.gox io.gox os.gox reflect.gox unicode.gox utf8.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
go/ast/check: $(CHECK_DEPS) go/ast/check: $(CHECK_DEPS)
@$(MKDIR_P) go/ast @$(MKDIR_P) go/ast
......
...@@ -150,5 +150,8 @@ testLoop: ...@@ -150,5 +150,8 @@ testLoop:
t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v", t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
i, bytediff(expected, actual)) i, bytediff(expected, actual))
} }
if testing.Short() { // The second test is expensive.
break
}
} }
} }
...@@ -389,6 +389,11 @@ func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflec ...@@ -389,6 +389,11 @@ func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflec
if err != nil { if err != nil {
return return
} }
// We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
// that a sequence of them can be parsed into a []string.
if t.tag == tagGeneralString {
t.tag = tagPrintableString
}
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag { if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
err = StructuralError{"sequence tag mismatch"} err = StructuralError{"sequence tag mismatch"}
return return
...@@ -516,7 +521,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -516,7 +521,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return return
} }
if params.explicit { if params.explicit {
if t.class == classContextSpecific && t.tag == *params.tag && (t.length == 0 || t.isCompound) { expectedClass := classContextSpecific
if params.application {
expectedClass = classApplication
}
if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
if t.length > 0 { if t.length > 0 {
t, offset, err = parseTagAndLength(bytes, offset) t, offset, err = parseTagAndLength(bytes, offset)
if err != nil { if err != nil {
...@@ -551,6 +560,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -551,6 +560,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
if universalTag == tagPrintableString && t.tag == tagIA5String { if universalTag == tagPrintableString && t.tag == tagIA5String {
universalTag = tagIA5String universalTag = tagIA5String
} }
// Likewise for GeneralString
if universalTag == tagPrintableString && t.tag == tagGeneralString {
universalTag = tagGeneralString
}
// Special case for time: UTCTime and GeneralizedTime both map to the // Special case for time: UTCTime and GeneralizedTime both map to the
// Go type time.Time. // Go type time.Time.
...@@ -566,6 +579,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -566,6 +579,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
expectedTag = *params.tag expectedTag = *params.tag
} }
if !params.explicit && params.application && params.tag != nil {
expectedClass = classApplication
expectedTag = *params.tag
}
// We have unwrapped any explicit tagging at this point. // We have unwrapped any explicit tagging at this point.
if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType { if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
// Tags don't match. Again, it could be an optional element. // Tags don't match. Again, it could be an optional element.
...@@ -701,6 +719,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -701,6 +719,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
v, err = parseIA5String(innerBytes) v, err = parseIA5String(innerBytes)
case tagT61String: case tagT61String:
v, err = parseT61String(innerBytes) v, err = parseT61String(innerBytes)
case tagGeneralString:
// GeneralString is specified in ISO-2022/ECMA-35,
// A brief review suggests that it includes structures
// that allow the encoding to change midstring and
// such. We give up and pass it as an 8-bit string.
v, err = parseT61String(innerBytes)
default: default:
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)} err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
} }
...@@ -776,8 +800,14 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { ...@@ -776,8 +800,14 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// Other ASN.1 types are not supported; if it encounters them, // Other ASN.1 types are not supported; if it encounters them,
// Unmarshal returns a parse error. // Unmarshal returns a parse error.
func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) { func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
return UnmarshalWithParams(b, val, "")
}
// UnmarshalWithParams allows field parameters to be specified for the
// top-level element. The form of the params is the same as the field tags.
func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
v := reflect.NewValue(val).(*reflect.PtrValue).Elem() v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
offset, err := parseField(v, b, 0, fieldParameters{}) offset, err := parseField(v, b, 0, parseFieldParameters(params))
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -249,11 +249,12 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame ...@@ -249,11 +249,12 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame
{"printable", fieldParameters{stringType: tagPrintableString}}, {"printable", fieldParameters{stringType: tagPrintableString}},
{"optional", fieldParameters{optional: true}}, {"optional", fieldParameters{optional: true}},
{"explicit", fieldParameters{explicit: true, tag: new(int)}}, {"explicit", fieldParameters{explicit: true, tag: new(int)}},
{"application", fieldParameters{application: true, tag: new(int)}},
{"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}}, {"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}},
{"default:42", fieldParameters{defaultValue: newInt64(42)}}, {"default:42", fieldParameters{defaultValue: newInt64(42)}},
{"tag:17", fieldParameters{tag: newInt(17)}}, {"tag:17", fieldParameters{tag: newInt(17)}},
{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}}, {"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, newInt64(42), newInt(17), 0, false}}, {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false}},
{"set", fieldParameters{set: true}}, {"set", fieldParameters{set: true}},
} }
......
...@@ -32,6 +32,7 @@ const ( ...@@ -32,6 +32,7 @@ const (
tagIA5String = 22 tagIA5String = 22
tagUTCTime = 23 tagUTCTime = 23
tagGeneralizedTime = 24 tagGeneralizedTime = 24
tagGeneralString = 27
) )
const ( const (
...@@ -67,7 +68,8 @@ type tagAndLength struct { ...@@ -67,7 +68,8 @@ type tagAndLength struct {
// fieldParameters is the parsed representation of tag string from a structure field. // fieldParameters is the parsed representation of tag string from a structure field.
type fieldParameters struct { type fieldParameters struct {
optional bool // true iff the field is OPTIONAL optional bool // true iff the field is OPTIONAL
explicit bool // true iff and EXPLICIT tag is in use. explicit bool // true iff an EXPLICIT tag is in use.
application bool // true iff an APPLICATION tag is in use.
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil). defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
stringType int // the string tag to use when marshaling. stringType int // the string tag to use when marshaling.
...@@ -89,7 +91,6 @@ func parseFieldParameters(str string) (ret fieldParameters) { ...@@ -89,7 +91,6 @@ func parseFieldParameters(str string) (ret fieldParameters) {
ret.explicit = true ret.explicit = true
if ret.tag == nil { if ret.tag == nil {
ret.tag = new(int) ret.tag = new(int)
*ret.tag = 0
} }
case part == "ia5": case part == "ia5":
ret.stringType = tagIA5String ret.stringType = tagIA5String
...@@ -109,6 +110,11 @@ func parseFieldParameters(str string) (ret fieldParameters) { ...@@ -109,6 +110,11 @@ func parseFieldParameters(str string) (ret fieldParameters) {
} }
case part == "set": case part == "set":
ret.set = true ret.set = true
case part == "application":
ret.application = true
if ret.tag == nil {
ret.tag = new(int)
}
} }
} }
return return
......
...@@ -716,18 +716,25 @@ var composites = []string{ ...@@ -716,18 +716,25 @@ var composites = []string{
func TestProbablyPrime(t *testing.T) { func TestProbablyPrime(t *testing.T) {
nreps := 20
if testing.Short() {
nreps = 1
}
for i, s := range primes { for i, s := range primes {
p, _ := new(Int).SetString(s, 10) p, _ := new(Int).SetString(s, 10)
if !ProbablyPrime(p, 20) { if !ProbablyPrime(p, nreps) {
t.Errorf("#%d prime found to be non-prime (%s)", i, s) t.Errorf("#%d prime found to be non-prime (%s)", i, s)
} }
} }
for i, s := range composites { for i, s := range composites {
c, _ := new(Int).SetString(s, 10) c, _ := new(Int).SetString(s, 10)
if ProbablyPrime(c, 20) { if ProbablyPrime(c, nreps) {
t.Errorf("#%d composite found to be prime (%s)", i, s) t.Errorf("#%d composite found to be prime (%s)", i, s)
} }
if testing.Short() {
break
}
} }
} }
......
...@@ -178,7 +178,11 @@ func TestBasicOperations(t *testing.T) { ...@@ -178,7 +178,11 @@ func TestBasicOperations(t *testing.T) {
func TestLargeStringWrites(t *testing.T) { func TestLargeStringWrites(t *testing.T) {
var buf Buffer var buf Buffer
for i := 3; i < 30; i += 3 { limit := 30
if testing.Short() {
limit = 9
}
for i := 3; i < limit; i += 3 {
s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data) s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data)
empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i)) empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i))
} }
...@@ -188,7 +192,11 @@ func TestLargeStringWrites(t *testing.T) { ...@@ -188,7 +192,11 @@ func TestLargeStringWrites(t *testing.T) {
func TestLargeByteWrites(t *testing.T) { func TestLargeByteWrites(t *testing.T) {
var buf Buffer var buf Buffer
for i := 3; i < 30; i += 3 { limit := 30
if testing.Short() {
limit = 9
}
for i := 3; i < limit; i += 3 {
s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, bytes) s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, bytes)
empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i)) empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i))
} }
......
...@@ -293,20 +293,10 @@ func Join(a [][]byte, sep []byte) []byte { ...@@ -293,20 +293,10 @@ func Join(a [][]byte, sep []byte) []byte {
} }
b := make([]byte, n) b := make([]byte, n)
bp := 0 bp := copy(b, a[0])
for i := 0; i < len(a); i++ { for _, s := range a[1:] {
s := a[i] bp += copy(b[bp:], sep)
for j := 0; j < len(s); j++ { bp += copy(b[bp:], s)
b[bp] = s[j]
bp++
}
if i+1 < len(a) {
s = sep
for j := 0; j < len(s); j++ {
b[bp] = s[j]
bp++
}
}
} }
return b return b
} }
......
...@@ -201,7 +201,10 @@ func TestIndexByte(t *testing.T) { ...@@ -201,7 +201,10 @@ func TestIndexByte(t *testing.T) {
// test a larger buffer with different sizes and alignments // test a larger buffer with different sizes and alignments
func TestIndexByteBig(t *testing.T) { func TestIndexByteBig(t *testing.T) {
const n = 1024 var n = 1024
if testing.Short() {
n = 128
}
b := make([]byte, n) b := make([]byte, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
// different start alignments // different start alignments
......
...@@ -33,6 +33,9 @@ func s(n uint64) string { ...@@ -33,6 +33,9 @@ func s(n uint64) string {
func TestVectorNums(t *testing.T) { func TestVectorNums(t *testing.T) {
if testing.Short() {
return
}
var v Vector var v Vector
c := int(0) c := int(0)
runtime.GC() runtime.GC()
...@@ -51,6 +54,9 @@ func TestVectorNums(t *testing.T) { ...@@ -51,6 +54,9 @@ func TestVectorNums(t *testing.T) {
func TestIntVectorNums(t *testing.T) { func TestIntVectorNums(t *testing.T) {
if testing.Short() {
return
}
var v IntVector var v IntVector
c := int(0) c := int(0)
runtime.GC() runtime.GC()
...@@ -69,6 +75,9 @@ func TestIntVectorNums(t *testing.T) { ...@@ -69,6 +75,9 @@ func TestIntVectorNums(t *testing.T) {
func TestStringVectorNums(t *testing.T) { func TestStringVectorNums(t *testing.T) {
if testing.Short() {
return
}
var v StringVector var v StringVector
c := "" c := ""
runtime.GC() runtime.GC()
......
...@@ -22,6 +22,10 @@ type ctr struct { ...@@ -22,6 +22,10 @@ type ctr struct {
// NewCTR returns a Stream which encrypts/decrypts using the given Block in // NewCTR returns a Stream which encrypts/decrypts using the given Block in
// counter mode. The length of iv must be the same as the Block's block size. // counter mode. The length of iv must be the same as the Block's block size.
func NewCTR(block Block, iv []byte) Stream { func NewCTR(block Block, iv []byte) Stream {
if len(iv) != block.BlockSize() {
panic("cipher.NewCTR: iv length must equal block size")
}
return &ctr{ return &ctr{
b: block, b: block,
ctr: dup(iv), ctr: dup(iv),
......
...@@ -20,12 +20,15 @@ func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) { ...@@ -20,12 +20,15 @@ func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) {
return return
} }
if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) { if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
t.Errorf("%s: public key invalid", tag, err) t.Errorf("%s: public key invalid: %s", tag, err)
} }
} }
func TestKeyGeneration(t *testing.T) { func TestKeyGeneration(t *testing.T) {
testKeyGeneration(t, elliptic.P224(), "p224") testKeyGeneration(t, elliptic.P224(), "p224")
if testing.Short() {
return
}
testKeyGeneration(t, elliptic.P256(), "p256") testKeyGeneration(t, elliptic.P256(), "p256")
testKeyGeneration(t, elliptic.P384(), "p384") testKeyGeneration(t, elliptic.P384(), "p384")
testKeyGeneration(t, elliptic.P521(), "p521") testKeyGeneration(t, elliptic.P521(), "p521")
...@@ -53,6 +56,9 @@ func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) { ...@@ -53,6 +56,9 @@ func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) {
func TestSignAndVerify(t *testing.T) { func TestSignAndVerify(t *testing.T) {
testSignAndVerify(t, elliptic.P224(), "p224") testSignAndVerify(t, elliptic.P224(), "p224")
if testing.Short() {
return
}
testSignAndVerify(t, elliptic.P256(), "p256") testSignAndVerify(t, elliptic.P256(), "p256")
testSignAndVerify(t, elliptic.P384(), "p384") testSignAndVerify(t, elliptic.P384(), "p384")
testSignAndVerify(t, elliptic.P521(), "p521") testSignAndVerify(t, elliptic.P521(), "p521")
...@@ -214,5 +220,8 @@ func TestVectors(t *testing.T) { ...@@ -214,5 +220,8 @@ func TestVectors(t *testing.T) {
if Verify(&pub, hashed, r, s) != test.ok { if Verify(&pub, hashed, r, s) != test.ok {
t.Errorf("%d: bad result", i) t.Errorf("%d: bad result", i)
} }
if testing.Short() {
break
}
} }
} }
...@@ -297,6 +297,9 @@ func TestBaseMult(t *testing.T) { ...@@ -297,6 +297,9 @@ func TestBaseMult(t *testing.T) {
if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y { if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%s, %s)", i, e.k, x, y, e.x, e.y) t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%s, %s)", i, e.k, x, y, e.x, e.y)
} }
if testing.Short() && i > 5 {
break
}
} }
} }
......
...@@ -90,5 +90,8 @@ func TestParse(t *testing.T) { ...@@ -90,5 +90,8 @@ func TestParse(t *testing.T) {
if !bytes.Equal(out, expected) { if !bytes.Equal(out, expected) {
t.Errorf("%d: output got: %x want: %x", i, out, expected) t.Errorf("%d: output got: %x want: %x", i, out, expected)
} }
if testing.Short() {
break
}
} }
} }
...@@ -11,7 +11,11 @@ import ( ...@@ -11,7 +11,11 @@ import (
) )
func TestRead(t *testing.T) { func TestRead(t *testing.T) {
b := make([]byte, 4e6) var n int = 4e6
if testing.Short() {
n = 1e5
}
b := make([]byte, n)
n, err := Read(b) n, err := Read(b)
if n != len(b) || err != nil { if n != len(b) || err != nil {
t.Fatalf("Read(buf) = %d, %s", n, err) t.Fatalf("Read(buf) = %d, %s", n, err)
......
...@@ -97,7 +97,11 @@ func TestEncryptPKCS1v15(t *testing.T) { ...@@ -97,7 +97,11 @@ func TestEncryptPKCS1v15(t *testing.T) {
return true return true
} }
quick.Check(tryEncryptDecrypt, nil) config := new(quick.Config)
if testing.Short() {
config.MaxCount = 10
}
quick.Check(tryEncryptDecrypt, config)
} }
// These test vectors were generated with `openssl rsautl -pkcs -encrypt` // These test vectors were generated with `openssl rsautl -pkcs -encrypt`
......
...@@ -15,7 +15,11 @@ import ( ...@@ -15,7 +15,11 @@ import (
func TestKeyGeneration(t *testing.T) { func TestKeyGeneration(t *testing.T) {
random := rand.Reader random := rand.Reader
priv, err := GenerateKey(random, 1024) size := 1024
if testing.Short() {
size = 128
}
priv, err := GenerateKey(random, size)
if err != nil { if err != nil {
t.Errorf("failed to generate key") t.Errorf("failed to generate key")
} }
...@@ -99,6 +103,9 @@ func TestDecryptOAEP(t *testing.T) { ...@@ -99,6 +103,9 @@ func TestDecryptOAEP(t *testing.T) {
t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in) t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in)
} }
} }
if testing.Short() {
break
}
} }
} }
......
...@@ -93,9 +93,10 @@ const ( ...@@ -93,9 +93,10 @@ const (
// ConnectionState records basic TLS details about the connection. // ConnectionState records basic TLS details about the connection.
type ConnectionState struct { type ConnectionState struct {
HandshakeComplete bool HandshakeComplete bool
CipherSuite uint16 CipherSuite uint16
NegotiatedProtocol string NegotiatedProtocol string
NegotiatedProtocolIsMutual bool
// the certificate chain that was presented by the other side // the certificate chain that was presented by the other side
PeerCertificates []*x509.Certificate PeerCertificates []*x509.Certificate
...@@ -124,7 +125,6 @@ type Config struct { ...@@ -124,7 +125,6 @@ type Config struct {
RootCAs *CASet RootCAs *CASet
// NextProtos is a list of supported, application level protocols. // NextProtos is a list of supported, application level protocols.
// Currently only server-side handling is supported.
NextProtos []string NextProtos []string
// ServerName is included in the client's handshake to support virtual // ServerName is included in the client's handshake to support virtual
......
...@@ -35,7 +35,8 @@ type Conn struct { ...@@ -35,7 +35,8 @@ type Conn struct {
ocspResponse []byte // stapled OCSP response ocspResponse []byte // stapled OCSP response
peerCertificates []*x509.Certificate peerCertificates []*x509.Certificate
clientProtocol string clientProtocol string
clientProtocolFallback bool
// first permanent error // first permanent error
errMutex sync.Mutex errMutex sync.Mutex
...@@ -761,6 +762,7 @@ func (c *Conn) ConnectionState() ConnectionState { ...@@ -761,6 +762,7 @@ func (c *Conn) ConnectionState() ConnectionState {
state.HandshakeComplete = c.handshakeComplete state.HandshakeComplete = c.handshakeComplete
if c.handshakeComplete { if c.handshakeComplete {
state.NegotiatedProtocol = c.clientProtocol state.NegotiatedProtocol = c.clientProtocol
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
state.CipherSuite = c.cipherSuite state.CipherSuite = c.cipherSuite
state.PeerCertificates = c.peerCertificates state.PeerCertificates = c.peerCertificates
} }
......
...@@ -29,6 +29,7 @@ func (c *Conn) clientHandshake() os.Error { ...@@ -29,6 +29,7 @@ func (c *Conn) clientHandshake() os.Error {
serverName: c.config.ServerName, serverName: c.config.ServerName,
supportedCurves: []uint16{curveP256, curveP384, curveP521}, supportedCurves: []uint16{curveP256, curveP384, curveP521},
supportedPoints: []uint8{pointFormatUncompressed}, supportedPoints: []uint8{pointFormatUncompressed},
nextProtoNeg: len(c.config.NextProtos) > 0,
} }
t := uint32(c.config.time()) t := uint32(c.config.time())
...@@ -66,6 +67,11 @@ func (c *Conn) clientHandshake() os.Error { ...@@ -66,6 +67,11 @@ func (c *Conn) clientHandshake() os.Error {
return c.sendAlert(alertUnexpectedMessage) return c.sendAlert(alertUnexpectedMessage)
} }
if !hello.nextProtoNeg && serverHello.nextProtoNeg {
c.sendAlert(alertHandshakeFailure)
return os.ErrorString("server advertised unrequested NPN")
}
suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite) suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
if suite == nil { if suite == nil {
return c.sendAlert(alertHandshakeFailure) return c.sendAlert(alertHandshakeFailure)
...@@ -267,6 +273,17 @@ func (c *Conn) clientHandshake() os.Error { ...@@ -267,6 +273,17 @@ func (c *Conn) clientHandshake() os.Error {
c.out.prepareCipherSpec(clientCipher, clientHash) c.out.prepareCipherSpec(clientCipher, clientHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
if serverHello.nextProtoNeg {
nextProto := new(nextProtoMsg)
proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos)
nextProto.proto = proto
c.clientProtocol = proto
c.clientProtocolFallback = fallback
finishedHash.Write(nextProto.marshal())
c.writeRecord(recordTypeHandshake, nextProto.marshal())
}
finished := new(finishedMsg) finished := new(finishedMsg)
finished.verifyData = finishedHash.clientSum(masterSecret) finished.verifyData = finishedHash.clientSum(masterSecret)
finishedHash.Write(finished.marshal()) finishedHash.Write(finished.marshal())
...@@ -299,3 +316,19 @@ func (c *Conn) clientHandshake() os.Error { ...@@ -299,3 +316,19 @@ func (c *Conn) clientHandshake() os.Error {
c.cipherSuite = suiteId c.cipherSuite = suiteId
return nil return nil
} }
// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
// set of client and server supported protocols. The set of client supported
// protocols must not be empty. It returns the resulting protocol and flag
// indicating if the fallback case was reached.
func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
for _, s := range serverProtos {
for _, c := range clientProtos {
if s == c {
return s, false
}
}
}
return clientProtos[0], true
}
...@@ -50,7 +50,7 @@ func TestRunClient(t *testing.T) { ...@@ -50,7 +50,7 @@ func TestRunClient(t *testing.T) {
testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
conn, err := Dial("tcp", "", "127.0.0.1:10443", testConfig) conn, err := Dial("tcp", "127.0.0.1:10443", testConfig)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -34,7 +34,11 @@ func TestMarshalUnmarshal(t *testing.T) { ...@@ -34,7 +34,11 @@ func TestMarshalUnmarshal(t *testing.T) {
for i, iface := range tests { for i, iface := range tests {
ty := reflect.NewValue(iface).Type() ty := reflect.NewValue(iface).Type()
for j := 0; j < 100; j++ { n := 100
if testing.Short() {
n = 5
}
for j := 0; j < n; j++ {
v, ok := quick.Value(ty, rand) v, ok := quick.Value(ty, rand)
if !ok { if !ok {
t.Errorf("#%d: failed to create value", i) t.Errorf("#%d: failed to create value", i)
......
...@@ -87,8 +87,9 @@ func Listen(network, laddr string, config *Config) (*Listener, os.Error) { ...@@ -87,8 +87,9 @@ func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
// Dial interprets a nil configuration as equivalent to // Dial interprets a nil configuration as equivalent to
// the zero configuration; see the documentation of Config // the zero configuration; see the documentation of Config
// for the defaults. // for the defaults.
func Dial(network, laddr, raddr string, config *Config) (*Conn, os.Error) { func Dial(network, addr string, config *Config) (*Conn, os.Error) {
c, err := net.Dial(network, laddr, raddr) raddr := addr
c, err := net.Dial(network, raddr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -304,6 +304,42 @@ const ( ...@@ -304,6 +304,42 @@ const (
KeyUsageDecipherOnly KeyUsageDecipherOnly
) )
// RFC 5280, 4.2.1.12 Extended Key Usage
//
// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
//
// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
//
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
var (
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
)
// ExtKeyUsage represents an extended set of actions that are valid for a given key.
// Each of the ExtKeyUsage* constants define a unique action.
type ExtKeyUsage int
const (
ExtKeyUsageAny ExtKeyUsage = iota
ExtKeyUsageServerAuth
ExtKeyUsageClientAuth
ExtKeyUsageCodeSigning
ExtKeyUsageEmailProtection
ExtKeyUsageTimeStamping
ExtKeyUsageOCSPSigning
)
// A Certificate represents an X.509 certificate. // A Certificate represents an X.509 certificate.
type Certificate struct { type Certificate struct {
Raw []byte // Raw ASN.1 DER contents. Raw []byte // Raw ASN.1 DER contents.
...@@ -320,6 +356,9 @@ type Certificate struct { ...@@ -320,6 +356,9 @@ type Certificate struct {
NotBefore, NotAfter *time.Time // Validity bounds. NotBefore, NotAfter *time.Time // Validity bounds.
KeyUsage KeyUsage KeyUsage KeyUsage
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
BasicConstraintsValid bool // if true then the next two fields are valid. BasicConstraintsValid bool // if true then the next two fields are valid.
IsCA bool IsCA bool
MaxPathLen int MaxPathLen int
...@@ -666,6 +705,44 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { ...@@ -666,6 +705,44 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
out.AuthorityKeyId = a.Id out.AuthorityKeyId = a.Id
continue continue
case 37:
// RFC 5280, 4.2.1.12. Extended Key Usage
// id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
//
// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
//
// KeyPurposeId ::= OBJECT IDENTIFIER
var keyUsage []asn1.ObjectIdentifier
_, err = asn1.Unmarshal(e.Value, &keyUsage)
if err != nil {
return nil, err
}
for _, u := range keyUsage {
switch {
case u.Equal(oidExtKeyUsageAny):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageAny)
case u.Equal(oidExtKeyUsageServerAuth):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageServerAuth)
case u.Equal(oidExtKeyUsageClientAuth):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageClientAuth)
case u.Equal(oidExtKeyUsageCodeSigning):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageCodeSigning)
case u.Equal(oidExtKeyUsageEmailProtection):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageEmailProtection)
case u.Equal(oidExtKeyUsageTimeStamping):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageTimeStamping)
case u.Equal(oidExtKeyUsageOCSPSigning):
out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageOCSPSigning)
default:
out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)
}
}
continue
case 14: case 14:
// RFC 5280, 4.2.1.2 // RFC 5280, 4.2.1.2
var keyid []byte var keyid []byte
......
...@@ -143,9 +143,6 @@ func TestLineAline(t *testing.T) { ...@@ -143,9 +143,6 @@ func TestLineAline(t *testing.T) {
} }
} }
// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then
// gotest: mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
// gotest: fi
func TestPCLine(t *testing.T) { func TestPCLine(t *testing.T) {
if !dotest() { if !dotest() {
return return
......
...@@ -15,31 +15,26 @@ var fset = token.NewFileSet() ...@@ -15,31 +15,26 @@ var fset = token.NewFileSet()
var grammars = []string{ var grammars = []string{
`Program = . `Program = .`,
`,
`Program = foo .
`Program = foo . foo = "foo" .`,
foo = "foo" .
`, `Program = "a" | "b" "c" .`,
`Program = "a" | "b" "c" . `Program = "a" ... "z" .`,
`,
`Program = Song .
`Program = "a" ... "z" . Song = { Note } .
`, Note = Do | (Re | Mi | Fa | So | La) | Ti .
Do = "c" .
`Program = Song . Re = "d" .
Song = { Note } . Mi = "e" .
Note = Do | (Re | Mi | Fa | So | La) | Ti . Fa = "f" .
Do = "c" . So = "g" .
Re = "d" . La = "a" .
Mi = "e" . Ti = ti .
Fa = "f" . ti = "b" .`,
So = "g" .
La = "a" .
Ti = ti .
ti = "b" .
`,
} }
......
...@@ -18,7 +18,7 @@ type parser struct { ...@@ -18,7 +18,7 @@ type parser struct {
scanner scanner.Scanner scanner scanner.Scanner
pos token.Pos // token position pos token.Pos // token position
tok token.Token // one token look-ahead tok token.Token // one token look-ahead
lit []byte // token literal lit string // token literal
} }
...@@ -44,7 +44,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { ...@@ -44,7 +44,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
// make the error message more specific // make the error message more specific
msg += ", found '" + p.tok.String() + "'" msg += ", found '" + p.tok.String() + "'"
if p.tok.IsLiteral() { if p.tok.IsLiteral() {
msg += " " + string(p.lit) msg += " " + p.lit
} }
} }
p.error(pos, msg) p.error(pos, msg)
...@@ -63,7 +63,7 @@ func (p *parser) expect(tok token.Token) token.Pos { ...@@ -63,7 +63,7 @@ func (p *parser) expect(tok token.Token) token.Pos {
func (p *parser) parseIdentifier() *Name { func (p *parser) parseIdentifier() *Name {
pos := p.pos pos := p.pos
name := string(p.lit) name := p.lit
p.expect(token.IDENT) p.expect(token.IDENT)
return &Name{pos, name} return &Name{pos, name}
} }
...@@ -73,7 +73,7 @@ func (p *parser) parseToken() *Token { ...@@ -73,7 +73,7 @@ func (p *parser) parseToken() *Token {
pos := p.pos pos := p.pos
value := "" value := ""
if p.tok == token.STRING { if p.tok == token.STRING {
value, _ = strconv.Unquote(string(p.lit)) value, _ = strconv.Unquote(p.lit)
// Unquote may fail with an error, but only if the scanner found // Unquote may fail with an error, but only if the scanner found
// an illegal string in the first place. In this case the error // an illegal string in the first place. In this case the error
// has already been reported. // has already been reported.
......
...@@ -22,7 +22,7 @@ type parser struct { ...@@ -22,7 +22,7 @@ type parser struct {
file *token.File file *token.File
pos token.Pos // token position pos token.Pos // token position
tok token.Token // one token look-ahead tok token.Token // one token look-ahead
lit []byte // token literal lit string // token literal
packs map[string]string // PackageName -> ImportPath packs map[string]string // PackageName -> ImportPath
rules map[string]expr // RuleName -> Expression rules map[string]expr // RuleName -> Expression
...@@ -62,7 +62,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { ...@@ -62,7 +62,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
// make the error message more specific // make the error message more specific
msg += ", found '" + p.tok.String() + "'" msg += ", found '" + p.tok.String() + "'"
if p.tok.IsLiteral() { if p.tok.IsLiteral() {
msg += " " + string(p.lit) msg += " " + p.lit
} }
} }
p.error(pos, msg) p.error(pos, msg)
...@@ -80,7 +80,7 @@ func (p *parser) expect(tok token.Token) token.Pos { ...@@ -80,7 +80,7 @@ func (p *parser) expect(tok token.Token) token.Pos {
func (p *parser) parseIdentifier() string { func (p *parser) parseIdentifier() string {
name := string(p.lit) name := p.lit
p.expect(token.IDENT) p.expect(token.IDENT)
return name return name
} }
...@@ -130,7 +130,7 @@ func (p *parser) parseRuleName() (string, bool) { ...@@ -130,7 +130,7 @@ func (p *parser) parseRuleName() (string, bool) {
func (p *parser) parseString() string { func (p *parser) parseString() string {
s := "" s := ""
if p.tok == token.STRING { if p.tok == token.STRING {
s, _ = strconv.Unquote(string(p.lit)) s, _ = strconv.Unquote(p.lit)
// Unquote may fail with an error, but only if the scanner found // Unquote may fail with an error, but only if the scanner found
// an illegal string in the first place. In this case the error // an illegal string in the first place. In this case the error
// has already been reported. // has already been reported.
...@@ -181,7 +181,7 @@ func (p *parser) parseField() expr { ...@@ -181,7 +181,7 @@ func (p *parser) parseField() expr {
var fname string var fname string
switch p.tok { switch p.tok {
case token.ILLEGAL: case token.ILLEGAL:
if string(p.lit) != "@" { if p.lit != "@" {
return nil return nil
} }
fname = "@" fname = "@"
......
...@@ -286,11 +286,11 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) { ...@@ -286,11 +286,11 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
} }
// Make the connection. // Make the connection.
if socket != "" { if socket != "" {
conn, err = net.Dial("unix", "", socket+":"+displayStr) conn, err = net.Dial("unix", socket+":"+displayStr)
} else if host != "" { } else if host != "" {
conn, err = net.Dial(protocol, "", host+":"+strconv.Itoa(6000+displayInt)) conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt))
} else { } else {
conn, err = net.Dial("unix", "", "/tmp/.X11-unix/X"+displayStr) conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr)
} }
if err != nil { if err != nil {
return nil, "", os.NewError("cannot connect to " + display + ": " + err.String()) return nil, "", os.NewError("cannot connect to " + display + ": " + err.String())
......
...@@ -39,9 +39,13 @@ type job struct { ...@@ -39,9 +39,13 @@ type job struct {
} }
func runTests(t *testing.T, baseName string, tests []test) { func runTests(t *testing.T, baseName string, tests []test) {
for i, test := range tests { delta := 1
if testing.Short() {
delta = 16
}
for i := 0; i < len(tests); i += delta {
name := fmt.Sprintf("%s[%d]", baseName, i) name := fmt.Sprintf("%s[%d]", baseName, i)
test.run(t, name) tests[i].run(t, name)
} }
} }
......
...@@ -205,7 +205,7 @@ func parseLoad(args []byte) (ident string, path string, err os.Error) { ...@@ -205,7 +205,7 @@ func parseLoad(args []byte) (ident string, path string, err os.Error) {
sc, ev := newScanner(args) sc, ev := newScanner(args)
var toks [4]token.Token var toks [4]token.Token
var lits [4][]byte var lits [4]string
for i := range toks { for i := range toks {
_, toks[i], lits[i] = sc.Scan() _, toks[i], lits[i] = sc.Scan()
} }
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
flag.Bool(...) // global options flag.Bool(...) // global options
flag.Parse() // parse leading command flag.Parse() // parse leading command
subcmd := flag.Arg[0] subcmd := flag.Arg(0)
switch subcmd { switch subcmd {
// add per-subcommand options // add per-subcommand options
} }
......
...@@ -442,6 +442,9 @@ func BenchmarkSprintfPrefixedInt(b *testing.B) { ...@@ -442,6 +442,9 @@ func BenchmarkSprintfPrefixedInt(b *testing.B) {
} }
func TestCountMallocs(t *testing.T) { func TestCountMallocs(t *testing.T) {
if testing.Short() {
return
}
mallocs := 0 - runtime.MemStats.Mallocs mallocs := 0 - runtime.MemStats.Mallocs
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
Sprintf("") Sprintf("")
......
...@@ -66,7 +66,7 @@ type Decl interface { ...@@ -66,7 +66,7 @@ type Decl interface {
// A Comment node represents a single //-style or /*-style comment. // A Comment node represents a single //-style or /*-style comment.
type Comment struct { type Comment struct {
Slash token.Pos // position of "/" starting the comment Slash token.Pos // position of "/" starting the comment
Text []byte // comment text (excluding '\n' for //-style comments) Text string // comment text (excluding '\n' for //-style comments)
} }
...@@ -199,7 +199,7 @@ type ( ...@@ -199,7 +199,7 @@ type (
BasicLit struct { BasicLit struct {
ValuePos token.Pos // literal position ValuePos token.Pos // literal position
Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o` Value string // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
} }
// A FuncLit node represents a function literal. // A FuncLit node represents a function literal.
...@@ -781,7 +781,7 @@ type ( ...@@ -781,7 +781,7 @@ type (
ImportSpec struct { ImportSpec struct {
Doc *CommentGroup // associated documentation; or nil Doc *CommentGroup // associated documentation; or nil
Name *Ident // local package name (including "."); or nil Name *Ident // local package name (including "."); or nil
Path *BasicLit // package path Path *BasicLit // import path
Comment *CommentGroup // line comments; or nil Comment *CommentGroup // line comments; or nil
} }
...@@ -925,8 +925,9 @@ type File struct { ...@@ -925,8 +925,9 @@ type File struct {
Package token.Pos // position of "package" keyword Package token.Pos // position of "package" keyword
Name *Ident // package name Name *Ident // package name
Decls []Decl // top-level declarations; or nil Decls []Decl // top-level declarations; or nil
Scope *Scope // package scope Scope *Scope // package scope (this file only)
Unresolved []*Ident // unresolved global identifiers Imports []*ImportSpec // imports in this file
Unresolved []*Ident // unresolved identifiers in this file
Comments []*CommentGroup // list of all comments in the source file Comments []*CommentGroup // list of all comments in the source file
} }
...@@ -944,9 +945,10 @@ func (f *File) End() token.Pos { ...@@ -944,9 +945,10 @@ func (f *File) End() token.Pos {
// collectively building a Go package. // collectively building a Go package.
// //
type Package struct { type Package struct {
Name string // package name Name string // package name
Scope *Scope // package scope Scope *Scope // package scope
Files map[string]*File // Go source files by filename Imports map[string]*Scope // map of import path -> package scope across all files
Files map[string]*File // Go source files by filename
} }
......
...@@ -304,7 +304,7 @@ const ( ...@@ -304,7 +304,7 @@ const (
// separator is an empty //-style comment that is interspersed between // separator is an empty //-style comment that is interspersed between
// different comment groups when they are concatenated into a single group // different comment groups when they are concatenated into a single group
// //
var separator = &Comment{noPos, []byte("//")} var separator = &Comment{noPos, "//"}
// MergePackageFiles creates a file AST by merging the ASTs of the // MergePackageFiles creates a file AST by merging the ASTs of the
...@@ -426,5 +426,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File { ...@@ -426,5 +426,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
} }
// TODO(gri) need to compute pkgScope and unresolved identifiers! // TODO(gri) need to compute pkgScope and unresolved identifiers!
return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, comments} // TODO(gri) need to compute imports!
return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, nil, comments}
} }
// 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.
// This file implements NewPackage.
package ast
import (
"fmt"
"go/scanner"
"go/token"
"os"
)
type pkgBuilder struct {
scanner.ErrorVector
fset *token.FileSet
}
func (p *pkgBuilder) error(pos token.Pos, msg string) {
p.Error(p.fset.Position(pos), msg)
}
func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) {
p.error(pos, fmt.Sprintf(format, args...))
}
func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
alt := scope.Insert(obj)
if alt == nil && altScope != nil {
// see if there is a conflicting declaration in altScope
alt = altScope.Lookup(obj.Name)
}
if alt != nil {
prevDecl := ""
if pos := alt.Pos(); pos.IsValid() {
prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.fset.Position(pos))
}
p.error(obj.Pos(), fmt.Sprintf("%s redeclared in this block%s", obj.Name, prevDecl))
}
}
func resolve(scope *Scope, ident *Ident) bool {
for ; scope != nil; scope = scope.Outer {
if obj := scope.Lookup(ident.Name); obj != nil {
ident.Obj = obj
return true
}
}
return false
}
// NewPackage uses an Importer to resolve imports. Given an importPath,
// an importer returns the imported package's name, its scope of exported
// objects, and an error, if any.
//
type Importer func(path string) (name string, scope *Scope, err os.Error)
// NewPackage creates a new Package node from a set of File nodes. It resolves
// unresolved identifiers across files and updates each file's Unresolved list
// accordingly. If a non-nil importer and universe scope are provided, they are
// used to resolve identifiers not declared in any of the package files. Any
// remaining unresolved identifiers are reported as undeclared. If the files
// belong to different packages, one package name is selected and files with
// different package name are reported and then ignored.
// The result is a package node and a scanner.ErrorList if there were errors.
//
func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) {
var p pkgBuilder
p.fset = fset
// complete package scope
pkgName := ""
pkgScope := NewScope(universe)
for _, file := range files {
// package names must match
switch name := file.Name.Name; {
case pkgName == "":
pkgName = name
case name != pkgName:
p.errorf(file.Package, "package %s; expected %s", name, pkgName)
continue // ignore this file
}
// collect top-level file objects in package scope
for _, obj := range file.Scope.Objects {
p.declare(pkgScope, nil, obj)
}
}
// imports maps import paths to package names and scopes
// TODO(gri): Eventually we like to get to the import scope from
// a package object. Then we can have a map path -> Obj.
type importedPkg struct {
name string
scope *Scope
}
imports := make(map[string]*importedPkg)
// complete file scopes with imports and resolve identifiers
for _, file := range files {
// ignore file if it belongs to a different package
// (error has already been reported)
if file.Name.Name != pkgName {
continue
}
// build file scope by processing all imports
importErrors := false
fileScope := NewScope(pkgScope)
for _, spec := range file.Imports {
// add import to global map of imports
path := string(spec.Path.Value)
path = path[1 : len(path)-1] // strip ""'s
pkg := imports[path]
if pkg == nil {
if importer == nil {
importErrors = true
continue
}
name, scope, err := importer(path)
if err != nil {
p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
importErrors = true
continue
}
pkg = &importedPkg{name, scope}
imports[path] = pkg
// TODO(gri) If a local package name != "." is provided,
// global identifier resolution could proceed even if the
// import failed. Consider adjusting the logic here a bit.
}
// local name overrides imported package name
name := pkg.name
if spec.Name != nil {
name = spec.Name.Name
}
// add import to file scope
if name == "." {
// merge imported scope with file scope
for _, obj := range pkg.scope.Objects {
p.declare(fileScope, pkgScope, obj)
}
} else {
// declare imported package object in file scope
obj := NewObj(Pkg, name)
obj.Decl = spec
p.declare(fileScope, pkgScope, obj)
}
}
// resolve identifiers
if importErrors {
// don't use the universe scope without correct imports
// (objects in the universe may be shadowed by imports;
// with missing imports identifiers might get resolved
// wrongly)
pkgScope.Outer = nil
}
i := 0
for _, ident := range file.Unresolved {
if !resolve(fileScope, ident) {
p.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
file.Unresolved[i] = ident
i++
}
}
file.Unresolved = file.Unresolved[0:i]
pkgScope.Outer = universe // reset universe scope
}
// collect all import paths and respective package scopes
importedScopes := make(map[string]*Scope)
for path, pkg := range imports {
importedScopes[path] = pkg.scope
}
return &Package{pkgName, pkgScope, importedScopes, files}, p.GetError(scanner.Sorted)
}
...@@ -39,16 +39,14 @@ func (s *Scope) Lookup(name string) *Object { ...@@ -39,16 +39,14 @@ func (s *Scope) Lookup(name string) *Object {
} }
// Insert attempts to insert a named object into the scope s. // Insert attempts to insert a named object obj into the scope s.
// If the scope does not contain an object with that name yet, // If the scope already contains an object alt with the same name,
// Insert inserts the object and returns it. Otherwise, Insert // Insert leaves the scope unchanged and returns alt. Otherwise
// leaves the scope unchanged and returns the object found in // it inserts obj and returns nil."
// the scope instead.
// //
func (s *Scope) Insert(obj *Object) (alt *Object) { func (s *Scope) Insert(obj *Object) (alt *Object) {
if alt = s.Objects[obj.Name]; alt == nil { if alt = s.Objects[obj.Name]; alt == nil {
s.Objects[obj.Name] = obj s.Objects[obj.Name] = obj
alt = obj
} }
return return
} }
...@@ -101,6 +99,11 @@ func (obj *Object) Pos() token.Pos { ...@@ -101,6 +99,11 @@ func (obj *Object) Pos() token.Pos {
return n.Pos() return n.Pos()
} }
} }
case *ImportSpec:
if d.Name != nil && d.Name.Name == name {
return d.Name.Pos()
}
return d.Path.Pos()
case *ValueSpec: case *ValueSpec:
for _, n := range d.Names { for _, n := range d.Names {
if n.Name == name { if n.Name == name {
......
...@@ -286,7 +286,7 @@ func unindent(block [][]byte) { ...@@ -286,7 +286,7 @@ func unindent(block [][]byte) {
// nor to have trailing spaces at the end of lines. // nor to have trailing spaces at the end of lines.
// The comment markers have already been removed. // The comment markers have already been removed.
// //
// Turn each run of multiple \n into </p><p> // Turn each run of multiple \n into </p><p>.
// Turn each run of indented lines into a <pre> block without indent. // Turn each run of indented lines into a <pre> block without indent.
// //
// URLs in the comment text are converted into links; if the URL also appears // URLs in the comment text are converted into links; if the URL also appears
......
...@@ -66,7 +66,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) { ...@@ -66,7 +66,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
n2 := len(comments.List) n2 := len(comments.List)
list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
copy(list, doc.doc.List) copy(list, doc.doc.List)
list[n1] = &ast.Comment{token.NoPos, []byte("//")} // separator line list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
copy(list[n1+1:], comments.List) copy(list[n1+1:], comments.List)
doc.doc = &ast.CommentGroup{list} doc.doc = &ast.CommentGroup{list}
} }
...@@ -105,7 +105,7 @@ func baseTypeName(typ ast.Expr) string { ...@@ -105,7 +105,7 @@ func baseTypeName(typ ast.Expr) string {
// if the type is not exported, the effect to // if the type is not exported, the effect to
// a client is as if there were no type name // a client is as if there were no type name
if t.IsExported() { if t.IsExported() {
return string(t.Name) return t.Name
} }
case *ast.StarExpr: case *ast.StarExpr:
return baseTypeName(t.X) return baseTypeName(t.X)
...@@ -300,9 +300,9 @@ func (doc *docReader) addFile(src *ast.File) { ...@@ -300,9 +300,9 @@ func (doc *docReader) addFile(src *ast.File) {
// collect BUG(...) comments // collect BUG(...) comments
for _, c := range src.Comments { for _, c := range src.Comments {
text := c.List[0].Text text := c.List[0].Text
if m := bug_markers.FindIndex(text); m != nil { if m := bug_markers.FindStringIndex(text); m != nil {
// found a BUG comment; maybe empty // found a BUG comment; maybe empty
if btxt := text[m[1]:]; bug_content.Match(btxt) { if btxt := text[m[1]:]; bug_content.MatchString(btxt) {
// non-empty BUG comment; collect comment without BUG prefix // non-empty BUG comment; collect comment without BUG prefix
list := copyCommentList(c.List) list := copyCommentList(c.List)
list[0].Text = text[m[1]:] list[0].Text = text[m[1]:]
......
...@@ -69,7 +69,7 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, ...@@ -69,7 +69,7 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
var p parser var p parser
p.init(fset, filename, data, 0) p.init(fset, filename, data, 0)
x := p.parseExpr() x := p.parseRhs()
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next() // consume automatically inserted semicolon, if any p.next() // consume automatically inserted semicolon, if any
} }
...@@ -159,7 +159,8 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st ...@@ -159,7 +159,8 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
name := src.Name.Name name := src.Name.Name
pkg, found := pkgs[name] pkg, found := pkgs[name]
if !found { if !found {
pkg = &ast.Package{name, nil, make(map[string]*ast.File)} // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
pkgs[name] = pkg pkgs[name] = pkg
} }
pkg.Files[filename] = src pkg.Files[filename] = src
......
...@@ -160,19 +160,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp ...@@ -160,19 +160,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// the first linebreak is always a formfeed since this section must not // the first linebreak is always a formfeed since this section must not
// depend on any previous formatting // depend on any previous formatting
prevBreak := -1 // index of last expression that was followed by a linebreak prevBreak := -1 // index of last expression that was followed by a linebreak
linebreakMin := 1 if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
if mode&periodSep != 0 {
// Make fragments like
//
// a.Bar(1,
// 2).Foo
//
// format correctly (a linebreak shouldn't be added before Foo) when
// doing period-separated expr lists by setting minimum linebreak to 0
// lines for them.
linebreakMin = 0
}
if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) {
ws = ignore ws = ignore
*multiLine = true *multiLine = true
prevBreak = 0 prevBreak = 0
...@@ -237,7 +225,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp ...@@ -237,7 +225,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// lines are broken using newlines so comments remain aligned // lines are broken using newlines so comments remain aligned
// unless forceFF is set or there are multiple expressions on // unless forceFF is set or there are multiple expressions on
// the same line in which case formfeed is used // the same line in which case formfeed is used
if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) { if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
ws = ignore ws = ignore
*multiLine = true *multiLine = true
prevBreak = i prevBreak = i
...@@ -363,7 +351,7 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool { ...@@ -363,7 +351,7 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
func (p *printer) setLineComment(text string) { func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, []byte(text)}}}) p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
} }
...@@ -527,7 +515,7 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { ...@@ -527,7 +515,7 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
} }
case *ast.StarExpr: case *ast.StarExpr:
if e.Op.String() == "/" { if e.Op == token.QUO { // `*/`
maxProblem = 5 maxProblem = 5
} }
......
...@@ -114,7 +114,7 @@ func check(t *testing.T, source, golden string, mode checkMode) { ...@@ -114,7 +114,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
// start a timer to produce a time-out signal // start a timer to produce a time-out signal
tc := make(chan int) tc := make(chan int)
go func() { go func() {
time.Sleep(20e9) // plenty of a safety margin, even for very slow machines time.Sleep(10e9) // plenty of a safety margin, even for very slow machines
tc <- 0 tc <- 0
}() }()
...@@ -156,12 +156,15 @@ var data = []entry{ ...@@ -156,12 +156,15 @@ var data = []entry{
func TestFiles(t *testing.T) { func TestFiles(t *testing.T) {
for _, e := range data { for i, e := range data {
source := filepath.Join(dataDir, e.source) source := filepath.Join(dataDir, e.source)
golden := filepath.Join(dataDir, e.golden) golden := filepath.Join(dataDir, e.golden)
check(t, source, golden, e.mode) check(t, source, golden, e.mode)
// TODO(gri) check that golden is idempotent // TODO(gri) check that golden is idempotent
//check(t, golden, golden, e.mode); //check(t, golden, golden, e.mode)
if testing.Short() && i >= 3 {
break
}
} }
} }
......
...@@ -253,8 +253,8 @@ bar` ...@@ -253,8 +253,8 @@ bar`
var _ = `` var _ = ``
var _ = `foo` var _ = `foo`
var _ = var _ =
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
var _ = // comment var _ = // comment
...@@ -262,8 +262,8 @@ bar` ...@@ -262,8 +262,8 @@ bar`
var _ = // comment var _ = // comment
`foo` `foo`
var _ = // comment var _ = // comment
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
var _ = /* comment */ `` var _ = /* comment */ ``
...@@ -276,12 +276,12 @@ bar` ...@@ -276,12 +276,12 @@ bar`
var _ = /* comment */ var _ = /* comment */
`foo` `foo`
var _ = /* comment */ var _ = /* comment */
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
var board = []int( var board = []int(
`........... `...........
........... ...........
....●●●.... ....●●●....
....●●●.... ....●●●....
...@@ -296,8 +296,8 @@ bar` ...@@ -296,8 +296,8 @@ bar`
var state = S{ var state = S{
"foo", "foo",
// the next line should not be indented // the next line should remain indented
`........... `...........
........... ...........
....●●●.... ....●●●....
....●●●.... ....●●●....
...@@ -619,3 +619,13 @@ func _() { ...@@ -619,3 +619,13 @@ func _() {
b.(T). b.(T).
c c
} }
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
os.O_TRUNC,0666); err != nil {
log.Fatal(err)
}
}
...@@ -256,7 +256,7 @@ var _ = ...@@ -256,7 +256,7 @@ var _ =
var _ = var _ =
`foo` `foo`
var _ = var _ =
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
...@@ -266,7 +266,7 @@ bar` ...@@ -266,7 +266,7 @@ bar`
var _ = // comment var _ = // comment
`foo` `foo`
var _ = // comment var _ = // comment
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
...@@ -282,7 +282,7 @@ bar` ...@@ -282,7 +282,7 @@ bar`
var _ = /* comment */ var _ = /* comment */
`foo` `foo`
var _ = /* comment */ var _ = /* comment */
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
...@@ -304,7 +304,7 @@ var board = []int( ...@@ -304,7 +304,7 @@ var board = []int(
var state = S{ var state = S{
"foo", "foo",
// the next line should not be indented // the next line should remain indented
`........... `...........
........... ...........
....●●●.... ....●●●....
...@@ -625,3 +625,13 @@ baz() ...@@ -625,3 +625,13 @@ baz()
(T). (T).
c c
} }
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
os.O_TRUNC, 0666); err != nil {
log.Fatal(err)
}
}
...@@ -239,7 +239,8 @@ func _() { ...@@ -239,7 +239,8 @@ func _() {
_ = `foo _ = `foo
bar` bar`
_ = `three spaces before the end of the line starting here: _ = `three spaces before the end of the line starting here:
they must not be removed` } they must not be removed`
}
func _() { func _() {
...@@ -252,8 +253,8 @@ bar` ...@@ -252,8 +253,8 @@ bar`
var _ = `` var _ = ``
var _ = `foo` var _ = `foo`
var _ = var _ =
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
var _ = // comment var _ = // comment
...@@ -261,8 +262,8 @@ bar` ...@@ -261,8 +262,8 @@ bar`
var _ = // comment var _ = // comment
`foo` `foo`
var _ = // comment var _ = // comment
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
var _ = /* comment */ `` var _ = /* comment */ ``
...@@ -275,12 +276,12 @@ bar` ...@@ -275,12 +276,12 @@ bar`
var _ = /* comment */ var _ = /* comment */
`foo` `foo`
var _ = /* comment */ var _ = /* comment */
// the next line should not be indented // the next line should remain indented
`foo `foo
bar` bar`
var board = []int( var board = []int(
`........... `...........
........... ...........
....●●●.... ....●●●....
....●●●.... ....●●●....
...@@ -295,8 +296,8 @@ bar` ...@@ -295,8 +296,8 @@ bar`
var state = S{ var state = S{
"foo", "foo",
// the next line should not be indented // the next line should remain indented
`........... `...........
........... ...........
....●●●.... ....●●●....
....●●●.... ....●●●....
...@@ -618,3 +619,13 @@ func _() { ...@@ -618,3 +619,13 @@ func _() {
b.(T). b.(T).
c c
} }
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
os.O_TRUNC,0666); err != nil {
log.Fatal(err)
}
}
...@@ -538,14 +538,12 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke ...@@ -538,14 +538,12 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
} }
var newline = []byte{'\n'} // Scan scans the next token and returns the token position,
// the token, and the literal string corresponding to the
// Scan scans the next token and returns the token position pos,
// the token tok, and the literal text lit corresponding to the
// token. The source end is indicated by token.EOF. // token. The source end is indicated by token.EOF.
// //
// If the returned token is token.SEMICOLON, the corresponding // If the returned token is token.SEMICOLON, the corresponding
// literal value is ";" if the semicolon was present in the source, // literal string is ";" if the semicolon was present in the source,
// and "\n" if the semicolon was inserted because of a newline or // and "\n" if the semicolon was inserted because of a newline or
// at EOF. // at EOF.
// //
...@@ -560,7 +558,7 @@ var newline = []byte{'\n'} ...@@ -560,7 +558,7 @@ var newline = []byte{'\n'}
// set with Init. Token positions are relative to that file // set with Init. Token positions are relative to that file
// and thus relative to the file set. // and thus relative to the file set.
// //
func (S *Scanner) Scan() (token.Pos, token.Token, []byte) { func (S *Scanner) Scan() (token.Pos, token.Token, string) {
scanAgain: scanAgain:
S.skipWhitespace() S.skipWhitespace()
...@@ -586,7 +584,7 @@ scanAgain: ...@@ -586,7 +584,7 @@ scanAgain:
case -1: case -1:
if S.insertSemi { if S.insertSemi {
S.insertSemi = false // EOF consumed S.insertSemi = false // EOF consumed
return S.file.Pos(offs), token.SEMICOLON, newline return S.file.Pos(offs), token.SEMICOLON, "\n"
} }
tok = token.EOF tok = token.EOF
case '\n': case '\n':
...@@ -594,7 +592,7 @@ scanAgain: ...@@ -594,7 +592,7 @@ scanAgain:
// set in the first place and exited early // set in the first place and exited early
// from S.skipWhitespace() // from S.skipWhitespace()
S.insertSemi = false // newline consumed S.insertSemi = false // newline consumed
return S.file.Pos(offs), token.SEMICOLON, newline return S.file.Pos(offs), token.SEMICOLON, "\n"
case '"': case '"':
insertSemi = true insertSemi = true
tok = token.STRING tok = token.STRING
...@@ -662,7 +660,7 @@ scanAgain: ...@@ -662,7 +660,7 @@ scanAgain:
S.offset = offs S.offset = offs
S.rdOffset = offs + 1 S.rdOffset = offs + 1
S.insertSemi = false // newline consumed S.insertSemi = false // newline consumed
return S.file.Pos(offs), token.SEMICOLON, newline return S.file.Pos(offs), token.SEMICOLON, "\n"
} }
S.scanComment() S.scanComment()
if S.mode&ScanComments == 0 { if S.mode&ScanComments == 0 {
...@@ -711,5 +709,9 @@ scanAgain: ...@@ -711,5 +709,9 @@ scanAgain:
if S.mode&InsertSemis != 0 { if S.mode&InsertSemis != 0 {
S.insertSemi = insertSemi S.insertSemi = insertSemi
} }
return S.file.Pos(offs), tok, S.src[offs:S.offset]
// TODO(gri): The scanner API should change such that the literal string
// is only valid if an actual literal was scanned. This will
// permit a more efficient implementation.
return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
} }
...@@ -234,12 +234,11 @@ func TestScan(t *testing.T) { ...@@ -234,12 +234,11 @@ func TestScan(t *testing.T) {
index := 0 index := 0
epos := token.Position{"", 0, 1, 1} // expected position epos := token.Position{"", 0, 1, 1} // expected position
for { for {
pos, tok, litb := s.Scan() pos, tok, lit := s.Scan()
e := elt{token.EOF, "", special} e := elt{token.EOF, "", special}
if index < len(tokens) { if index < len(tokens) {
e = tokens[index] e = tokens[index]
} }
lit := string(litb)
if tok == token.EOF { if tok == token.EOF {
lit = "<EOF>" lit = "<EOF>"
epos.Line = src_linecount epos.Line = src_linecount
...@@ -257,7 +256,7 @@ func TestScan(t *testing.T) { ...@@ -257,7 +256,7 @@ func TestScan(t *testing.T) {
} }
epos.Offset += len(lit) + len(whitespace) epos.Offset += len(lit) + len(whitespace)
epos.Line += newlineCount(lit) + whitespace_linecount epos.Line += newlineCount(lit) + whitespace_linecount
if tok == token.COMMENT && litb[1] == '/' { if tok == token.COMMENT && lit[1] == '/' {
// correct for unaccounted '/n' in //-style comment // correct for unaccounted '/n' in //-style comment
epos.Offset++ epos.Offset++
epos.Line++ epos.Line++
...@@ -292,7 +291,7 @@ func checkSemi(t *testing.T, line string, mode uint) { ...@@ -292,7 +291,7 @@ func checkSemi(t *testing.T, line string, mode uint) {
semiPos.Column++ semiPos.Column++
pos, tok, lit = S.Scan() pos, tok, lit = S.Scan()
if tok == token.SEMICOLON { if tok == token.SEMICOLON {
if string(lit) != semiLit { if lit != semiLit {
t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit) t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
} }
checkPos(t, line, pos, semiPos) checkPos(t, line, pos, semiPos)
...@@ -493,7 +492,7 @@ func TestLineComments(t *testing.T) { ...@@ -493,7 +492,7 @@ func TestLineComments(t *testing.T) {
for _, s := range segments { for _, s := range segments {
p, _, lit := S.Scan() p, _, lit := S.Scan()
pos := file.Position(p) pos := file.Position(p)
checkPos(t, string(lit), p, token.Position{s.filename, pos.Offset, s.line, pos.Column}) checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
} }
if S.ErrorCount != 0 { if S.ErrorCount != 0 {
...@@ -547,10 +546,10 @@ func TestIllegalChars(t *testing.T) { ...@@ -547,10 +546,10 @@ func TestIllegalChars(t *testing.T) {
for offs, ch := range src { for offs, ch := range src {
pos, tok, lit := s.Scan() pos, tok, lit := s.Scan()
if poffs := file.Offset(pos); poffs != offs { if poffs := file.Offset(pos); poffs != offs {
t.Errorf("bad position for %s: got %d, expected %d", string(lit), poffs, offs) t.Errorf("bad position for %s: got %d, expected %d", lit, poffs, offs)
} }
if tok == token.ILLEGAL && string(lit) != string(ch) { if tok == token.ILLEGAL && lit != string(ch) {
t.Errorf("bad token: got %s, expected %s", string(lit), string(ch)) t.Errorf("bad token: got %s, expected %s", lit, string(ch))
} }
} }
......
...@@ -126,10 +126,7 @@ const ( ...@@ -126,10 +126,7 @@ const (
) )
// At the moment we have no array literal syntax that lets us describe var tokens = [...]string{
// the index for each element - use a map for now to make sure they are
// in sync.
var tokens = map[Token]string{
ILLEGAL: "ILLEGAL", ILLEGAL: "ILLEGAL",
EOF: "EOF", EOF: "EOF",
...@@ -237,10 +234,14 @@ var tokens = map[Token]string{ ...@@ -237,10 +234,14 @@ var tokens = map[Token]string{
// constant name (e.g. for the token IDENT, the string is "IDENT"). // constant name (e.g. for the token IDENT, the string is "IDENT").
// //
func (tok Token) String() string { func (tok Token) String() string {
if str, exists := tokens[tok]; exists { s := ""
return str if 0 <= tok && tok < Token(len(tokens)) {
s = tokens[tok]
} }
return "token(" + strconv.Itoa(int(tok)) + ")" if s == "" {
s = "token(" + strconv.Itoa(int(tok)) + ")"
}
return s
} }
......
...@@ -33,7 +33,7 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast ...@@ -33,7 +33,7 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast
//obj.N = n //obj.N = n
name.Obj = obj name.Obj = obj
if name.Name != "_" { if name.Name != "_" {
if alt := scope.Insert(obj); alt != obj { if alt := scope.Insert(obj); alt != nil {
tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String()) tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
} }
} }
......
...@@ -53,7 +53,7 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E ...@@ -53,7 +53,7 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E
// //
func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error { func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error {
// create a single-file dummy package // create a single-file dummy package
pkg := &ast.Package{file.Name.Name, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}} pkg := &ast.Package{file.Name.Name, nil, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
return CheckPackage(fset, pkg, importer) return CheckPackage(fset, pkg, importer)
} }
...@@ -327,8 +327,8 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) { ...@@ -327,8 +327,8 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
if ftype != nil { if ftype != nil {
for _, par := range ftype.Params.Objects { for _, par := range ftype.Params.Objects {
if par.Name != "_" { if par.Name != "_" {
obj := tc.topScope.Insert(par) alt := tc.topScope.Insert(par)
assert(obj == par) // ftype has no double declarations assert(alt == nil) // ftype has no double declarations
} }
} }
} }
......
...@@ -78,7 +78,7 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) { ...@@ -78,7 +78,7 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
case token.EOF: case token.EOF:
break loop break loop
case token.COMMENT: case token.COMMENT:
s := errRx.FindSubmatch(lit) s := errRx.FindStringSubmatch(lit)
if len(s) == 2 { if len(s) == 2 {
list = append(list, &scanner.Error{fset.Position(prev), string(s[1])}) list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
} }
......
...@@ -14,7 +14,7 @@ var Universe *ast.Scope ...@@ -14,7 +14,7 @@ var Universe *ast.Scope
func def(obj *ast.Object) { func def(obj *ast.Object) {
alt := Universe.Insert(obj) alt := Universe.Insert(obj)
if alt != obj { if alt != nil {
panic("object declared twice") panic("object declared twice")
} }
} }
......
...@@ -407,7 +407,7 @@ func (s *structType) string() string { return s.safeString(make(map[typeId]bool) ...@@ -407,7 +407,7 @@ func (s *structType) string() string { return s.safeString(make(map[typeId]bool)
func newStructType(name string) *structType { func newStructType(name string) *structType {
s := &structType{CommonType{Name: name}, nil} s := &structType{CommonType{Name: name}, nil}
// For historical reasons we set the id here rather than init. // For historical reasons we set the id here rather than init.
// Se the comment in newTypeObject for details. // See the comment in newTypeObject for details.
setTypeId(s) setTypeId(s)
return s return s
} }
...@@ -545,7 +545,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, os.Error) { ...@@ -545,7 +545,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
// getType returns the Gob type describing the given reflect.Type. // getType returns the Gob type describing the given reflect.Type.
// Should be called only when handling GobEncoders/Decoders, // Should be called only when handling GobEncoders/Decoders,
// which may be pointers. All other types are handled through the // which may be pointers. All other types are handled through the
// base type, never a pointer. // base type, never a pointer.
// typeLock must be held. // typeLock must be held.
func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) { func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
typ, present := types[rt] typ, present := types[rt]
...@@ -561,7 +561,7 @@ func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) ...@@ -561,7 +561,7 @@ func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error)
func checkId(want, got typeId) { func checkId(want, got typeId) {
if want != got { if want != got {
fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(got)) fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string()) panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
} }
} }
......
...@@ -154,7 +154,10 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { ...@@ -154,7 +154,10 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
// handle Content-Range header. // handle Content-Range header.
// TODO(adg): handle multiple ranges // TODO(adg): handle multiple ranges
ranges, err := parseRange(r.Header.Get("Range"), size) ranges, err := parseRange(r.Header.Get("Range"), size)
if err != nil || len(ranges) > 1 { if err == nil && len(ranges) > 1 {
err = os.ErrorString("multiple ranges not supported")
}
if err != nil {
Error(w, err.String(), StatusRequestedRangeNotSatisfiable) Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
return return
} }
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
// //
// pprof http://localhost:6060/debug/pprof/heap // pprof http://localhost:6060/debug/pprof/heap
// //
// Or to look at a 30-second CPU profile:
//
// pprof http://localhost:6060/debug/pprof/profile
//
package pprof package pprof
import ( import (
...@@ -29,10 +33,12 @@ import ( ...@@ -29,10 +33,12 @@ import (
"runtime/pprof" "runtime/pprof"
"strconv" "strconv"
"strings" "strings"
"time"
) )
func init() { func init() {
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline)) http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap)) http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol)) http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
} }
...@@ -41,22 +47,46 @@ func init() { ...@@ -41,22 +47,46 @@ func init() {
// command line, with arguments separated by NUL bytes. // command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline. // The package initialization registers it as /debug/pprof/cmdline.
func Cmdline(w http.ResponseWriter, r *http.Request) { func Cmdline(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprintf(w, strings.Join(os.Args, "\x00")) fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
} }
// Heap responds with the pprof-formatted heap profile. // Heap responds with the pprof-formatted heap profile.
// The package initialization registers it as /debug/pprof/heap. // The package initialization registers it as /debug/pprof/heap.
func Heap(w http.ResponseWriter, r *http.Request) { func Heap(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
pprof.WriteHeapProfile(w) pprof.WriteHeapProfile(w)
} }
// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
sec, _ := strconv.Atoi64(r.FormValue("seconds"))
if sec == 0 {
sec = 30
}
// Set Content Type assuming StartCPUProfile will work,
// because if it does it starts writing.
w.Header().Set("Content-Type", "application/octet-stream")
if err := pprof.StartCPUProfile(w); err != nil {
// StartCPUProfile failed, so no writes yet.
// Can change header back to text content
// and send error code.
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
return
}
time.Sleep(sec * 1e9)
pprof.StopCPUProfile()
}
// Symbol looks up the program counters listed in the request, // Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names. // responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol. // The package initialization registers it as /debug/pprof/symbol.
func Symbol(w http.ResponseWriter, r *http.Request) { func Symbol(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
// We don't know how many symbols we have, but we // We don't know how many symbols we have, but we
// do have symbol information. Pprof only cares whether // do have symbol information. Pprof only cares whether
......
...@@ -175,7 +175,7 @@ func TestHostHandlers(t *testing.T) { ...@@ -175,7 +175,7 @@ func TestHostHandlers(t *testing.T) {
ts := httptest.NewServer(nil) ts := httptest.NewServer(nil)
defer ts.Close() defer ts.Close()
conn, err := net.Dial("tcp", "", ts.Listener.Addr().String()) conn, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -265,7 +265,7 @@ func TestServerTimeouts(t *testing.T) { ...@@ -265,7 +265,7 @@ func TestServerTimeouts(t *testing.T) {
// Slow client that should timeout. // Slow client that should timeout.
t1 := time.Nanoseconds() t1 := time.Nanoseconds()
conn, err := net.Dial("tcp", "", fmt.Sprintf("localhost:%d", addr.Port)) conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", addr.Port))
if err != nil { if err != nil {
t.Fatalf("Dial: %v", err) t.Fatalf("Dial: %v", err)
} }
...@@ -348,7 +348,7 @@ func TestIdentityResponse(t *testing.T) { ...@@ -348,7 +348,7 @@ func TestIdentityResponse(t *testing.T) {
} }
// Verify that the connection is closed when the declared Content-Length // Verify that the connection is closed when the declared Content-Length
// is larger than what the handler wrote. // is larger than what the handler wrote.
conn, err := net.Dial("tcp", "", ts.Listener.Addr().String()) conn, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil { if err != nil {
t.Fatalf("error dialing: %v", err) t.Fatalf("error dialing: %v", err)
} }
...@@ -377,7 +377,7 @@ func TestServeHTTP10Close(t *testing.T) { ...@@ -377,7 +377,7 @@ func TestServeHTTP10Close(t *testing.T) {
})) }))
defer s.Close() defer s.Close()
conn, err := net.Dial("tcp", "", s.Listener.Addr().String()) conn, err := net.Dial("tcp", s.Listener.Addr().String())
if err != nil { if err != nil {
t.Fatal("dial error:", err) t.Fatal("dial error:", err)
} }
......
...@@ -195,7 +195,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) { ...@@ -195,7 +195,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
return pc, nil return pc, nil
} }
conn, err := net.Dial("tcp", "", cm.addr()) conn, err := net.Dial("tcp", cm.addr())
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -34,6 +34,12 @@ var filenames = []string{ ...@@ -34,6 +34,12 @@ var filenames = []string{
"basn6a16", "basn6a16",
} }
var filenamesShort = []string{
"basn0g01",
"basn0g04-31",
"basn6a16",
}
func readPng(filename string) (image.Image, os.Error) { func readPng(filename string) (image.Image, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0444) f, err := os.Open(filename, os.O_RDONLY, 0444)
if err != nil { if err != nil {
...@@ -157,7 +163,11 @@ func sng(w io.WriteCloser, filename string, png image.Image) { ...@@ -157,7 +163,11 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
} }
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
for _, fn := range filenames { names := filenames
if testing.Short() {
names = filenamesShort
}
for _, fn := range names {
// Read the .png file. // Read the .png file.
img, err := readPng("testdata/pngsuite/" + fn + ".png") img, err := readPng("testdata/pngsuite/" + fn + ".png")
if err != nil { if err != nil {
......
...@@ -32,7 +32,11 @@ func diff(m0, m1 image.Image) os.Error { ...@@ -32,7 +32,11 @@ func diff(m0, m1 image.Image) os.Error {
func TestWriter(t *testing.T) { func TestWriter(t *testing.T) {
// The filenames variable is declared in reader_test.go. // The filenames variable is declared in reader_test.go.
for _, fn := range filenames { names := filenames
if testing.Short() {
names = filenamesShort
}
for _, fn := range names {
qfn := "testdata/pngsuite/" + fn + ".png" qfn := "testdata/pngsuite/" + fn + ".png"
// Read the image. // Read the image.
m0, err := readPng(qfn) m0, err := readPng(qfn)
......
...@@ -157,6 +157,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -157,6 +157,7 @@ func TestUnmarshal(t *testing.T) {
} }
func TestUnmarshalMarshal(t *testing.T) { func TestUnmarshalMarshal(t *testing.T) {
initBig()
var v interface{} var v interface{}
if err := Unmarshal(jsonBig, &v); err != nil { if err := Unmarshal(jsonBig, &v); err != nil {
t.Fatalf("Unmarshal: %v", err) t.Fatalf("Unmarshal: %v", err)
......
...@@ -85,6 +85,7 @@ func TestIndent(t *testing.T) { ...@@ -85,6 +85,7 @@ func TestIndent(t *testing.T) {
// Tests of a large random structure. // Tests of a large random structure.
func TestCompactBig(t *testing.T) { func TestCompactBig(t *testing.T) {
initBig()
var buf bytes.Buffer var buf bytes.Buffer
if err := Compact(&buf, jsonBig); err != nil { if err := Compact(&buf, jsonBig); err != nil {
t.Fatalf("Compact: %v", err) t.Fatalf("Compact: %v", err)
...@@ -98,6 +99,7 @@ func TestCompactBig(t *testing.T) { ...@@ -98,6 +99,7 @@ func TestCompactBig(t *testing.T) {
} }
func TestIndentBig(t *testing.T) { func TestIndentBig(t *testing.T) {
initBig()
var buf bytes.Buffer var buf bytes.Buffer
if err := Indent(&buf, jsonBig, "", "\t"); err != nil { if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
t.Fatalf("Indent1: %v", err) t.Fatalf("Indent1: %v", err)
...@@ -135,6 +137,7 @@ func TestIndentBig(t *testing.T) { ...@@ -135,6 +137,7 @@ func TestIndentBig(t *testing.T) {
} }
func TestNextValueBig(t *testing.T) { func TestNextValueBig(t *testing.T) {
initBig()
var scan scanner var scan scanner
item, rest, err := nextValue(jsonBig, &scan) item, rest, err := nextValue(jsonBig, &scan)
if err != nil { if err != nil {
...@@ -160,6 +163,7 @@ func TestNextValueBig(t *testing.T) { ...@@ -160,6 +163,7 @@ func TestNextValueBig(t *testing.T) {
} }
func BenchmarkSkipValue(b *testing.B) { func BenchmarkSkipValue(b *testing.B) {
initBig()
var scan scanner var scan scanner
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
nextValue(jsonBig, &scan) nextValue(jsonBig, &scan)
...@@ -191,12 +195,23 @@ func trim(b []byte) []byte { ...@@ -191,12 +195,23 @@ func trim(b []byte) []byte {
var jsonBig []byte var jsonBig []byte
func init() { const (
b, err := Marshal(genValue(10000)) big = 10000
if err != nil { small = 100
panic(err) )
func initBig() {
n := big
if testing.Short() {
n = small
}
if len(jsonBig) != n {
b, err := Marshal(genValue(n))
if err != nil {
panic(err)
}
jsonBig = b
} }
jsonBig = b
} }
func genValue(n int) interface{} { func genValue(n int) interface{} {
......
// 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.
// Stub cgo routines for systems that do not use cgo to do network lookups.
package net
import "os"
func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
return nil, nil, false
}
func cgoLookupPort(network, service string) (port int, err os.Error, completed bool) {
return 0, nil, false
}
func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
return nil, nil, false
}
...@@ -6,9 +6,7 @@ package net ...@@ -6,9 +6,7 @@ package net
import "os" import "os"
// Dial connects to the remote address raddr on the network net. // Dial connects to the address addr on the network net.
// If the string laddr is not empty, it is used as the local address
// for the connection.
// //
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
...@@ -16,79 +14,56 @@ import "os" ...@@ -16,79 +14,56 @@ import "os"
// //
// For IP networks, addresses have the form host:port. If host is // For IP networks, addresses have the form host:port. If host is
// a literal IPv6 address, it must be enclosed in square brackets. // a literal IPv6 address, it must be enclosed in square brackets.
// The functions JoinHostPort and SplitHostPort manipulate
// addresses in this form.
// //
// Examples: // Examples:
// Dial("tcp", "", "12.34.56.78:80") // Dial("tcp", "12.34.56.78:80")
// Dial("tcp", "", "google.com:80") // Dial("tcp", "google.com:80")
// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80") // Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
// //
func Dial(net, laddr, raddr string) (c Conn, err os.Error) { func Dial(net, addr string) (c Conn, err os.Error) {
raddr := addr
if raddr == "" {
return nil, &OpError{"dial", net, nil, errMissingAddress}
}
switch net { switch net {
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6":
var la, ra *TCPAddr var ra *TCPAddr
if laddr != "" { if ra, err = ResolveTCPAddr(raddr); err != nil {
if la, err = ResolveTCPAddr(laddr); err != nil { goto Error
goto Error
}
}
if raddr != "" {
if ra, err = ResolveTCPAddr(raddr); err != nil {
goto Error
}
} }
c, err := DialTCP(net, la, ra) c, err := DialTCP(net, nil, ra)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return c, nil return c, nil
case "udp", "udp4", "udp6": case "udp", "udp4", "udp6":
var la, ra *UDPAddr var ra *UDPAddr
if laddr != "" { if ra, err = ResolveUDPAddr(raddr); err != nil {
if la, err = ResolveUDPAddr(laddr); err != nil { goto Error
goto Error
}
}
if raddr != "" {
if ra, err = ResolveUDPAddr(raddr); err != nil {
goto Error
}
} }
c, err := DialUDP(net, la, ra) c, err := DialUDP(net, nil, ra)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return c, nil return c, nil
case "unix", "unixgram", "unixpacket": case "unix", "unixgram", "unixpacket":
var la, ra *UnixAddr var ra *UnixAddr
if raddr != "" { if ra, err = ResolveUnixAddr(net, raddr); err != nil {
if ra, err = ResolveUnixAddr(net, raddr); err != nil { goto Error
goto Error
}
}
if laddr != "" {
if la, err = ResolveUnixAddr(net, laddr); err != nil {
goto Error
}
} }
c, err = DialUnix(net, la, ra) c, err = DialUnix(net, nil, ra)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return c, nil return c, nil
case "ip", "ip4", "ip6": case "ip", "ip4", "ip6":
var la, ra *IPAddr var ra *IPAddr
if laddr != "" { if ra, err = ResolveIPAddr(raddr); err != nil {
if la, err = ResolveIPAddr(laddr); err != nil { goto Error
goto Error
}
}
if raddr != "" {
if ra, err = ResolveIPAddr(raddr); err != nil {
goto Error
}
} }
c, err := DialIP(net, la, ra) c, err := DialIP(net, nil, ra)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -32,7 +32,7 @@ func fetchGoogle(t *testing.T, fd Conn, network, addr string) { ...@@ -32,7 +32,7 @@ func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
} }
func doDial(t *testing.T, network, addr string) { func doDial(t *testing.T, network, addr string) {
fd, err := Dial(network, "", addr) fd, err := Dial(network, addr)
if err != nil { if err != nil {
t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err) t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
return return
...@@ -55,6 +55,13 @@ var googleaddrs = []string{ ...@@ -55,6 +55,13 @@ var googleaddrs = []string{
"[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set "[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set
} }
func TestLookupCNAME(t *testing.T) {
cname, err := LookupCNAME("www.google.com")
if cname != "www.l.google.com." || err != nil {
t.Errorf(`LookupCNAME("www.google.com.") = %q, %v, want "www.l.google.com.", nil`, cname, err)
}
}
func TestDialGoogle(t *testing.T) { func TestDialGoogle(t *testing.T) {
// If no ipv6 tunnel, don't try the last address. // If no ipv6 tunnel, don't try the last address.
if !*ipv6 { if !*ipv6 {
...@@ -64,14 +71,14 @@ func TestDialGoogle(t *testing.T) { ...@@ -64,14 +71,14 @@ func TestDialGoogle(t *testing.T) {
// Insert an actual IP address for google.com // Insert an actual IP address for google.com
// into the table. // into the table.
_, addrs, err := LookupHost("www.google.com") addrs, err := LookupIP("www.google.com")
if err != nil { if err != nil {
t.Fatalf("lookup www.google.com: %v", err) t.Fatalf("lookup www.google.com: %v", err)
} }
if len(addrs) == 0 { if len(addrs) == 0 {
t.Fatalf("no addresses for www.google.com") t.Fatalf("no addresses for www.google.com")
} }
ip := ParseIP(addrs[0]).To4() ip := addrs[0].To4()
for i, s := range googleaddrs { for i, s := range googleaddrs {
if strings.Contains(s, "%") { if strings.Contains(s, "%") {
......
...@@ -159,7 +159,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs ...@@ -159,7 +159,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
// all the cfg.servers[i] are IP addresses, which // all the cfg.servers[i] are IP addresses, which
// Dial will use without a DNS lookup. // Dial will use without a DNS lookup.
server := cfg.servers[i] + ":53" server := cfg.servers[i] + ":53"
c, cerr := Dial("udp", "", server) c, cerr := Dial("udp", server)
if cerr != nil { if cerr != nil {
err = cerr err = cerr
continue continue
...@@ -178,12 +178,23 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs ...@@ -178,12 +178,23 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
return return
} }
func convertRR_A(records []dnsRR) []string { func convertRR_A(records []dnsRR) []IP {
addrs := make([]string, len(records)) addrs := make([]IP, len(records))
for i := 0; i < len(records); i++ { for i := 0; i < len(records); i++ {
rr := records[i] rr := records[i]
a := rr.(*dnsRR_A).A a := rr.(*dnsRR_A).A
addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String() addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
}
return addrs
}
func convertRR_AAAA(records []dnsRR) []IP {
addrs := make([]IP, len(records))
for i := 0; i < len(records); i++ {
rr := records[i]
a := make(IP, 16)
copy(a, rr.(*dnsRR_AAAA).AAAA[:])
addrs[i] = a
} }
return addrs return addrs
} }
...@@ -294,10 +305,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro ...@@ -294,10 +305,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
return return
} }
// LookupHost looks for name using the local hosts file and DNS resolver. // goLookupHost is the native Go implementation of LookupHost.
// It returns the canonical name for the host and an array of that func goLookupHost(name string) (addrs []string, err os.Error) {
// host's addresses.
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
onceLoadConfig.Do(loadConfig) onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil { if dnserr != nil || cfg == nil {
err = dnserr err = dnserr
...@@ -306,18 +315,69 @@ func LookupHost(name string) (cname string, addrs []string, err os.Error) { ...@@ -306,18 +315,69 @@ func LookupHost(name string) (cname string, addrs []string, err os.Error) {
// Use entries from /etc/hosts if they match. // Use entries from /etc/hosts if they match.
addrs = lookupStaticHost(name) addrs = lookupStaticHost(name)
if len(addrs) > 0 { if len(addrs) > 0 {
cname = name return
}
ips, err := goLookupIP(name)
if err != nil {
return
}
addrs = make([]string, 0, len(ips))
for _, ip := range ips {
addrs = append(addrs, ip.String())
}
return
}
// goLookupIP is the native Go implementation of LookupIP.
func goLookupIP(name string) (addrs []IP, err os.Error) {
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return return
} }
var records []dnsRR var records []dnsRR
var cname string
cname, records, err = lookup(name, dnsTypeA) cname, records, err = lookup(name, dnsTypeA)
if err != nil { if err != nil {
return return
} }
addrs = convertRR_A(records) addrs = convertRR_A(records)
if cname != "" {
name = cname
}
_, records, err = lookup(name, dnsTypeAAAA)
if err != nil && len(addrs) > 0 {
// Ignore error because A lookup succeeded.
err = nil
}
if err != nil {
return
}
addrs = append(addrs, convertRR_AAAA(records)...)
return
}
// LookupCNAME returns the canonical DNS host for the given name.
// Callers that do not care about the canonical name can call
// LookupHost or LookupIP directly; both take care of resolving
// the canonical name as part of the lookup.
func LookupCNAME(name string) (cname string, err os.Error) {
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
}
_, rr, err := lookup(name, dnsTypeCNAME)
if err != nil {
return
}
if len(rr) >= 0 {
cname = rr[0].(*dnsRR_CNAME).Cname
}
return return
} }
// An SRV represents a single DNS SRV record.
type SRV struct { type SRV struct {
Target string Target string
Port uint16 Port uint16
...@@ -344,11 +404,13 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os. ...@@ -344,11 +404,13 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return return
} }
// An MX represents a single DNS MX record.
type MX struct { type MX struct {
Host string Host string
Pref uint16 Pref uint16
} }
// LookupMX returns the DNS MX records associated with name.
func LookupMX(name string) (entries []*MX, err os.Error) { func LookupMX(name string) (entries []*MX, err os.Error) {
var records []dnsRR var records []dnsRR
_, records, err = lookup(name, dnsTypeMX) _, records, err = lookup(name, dnsTypeMX)
......
...@@ -50,6 +50,7 @@ const ( ...@@ -50,6 +50,7 @@ const (
dnsTypeMINFO = 14 dnsTypeMINFO = 14
dnsTypeMX = 15 dnsTypeMX = 15
dnsTypeTXT = 16 dnsTypeTXT = 16
dnsTypeAAAA = 28
dnsTypeSRV = 33 dnsTypeSRV = 33
// valid dnsQuestion.qtype only // valid dnsQuestion.qtype only
...@@ -244,8 +245,18 @@ type dnsRR_A struct { ...@@ -244,8 +245,18 @@ type dnsRR_A struct {
A uint32 "ipv4" A uint32 "ipv4"
} }
func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr } func (rr *dnsRR_A) Header() *dnsRR_Header {
return &rr.Hdr
}
type dnsRR_AAAA struct {
Hdr dnsRR_Header
AAAA [16]byte "ipv6"
}
func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
return &rr.Hdr
}
// Packing and unpacking. // Packing and unpacking.
// //
...@@ -270,6 +281,7 @@ var rr_mk = map[int]func() dnsRR{ ...@@ -270,6 +281,7 @@ var rr_mk = map[int]func() dnsRR{
dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) }, dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) }, dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
dnsTypeA: func() dnsRR { return new(dnsRR_A) }, dnsTypeA: func() dnsRR { return new(dnsRR_A) },
dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
} }
// Pack a domain name s into msg[off:]. // Pack a domain name s into msg[off:].
...@@ -377,7 +389,7 @@ Loop: ...@@ -377,7 +389,7 @@ Loop:
// TODO(rsc): Move into generic library? // TODO(rsc): Move into generic library?
// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string, // Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
// and other (often anonymous) structs. // [n]byte, and other (often anonymous) structs.
func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
for i := 0; i < val.NumField(); i++ { for i := 0; i < val.NumField(); i++ {
f := val.Type().(*reflect.StructType).Field(i) f := val.Type().(*reflect.StructType).Field(i)
...@@ -410,6 +422,16 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o ...@@ -410,6 +422,16 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
msg[off+3] = byte(i) msg[off+3] = byte(i)
off += 4 off += 4
} }
case *reflect.ArrayValue:
if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
goto BadType
}
n := fv.Len()
if off+n > len(msg) {
return len(msg), false
}
reflect.Copy(reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue), fv)
off += n
case *reflect.StringValue: case *reflect.StringValue:
// There are multiple string encodings. // There are multiple string encodings.
// The tag distinguishes ordinary strings from domain names. // The tag distinguishes ordinary strings from domain names.
...@@ -478,6 +500,16 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ...@@ -478,6 +500,16 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
fv.Set(uint64(i)) fv.Set(uint64(i))
off += 4 off += 4
} }
case *reflect.ArrayValue:
if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
goto BadType
}
n := fv.Len()
if off+n > len(msg) {
return len(msg), false
}
reflect.Copy(fv, reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue))
off += n
case *reflect.StringValue: case *reflect.StringValue:
var s string var s string
switch f.Tag { switch f.Tag {
...@@ -515,7 +547,8 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { ...@@ -515,7 +547,8 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
// Generic struct printer. // Generic struct printer.
// Doesn't care about the string tag "domain-name", // Doesn't care about the string tag "domain-name",
// but does look for an "ipv4" tag on uint32 variables, // but does look for an "ipv4" tag on uint32 variables
// and the "ipv6" tag on array variables,
// printing them as IP addresses. // printing them as IP addresses.
func printStructValue(val *reflect.StructValue) string { func printStructValue(val *reflect.StructValue) string {
s := "{" s := "{"
...@@ -533,6 +566,9 @@ func printStructValue(val *reflect.StructValue) string { ...@@ -533,6 +566,9 @@ func printStructValue(val *reflect.StructValue) string {
} else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" { } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
i := fv.Get() i := fv.Get()
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String() s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
} else if fv, ok := fval.(*reflect.ArrayValue); ok && f.Tag == "ipv6" {
i := fv.Interface().([]byte)
s += IP(i).String()
} else { } else {
s += fmt.Sprint(fval.Interface()) s += fmt.Sprint(fval.Interface())
} }
......
...@@ -274,19 +274,25 @@ func startServer() { ...@@ -274,19 +274,25 @@ func startServer() {
pollserver = p pollserver = p
} }
func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
onceStartServer.Do(startServer) onceStartServer.Do(startServer)
if e := syscall.SetNonblock(fd, true); e != 0 { if e := syscall.SetNonblock(fd, true); e != 0 {
return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)} return nil, os.Errno(e)
} }
f = &netFD{ f = &netFD{
sysfd: fd, sysfd: fd,
family: family, family: family,
proto: proto, proto: proto,
net: net, net: net,
laddr: laddr,
raddr: raddr,
} }
f.cr = make(chan bool, 1)
f.cw = make(chan bool, 1)
return f, nil
}
func (fd *netFD) setAddr(laddr, raddr Addr) {
fd.laddr = laddr
fd.raddr = raddr
var ls, rs string var ls, rs string
if laddr != nil { if laddr != nil {
ls = laddr.String() ls = laddr.String()
...@@ -294,10 +300,23 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err ...@@ -294,10 +300,23 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err
if raddr != nil { if raddr != nil {
rs = raddr.String() rs = raddr.String()
} }
f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs) fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
f.cr = make(chan bool, 1) }
f.cw = make(chan bool, 1)
return f, nil func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
e := syscall.Connect(fd.sysfd, ra)
if e == syscall.EINPROGRESS {
var errno int
pollserver.WaitWrite(fd)
e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
if errno != 0 {
return os.NewSyscallError("getsockopt", errno)
}
}
if e != 0 {
return os.Errno(e)
}
return nil
} }
// Add a reference to this fd. // Add a reference to this fd.
...@@ -593,10 +612,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. ...@@ -593,10 +612,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
syscall.CloseOnExec(s) syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock() syscall.ForkLock.RUnlock()
if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil { if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil {
syscall.Close(s) syscall.Close(s)
return nil, err return nil, err
} }
nfd.setAddr(fd.laddr, toAddr(sa))
return nfd, nil return nfd, nil
} }
......
...@@ -225,29 +225,40 @@ type netFD struct { ...@@ -225,29 +225,40 @@ type netFD struct {
wio sync.Mutex wio sync.Mutex
} }
func allocFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD) { func allocFD(fd, family, proto int, net string) (f *netFD) {
f = &netFD{ f = &netFD{
sysfd: fd, sysfd: fd,
family: family, family: family,
proto: proto, proto: proto,
net: net, net: net,
laddr: laddr,
raddr: raddr,
} }
runtime.SetFinalizer(f, (*netFD).Close) runtime.SetFinalizer(f, (*netFD).Close)
return f return f
} }
func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
if initErr != nil { if initErr != nil {
return nil, initErr return nil, initErr
} }
onceStartServer.Do(startServer) onceStartServer.Do(startServer)
// Associate our socket with resultsrv.iocp. // Associate our socket with resultsrv.iocp.
if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 { if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)} return nil, os.Errno(e)
}
return allocFD(fd, family, proto, net), nil
}
func (fd *netFD) setAddr(laddr, raddr Addr) {
fd.laddr = laddr
fd.raddr = raddr
}
func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
e := syscall.Connect(fd.sysfd, ra)
if e != 0 {
return os.Errno(e)
} }
return allocFD(fd, family, proto, net, laddr, raddr), nil return nil
} }
// Add a reference to this fd. // Add a reference to this fd.
...@@ -497,7 +508,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. ...@@ -497,7 +508,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
lsa, _ := lrsa.Sockaddr() lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.Sockaddr() rsa, _ := rrsa.Sockaddr()
return allocFD(s, fd.family, fd.proto, fd.net, toAddr(lsa), toAddr(rsa)), nil nfd = allocFD(s, fd.family, fd.proto, fd.net)
nfd.setAddr(toAddr(lsa), toAddr(rsa))
return nfd, nil
} }
// Not implemeted functions. // Not implemeted functions.
......
// 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
}
// 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"
"reflect"
"runtime"
"syscall"
"testing"
)
type listenerFile interface {
Listener
File() (f *os.File, err os.Error)
}
type packetConnFile interface {
PacketConn
File() (f *os.File, err os.Error)
}
type connFile interface {
Conn
File() (f *os.File, err os.Error)
}
func testFileListener(t *testing.T, net, laddr string) {
if net == "tcp" {
laddr += ":0" // any available port
}
l, err := Listen(net, laddr)
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
defer l.Close()
lf := l.(listenerFile)
f, err := lf.File()
if err != nil {
t.Fatalf("File failed: %v", err)
}
c, err := FileListener(f)
if err != nil {
t.Fatalf("FileListener failed: %v", err)
}
if !reflect.DeepEqual(l.Addr(), c.Addr()) {
t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
}
if err := c.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
if err := f.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
}
func TestFileListener(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
testFileListener(t, "tcp", "127.0.0.1")
testFileListener(t, "tcp", "127.0.0.1")
if kernelSupportsIPv6() {
testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
testFileListener(t, "tcp", "127.0.0.1")
testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
}
if syscall.OS == "linux" {
testFileListener(t, "unix", "@gotest/net")
testFileListener(t, "unixpacket", "@gotest/net")
}
}
func testFilePacketConn(t *testing.T, pcf packetConnFile) {
f, err := pcf.File()
if err != nil {
t.Fatalf("File failed: %v", err)
}
c, err := FilePacketConn(f)
if err != nil {
t.Fatalf("FilePacketConn failed: %v", err)
}
if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
}
if err := c.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
if err := f.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
}
func testFilePacketConnListen(t *testing.T, net, laddr string) {
l, err := ListenPacket(net, laddr)
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
testFilePacketConn(t, l.(packetConnFile))
if err := l.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
}
func testFilePacketConnDial(t *testing.T, net, raddr string) {
c, err := Dial(net, raddr)
if err != nil {
t.Fatalf("Dial failed: %v", err)
}
testFilePacketConn(t, c.(packetConnFile))
if err := c.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
}
func TestFilePacketConn(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
testFilePacketConnListen(t, "udp", "127.0.0.1:0")
testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
if kernelSupportsIPv6() {
testFilePacketConnListen(t, "udp", "[::1]:0")
testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
}
if syscall.OS == "linux" {
testFilePacketConnListen(t, "unixgram", "@gotest1/net")
}
}
// 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 FileConn(f *os.File) (c Conn, err os.Error) {
// TODO: Implement this
return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
}
func FileListener(f *os.File) (l Listener, err os.Error) {
// TODO: Implement this
return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
}
func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
// TODO: Implement this
return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
}
...@@ -13,7 +13,6 @@ type hostTest struct { ...@@ -13,7 +13,6 @@ type hostTest struct {
ips []IP ips []IP
} }
var hosttests = []hostTest{ var hosttests = []hostTest{
{"odin", []IP{ {"odin", []IP{
IPv4(127, 0, 0, 2), IPv4(127, 0, 0, 2),
......
...@@ -474,13 +474,13 @@ func parseIPv6(s string) IP { ...@@ -474,13 +474,13 @@ func parseIPv6(s string) IP {
return p return p
} }
// A SyntaxError represents a malformed text string and the type of string that was expected. // A ParseError represents a malformed text string and the type of string that was expected.
type SyntaxError struct { type ParseError struct {
Type string Type string
Text string Text string
} }
func (e *SyntaxError) String() string { func (e *ParseError) String() string {
return "invalid " + e.Type + ": " + e.Text return "invalid " + e.Type + ": " + e.Text
} }
...@@ -507,33 +507,46 @@ func ParseIP(s string) IP { ...@@ -507,33 +507,46 @@ func ParseIP(s string) IP {
} }
// ParseCIDR parses s as a CIDR notation IP address and mask, // ParseCIDR parses s as a CIDR notation IP address and mask,
// like "192.168.100.1/24" or "2001:DB8::/48". // like "192.168.100.1/24", "2001:DB8::/48", as defined in
// RFC 4632 and RFC 4291.
func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) { func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
i := byteIndex(s, '/') i := byteIndex(s, '/')
if i < 0 { if i < 0 {
return nil, nil, &SyntaxError{"CIDR address", s} return nil, nil, &ParseError{"CIDR address", s}
} }
ipstr, maskstr := s[:i], s[i+1:] ipstr, maskstr := s[:i], s[i+1:]
ip = ParseIP(ipstr) iplen := 4
ip = parseIPv4(ipstr)
if ip == nil {
iplen = 16
ip = parseIPv6(ipstr)
}
nn, i, ok := dtoi(maskstr, 0) nn, i, ok := dtoi(maskstr, 0)
if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*len(ip) { if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*iplen {
return nil, nil, &SyntaxError{"CIDR address", s} return nil, nil, &ParseError{"CIDR address", s}
} }
n := uint(nn) n := uint(nn)
if len(ip) == 4 { if iplen == 4 {
v4mask := ^uint32(0xffffffff >> n) v4mask := ^uint32(0xffffffff >> n)
mask = IPMask(IPv4(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask))) mask = IPv4Mask(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask))
return ip, mask, nil } else {
} mask = make(IPMask, 16)
mask = make(IPMask, 16) for i := 0; i < 16; i++ {
for i := 0; i < 16; i++ { if n >= 8 {
if n >= 8 { mask[i] = 0xff
mask[i] = 0xff n -= 8
n -= 8 continue
continue }
mask[i] = ^byte(0xff >> n)
n = 0
}
}
// address must not have any bits not in mask
for i := range ip {
if ip[i]&^mask[i] != 0 {
return nil, nil, &ParseError{"CIDR address", s}
} }
mask[i] = ^byte(0xff >> n)
n = 0
} }
return ip, mask, nil return ip, mask, nil
} }
...@@ -5,30 +5,26 @@ ...@@ -5,30 +5,26 @@
package net package net
import ( import (
"bytes"
"reflect"
"testing" "testing"
"os"
) )
func isEqual(a, b IP) bool { func isEqual(a, b []byte) bool {
if a == nil && b == nil { if a == nil && b == nil {
return true return true
} }
if a == nil || b == nil || len(a) != len(b) { if a == nil || b == nil {
return false return false
} }
for i := 0; i < len(a); i++ { return bytes.Equal(a, b)
if a[i] != b[i] {
return false
}
}
return true
} }
type parseIPTest struct { var parseiptests = []struct {
in string in string
out IP out IP
} }{
var parseiptests = []parseIPTest{
{"127.0.1.2", IPv4(127, 0, 1, 2)}, {"127.0.1.2", IPv4(127, 0, 1, 2)},
{"127.0.0.1", IPv4(127, 0, 0, 1)}, {"127.0.0.1", IPv4(127, 0, 0, 1)},
{"127.0.0.256", nil}, {"127.0.0.256", nil},
...@@ -43,20 +39,17 @@ var parseiptests = []parseIPTest{ ...@@ -43,20 +39,17 @@ var parseiptests = []parseIPTest{
} }
func TestParseIP(t *testing.T) { func TestParseIP(t *testing.T) {
for i := 0; i < len(parseiptests); i++ { for _, tt := range parseiptests {
tt := parseiptests[i]
if out := ParseIP(tt.in); !isEqual(out, tt.out) { if out := ParseIP(tt.in); !isEqual(out, tt.out) {
t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out) t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
} }
} }
} }
type ipStringTest struct { var ipstringtests = []struct {
in IP in IP
out string out string
} }{
var ipstringtests = []ipStringTest{
// cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation) // cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
...@@ -85,10 +78,67 @@ var ipstringtests = []ipStringTest{ ...@@ -85,10 +78,67 @@ var ipstringtests = []ipStringTest{
} }
func TestIPString(t *testing.T) { func TestIPString(t *testing.T) {
for i := 0; i < len(ipstringtests); i++ { for _, tt := range ipstringtests {
tt := ipstringtests[i]
if out := tt.in.String(); out != tt.out { if out := tt.in.String(); out != tt.out {
t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out) t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
} }
} }
} }
var parsecidrtests = []struct {
in string
ip IP
mask IPMask
err os.Error
}{
{"135.104.0.0/32", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255), nil},
{"0.0.0.0/24", IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
{"135.104.0.0/24", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
{"135.104.0.1/32", IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255), nil},
{"135.104.0.1/24", nil, nil, &ParseError{"CIDR address", "135.104.0.1/24"}},
{"::1/128", ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")), nil},
{"abcd:2345::/127", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")), nil},
{"abcd:2345::/65", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::")), nil},
{"abcd:2345::/64", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::")), nil},
{"abcd:2345::/63", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::")), nil},
{"abcd:2345::/33", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::")), nil},
{"abcd:2345::/32", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::")), nil},
{"abcd:2344::/31", ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::")), nil},
{"abcd:2300::/24", ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::")), nil},
{"abcd:2345::/24", nil, nil, &ParseError{"CIDR address", "abcd:2345::/24"}},
{"2001:DB8::/48", ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::")), nil},
}
func TestParseCIDR(t *testing.T) {
for _, tt := range parsecidrtests {
if ip, mask, err := ParseCIDR(tt.in); !isEqual(ip, tt.ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
}
}
}
var splitjointests = []struct {
Host string
Port string
Join string
}{
{"www.google.com", "80", "www.google.com:80"},
{"127.0.0.1", "1234", "127.0.0.1:1234"},
{"::1", "80", "[::1]:80"},
}
func TestSplitHostPort(t *testing.T) {
for _, tt := range splitjointests {
if host, port, err := SplitHostPort(tt.Join); host != tt.Host || port != tt.Port || err != nil {
t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.Join, host, port, err, tt.Host, tt.Port)
}
}
}
func TestJoinHostPort(t *testing.T) {
for _, tt := range splitjointests {
if join := JoinHostPort(tt.Host, tt.Port); join != tt.Join {
t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.Host, tt.Port, join, tt.Join)
}
}
}
...@@ -240,7 +240,7 @@ func hostToIP(host string) (ip IP, err os.Error) { ...@@ -240,7 +240,7 @@ func hostToIP(host string) (ip IP, err os.Error) {
addr = ParseIP(host) addr = ParseIP(host)
if addr == nil { if addr == nil {
// Not an IP address. Try as a DNS name. // Not an IP address. Try as a DNS name.
_, addrs, err1 := LookupHost(host) addrs, err1 := LookupHost(host)
if err1 != nil { if err1 != nil {
err = err1 err = err1
goto Error goto Error
......
...@@ -170,9 +170,10 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) { ...@@ -170,9 +170,10 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
return nil, InvalidAddrError("unexpected socket family") return nil, InvalidAddrError("unexpected socket family")
} }
// Split "host:port" into "host" and "port". // SplitHostPort splits a network address of the form
// Host cannot contain colons unless it is bracketed. // "host:port" or "[host]:port" into host and port.
func splitHostPort(hostport string) (host, port string, err os.Error) { // The latter form must be used when host contains a colon.
func SplitHostPort(hostport string) (host, port string, err os.Error) {
// The port starts after the last colon. // The port starts after the last colon.
i := last(hostport, ':') i := last(hostport, ':')
if i < 0 { if i < 0 {
...@@ -195,9 +196,9 @@ func splitHostPort(hostport string) (host, port string, err os.Error) { ...@@ -195,9 +196,9 @@ func splitHostPort(hostport string) (host, port string, err os.Error) {
return return
} }
// Join "host" and "port" into "host:port". // JoinHostPort combines host and port into a network address
// If host contains colons, will join into "[host]:port". // of the form "host:port" or, if host contains a colon, "[host]:port".
func joinHostPort(host, port string) string { func JoinHostPort(host, port string) string {
// If host has colons, have to bracket it. // If host has colons, have to bracket it.
if byteIndex(host, ':') >= 0 { if byteIndex(host, ':') >= 0 {
return "[" + host + "]:" + port return "[" + host + "]:" + port
...@@ -207,7 +208,7 @@ func joinHostPort(host, port string) string { ...@@ -207,7 +208,7 @@ func joinHostPort(host, port string) string {
// Convert "host:port" into IP address and port. // Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) { func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
host, port, err := splitHostPort(hostport) host, port, err := SplitHostPort(hostport)
if err != nil { if err != nil {
goto Error goto Error
} }
...@@ -218,7 +219,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) { ...@@ -218,7 +219,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
addr = ParseIP(host) addr = ParseIP(host)
if addr == nil { if addr == nil {
// Not an IP address. Try as a DNS name. // Not an IP address. Try as a DNS name.
_, addrs, err1 := LookupHost(host) addrs, err1 := LookupHost(host)
if err1 != nil { if err1 != nil {
err = err1 err = err1
goto Error goto Error
......
// 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"
)
// LookupHost looks up the given host using the local resolver.
// It returns an array of that host's addresses.
func LookupHost(host string) (addrs []string, err os.Error) {
addrs, err, ok := cgoLookupHost(host)
if !ok {
addrs, err = goLookupHost(host)
}
return
}
// LookupIP looks up host using the local resolver.
// It returns an array of that host's IPv4 and IPv6 addresses.
func LookupIP(host string) (addrs []IP, err os.Error) {
addrs, err, ok := cgoLookupIP(host)
if !ok {
addrs, err = goLookupIP(host)
}
return
}
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err os.Error) {
port, err, ok := cgoLookupPort(network, service)
if !ok {
port, err = goLookupPort(network, service)
}
return
}
...@@ -15,50 +15,49 @@ var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check f ...@@ -15,50 +15,49 @@ var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check f
type DialErrorTest struct { type DialErrorTest struct {
Net string Net string
Laddr string
Raddr string Raddr string
Pattern string Pattern string
} }
var dialErrorTests = []DialErrorTest{ var dialErrorTests = []DialErrorTest{
{ {
"datakit", "", "mh/astro/r70", "datakit", "mh/astro/r70",
"dial datakit mh/astro/r70: unknown network datakit", "dial datakit mh/astro/r70: unknown network datakit",
}, },
{ {
"tcp", "", "127.0.0.1:☺", "tcp", "127.0.0.1:☺",
"dial tcp 127.0.0.1:☺: unknown port tcp/☺", "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
}, },
{ {
"tcp", "", "no-such-name.google.com.:80", "tcp", "no-such-name.google.com.:80",
"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)", "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
}, },
{ {
"tcp", "", "no-such-name.no-such-top-level-domain.:80", "tcp", "no-such-name.no-such-top-level-domain.:80",
"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)", "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
}, },
{ {
"tcp", "", "no-such-name:80", "tcp", "no-such-name:80",
`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`, `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
}, },
{ {
"tcp", "", "mh/astro/r70:http", "tcp", "mh/astro/r70:http",
"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name", "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
}, },
{ {
"unix", "", "/etc/file-not-found", "unix", "/etc/file-not-found",
"dial unix /etc/file-not-found: [nN]o such file or directory", "dial unix /etc/file-not-found: [nN]o such file or directory",
}, },
{ {
"unix", "", "/etc/", "unix", "/etc/",
"dial unix /etc/: ([pP]ermission denied|[sS]ocket operation on non-socket|[cC]onnection refused)", "dial unix /etc/: ([pP]ermission denied|socket operation on non-socket|connection refused)",
}, },
{ {
"unixpacket", "", "/etc/file-not-found", "unixpacket", "/etc/file-not-found",
"dial unixpacket /etc/file-not-found: no such file or directory", "dial unixpacket /etc/file-not-found: no such file or directory",
}, },
{ {
"unixpacket", "", "/etc/", "unixpacket", "/etc/",
"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
}, },
} }
...@@ -69,7 +68,7 @@ func TestDialError(t *testing.T) { ...@@ -69,7 +68,7 @@ func TestDialError(t *testing.T) {
return return
} }
for i, tt := range dialErrorTests { for i, tt := range dialErrorTests {
c, e := Dial(tt.Net, tt.Laddr, tt.Raddr) c, e := Dial(tt.Net, tt.Raddr)
if c != nil { if c != nil {
c.Close() c.Close()
} }
......
...@@ -50,8 +50,8 @@ func readServices() { ...@@ -50,8 +50,8 @@ func readServices() {
file.close() file.close()
} }
// LookupPort looks up the port for the given network and service. // goLookupPort is the native Go implementation of LookupPort.
func LookupPort(network, service string) (port int, err os.Error) { func goLookupPort(network, service string) (port int, err os.Error) {
onceReadServices.Do(readServices) onceReadServices.Do(readServices)
switch network { switch network {
......
...@@ -54,13 +54,15 @@ func runServe(t *testing.T, network, addr string, listening chan<- string, done ...@@ -54,13 +54,15 @@ func runServe(t *testing.T, network, addr string, listening chan<- string, done
} }
func connect(t *testing.T, network, addr string, isEmpty bool) { func connect(t *testing.T, network, addr string, isEmpty bool) {
var laddr string var fd Conn
var err os.Error
if network == "unixgram" { if network == "unixgram" {
laddr = addr + ".local" fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
} else {
fd, err = Dial(network, addr)
} }
fd, err := Dial(network, laddr, addr)
if err != nil { if err != nil {
t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err) t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
} }
fd.SetReadTimeout(1e9) // 1s fd.SetReadTimeout(1e9) // 1s
......
...@@ -52,14 +52,16 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal ...@@ -52,14 +52,16 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
} }
} }
if fd, err = newFD(s, f, p, net); err != nil {
closesocket(s)
return nil, err
}
if ra != nil { if ra != nil {
e = syscall.Connect(s, ra) if err = fd.connect(ra); err != nil {
for e == syscall.EINTR { fd.sysfd = -1
e = syscall.Connect(s, ra)
}
if e != 0 {
closesocket(s) closesocket(s)
return nil, os.Errno(e) return nil, err
} }
} }
...@@ -68,12 +70,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal ...@@ -68,12 +70,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
sa, _ = syscall.Getpeername(s) sa, _ = syscall.Getpeername(s)
raddr := toAddr(sa) raddr := toAddr(sa)
fd, err = newFD(s, f, p, net, laddr, raddr) fd.setAddr(laddr, raddr)
if err != nil {
closesocket(s)
return nil, err
}
return fd, nil return fd, nil
} }
...@@ -170,9 +167,9 @@ func (e *UnknownSocketError) String() string { ...@@ -170,9 +167,9 @@ func (e *UnknownSocketError) String() string {
func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) { func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
switch a := sa.(type) { switch a := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
case *syscall.SockaddrInet6: case *syscall.SockaddrInet6:
return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
case *syscall.SockaddrUnix: case *syscall.SockaddrUnix:
return a.Name, nil return a.Name, nil
} }
......
...@@ -34,7 +34,7 @@ func (a *TCPAddr) String() string { ...@@ -34,7 +34,7 @@ func (a *TCPAddr) String() string {
if a == nil { if a == nil {
return "<nil>" return "<nil>"
} }
return joinHostPort(a.IP.String(), itoa(a.Port)) return JoinHostPort(a.IP.String(), itoa(a.Port))
} }
func (a *TCPAddr) family() int { func (a *TCPAddr) family() int {
...@@ -213,8 +213,9 @@ func (c *TCPConn) SetNoDelay(noDelay bool) os.Error { ...@@ -213,8 +213,9 @@ func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
// Closing c does not affect f, and closing f does not affect c. // Closing c does not affect f, and closing f does not affect c.
func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() } func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
// DialTCP is like Dial but can only connect to TCP networks // DialTCP connects to the remote address raddr on the network net,
// and returns a TCPConn structure. // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
// as the local address for the connection.
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) { func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
if raddr == nil { if raddr == nil {
return nil, &OpError{"dial", "tcp", nil, errMissingAddress} return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
......
...@@ -78,7 +78,7 @@ func (c *Conn) Close() os.Error { ...@@ -78,7 +78,7 @@ func (c *Conn) Close() os.Error {
// Dial connects to the given address on the given network using net.Dial // Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection. // and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, os.Error) { func Dial(network, addr string) (*Conn, os.Error) {
c, err := net.Dial(network, "", addr) c, err := net.Dial(network, addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -11,7 +11,7 @@ import ( ...@@ -11,7 +11,7 @@ import (
) )
func testTimeout(t *testing.T, network, addr string, readFrom bool) { func testTimeout(t *testing.T, network, addr string, readFrom bool) {
fd, err := Dial(network, "", addr) fd, err := Dial(network, addr)
if err != nil { if err != nil {
t.Errorf("dial %s %s failed: %v", network, addr, err) t.Errorf("dial %s %s failed: %v", network, addr, err)
return return
......
...@@ -34,7 +34,7 @@ func (a *UDPAddr) String() string { ...@@ -34,7 +34,7 @@ func (a *UDPAddr) String() string {
if a == nil { if a == nil {
return "<nil>" return "<nil>"
} }
return joinHostPort(a.IP.String(), itoa(a.Port)) return JoinHostPort(a.IP.String(), itoa(a.Port))
} }
func (a *UDPAddr) family() int { func (a *UDPAddr) family() int {
......
...@@ -48,7 +48,7 @@ func NewImporter(conn io.ReadWriter) *Importer { ...@@ -48,7 +48,7 @@ func NewImporter(conn io.ReadWriter) *Importer {
// Import imports a set of channels from the given network and address. // Import imports a set of channels from the given network and address.
func Import(network, remoteaddr string) (*Importer, os.Error) { func Import(network, remoteaddr string) (*Importer, os.Error) {
conn, err := net.Dial(network, "", remoteaddr) conn, err := net.Dial(network, remoteaddr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -399,7 +399,7 @@ func TestImportFlowControl(t *testing.T) { ...@@ -399,7 +399,7 @@ func TestImportFlowControl(t *testing.T) {
func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) { func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
go func() { go func() {
time.Sleep(1e9) time.Sleep(0.5e9)
sendDone <- false sendDone <- false
}() }()
......
...@@ -108,3 +108,21 @@ func Truncate(name string, size int64) Error { ...@@ -108,3 +108,21 @@ func Truncate(name string, size int64) Error {
} }
return nil return nil
} }
// basename removes trailing slashes and the leading directory name from path name
func basename(name string) string {
i := len(name) - 1
// Remove trailing slashes
for ; i > 0 && name[i] == '/'; i-- {
name = name[:i]
}
// Remove leading directory name
for i--; i >= 0; i-- {
if name[i] == '/' {
name = name[i+1:]
break
}
}
return name
}
...@@ -208,7 +208,7 @@ func DialHTTP(network, address string) (*Client, os.Error) { ...@@ -208,7 +208,7 @@ func DialHTTP(network, address string) (*Client, os.Error) {
// at the specified network address and path. // at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, os.Error) { func DialHTTPPath(network, address, path string) (*Client, os.Error) {
var err os.Error var err os.Error
conn, err := net.Dial(network, "", address) conn, err := net.Dial(network, address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -229,7 +229,7 @@ func DialHTTPPath(network, address, path string) (*Client, os.Error) { ...@@ -229,7 +229,7 @@ func DialHTTPPath(network, address, path string) (*Client, os.Error) {
// Dial connects to an RPC server at the specified network address. // Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, os.Error) { func Dial(network, address string) (*Client, os.Error) {
conn, err := net.Dial(network, "", address) conn, err := net.Dial(network, address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -116,7 +116,7 @@ func NewClient(conn io.ReadWriteCloser) *rpc.Client { ...@@ -116,7 +116,7 @@ func NewClient(conn io.ReadWriteCloser) *rpc.Client {
// Dial connects to a JSON-RPC server at the specified network address. // Dial connects to a JSON-RPC server at the specified network address.
func Dial(network, address string) (*rpc.Client, os.Error) { func Dial(network, address string) (*rpc.Client, os.Error) {
conn, err := net.Dial(network, "", address) conn, err := net.Dial(network, address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -15,7 +15,15 @@ import ( ...@@ -15,7 +15,15 @@ import (
) )
func TestCPUProfile(t *testing.T) { func TestCPUProfile(t *testing.T) {
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { switch runtime.GOOS {
case "darwin":
// see Apple Bug Report #9177434 (copied into change description)
return
case "plan9":
// unimplemented
return
case "windows":
// unimplemented
return return
} }
......
...@@ -39,7 +39,7 @@ type Client struct { ...@@ -39,7 +39,7 @@ type Client struct {
// Dial returns a new Client connected to an SMTP server at addr. // Dial returns a new Client connected to an SMTP server at addr.
func Dial(addr string) (*Client, os.Error) { func Dial(addr string) (*Client, os.Error) {
conn, err := net.Dial("tcp", "", addr) conn, err := net.Dial("tcp", addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -74,7 +74,11 @@ func TestSortStrings(t *testing.T) { ...@@ -74,7 +74,11 @@ func TestSortStrings(t *testing.T) {
} }
func TestSortLarge_Random(t *testing.T) { func TestSortLarge_Random(t *testing.T) {
data := make([]int, 1000000) n := 1000000
if testing.Short() {
n /= 100
}
data := make([]int, n)
for i := 0; i < len(data); i++ { for i := 0; i < len(data); i++ {
data[i] = rand.Intn(100) data[i] = rand.Intn(100)
} }
...@@ -174,6 +178,9 @@ func lg(n int) int { ...@@ -174,6 +178,9 @@ func lg(n int) int {
func TestBentleyMcIlroy(t *testing.T) { func TestBentleyMcIlroy(t *testing.T) {
sizes := []int{100, 1023, 1024, 1025} sizes := []int{100, 1023, 1024, 1025}
if testing.Short() {
sizes = []int{100, 127, 128, 129}
}
dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"} dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"} modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
var tmp1, tmp2 [1025]int var tmp1, tmp2 [1025]int
......
...@@ -275,20 +275,10 @@ func Join(a []string, sep string) string { ...@@ -275,20 +275,10 @@ func Join(a []string, sep string) string {
} }
b := make([]byte, n) b := make([]byte, n)
bp := 0 bp := copy(b, a[0])
for i := 0; i < len(a); i++ { for _, s := range a[1:] {
s := a[i] bp += copy(b[bp:], sep)
for j := 0; j < len(s); j++ { bp += copy(b[bp:], s)
b[bp] = s[j]
bp++
}
if i+1 < len(a) {
s = sep
for j := 0; j < len(s); j++ {
b[bp] = s[j]
bp++
}
}
} }
return string(b) return string(b)
} }
...@@ -312,9 +302,19 @@ func Map(mapping func(rune int) int, s string) string { ...@@ -312,9 +302,19 @@ func Map(mapping func(rune int) int, s string) string {
// fine. It could also shrink but that falls out naturally. // fine. It could also shrink but that falls out naturally.
maxbytes := len(s) // length of b maxbytes := len(s) // length of b
nbytes := 0 // number of bytes encoded in b nbytes := 0 // number of bytes encoded in b
b := make([]byte, maxbytes) // The output buffer b is initialized on demand, the first
for _, c := range s { // time a character differs.
var b []byte
for i, c := range s {
rune := mapping(c) rune := mapping(c)
if b == nil {
if rune == c {
continue
}
b = make([]byte, maxbytes)
nbytes = copy(b, s[:i])
}
if rune >= 0 { if rune >= 0 {
wid := 1 wid := 1
if rune >= utf8.RuneSelf { if rune >= utf8.RuneSelf {
...@@ -330,6 +330,9 @@ func Map(mapping func(rune int) int, s string) string { ...@@ -330,6 +330,9 @@ func Map(mapping func(rune int) int, s string) string {
nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune) nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
} }
} }
if b == nil {
return s
}
return string(b[0:nbytes]) return string(b[0:nbytes])
} }
......
...@@ -6,10 +6,12 @@ package strings_test ...@@ -6,10 +6,12 @@ package strings_test
import ( import (
"os" "os"
"reflect"
"strconv" "strconv"
. "strings" . "strings"
"testing" "testing"
"unicode" "unicode"
"unsafe"
"utf8" "utf8"
) )
...@@ -429,12 +431,32 @@ func TestMap(t *testing.T) { ...@@ -429,12 +431,32 @@ func TestMap(t *testing.T) {
if m != expect { if m != expect {
t.Errorf("drop: expected %q got %q", expect, m) t.Errorf("drop: expected %q got %q", expect, m)
} }
// 6. Identity
identity := func(rune int) int {
return rune
}
orig := "Input string that we expect not to be copied."
m = Map(identity, orig)
if (*reflect.StringHeader)(unsafe.Pointer(&orig)).Data !=
(*reflect.StringHeader)(unsafe.Pointer(&m)).Data {
t.Error("unexpected copy during identity map")
}
} }
func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
func BenchmarkMapNoChanges(b *testing.B) {
identity := func(rune int) int {
return rune
}
for i := 0; i < b.N; i++ {
Map(identity, "Some string that won't be modified.")
}
}
func TestSpecialCase(t *testing.T) { func TestSpecialCase(t *testing.T) {
lower := "abcçdefgğhıijklmnoöprsştuüvyz" lower := "abcçdefgğhıijklmnoöprsştuüvyz"
upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ" upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
...@@ -617,7 +639,11 @@ func equal(m string, s1, s2 string, t *testing.T) bool { ...@@ -617,7 +639,11 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
func TestCaseConsistency(t *testing.T) { func TestCaseConsistency(t *testing.T) {
// Make a string of all the runes. // Make a string of all the runes.
a := make([]int, unicode.MaxRune+1) numRunes := unicode.MaxRune + 1
if testing.Short() {
numRunes = 1000
}
a := make([]int, numRunes)
for i := range a { for i := range a {
a[i] = i a[i] = i
} }
...@@ -627,10 +653,10 @@ func TestCaseConsistency(t *testing.T) { ...@@ -627,10 +653,10 @@ func TestCaseConsistency(t *testing.T) {
lower := ToLower(s) lower := ToLower(s)
// Consistency checks // Consistency checks
if n := utf8.RuneCountInString(upper); n != unicode.MaxRune+1 { if n := utf8.RuneCountInString(upper); n != numRunes {
t.Error("rune count wrong in upper:", n) t.Error("rune count wrong in upper:", n)
} }
if n := utf8.RuneCountInString(lower); n != unicode.MaxRune+1 { if n := utf8.RuneCountInString(lower); n != numRunes {
t.Error("rune count wrong in lower:", n) t.Error("rune count wrong in lower:", n)
} }
if !equal("ToUpper(upper)", ToUpper(upper), upper, t) { if !equal("ToUpper(upper)", ToUpper(upper), upper, t) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment