Commit 5140ff6b authored by Jeromy's avatar Jeromy
Browse files

make ping its own protocol



License: MIT
Signed-off-by: default avatarJeromy <jeromyj@gmail.com>
parent cbbbda10
package ping
import (
"bytes"
"errors"
"io"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
host "github.com/ipfs/go-ipfs/p2p/host"
inet "github.com/ipfs/go-ipfs/p2p/net"
peer "github.com/ipfs/go-ipfs/p2p/peer"
eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
u "github.com/ipfs/go-ipfs/util"
)
var log = eventlog.Logger("ping")
const PingSize = 32
const ID = "/ipfs/ping"
type PingService struct {
Host host.Host
}
func NewPingService(h host.Host) *PingService {
ps := &PingService{h}
h.SetStreamHandler(ID, ps.PingHandler)
return ps
}
func (p *PingService) PingHandler(s inet.Stream) {
buf := make([]byte, PingSize)
for {
_, err := io.ReadFull(s, buf)
if err != nil {
log.Debug(err)
return
}
_, err = s.Write(buf)
if err != nil {
log.Debug(err)
return
}
}
}
func (ps *PingService) Ping(ctx context.Context, p peer.ID) (<-chan time.Duration, error) {
s, err := ps.Host.NewStream(ID, p)
if err != nil {
return nil, err
}
out := make(chan time.Duration)
go func() {
defer close(out)
for {
select {
case <-ctx.Done():
return
default:
t, err := ping(s)
if err != nil {
log.Debugf("ping error: %s", err)
return
}
select {
case out <- t:
case <-ctx.Done():
return
}
}
}
}()
return out, nil
}
func ping(s inet.Stream) (time.Duration, error) {
buf := make([]byte, PingSize)
u.NewTimeSeededRand().Read(buf)
before := time.Now()
_, err := s.Write(buf)
if err != nil {
return 0, err
}
rbuf := make([]byte, PingSize)
_, err = io.ReadFull(s, rbuf)
if err != nil {
return 0, err
}
if !bytes.Equal(buf, rbuf) {
return 0, errors.New("ping packet was incorrect!")
}
return time.Now().Sub(before), nil
}
package ping
import (
"testing"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
peer "github.com/ipfs/go-ipfs/p2p/peer"
netutil "github.com/ipfs/go-ipfs/p2p/test/util"
)
func TestPing(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
h1 := netutil.GenHostSwarm(t, ctx)
h2 := netutil.GenHostSwarm(t, ctx)
err := h1.Connect(ctx, peer.PeerInfo{
ID: h2.ID(),
Addrs: h2.Addrs(),
})
if err != nil {
t.Fatal(err)
}
ps1 := NewPingService(h1)
ps2 := NewPingService(h2)
testPing(t, ps1, h2.ID())
testPing(t, ps2, h1.ID())
}
func testPing(t *testing.T, ps *PingService, p peer.ID) {
pctx, cancel := context.WithCancel(context.Background())
defer cancel()
ts, err := ps.Ping(pctx, p)
if err != nil {
t.Fatal(err)
}
for i := 0; i < 5; i++ {
select {
case took := <-ts:
t.Log("ping took: ", took)
case <-time.After(time.Second * 4):
t.Fatal("failed to receive ping")
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment