This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
152 lines (122 sloc)
3.97 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "io/ioutil" | |
| "log" | |
| "github.com/libp2p/go-libp2p-core/host" | |
| "github.com/libp2p/go-libp2p-core/network" | |
| proto "github.com/gogo/protobuf/proto" | |
| uuid "github.com/google/uuid" | |
| p2p "github.com/libp2p/go-libp2p-examples/multipro/pb" | |
| ) | |
| // pattern: /protocol-name/request-or-response-message/version | |
| const pingRequest = "/ping/pingreq/0.0.1" | |
| const pingResponse = "/ping/pingresp/0.0.1" | |
| // PingProtocol type | |
| type PingProtocol struct { | |
| node *Node // local host | |
| requests map[string]*p2p.PingRequest // used to access request data from response handlers | |
| done chan bool // only for demo purposes to stop main from terminating | |
| } | |
| func NewPingProtocol(node *Node, done chan bool) *PingProtocol { | |
| p := &PingProtocol{node: node, requests: make(map[string]*p2p.PingRequest), done: done} | |
| node.SetStreamHandler(pingRequest, p.onPingRequest) | |
| node.SetStreamHandler(pingResponse, p.onPingResponse) | |
| return p | |
| } | |
| // remote peer requests handler | |
| func (p *PingProtocol) onPingRequest(s network.Stream) { | |
| // get request data | |
| data := &p2p.PingRequest{} | |
| buf, err := ioutil.ReadAll(s) | |
| if err != nil { | |
| s.Reset() | |
| log.Println(err) | |
| return | |
| } | |
| s.Close() | |
| // unmarshal it | |
| proto.Unmarshal(buf, data) | |
| if err != nil { | |
| log.Println(err) | |
| return | |
| } | |
| log.Printf("%s: Received ping request from %s. Message: %s", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.Message) | |
| valid := p.node.authenticateMessage(data, data.MessageData) | |
| if !valid { | |
| log.Println("Failed to authenticate message") | |
| return | |
| } | |
| // generate response message | |
| log.Printf("%s: Sending ping response to %s. Message id: %s...", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id) | |
| resp := &p2p.PingResponse{MessageData: p.node.NewMessageData(data.MessageData.Id, false), | |
| Message: fmt.Sprintf("Ping response from %s", p.node.ID())} | |
| // sign the data | |
| signature, err := p.node.signProtoMessage(resp) | |
| if err != nil { | |
| log.Println("failed to sign response") | |
| return | |
| } | |
| // add the signature to the message | |
| resp.MessageData.Sign = signature | |
| // send the response | |
| ok := p.node.sendProtoMessage(s.Conn().RemotePeer(), pingResponse, resp) | |
| if ok { | |
| log.Printf("%s: Ping response to %s sent.", s.Conn().LocalPeer().String(), s.Conn().RemotePeer().String()) | |
| } | |
| } | |
| // remote ping response handler | |
| func (p *PingProtocol) onPingResponse(s network.Stream) { | |
| data := &p2p.PingResponse{} | |
| buf, err := ioutil.ReadAll(s) | |
| if err != nil { | |
| s.Reset() | |
| log.Println(err) | |
| return | |
| } | |
| s.Close() | |
| // unmarshal it | |
| proto.Unmarshal(buf, data) | |
| if err != nil { | |
| log.Println(err) | |
| return | |
| } | |
| valid := p.node.authenticateMessage(data, data.MessageData) | |
| if !valid { | |
| log.Println("Failed to authenticate message") | |
| return | |
| } | |
| // locate request data and remove it if found | |
| _, ok := p.requests[data.MessageData.Id] | |
| if ok { | |
| // remove request from map as we have processed it here | |
| delete(p.requests, data.MessageData.Id) | |
| } else { | |
| log.Println("Failed to locate request data boject for response") | |
| return | |
| } | |
| log.Printf("%s: Received ping response from %s. Message id:%s. Message: %s.", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id, data.Message) | |
| p.done <- true | |
| } | |
| func (p *PingProtocol) Ping(host host.Host) bool { | |
| log.Printf("%s: Sending ping to: %s....", p.node.ID(), host.ID()) | |
| // create message data | |
| req := &p2p.PingRequest{MessageData: p.node.NewMessageData(uuid.New().String(), false), | |
| Message: fmt.Sprintf("Ping from %s", p.node.ID())} | |
| // sign the data | |
| signature, err := p.node.signProtoMessage(req) | |
| if err != nil { | |
| log.Println("failed to sign pb data") | |
| return false | |
| } | |
| // add the signature to the message | |
| req.MessageData.Sign = signature | |
| ok := p.node.sendProtoMessage(host.ID(), pingRequest, req) | |
| if !ok { | |
| return false | |
| } | |
| // store ref request so response handler has access to it | |
| p.requests[req.MessageData.Id] = req | |
| log.Printf("%s: Ping to: %s was sent. Message Id: %s, Message: %s", p.node.ID(), host.ID(), req.MessageData.Id, req.Message) | |
| return true | |
| } |