udp: Implement initial connection protocol

This commit is contained in:
Justin Li 2015-02-20 01:12:47 -05:00
parent 778b64defa
commit c2770ee741
7 changed files with 142 additions and 4 deletions

View file

@ -80,11 +80,13 @@ The available keys and their default values are as follows:
- `respect_af: false` if responses should only include peers of the same address family as the announcing peer
- `client_whitelist_enabled: false` if peer IDs should be matched against the whitelist
- `client_whitelist: []` list of peer ID prefixes to allow
- `http_listen_addr: ":6881"` listen address for the HTTP server
- `http_listen_addr: ""` listen address for the HTTP server
- `http_request_timeout: "10s"`
- `http_read_timeout: "10s"`
- `http_write_timeout: "10s"`
- `http_listen_limit: 0`
- `udp_listen_addr: ""` listen address for the UDP server
- `udp_read_buffer_size: undefined` size of the UDP socket's kernel read buffer
- `driver: "noop"`
- `stats_buffer_size: 0`
- `include_mem_stats: true`

BIN
chihaya Executable file

Binary file not shown.

View file

@ -9,6 +9,7 @@ import (
"os"
"runtime"
"runtime/pprof"
"sync"
"github.com/golang/glog"
@ -16,6 +17,7 @@ import (
"github.com/chihaya/chihaya/http"
"github.com/chihaya/chihaya/stats"
"github.com/chihaya/chihaya/tracker"
"github.com/chihaya/chihaya/udp"
// See the README for how to import custom drivers.
_ "github.com/chihaya/chihaya/backend/noop"
@ -77,7 +79,25 @@ func Boot() {
glog.Fatal("New: ", err)
}
http.Serve(cfg, tkr)
var wg sync.WaitGroup
if cfg.HTTPListenAddr != "" {
wg.Add(1)
go func() {
defer wg.Done()
http.Serve(cfg, tkr)
}()
}
if cfg.UDPListenAddr != "" {
wg.Add(1)
go func() {
defer wg.Done()
udp.Serve(cfg, tkr)
}()
}
wg.Wait()
if err := tkr.Close(); err != nil {
glog.Errorf("Failed to shut down tracker cleanly: %s", err.Error())

View file

@ -134,14 +134,14 @@ var DefaultConfig = Config{
},
HTTPConfig: HTTPConfig{
HTTPListenAddr: ":6881",
HTTPListenAddr: "",
HTTPRequestTimeout: Duration{10 * time.Second},
HTTPReadTimeout: Duration{10 * time.Second},
HTTPWriteTimeout: Duration{10 * time.Second},
},
UDPConfig: UDPConfig{
UDPListenAddr: ":6881",
UDPListenAddr: "",
},
DriverConfig: DriverConfig{

View file

@ -12,6 +12,7 @@
"respect_af": false,
"client_whitelist_enabled": false,
"client_whitelist": ["OP1011"],
"udp_listen_addr": ":6881",
"http_listen_addr": ":6881",
"http_request_timeout": "10s",
"http_read_timeout": "10s",

45
udp/protocol.go Normal file
View file

@ -0,0 +1,45 @@
// Copyright 2015 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.
package udp
import (
"bytes"
"encoding/binary"
"net"
)
var initialConnectionID = []byte{0x04, 0x17, 0x27, 0x10, 0x19, 0x80}
func (srv *Server) handlePacket(packet []byte, addr *net.UDPAddr) (response []byte) {
if len(packet) < 16 {
return nil // Malformed, no client packets are less than 16 bytes.
}
connID := packet[0:8]
action := binary.BigEndian.Uint32(packet[8:12])
transactionID := packet[12:16]
generatedConnID := GenerateConnectionID(addr.IP)
switch action {
case 0:
// Connect request.
if !bytes.Equal(connID, initialConnectionID) {
return nil // Malformed packet.
}
response = make([]byte, 16)
writeHeader(response, action, transactionID)
copy(response[8:], generatedConnID)
case 1:
// Announce request.
}
return
}
func writeHeader(response []byte, action uint32, transactionID []byte) {
binary.BigEndian.PutUint32(response, action)
copy(response[4:], transactionID)
}

70
udp/udp.go Normal file
View file

@ -0,0 +1,70 @@
// Copyright 2015 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.
// Package udp implements a UDP BitTorrent tracker per BEP 15 and BEP 41.
// IPv6 is currently unsupported as there is no widely-implemented standard.
package udp
import (
"net"
"github.com/golang/glog"
"github.com/pushrax/bufferpool"
"github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/tracker"
)
// Server represents a UDP torrent tracker.
type Server struct {
config *config.Config
tracker *tracker.Tracker
}
func (srv *Server) ListenAndServe() error {
listenAddr, err := net.ResolveUDPAddr("udp", srv.config.UDPListenAddr)
if err != nil {
return err
}
sock, err := net.ListenUDP("udp", listenAddr)
defer sock.Close()
if err != nil {
return err
}
if srv.config.UDPReadBufferSize > 0 {
sock.SetReadBuffer(srv.config.UDPReadBufferSize)
}
pool := bufferpool.New(1000, 2048)
for {
buffer := pool.TakeSlice()
n, addr, err := sock.ReadFromUDP(buffer)
if err != nil {
return err
}
go func() {
response := srv.handlePacket(buffer[:n], addr)
if response != nil {
sock.WriteToUDP(response, addr)
}
pool.GiveSlice(buffer)
}()
}
}
func Serve(cfg *config.Config, tkr *tracker.Tracker) {
srv := &Server{
config: cfg,
tracker: tkr,
}
glog.V(0).Info("Starting UDP on ", cfg.UDPListenAddr)
if err := srv.ListenAndServe(); err != nil {
glog.Errorf("Failed to run UDP server: %s", err.Error())
}
}