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 }