Created
April 16, 2016 19:10
-
-
Save Ell/b666a989928c6b6292eb35fd2dc7f564 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 ( | |
"bytes" | |
"encoding/binary" | |
"errors" | |
log "github.com/Sirupsen/logrus" | |
"net" | |
) | |
type server struct { | |
conn *net.UDPConn | |
} | |
type packet struct { | |
address *net.UDPAddr | |
buf []byte | |
} | |
type recvConnect struct { | |
ConnectionID int64 | |
Action int32 | |
TransactionID int32 | |
} | |
type replyConnect struct { | |
Action int32 | |
TransactionID int32 | |
ConnectionID int64 | |
} | |
type recvAnnounce struct { | |
ConnectionID int64 | |
Action int32 | |
TransactionID int32 | |
InfoHash [20]byte | |
PeerID [20]byte | |
Downloaded int64 | |
Left int64 | |
Uploaded int64 | |
Event int32 | |
IP uint32 | |
Key uint32 | |
NumWant int32 | |
Port uint16 | |
Extensions uint16 | |
} | |
type replyAnnounce struct { | |
Action int32 | |
TransactionID int32 | |
Interval int32 | |
Leechers int32 | |
Seeders int32 | |
} | |
type peer struct { | |
IP int32 | |
Port uint16 | |
} | |
type recvScrape struct { | |
ConnectionID int64 | |
Action int32 | |
TransactionID int32 | |
InfoHashes [][20]byte | |
} | |
type replyScrape struct { | |
Action int32 | |
TransactionID int32 | |
InfoHashes []infoHash | |
} | |
type infoHash struct { | |
Complete int32 | |
Downloaded int32 | |
Incomplete int32 | |
} | |
type trackerError struct { | |
Action int32 | |
TransactionID int32 | |
ErrorString []byte | |
} | |
// StartServer starts a new UDP tracker instance | |
func StartServer(config *Config) error { | |
log.SetFormatter(&log.JSONFormatter{}) | |
serverAddress, err := net.ResolveUDPAddr("udp4", config.Server.ListenAddress) | |
if err != nil { | |
return err | |
} | |
conn, err := net.ListenUDP("udp", serverAddress) | |
if err != nil { | |
return err | |
} | |
log.Infof("Starting server and listening on %s", serverAddress.String()) | |
s := server{ | |
conn: conn, | |
} | |
for { | |
var buf []byte | |
size, addr, err := conn.ReadFromUDP(buf) | |
if err != nil { | |
log.Error(err) | |
continue | |
} | |
if size <= 0 { | |
continue | |
} | |
p := packet{ | |
address: addr, | |
buf: buf, | |
} | |
if err != nil { | |
go s.handleErrorResponse(p, err) | |
} else { | |
go s.packetHandler(p) | |
} | |
} | |
} | |
func (s *server) packetHandler(p packet) { | |
header := struct { | |
ConnectionID int64 | |
Action int32 | |
TransactionID int32 | |
}{} | |
b := bytes.NewBuffer(p.buf) | |
err := binary.Read(b, binary.BigEndian, &header) | |
if err != nil { | |
s.handleErrorResponse(p, err) | |
return | |
} | |
switch header.Action { | |
case 0: | |
go s.handleConnectRequest(p) | |
case 1: | |
go s.handleAnnounceRequest(p) | |
case 2: | |
go s.handleScrapeRequest(p) | |
default: | |
go s.handleErrorResponse(p, errors.New("Unhandled action type: "+string(header.Action))) | |
} | |
} | |
func (s *server) handleConnectRequest(p packet) { | |
logRequestInfo(p, "Got connect request") | |
} | |
func (s *server) handleAnnounceRequest(p packet) { | |
logRequestInfo(p, "Got announce request") | |
} | |
func (s *server) handleScrapeRequest(p packet) { | |
logRequestInfo(p, "Got scrape request") | |
} | |
func (s *server) handleErrorResponse(p packet, err error) { | |
log.WithFields(log.Fields{ | |
"address": p.address.String(), | |
"error": err.Error(), | |
"body": p.buf, | |
}).Error(err.Error()) | |
} | |
func logRequestInfo(p packet, desc string) { | |
log.WithFields(log.Fields{ | |
"address": p.address.String(), | |
"body": p.buf, | |
}).Info(desc) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment