The Go Programming Language

Source file src/pkg/net/server_test.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package net
     6	
     7	import (
     8		"flag"
     9		"io"
    10		"os"
    11		"strings"
    12		"syscall"
    13		"testing"
    14		"runtime"
    15	)
    16	
    17	// Do not test empty datagrams by default.
    18	// It causes unexplained timeouts on some systems,
    19	// including Snow Leopard.  I think that the kernel
    20	// doesn't quite expect them.
    21	var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
    22	
    23	func runEcho(fd io.ReadWriter, done chan<- int) {
    24		var buf [1024]byte
    25	
    26		for {
    27			n, err := fd.Read(buf[0:])
    28			if err != nil || n == 0 || string(buf[:n]) == "END" {
    29				break
    30			}
    31			fd.Write(buf[0:n])
    32		}
    33		done <- 1
    34	}
    35	
    36	func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
    37		l, err := Listen(network, addr)
    38		if err != nil {
    39			t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
    40		}
    41		listening <- l.Addr().String()
    42	
    43		for {
    44			fd, err := l.Accept()
    45			if err != nil {
    46				break
    47			}
    48			echodone := make(chan int)
    49			go runEcho(fd, echodone)
    50			<-echodone // make sure Echo stops
    51			l.Close()
    52		}
    53		done <- 1
    54	}
    55	
    56	func connect(t *testing.T, network, addr string, isEmpty bool) {
    57		var fd Conn
    58		var err os.Error
    59		if network == "unixgram" {
    60			fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
    61		} else {
    62			fd, err = Dial(network, addr)
    63		}
    64		if err != nil {
    65			t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
    66		}
    67		fd.SetReadTimeout(1e9) // 1s
    68	
    69		var b []byte
    70		if !isEmpty {
    71			b = []byte("hello, world\n")
    72		}
    73		var b1 [100]byte
    74	
    75		n, err1 := fd.Write(b)
    76		if n != len(b) {
    77			t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
    78		}
    79	
    80		n, err1 = fd.Read(b1[0:])
    81		if n != len(b) || err1 != nil {
    82			t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
    83		}
    84	
    85		// Send explicit ending for unixpacket.
    86		// Older Linux kernels do stop reads on close.
    87		if network == "unixpacket" {
    88			fd.Write([]byte("END"))
    89		}
    90	
    91		fd.Close()
    92	}
    93	
    94	func doTest(t *testing.T, network, listenaddr, dialaddr string) {
    95		t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr)
    96		switch listenaddr {
    97		case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
    98			if testing.Short() || avoidMacFirewall {
    99				t.Logf("skip wildcard listen during short test")
   100				return
   101			}
   102		}
   103		listening := make(chan string)
   104		done := make(chan int)
   105		if network == "tcp" || network == "tcp4" || network == "tcp6" {
   106			listenaddr += ":0" // any available port
   107		}
   108		go runServe(t, network, listenaddr, listening, done)
   109		addr := <-listening // wait for server to start
   110		if network == "tcp" || network == "tcp4" || network == "tcp6" {
   111			dialaddr += addr[strings.LastIndex(addr, ":"):]
   112		}
   113		connect(t, network, dialaddr, false)
   114		<-done // make sure server stopped
   115	}
   116	
   117	func TestTCPServer(t *testing.T) {
   118		doTest(t, "tcp", "", "127.0.0.1")
   119		doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
   120		doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
   121		doTest(t, "tcp4", "", "127.0.0.1")
   122		doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
   123		doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
   124		if supportsIPv6 {
   125			doTest(t, "tcp", "", "[::1]")
   126			doTest(t, "tcp", "[::]", "[::1]")
   127			doTest(t, "tcp", "[::1]", "[::1]")
   128			doTest(t, "tcp6", "", "[::1]")
   129			doTest(t, "tcp6", "[::]", "[::1]")
   130			doTest(t, "tcp6", "[::1]", "[::1]")
   131		}
   132		if supportsIPv6 && supportsIPv4map {
   133			doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
   134			doTest(t, "tcp", "[::]", "127.0.0.1")
   135			doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
   136			doTest(t, "tcp6", "", "127.0.0.1")
   137			doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
   138			doTest(t, "tcp6", "[::]", "127.0.0.1")
   139			doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
   140			doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
   141			doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
   142			doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
   143			doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
   144			doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
   145		}
   146	}
   147	
   148	func TestUnixServer(t *testing.T) {
   149		// "unix" sockets are not supported on windows and Plan 9.
   150		if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
   151			return
   152		}
   153		os.Remove("/tmp/gotest.net")
   154		doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
   155		os.Remove("/tmp/gotest.net")
   156		if syscall.OS == "linux" {
   157			doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
   158			os.Remove("/tmp/gotest.net")
   159			// Test abstract unix domain socket, a Linux-ism
   160			doTest(t, "unix", "@gotest/net", "@gotest/net")
   161			doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
   162		}
   163	}
   164	
   165	func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
   166		c, err := ListenPacket(network, addr)
   167		if err != nil {
   168			t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
   169		}
   170		listening <- c.LocalAddr().String()
   171		c.SetReadTimeout(10e6) // 10ms
   172		var buf [1000]byte
   173	Run:
   174		for {
   175			n, addr, err := c.ReadFrom(buf[0:])
   176			if e, ok := err.(Error); ok && e.Timeout() {
   177				select {
   178				case done <- 1:
   179					break Run
   180				default:
   181					continue Run
   182				}
   183			}
   184			if err != nil {
   185				break
   186			}
   187			if _, err = c.WriteTo(buf[0:n], addr); err != nil {
   188				t.Fatalf("WriteTo %v: %v", addr, err)
   189			}
   190		}
   191		c.Close()
   192		done <- 1
   193	}
   194	
   195	func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
   196		t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr)
   197		listening := make(chan string)
   198		done := make(chan int)
   199		if network == "udp" {
   200			listenaddr += ":0" // any available port
   201		}
   202		go runPacket(t, network, listenaddr, listening, done)
   203		addr := <-listening // wait for server to start
   204		if network == "udp" {
   205			dialaddr += addr[strings.LastIndex(addr, ":"):]
   206		}
   207		connect(t, network, dialaddr, isEmpty)
   208		<-done // tell server to stop
   209		<-done // wait for stop
   210	}
   211	
   212	func TestUDPServer(t *testing.T) {
   213		if !*testUDP {
   214			return
   215		}
   216		for _, isEmpty := range []bool{false, true} {
   217			doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
   218			doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
   219			if supportsIPv6 && supportsIPv4map {
   220				doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
   221				doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
   222				doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
   223			}
   224		}
   225	}
   226	
   227	func TestUnixDatagramServer(t *testing.T) {
   228		// "unix" sockets are not supported on windows and Plan 9.
   229		if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
   230			return
   231		}
   232		for _, isEmpty := range []bool{false} {
   233			os.Remove("/tmp/gotest1.net")
   234			os.Remove("/tmp/gotest1.net.local")
   235			doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
   236			os.Remove("/tmp/gotest1.net")
   237			os.Remove("/tmp/gotest1.net.local")
   238			if syscall.OS == "linux" {
   239				// Test abstract unix domain socket, a Linux-ism
   240				doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
   241			}
   242		}
   243	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.