func TestInitiateHandshakes(t *testing.T) { Convey("Sends out handshake request to every IP in list", t, func() { s := NewBTService(port, []byte(peerIDRemote)) mc := NewMockConnectionFetcher() s.ConnectionFetcher = mc s.AddHash(hash) _ = s.StartListening() // TODO: check that peer data is saved within service data structure peers := make([]structure.Peer, 2) peers[0] = structure.Peer{IP: net.IPv4(192, 168, 1, 1), Port: 55556} peers[1] = structure.Peer{IP: net.IPv4(192, 168, 1, 2), Port: 55557} s.InitiateHandshakes(hash, peers) for _, p := range peers { c0 := mc.Conns[p.AddrString()].Conn.(*MockConnection) hs, err := structure.ReadHandshake(bytes.NewReader(<-c0.ReceiveBytesChan)) So(hs, ShouldNotBeNil) So(err, ShouldBeNil) hs, _ = structure.NewHandshake(hash, []byte(peerIDClient)) c0.SendMessage(hs) } time.Sleep(time.Millisecond) So(len(s.Peers), ShouldEqual, len(peers)) _ = s.StopListening() time.Sleep(time.Millisecond) So(s.Listening, ShouldBeFalse) }) }
func TestConversation(t *testing.T) { Convey("Receives Bitfield message and sends Interested message", t, func(ctx C) { s := NewBTService(port, []byte(peerIDRemote)) mc := NewMockConnectionFetcher() s.ConnectionFetcher = mc s.AddHash(hash) _ = s.StartListening() // TODO: check that peer data is saved within service data structure peers := make([]structure.Peer, 1) peers[0] = structure.Peer{IP: net.IPv4(192, 168, 1, 1), Port: 55556} // peers[1] = structure.Peer{IP: net.IPv4(192, 168, 1, 2), Port: 55557} s.InitiateHandshakes(hash, peers) wg := sync.WaitGroup{} wg.Add(len(peers)) for _, p := range peers { go func(pp structure.Peer) { c0 := mc.Conns[pp.AddrString()].Conn.(*MockConnection) hs, err := structure.ReadHandshake(bytes.NewReader(<-c0.ReceiveBytesChan)) ctx.So(hs, ShouldNotBeNil) ctx.So(err, ShouldBeNil) hs, _ = structure.NewHandshake(hash, []byte(peerIDClient)) t.Log("---TEST--- Send Handshake") c0.SendMessage(hs) bf := structure.BitFieldFromHexString("\xff\xff\xff\x01") msg0 := structure.NewBitFieldMessage(bf) c0.SendMessage(msg0) m, err := ReadMessageOrTimeout(c0, ctx) ctx.So(err, ShouldBeNil) ctx.So(m.GetType(), ShouldEqual, structure.MessageTypeInterested) // TODO: Check why byte equality doesn't work btc := s.LookupConn(pp.AddrString()) t.Logf("BTC: %q\n", btc.BitField.String()) t.Logf("BF : %q\n", bf.String()) ctx.So(bf.String(), ShouldEqual, btc.BitField.String()) ctx.So(btc.PeerChoking, ShouldBeTrue) msg1 := structure.NewUnchokeMessage() c0.SendMessage(msg1) m, err = ReadMessageOrTimeout(c0, ctx) ctx.So(btc.PeerChoking, ShouldBeFalse) ctx.So(err, ShouldBeNil) ctx.So(m.GetType(), ShouldEqual, structure.MessageTypeRequest) wg.Done() }(p) } wg.Wait() _ = s.StopListening() }) }
func TestHave(t *testing.T) { Convey("Receives Have Messages and update BitField", t, func(ctx C) { s := NewBTService(port, []byte(peerIDRemote)) mc := NewMockConnectionFetcher() s.ConnectionFetcher = mc s.AddHash(hash) _ = s.StartListening() // TODO: check that peer data is saved within service data structure peers := make([]structure.Peer, 1) peers[0] = structure.Peer{IP: net.IPv4(192, 168, 1, 1), Port: 55557} // peers[1] = structure.Peer{IP: net.IPv4(192, 168, 1, 2), Port: 55557} s.InitiateHandshakes(hash, peers) wg := sync.WaitGroup{} wg.Add(len(peers)) for _, p := range peers { go func(pp structure.Peer) { c0 := mc.Conns[pp.AddrString()].Conn.(*MockConnection) hs, err := structure.ReadHandshake(bytes.NewReader(<-c0.ReceiveBytesChan)) ctx.So(hs, ShouldNotBeNil) ctx.So(err, ShouldBeNil) hs, _ = structure.NewHandshake(hash, []byte(peerIDClient)) c0.SendMessage(hs) bf := structure.BitFieldFromHexString("\x00\x00\x00\x01") msg0 := structure.NewBitFieldMessage(bf) c0.SendMessage(msg0) m, err := ReadMessageOrTimeout(c0, ctx) ctx.So(err, ShouldBeNil) ctx.So(m.GetType(), ShouldEqual, structure.MessageTypeInterested) haveMsg := structure.NewHaveMessage(0) c0.SendMessage(haveMsg) time.Sleep(time.Millisecond) // TODO: Check why byte equality doesn't work btc := s.LookupConn(pp.AddrString()) ctx.Printf("BTC: %q\n", btc.BitField.String()) ctx.Printf("BF : %q\n", bf.String()) updatedBF := structure.BitFieldFromHexString("\x80\x00\x00\x01") ctx.Printf("UBF: %q\n", updatedBF.String()) isEqual := updatedBF.String() == btc.BitField.String() ctx.So(isEqual, ShouldBeTrue) wg.Done() }(p) } wg.Wait() _ = s.StopListening() time.Sleep(time.Millisecond) }) }
func (s *BTService) InitiateHandshakes(hash []byte, peers []structure.Peer) { for _, peer := range peers { addr := fmt.Sprintf("%q:%d", peer.IP, peer.Port) log.Printf("[InitiateHandshakes] Address: %q", addr) btc, err := s.ConnectionFetcher.Dial(addr) if err != nil { // TODO: Try more than once before giving up? continue } hs, _ := structure.NewHandshake(hash, s.PeerID) btc.Write(hs.Bytes()) btc.Hash = string(hash) btc.State = BTStateWaitingForHandshake btc.handleConnection(s) btc.HandshakeChan <- true } }
func (btc *BTConn) readLoop(addChan, leaveChan chan<- *BTConn) { for { select { case _ = <-btc.HandshakeChan: log.Printf("[readLoop] Waiting for Handshake\n") peerHs, err := handleHandshake(btc) if err != nil { log.Printf("[readLoop] Error: %q", err.Error()) btc.Close() leaveChan <- btc continue } log.Printf("[readLoop] State: %q", btc.State) switch btc.State { case BTStateWaitingForHandshake: log.Printf("[readLoop] HashMatch? %q === %q?", btc.Hash, string(peerHs.Hash)) if btc.Hash != string(peerHs.Hash) { // TODO: What if same connection is handling multiple hashes? log.Printf("[readLoop] Hash mismatch\n") btc.Close() leaveChan <- btc continue } case BTStateStartListening: log.Printf("Writing byte %q\n", btc) respHs, err := structure.NewHandshake(peerHs.Hash, []byte(btc.PeerID)) log.Println("[readLoop] respHS ", respHs) if err != nil { log.Printf("[readLoop] %q\n", err.Error()) btc.Close() leaveChan <- btc continue } btc.Write(respHs.Bytes()) default: log.Printf("[readLoop] BAD STATE: %d", btc.State) btc.Close() leaveChan <- btc continue } addChan <- btc log.Printf("AAAAAAAAAAAAAAAAAAAAAAAA: %q", btc.Addr) btc.State = BTStateReadyForMessages btc.MessageChan <- true case _ = <-btc.MessageChan: log.Printf("[readLoop] Reading from MessageChan: %q", btc) m, err := structure.ReadMessage(btc) if err != nil { log.Printf("[readLoop] Error reading message: %s", err) btc.Close() leaveChan <- btc continue } log.Printf("[readLoop] Did Read from MessageChan: %q", m) switch m.(type) { case *structure.KeepAliveMessage: log.Println("[readLoop] Received: KeepAlive MESSAGE") // TODO: reset disconnect timer break case *structure.ChokeMessage: break case *structure.UnchokeMessage: log.Println("[readLoop] Received: Unchoke MESSAGE") btc.PeerChoking = false btc.WriteChan <- structure.NewRequestMessage(0x00000bb0, 0x00024000, 0x00004000) case *structure.BitFieldMessage: log.Println("[readLoop] Received: Bit Field MESSAGE") btc.BitField = m.(*structure.BitFieldMessage).BitField btc.WriteChan <- structure.NewInterestedMessage() case *structure.HaveMessage: log.Println("[readLoop] Received: Have MESSAGE") pi := m.(*structure.HaveMessage).PieceIndex log.Printf("[readLoop] Have Message Index: %q", pi) log.Printf("BIT 0: %q", btc.BitField.Get(0)) btc.BitField.Set(uint32(pi), 1) log.Printf("BIT 0: %q", btc.BitField.Get(0)) // case *structure.PieceMessage: // log.Println("[readLoop] Received: Piece MESSAGE") default: log.Println("[readLoop] Received: OTHER MESSAGE") } log.Println("[readLoop] Received Message: ", m) btc.MessageChan <- true } } }