// The first thing to do after a connection is established is to exchange version. // For kaiju it goes as follows: // 1. Send out my version message, if outgoing == true // 2. Expect the remote peer send it's version message // 3. Once the message from remote peer is received, send verack // 4. Send out my version message, if outgoing == false // 5. Done, knet.Peer starts to work func (p *Peer) versionHankshake() error { // Step 1 if p.outgoing { err := p.sendVersionMsg() if err != nil { return err } } // Step 2 msg, err := btcmsg.ReadMsg(p.conn) if err != nil { return err } else { if ver, ok := msg.(*btcmsg.Message_version); ok { // TODO: more check p.info = ver.Addr_from } else { return errors.New("Wrong message type when doing versionHankshake") } } // Step 3 vamsg := btcmsg.NewVerAckMsg() err = btcmsg.WriteMsg(p.conn, vamsg) if err != nil { return err } // Step 4 if !p.outgoing { err := p.sendVersionMsg() if err != nil { return err } } return nil }
func (p *Peer) loopMain() { // This "running" is used to fix a bug about "break", // so if you break in "select", you cannot get out of "for". running := true for running { select { case m := <-p.sendChan: ch := make(chan error, 1) go func() { ch <- btcmsg.WriteMsg(p.conn, m.msg) }() select { case err := <-ch: if m.errChan != nil { m.errChan <- err } if err != nil { running = false } case <-time.After(m.timeout): if m.errChan != nil { m.errChan <- errors.New("Peer send message timeout.") } if m.timeout >= defaultSendMsgTimeout { running = false } case <-p.done: running = false } case <-p.keepAliveTimer.C: ping := btcmsg.NewPingMsg().(*btcmsg.Message_ping) ping.Nonce = uint64(p.handle) p.sendMsg(ping, 0, nil) case <-p.kickTimer.C: p.kick() case <-p.done: running = false } } p.cleanUp() }
func (p *Peer) sendVersionMsg() error { vmsg := btcmsg.NewLocalVersionMsg(p.info) return btcmsg.WriteMsg(p.conn, vmsg) }