go.dedis.ch/onet/v4@v4.0.0-pre1/network/tcp_test.go (about) 1 package network 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "net" 8 "strconv" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 "go.dedis.ch/kyber/v4/util/key" 15 "go.dedis.ch/onet/v4/log" 16 "golang.org/x/xerrors" 17 ) 18 19 func init() { 20 RegisterMessage(BigMsg{}) 21 SimpleMessageType = RegisterMessage(SimpleMessage{}) 22 } 23 24 type BigMsg struct { 25 Array []byte 26 } 27 28 type fakeConn struct { 29 // how many bytes does it write at maximum at each call 30 max int 31 // do we fail on the first write 32 fail1 bool 33 done1 bool 34 // do we fail on every successive write 35 failRest bool 36 // how many total bytes have we written 37 writtenBytes int 38 *net.TCPConn 39 } 40 41 type fakeAddr string 42 43 func (f fakeAddr) Network() string { 44 return "network" 45 } 46 47 func (f fakeAddr) String() string { 48 return "network-string" 49 } 50 51 func (f *fakeConn) Read(b []byte) (n int, e error) { 52 return 0, nil 53 } 54 55 func (f *fakeConn) Write(b []byte) (n int, e error) { 56 if !f.done1 && f.fail1 { 57 return 0, ErrUnknown 58 } else if f.failRest { 59 return 0, ErrUnknown 60 } 61 if len(b) < f.max { 62 f.writtenBytes += len(b) 63 return len(b), nil 64 } 65 f.writtenBytes += f.max 66 return f.max, nil 67 } 68 69 func TestTCPsendRaw(t *testing.T) { 70 tests := []struct { 71 msg []byte 72 conn *fakeConn 73 errExpected bool 74 bytesExpected int 75 }{ 76 { // fail at writing size 77 make([]byte, 100), 78 &fakeConn{100, true, false, false, 0, &net.TCPConn{}}, 79 true, 80 0, 81 }, 82 { // fail at writing msg 83 make([]byte, 100), 84 &fakeConn{100, false, false, true, 0, &net.TCPConn{}}, 85 true, 86 0, 87 }, 88 { // write undersize message 89 make([]byte, 99), 90 &fakeConn{100, false, false, false, 0, &net.TCPConn{}}, 91 false, 92 99, 93 }, 94 { // write exact message 95 make([]byte, 100), 96 &fakeConn{100, false, false, false, 0, &net.TCPConn{}}, 97 false, 98 100, 99 }, 100 { // write oversize message 101 make([]byte, 101), 102 &fakeConn{100, false, false, false, 0, &net.TCPConn{}}, 103 false, 104 101, 105 }, 106 } 107 108 for i, test := range tests { 109 tcp := &TCPConn{ 110 conn: test.conn, 111 } 112 _, err := tcp.sendRaw(test.msg) 113 if test.errExpected { 114 if err == nil { 115 t.Error("Should have had an error here") 116 } 117 continue 118 } 119 // - 4 is for the size, uint32_t 120 if test.bytesExpected != test.conn.writtenBytes-4 { 121 t.Error(i, "Wrong number of bytes? ", test.bytesExpected, test.conn.writtenBytes) 122 } 123 } 124 } 125 126 // Test the receiving part of a message for tcp connections if the response is 127 // buffered correctly. 128 func TestTCPConnReceiveRaw(t *testing.T) { 129 addr := make(chan string) 130 done := make(chan bool) 131 check := make(chan bool) 132 133 checking := func() bool { 134 select { 135 case <-check: 136 return false 137 case <-time.After(20 * time.Millisecond): 138 return true 139 } 140 } 141 // prepare the msg 142 msg := &BigMsg{Array: make([]byte, 7893)} 143 buff, err := Marshal(msg) 144 require.Nil(t, err) 145 146 fn := func(c net.Conn) { 147 // different slices of bytes 148 maxChunk := 1400 149 slices := make([][]byte, 0) 150 currentChunk := 0 151 for currentChunk+maxChunk < len(buff) { 152 slices = append(slices, buff[currentChunk:currentChunk+maxChunk]) 153 currentChunk += maxChunk 154 } 155 slices = append(slices, buff[currentChunk:]) 156 // send the size first 157 binary.Write(c, globalOrder, Size(len(buff))) 158 // then send pieces and check if the other side already returned or not 159 for i, slice := range slices[:len(slices)-1] { 160 log.Lvlf1("Will write slice %d/%d...", i+1, len(slices)) 161 if n, err := c.Write(slice); err != nil || n != len(slice) { 162 t.Fatal("Could not write enough") 163 } 164 log.Lvl1(" OK") 165 if !checking() { 166 t.Fatal("Already returned even if not finished") 167 } 168 time.Sleep(5 * time.Millisecond) 169 } 170 // the last one should make the other end return 171 log.Lvl1("Will write last piece...") 172 if n, err := c.Write(slices[len(slices)-1]); n != len(slices[len(slices)-1]) || err != nil { 173 t.Fatal("could not send the last piece") 174 } 175 log.Lvl1(" OK") 176 check <- true 177 } 178 179 fnBad := func(c net.Conn) { 180 // send the size first 181 binary.Write(c, globalOrder, Size(MaxPacketSize+1)) 182 } 183 184 listen := func(f func(c net.Conn)) { 185 ln, err := net.Listen("tcp", "127.0.0.1:0") 186 require.Nil(t, err) 187 addr <- ln.Addr().String() 188 c, err := ln.Accept() 189 require.Nil(t, err) 190 f(c) 191 <-done 192 require.Nil(t, ln.Close()) 193 done <- true 194 } 195 go listen(fn) 196 197 // get addr 198 listeningAddr := <-addr 199 c, err := NewTCPConn(NewTCPAddress(listeningAddr), tSuite) 200 require.Nil(t, err) 201 202 buffRaw, err := c.receiveRaw() 203 checking() 204 if !bytes.Equal(buff, buffRaw) { 205 t.Fatal("Bytes are not the same ") 206 } else if err != nil { 207 t.Error(err) 208 } 209 210 // tell the listener to close 211 done <- true 212 // wait until it is closed 213 <-done 214 215 go listen(fnBad) 216 217 listeningAddr = <-addr 218 c, err = NewTCPConn(NewTCPAddress(listeningAddr), tSuite) 219 require.Nil(t, err) 220 221 _, err = c.receiveRaw() 222 require.NotNil(t, err) 223 224 require.Nil(t, c.Close()) 225 // tell the listener to close 226 done <- true 227 // wait until it is closed 228 <-done 229 230 } 231 232 // test the creation of a new conn by opening a golang 233 // listener and making a TCPConn connect to it,then close it. 234 func TestTCPConn(t *testing.T) { 235 addr := make(chan string) 236 done := make(chan bool) 237 238 _, err := NewTCPConn(NewTCPAddress("127.0.0.1:7878"), tSuite) 239 if err == nil { 240 t.Fatal("Should not be able to connect here") 241 } 242 go func() { 243 ln, err := net.Listen("tcp", "127.0.0.1:0") 244 require.Nil(t, err) 245 addr <- ln.Addr().String() 246 _, err = ln.Accept() 247 require.Nil(t, err) 248 // wait until it can be closed 249 <-done 250 require.Nil(t, ln.Close()) 251 done <- true 252 }() 253 254 // get addr 255 listeningAddr := <-addr 256 c, err := NewTCPConn(NewTCPAddress(listeningAddr), tSuite) 257 require.Nil(t, err) 258 require.Equal(t, c.Local().NetworkAddress(), c.conn.LocalAddr().String()) 259 require.Equal(t, c.Type(), PlainTCP) 260 require.Nil(t, c.Close()) 261 // tell the listener to close 262 done <- true 263 // wait until it is closed 264 <-done 265 } 266 267 func TestTCPConnTimeout(t *testing.T) { 268 var timeoutForTest = 100 * time.Millisecond 269 270 // Need to lock because using 'timeout' from 'tcp.go'. 271 timeoutLock.Lock() 272 tmp := timeout 273 timeout = timeoutForTest 274 dialTimeout = timeoutForTest 275 timeoutLock.Unlock() 276 277 defer func() { 278 timeoutLock.Lock() 279 timeout = tmp 280 timeoutLock.Unlock() 281 }() 282 283 addr := NewAddress(PlainTCP, "127.0.0.1:5678") 284 ln, err := NewTCPListener(addr, tSuite) 285 if err != nil { 286 t.Fatal("error setup listener", err) 287 } 288 ready := make(chan bool) 289 connStat := make(chan error) 290 291 connFn := func(c Conn) { 292 // receive first a good packet 293 _, err := c.Receive() 294 connStat <- err 295 296 // then this receive should throw out the error 297 _, err = c.Receive() 298 connStat <- err 299 300 // put the far-side receiver into broken mode 301 tc := c.(*TCPConn) 302 tc.receiveRawTest = func() ([]byte, error) { 303 time.Sleep(2 * timeoutForTest) 304 return nil, nil 305 } 306 307 // this should throw also: need to send enough bytes here 308 // that we overload the kernel's buffers and it creates 309 // back-pressure on us to stop sending by blocking on 310 // the send system call so that Go's SendDeadline is passed. 311 msg := &BigMsg{Array: make([]byte, 20*1e6)} 312 _, err = c.Send(msg) 313 connStat <- err 314 } 315 go func() { 316 ready <- true 317 err := ln.Listen(connFn) 318 require.Nil(t, err, "Listener stop incorrectly") 319 }() 320 321 <-ready 322 c, err := NewTCPConn(addr, tSuite) 323 require.Nil(t, err, "Could not open connection") 324 // Test bandwitdth measurements also 325 sentLen, err := c.Send(&SimpleMessage{3}) 326 require.Nil(t, err) 327 require.NotZero(t, sentLen) 328 select { 329 case err := <-connStat: 330 assert.NoError(t, err) 331 case <-time.After(2 * timeoutForTest): 332 t.Error("Did not received message after timeout...") 333 } 334 335 // find the timeout from recv 336 select { 337 case err := <-connStat: 338 assert.Error(t, err) 339 case <-time.After(2 * timeoutForTest): 340 t.Error("Did not received message after timeout...") 341 } 342 343 // the timeout from send too 344 select { 345 case err := <-connStat: 346 assert.True(t, xerrors.Is(err, ErrTimeout)) 347 case <-time.After(10 * timeoutForTest): 348 t.Error("Did not received message after timeout...") 349 } 350 351 assert.Nil(t, c.Close()) 352 assert.Nil(t, ln.Stop()) 353 } 354 355 func TestTCPDialTimeout(t *testing.T) { 356 oldDialTimeout := dialTimeout 357 SetTCPDialTimeout(100 * time.Millisecond) 358 defer SetTCPDialTimeout(oldDialTimeout) 359 360 // We're hoping that Cloudflare is not running a server on this address 361 // so we'll get a timeout error. 362 addr := NewAddress(PlainTCP, "1.1.1.2:1234") 363 done := make(chan struct{}, 1) 364 go func() { 365 _, err := NewTCPConn(addr, tSuite) 366 require.Contains(t, err.Error(), "timeout") 367 done <- struct{}{} 368 }() 369 370 select { 371 case <-done: 372 case <-time.After(time.Second): 373 require.Fail(t, "should have timed out after a short duration") 374 } 375 } 376 377 func TestTCPConnWithListener(t *testing.T) { 378 addr := NewAddress(PlainTCP, "127.0.0.1:5678") 379 ln, err := NewTCPListener(addr, tSuite) 380 if err != nil { 381 t.Fatal("error setup listener", err) 382 } 383 ready := make(chan bool) 384 stop := make(chan bool) 385 connStat := make(chan uint64) 386 387 connFn := func(c Conn) { 388 connStat <- c.Rx() 389 c.Receive() 390 connStat <- c.Rx() 391 } 392 go func() { 393 ready <- true 394 err := ln.Listen(connFn) 395 require.Nil(t, err, "Listener stop incorrectly") 396 stop <- true 397 }() 398 399 <-ready 400 c, err := NewTCPConn(addr, tSuite) 401 require.Nil(t, err, "Could not open connection") 402 // Test bandwitdth measurements also 403 rx1 := <-connStat 404 tx1 := c.Tx() 405 sentLen, err := c.Send(&SimpleMessage{3}) 406 require.Nil(t, err) 407 tx2 := c.Tx() 408 rx2 := <-connStat 409 410 if (tx2 - tx1) != (rx2 - rx1) { 411 t.Errorf("Connections did see same bytes? %d tx vs %d rx", (tx2 - tx1), (rx2 - rx1)) 412 } 413 require.Equal(t, tx2-tx1, sentLen) 414 415 require.Nil(t, ln.Stop(), "Error stopping listener") 416 select { 417 case <-stop: 418 case <-time.After(100 * time.Millisecond): 419 t.Fatal("Could not stop listener") 420 421 } 422 } 423 424 // will create a TCPListener with a specific address to listen on and 425 // open a golang net.TCPConn to it 426 func TestTCPListenerWithListenAddr(t *testing.T) { 427 // Testing different wrong configurations. 428 testVectorWrong := []struct { 429 addr Address 430 listen string 431 }{ 432 {NewAddress(PlainTCP, "1.2.3.4:0"), ":0"}, 433 } 434 for _, tv := range testVectorWrong { 435 _, err := NewTCPListenerWithListenAddr(tv.addr, tSuite, tv.listen) 436 require.NotNil(t, err, fmt.Sprintf(`Should fail: invalid combination of 437 'addr' (%s) and 'listenAddr' (%s)`, tv.addr, tv.listen)) 438 } 439 440 // Testing different working configurations. 441 testVector := []struct { 442 addr Address 443 listen string 444 expectedHost string 445 }{ 446 {NewAddress(PlainTCP, "1.2.3.4:0"), "127.0.0.1", "127.0.0.1"}, 447 {NewAddress(PlainTCP, "1.2.3.4:0"), "127.0.0.1:0", "127.0.0.1"}, 448 {NewAddress(PlainTCP, "1.2.3.4:0"), "", "::"}, 449 } 450 for _, tv := range testVector { 451 ln, err := NewTCPListenerWithListenAddr(tv.addr, tSuite, tv.listen) 452 require.Nil(t, err, "Error setup listener") 453 host, _, err := net.SplitHostPort(ln.Address().NetworkAddress()) 454 require.Nil(t, err, "Error splitting address of listener") 455 require.Equal(t, tv.expectedHost, host) 456 457 ready := make(chan bool) 458 stop := make(chan bool) 459 connReceived := make(chan bool) 460 461 connFn := func(c Conn) { 462 connReceived <- true 463 c.Close() 464 } 465 go func() { 466 ready <- true 467 err := ln.Listen(connFn) 468 require.Nil(t, err, "Listener stop incorrectly") 469 stop <- true 470 }() 471 472 <-ready 473 _, err = net.Dial("tcp", ln.Address().NetworkAddress()) 474 require.Nil(t, err, "Could not open connection") 475 <-connReceived 476 require.Nil(t, ln.Stop(), "Error stopping listener") 477 select { 478 case <-stop: 479 case <-time.After(100 * time.Millisecond): 480 t.Fatal("Could not stop listener") 481 } 482 483 require.Nil(t, ln.listen(nil)) 484 } 485 486 // Testing different working configurations using static ports (but not 487 // listening because we don't want to risk any error). 488 testVectorStaticPort := []struct { 489 addr Address 490 listen string 491 expectedAddress string 492 }{ 493 {NewAddress(PlainTCP, "1.2.3.4:1234"), "4.3.2.1", "4.3.2.1:1234"}, 494 {NewAddress(PlainTCP, "1.2.3.4:1234"), "4.3.2.1:4321", "4.3.2.1:4321"}, 495 {NewAddress(PlainTCP, "1.2.3.4:1234"), "", ":1234"}, 496 } 497 for _, tv := range testVectorStaticPort { 498 // using directly 'getListenAddress' which is used by 499 // 'NewTCPListenerWithListenAddr' to figure out the address to listen 500 // to given the server address and listen address from 'private.toml' 501 listenAddr, err := getListenAddress(tv.addr, tv.listen) 502 require.Nil(t, err, "Error getting the listen address") 503 require.Equal(t, tv.expectedAddress, listenAddr) 504 } 505 } 506 507 // will create a TCPListener globally binding & open a golang net.TCPConn to it 508 func TestTCPListener(t *testing.T) { 509 addr := NewAddress(PlainTCP, "127.0.0.1:0") 510 ln, err := NewTCPListener(addr, tSuite) 511 require.Nil(t, err, "Error setup listener") 512 513 // Making sure the listener is globally binding 514 host, _, err := net.SplitHostPort(ln.Address().NetworkAddress()) 515 require.Nil(t, err, "Error splitting address of listener") 516 require.Equal(t, "::", host, "Listener did not bind globally when given no specific listen address") 517 518 ready := make(chan bool) 519 stop := make(chan bool) 520 connReceived := make(chan bool) 521 522 connFn := func(c Conn) { 523 connReceived <- true 524 c.Close() 525 } 526 go func() { 527 ready <- true 528 err := ln.Listen(connFn) 529 require.Nil(t, err, "Listener stop incorrectly") 530 stop <- true 531 }() 532 533 <-ready 534 _, err = net.Dial("tcp", ln.Address().NetworkAddress()) 535 require.Nil(t, err, "Could not open connection") 536 <-connReceived 537 require.Nil(t, ln.Stop(), "Error stopping listener") 538 select { 539 case <-stop: 540 case <-time.After(100 * time.Millisecond): 541 t.Fatal("Could not stop listener") 542 } 543 544 require.Nil(t, ln.listen(nil)) 545 } 546 547 func TestTCPRouter(t *testing.T) { 548 wrongAddr := &ServerIdentity{Address: NewLocalAddress("127.0.0.1:2000")} 549 _, err := NewTCPRouter(wrongAddr, tSuite) 550 if err == nil { 551 t.Fatal("Should not setup Router with local address") 552 } 553 554 addr := &ServerIdentity{Address: NewAddress(PlainTCP, "127.0.0.1:2000")} 555 h1, err := NewTCPRouter(addr, tSuite) 556 if err != nil { 557 t.Fatal("Could not setup host") 558 } 559 defer h1.Stop() 560 _, err = NewTCPRouter(addr, tSuite) 561 if err == nil { 562 t.Fatal("Should not succeed with same port") 563 } 564 } 565 566 // Test closing and opening of Host on same address 567 func TestTCPHostClose(t *testing.T) { 568 h1, err := NewTestTCPHost(2001) 569 if err != nil { 570 t.Fatal("Error setup TestTCPHost") 571 } 572 h2, err2 := NewTestTCPHost(2002) 573 if err2 != nil { 574 t.Fatal("Error setup TestTCPHost2") 575 } 576 go h1.Listen(acceptAndClose) 577 si := NewTestServerIdentity(NewLocalAddress("127.0.0.1:7878")) 578 if _, err := h2.Connect(si); err == nil { 579 t.Fatal("Should not connect to dummy address or different type") 580 } 581 _, err = h2.Connect(NewTestServerIdentity(h1.TCPListener.Address())) 582 if err != nil { 583 t.Fatal("Couldn't Connect()", err) 584 } 585 586 err = h1.Stop() 587 if err != nil { 588 t.Fatal("Couldn't close:", err) 589 } 590 err = h2.Stop() 591 if err != nil { 592 t.Fatal("Couldn't close:", err) 593 } 594 log.Lvl3("Finished first connection, starting 2nd") 595 h3, err3 := NewTestTCPHost(2003) 596 if err3 != nil { 597 t.Fatal("Could not setup host", err) 598 } 599 go h3.Listen(acceptAndClose) 600 _, err = h2.Connect(NewTestServerIdentity(h3.TCPListener.Address())) 601 if err != nil { 602 t.Fatal(h2, "Couldn Connect() to", h3) 603 } 604 log.Lvl3("Closing h3") 605 err = h3.Stop() 606 if err != nil { 607 // try closing the underlying connection manually and fail 608 t.Fatal("Couldn't Stop()", h3) 609 } 610 } 611 612 type dummyErr struct { 613 timeout bool 614 temporary bool 615 } 616 617 func (d *dummyErr) Timeout() bool { 618 return d.timeout 619 } 620 621 func (d *dummyErr) Temporary() bool { 622 return d.temporary 623 } 624 625 func (d *dummyErr) Error() string { 626 return "dummy error" 627 } 628 629 func TestHandleError(t *testing.T) { 630 require.Equal(t, ErrClosed, handleError(xerrors.New("use of closed"))) 631 require.Equal(t, ErrCanceled, handleError(xerrors.New("canceled"))) 632 require.Equal(t, ErrEOF, handleError(xerrors.New("EOF"))) 633 634 require.Equal(t, ErrUnknown, handleError(xerrors.New("random error"))) 635 636 de := dummyErr{true, true} 637 de.temporary = false 638 require.Equal(t, ErrTimeout, handleError(&de)) 639 de.timeout = false 640 require.Equal(t, ErrUnknown, handleError(&de)) 641 } 642 643 func NewTestTCPHost(port int) (*TCPHost, error) { 644 addr := NewTCPAddress("127.0.0.1:" + strconv.Itoa(port)) 645 kp := key.NewKeyPair(tSuite) 646 e := NewServerIdentity(kp.Public, addr) 647 e.SetPrivate(kp.Private) 648 return NewTCPHost(e, tSuite) 649 } 650 651 // Returns a ServerIdentity out of the address 652 func NewTestServerIdentity(address Address) *ServerIdentity { 653 kp := key.NewKeyPair(tSuite) 654 e := NewServerIdentity(kp.Public, address) 655 return e 656 } 657 658 // SimpleMessage is just used to transfer one integer 659 type SimpleMessage struct { 660 I int64 661 } 662 663 var SimpleMessageType MessageTypeID 664 665 type simpleMessageProc struct { 666 t *testing.T 667 relay chan SimpleMessage 668 } 669 670 func newSimpleMessageProc(t *testing.T) *simpleMessageProc { 671 return &simpleMessageProc{ 672 t: t, 673 relay: make(chan SimpleMessage), 674 } 675 } 676 677 func (smp *simpleMessageProc) Process(e *Envelope) { 678 if e.MsgType != SimpleMessageType { 679 smp.t.Fatal("Wrong message") 680 } 681 sm := e.Msg.(*SimpleMessage) 682 smp.relay <- *sm 683 } 684 685 type statusMessage struct { 686 Ok bool 687 Val int64 688 } 689 690 var statusMsgID = RegisterMessage(statusMessage{}) 691 692 type simpleProcessor struct { 693 relay chan statusMessage 694 } 695 696 func newSimpleProcessor() *simpleProcessor { 697 return &simpleProcessor{ 698 relay: make(chan statusMessage), 699 } 700 } 701 func (sp *simpleProcessor) Process(env *Envelope) { 702 if env.MsgType != statusMsgID { 703 704 sp.relay <- statusMessage{false, 0} 705 } 706 sm := env.Msg.(*statusMessage) 707 708 sp.relay <- *sm 709 } 710 711 func sendrcvProc(from, to *Router) error { 712 sp := newSimpleProcessor() 713 // new processing 714 to.RegisterProcessor(sp, statusMsgID) 715 sentLen, err := from.Send(to.ServerIdentity, &statusMessage{true, 10}) 716 if err != nil { 717 return err 718 } 719 if sentLen == 0 { 720 return xerrors.New("sentLen is zero") 721 } 722 723 select { 724 case <-sp.relay: 725 err = nil 726 case <-time.After(1 * time.Second): 727 err = xerrors.New("timeout") 728 } 729 // delete the processing 730 to.RegisterProcessor(nil, statusMsgID) 731 return err 732 } 733 734 func waitConnections(r *Router, sid *ServerIdentity) error { 735 for i := 0; i < 10; i++ { 736 c := r.connection(sid.ID) 737 if c != nil { 738 return nil 739 } 740 time.Sleep(WaitRetry) 741 } 742 return xerrors.Errorf("Didn't see connection to %s in router", sid.Address) 743 } 744 745 func acceptAndClose(c Conn) { 746 c.Close() 747 return 748 }