github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/internal/socket/socket_test.go (about)

     1  // Copyright 2017 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  // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
     6  
     7  package socket_test
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"net"
    13  	"runtime"
    14  	"syscall"
    15  	"testing"
    16  
    17  	"github.com/Andyfoo/golang/x/net/internal/socket"
    18  	"github.com/Andyfoo/golang/x/net/nettest"
    19  )
    20  
    21  func TestSocket(t *testing.T) {
    22  	t.Run("Option", func(t *testing.T) {
    23  		testSocketOption(t, &socket.Option{Level: syscall.SOL_SOCKET, Name: syscall.SO_RCVBUF, Len: 4})
    24  	})
    25  }
    26  
    27  func testSocketOption(t *testing.T, so *socket.Option) {
    28  	c, err := nettest.NewLocalPacketListener("udp")
    29  	if err != nil {
    30  		t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
    31  	}
    32  	defer c.Close()
    33  	cc, err := socket.NewConn(c.(net.Conn))
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	const N = 2048
    38  	if err := so.SetInt(cc, N); err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	n, err := so.GetInt(cc)
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	if n < N {
    46  		t.Fatalf("got %d; want greater than or equal to %d", n, N)
    47  	}
    48  }
    49  
    50  type mockControl struct {
    51  	Level int
    52  	Type  int
    53  	Data  []byte
    54  }
    55  
    56  func TestControlMessage(t *testing.T) {
    57  	switch runtime.GOOS {
    58  	case "windows":
    59  		t.Skipf("not supported on %s", runtime.GOOS)
    60  	}
    61  
    62  	for _, tt := range []struct {
    63  		cs []mockControl
    64  	}{
    65  		{
    66  			[]mockControl{
    67  				{Level: 1, Type: 1},
    68  			},
    69  		},
    70  		{
    71  			[]mockControl{
    72  				{Level: 2, Type: 2, Data: []byte{0xfe}},
    73  			},
    74  		},
    75  		{
    76  			[]mockControl{
    77  				{Level: 3, Type: 3, Data: []byte{0xfe, 0xff, 0xff, 0xfe}},
    78  			},
    79  		},
    80  		{
    81  			[]mockControl{
    82  				{Level: 4, Type: 4, Data: []byte{0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe}},
    83  			},
    84  		},
    85  		{
    86  			[]mockControl{
    87  				{Level: 4, Type: 4, Data: []byte{0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe}},
    88  				{Level: 2, Type: 2, Data: []byte{0xfe}},
    89  			},
    90  		},
    91  	} {
    92  		var w []byte
    93  		var tailPadLen int
    94  		mm := socket.NewControlMessage([]int{0})
    95  		for i, c := range tt.cs {
    96  			m := socket.NewControlMessage([]int{len(c.Data)})
    97  			l := len(m) - len(mm)
    98  			if i == len(tt.cs)-1 && l > len(c.Data) {
    99  				tailPadLen = l - len(c.Data)
   100  			}
   101  			w = append(w, m...)
   102  		}
   103  
   104  		var err error
   105  		ww := make([]byte, len(w))
   106  		copy(ww, w)
   107  		m := socket.ControlMessage(ww)
   108  		for _, c := range tt.cs {
   109  			if err = m.MarshalHeader(c.Level, c.Type, len(c.Data)); err != nil {
   110  				t.Fatalf("(%v).MarshalHeader() = %v", tt.cs, err)
   111  			}
   112  			copy(m.Data(len(c.Data)), c.Data)
   113  			m = m.Next(len(c.Data))
   114  		}
   115  		m = socket.ControlMessage(w)
   116  		for _, c := range tt.cs {
   117  			m, err = m.Marshal(c.Level, c.Type, c.Data)
   118  			if err != nil {
   119  				t.Fatalf("(%v).Marshal() = %v", tt.cs, err)
   120  			}
   121  		}
   122  		if !bytes.Equal(ww, w) {
   123  			t.Fatalf("got %#v; want %#v", ww, w)
   124  		}
   125  
   126  		ws := [][]byte{w}
   127  		if tailPadLen > 0 {
   128  			// Test a message with no tail padding.
   129  			nopad := w[:len(w)-tailPadLen]
   130  			ws = append(ws, [][]byte{nopad}...)
   131  		}
   132  		for _, w := range ws {
   133  			ms, err := socket.ControlMessage(w).Parse()
   134  			if err != nil {
   135  				t.Fatalf("(%v).Parse() = %v", tt.cs, err)
   136  			}
   137  			for i, m := range ms {
   138  				lvl, typ, dataLen, err := m.ParseHeader()
   139  				if err != nil {
   140  					t.Fatalf("(%v).ParseHeader() = %v", tt.cs, err)
   141  				}
   142  				if lvl != tt.cs[i].Level || typ != tt.cs[i].Type || dataLen != len(tt.cs[i].Data) {
   143  					t.Fatalf("%v: got %d, %d, %d; want %d, %d, %d", tt.cs[i], lvl, typ, dataLen, tt.cs[i].Level, tt.cs[i].Type, len(tt.cs[i].Data))
   144  				}
   145  			}
   146  		}
   147  	}
   148  }
   149  
   150  func TestUDP(t *testing.T) {
   151  	switch runtime.GOOS {
   152  	case "windows":
   153  		t.Skipf("not supported on %s", runtime.GOOS)
   154  	}
   155  
   156  	c, err := nettest.NewLocalPacketListener("udp")
   157  	if err != nil {
   158  		t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
   159  	}
   160  	defer c.Close()
   161  	cc, err := socket.NewConn(c.(net.Conn))
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  
   166  	t.Run("Message", func(t *testing.T) {
   167  		data := []byte("HELLO-R-U-THERE")
   168  		wm := socket.Message{
   169  			Buffers: bytes.SplitAfter(data, []byte("-")),
   170  			Addr:    c.LocalAddr(),
   171  		}
   172  		if err := cc.SendMsg(&wm, 0); err != nil {
   173  			t.Fatal(err)
   174  		}
   175  		b := make([]byte, 32)
   176  		rm := socket.Message{
   177  			Buffers: [][]byte{b[:1], b[1:3], b[3:7], b[7:11], b[11:]},
   178  		}
   179  		if err := cc.RecvMsg(&rm, 0); err != nil {
   180  			t.Fatal(err)
   181  		}
   182  		if !bytes.Equal(b[:rm.N], data) {
   183  			t.Fatalf("got %#v; want %#v", b[:rm.N], data)
   184  		}
   185  	})
   186  	switch runtime.GOOS {
   187  	case "android", "linux":
   188  		t.Run("Messages", func(t *testing.T) {
   189  			data := []byte("HELLO-R-U-THERE")
   190  			wmbs := bytes.SplitAfter(data, []byte("-"))
   191  			wms := []socket.Message{
   192  				{Buffers: wmbs[:1], Addr: c.LocalAddr()},
   193  				{Buffers: wmbs[1:], Addr: c.LocalAddr()},
   194  			}
   195  			n, err := cc.SendMsgs(wms, 0)
   196  			if err != nil {
   197  				t.Fatal(err)
   198  			}
   199  			if n != len(wms) {
   200  				t.Fatalf("got %d; want %d", n, len(wms))
   201  			}
   202  			b := make([]byte, 32)
   203  			rmbs := [][][]byte{{b[:len(wmbs[0])]}, {b[len(wmbs[0]):]}}
   204  			rms := []socket.Message{
   205  				{Buffers: rmbs[0]},
   206  				{Buffers: rmbs[1]},
   207  			}
   208  			n, err = cc.RecvMsgs(rms, 0)
   209  			if err != nil {
   210  				t.Fatal(err)
   211  			}
   212  			if n != len(rms) {
   213  				t.Fatalf("got %d; want %d", n, len(rms))
   214  			}
   215  			nn := 0
   216  			for i := 0; i < n; i++ {
   217  				nn += rms[i].N
   218  			}
   219  			if !bytes.Equal(b[:nn], data) {
   220  				t.Fatalf("got %#v; want %#v", b[:nn], data)
   221  			}
   222  		})
   223  	}
   224  
   225  	// The behavior of transmission for zero byte paylaod depends
   226  	// on each platform implementation. Some may transmit only
   227  	// protocol header and options, other may transmit nothing.
   228  	// We test only that SendMsg and SendMsgs will not crash with
   229  	// empty buffers.
   230  	wm := socket.Message{
   231  		Buffers: [][]byte{{}},
   232  		Addr:    c.LocalAddr(),
   233  	}
   234  	cc.SendMsg(&wm, 0)
   235  	wms := []socket.Message{
   236  		{Buffers: [][]byte{{}}, Addr: c.LocalAddr()},
   237  	}
   238  	cc.SendMsgs(wms, 0)
   239  }
   240  
   241  func BenchmarkUDP(b *testing.B) {
   242  	c, err := nettest.NewLocalPacketListener("udp")
   243  	if err != nil {
   244  		b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
   245  	}
   246  	defer c.Close()
   247  	cc, err := socket.NewConn(c.(net.Conn))
   248  	if err != nil {
   249  		b.Fatal(err)
   250  	}
   251  	data := []byte("HELLO-R-U-THERE")
   252  	wm := socket.Message{
   253  		Buffers: [][]byte{data},
   254  		Addr:    c.LocalAddr(),
   255  	}
   256  	rm := socket.Message{
   257  		Buffers: [][]byte{make([]byte, 128)},
   258  		OOB:     make([]byte, 128),
   259  	}
   260  
   261  	for M := 1; M <= 1<<9; M = M << 1 {
   262  		b.Run(fmt.Sprintf("Iter-%d", M), func(b *testing.B) {
   263  			for i := 0; i < b.N; i++ {
   264  				for j := 0; j < M; j++ {
   265  					if err := cc.SendMsg(&wm, 0); err != nil {
   266  						b.Fatal(err)
   267  					}
   268  					if err := cc.RecvMsg(&rm, 0); err != nil {
   269  						b.Fatal(err)
   270  					}
   271  				}
   272  			}
   273  		})
   274  		switch runtime.GOOS {
   275  		case "android", "linux":
   276  			wms := make([]socket.Message, M)
   277  			for i := range wms {
   278  				wms[i].Buffers = [][]byte{data}
   279  				wms[i].Addr = c.LocalAddr()
   280  			}
   281  			rms := make([]socket.Message, M)
   282  			for i := range rms {
   283  				rms[i].Buffers = [][]byte{make([]byte, 128)}
   284  				rms[i].OOB = make([]byte, 128)
   285  			}
   286  			b.Run(fmt.Sprintf("Batch-%d", M), func(b *testing.B) {
   287  				for i := 0; i < b.N; i++ {
   288  					if _, err := cc.SendMsgs(wms, 0); err != nil {
   289  						b.Fatal(err)
   290  					}
   291  					if _, err := cc.RecvMsgs(rms, 0); err != nil {
   292  						b.Fatal(err)
   293  					}
   294  				}
   295  			})
   296  		}
   297  	}
   298  }