Files
serverlist/server_list/ping.py
ShadowNinja ae96c3a244 Remove periodic ping
Servers are already re-pinged on update.
2023-10-16 21:45:27 -04:00

99 lines
2.3 KiB
Python

import time
import socket
from .app import app
from .util import get_addr_info
# Initial packet of type ORIGINAL, with no data.
# This should prompt the server to assign us a peer id.
# [0] u32 protocol_id (PROTOCOL_ID)
# [4] session_t sender_peer_id (PEER_ID_INEXISTENT)
# [6] u8 channel
# [7] u8 type (PACKET_TYPE_ORIGINAL)
PING_PACKET = b"\x4f\x45\x74\x03\x00\x00\x00\x01"
def get_ping_reply(data):
# [0] u32 protocol_id (PROTOCOL_ID)
# [4] session_t sender_peer_id
# [6] u8 channel
# [7] u8 type (PACKET_TYPE_RELIABLE)
# [8] u16 sequence number
# [10] u8 type (PACKET_TYPE_CONTROL)
# [11] u8 controltype (CONTROLTYPE_SET_PEER_ID)
# [12] session_t peer_id_new
peer_id = data[12:14]
# Send packet of type CONTROL, subtype DISCO,
# to cleanly close our server connection.
# [0] u32 protocol_id (PROTOCOL_ID)
# [4] session_t sender_peer_id
# [6] u8 channel
# [7] u8 type (PACKET_TYPE_CONTROL)
# [8] u8 controltype (CONTROLTYPE_DISCO)
return b"\x4f\x45\x74\x03" + peer_id + b"\x00\x00\x03"
def ping_server_addresses(address, port):
pings = []
addr_info = get_addr_info(address, port)
for record in addr_info:
ping = server_up(record)
if not ping:
app.logger.warning("Could not connect to %s:%d using resolved info %r.",
address, port, record)
return None
pings.append(ping)
return pings
def ping_server(sock):
sock.send(PING_PACKET)
# Receive reliable packet of type CONTROL, subtype SET_PEER_ID,
# with our assigned peer id as data.
start = time.time()
data = sock.recv(1024)
end = time.time()
if not data:
return None
sock.send(get_ping_reply(data))
return end - start
# Returns ping time in seconds (up) or None (down).
def server_up(info):
"""Pings a Minetest server to check if it is online.
"""
try:
sock = socket.socket(info[0], info[1], info[2])
sock.settimeout(2)
sock.connect(info[4])
except OSError:
return None
attempts = 0
pings = []
while len(pings) < 3 and attempts - len(pings) < 3:
attempts += 1
try:
ping = ping_server(sock)
if ping is not None:
pings.append(ping)
except socket.timeout:
pass
except ConnectionRefusedError:
return None
except OSError:
return None
sock.close()
if len(pings) != 0:
return min(pings)
return None