Skip to content

Instantly share code, notes, and snippets.

@anacrolix
Created June 29, 2020 04:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anacrolix/06ba77f570c7f3f315b0ad1afcc1ecdc to your computer and use it in GitHub Desktop.
Save anacrolix/06ba77f570c7f3f315b0ad1afcc1ecdc to your computer and use it in GitHub Desktop.
use "net"
use "logger"
use "time"
actor Main
new create(env: Env) =>
let auth =
try
env.root as AmbientAuth
else
env.exitcode(1)
env.err.print("bad root auth")
return
end
RunServer(auth, env)
actor RunServer
let _auth: AmbientAuth
let _env: Env
var _server: (DhtServer|None) = None
new create(auth: AmbientAuth, env: Env) =>
_auth = auth
_env = env
UDPSocket(_auth, recover MyNotify(env, this, auth) end where service = "42069")
be socket_ready(sock: UDPSocket) =>
dispose_server()
_server = DhtServer(
sock,
DNSAuth(_auth),
StringLogger(Fine, _env.out))
.>bootstrap()
fun dispose_server() =>
try
(_server as DhtServer).dispose()
end
be socket_closed() =>
dispose_server()
primitive StringifyNetAddress
fun apply(na: NetAddress, reversedns: (DNSLookupAuth | None) = None): String =>
(let host, let service) =
try
na.name(where reversedns=reversedns)?
else
return "unknown"
end
host + ":" + service + "(" + _if(na.ip4(), "4") + _if(na.ip6(), "6") + ")"
fun _if(b: Bool, c: String): String =>
if b then c else "" end
class MyNotify
let _env: Env
let _notify: RunServer
let _auth: (DNSLookupAuth|None)
new create(env: Env, notify: RunServer, auth: (DNSLookupAuth|None)) =>
_env = env
_notify = notify
_auth = auth
fun listening(sock: UDPSocket ref) =>
_env.out.print("listening at "+StringifyNetAddress(sock.local_address()))
_notify.socket_ready(sock)
fun received(_: UDPSocket, data: Array[U8 val] iso, from: NetAddress val) =>
_env.out.print("got reply from " + StringifyNetAddress(from) + ": " + String.from_array(consume data))
fun not_listening(_: UDPSocket) =>
_env.err.print("not listening")
fun closed(_: UDPSocket) =>
_env.err.print("socket closed")
_notify.socket_closed()
primitive GlobalBootstrapAddrs
fun apply(): Array[(String, String)] val =>
[
("router.utorrent.com", "6881")
("router.bittorrent.com", "6881")
("dht.transmissionbt.com", "6881")
("dht.aelitis.com", "6881") // Vuze
("router.silotis.us", "6881") // IPv6
("dht.libtorrent.org", "25401")
]
actor DhtServer
let _socket: UDPSocket
let _auth: DNSLookupAuth
let _logger: Logger[String]
let _timers: Timers = Timers
var outstanding: USize = 0
new create(socket: UDPSocket, auth: DNSLookupAuth, logger: Logger[String]) =>
_socket = socket
_auth = auth
_logger = logger
be bootstrap(addrs: Array[(String,String)] val = GlobalBootstrapAddrs()) =>
for (host, service) in addrs.values() do
for na in DNS(_auth, host, service).values() do
ping(na)
end
end
be dispose() =>
_timers.dispose()
_socket.dispose()
be completed_transaction() =>
outstanding = outstanding - 1
_logger(Fine) and _logger.log(outstanding.string())
if outstanding == 0 then
dispose()
end
be ping(na: NetAddress) =>
_logger(Fine) and _logger.log("pinging: " + StringifyNetAddress(na))
_socket.write("d1:ad2:id20:55ca6286e3e4f4fba5d0e1:q4:ping1:t3:xxx1:y1:qe", na)
outstanding = outstanding + 1
let server = recover this end
_timers(Timer(
object iso is TimerNotify
fun apply(_: Timer, _: U64): Bool =>
server.completed_transaction()
false
end,
Nanos.from_seconds(2)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment