mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-26 13:34:22 +01:00
ef79dac020
isn't really finished yet. Well, well. We'll see about that :-)
202 lines
5.6 KiB
Python
202 lines
5.6 KiB
Python
import socket
|
|
import SocketServer
|
|
import struct
|
|
|
|
FRODO_NETWORK_MAGIC = 0x1976
|
|
|
|
HELLO = 99
|
|
LIST_PEERS = 98
|
|
PEER_CONNECT = 97
|
|
DISCONNECT = 96
|
|
PING = 95
|
|
ACK = 94
|
|
STOP = 55
|
|
|
|
# Some of the Frodo network packets. There are more packets, but these
|
|
# are not interesting to the broker (and shouldn't be sent there either!)
|
|
packet_class_by_type = {
|
|
HELLO : HelloPacket,
|
|
LIST_PEERS : ListPeersPacket,
|
|
PEER_CONNECT : ListPeersPacket,
|
|
DISCONNECT : DisconnectPacket,
|
|
|
|
PING : PingPacket,
|
|
ACK : PingPacket, # Ping and ack are the same
|
|
|
|
STOP : StopPacket,
|
|
}
|
|
|
|
class Packet:
|
|
def __init__(self, data):
|
|
"""Create a new packet from raw data. Data should always be in network
|
|
byte order"""
|
|
self.magic = struct.unpack(">H", data, offset = 0)[0]
|
|
self.type = struct.unpack(">H", data, offset = 2)[0]
|
|
self.size = struct.unpack(">L", data, offset = 4)[0]
|
|
|
|
def __init__(self, magic, type, size):
|
|
"""Create a new packet"""
|
|
self.magic = magic
|
|
self.type = type
|
|
self.size = size
|
|
|
|
def get_magic(self):
|
|
return self.magic
|
|
|
|
def get_type(self):
|
|
return self.type
|
|
|
|
def get_size(self):
|
|
return self.size
|
|
|
|
def marshal(self):
|
|
return struct.pack(">HHL", self.magic, self.type, self.size)
|
|
|
|
class PingPacket(Packet):
|
|
def __init__(self, seq):
|
|
Packet.__init__(self, FRODO_NETWORK_MAGIC, TYPE_PING, 9)
|
|
self.seq = seq
|
|
|
|
def get_seq(self):
|
|
return self.seq
|
|
|
|
def marshal(self):
|
|
return Packet.marshal(self) + struct.pack(">B", self.seq)
|
|
|
|
class PeerInfo:
|
|
def __init__(self, data):
|
|
self.private_port = int(struct.unpack(">H", data, offset = 0)[0])
|
|
self.public_port = int(struct.unpack(">H", data, offset = 2)[0])
|
|
self.private_ip = self.mangle_ip(struct.unpack(">BBBB", data, offset = 4))
|
|
self.public_ip = self.mangle_ip(struct.unpack(">BBBB", data, offset = 8))
|
|
self.key = int(struct.unpack(">H", data, offset = 12)[0])
|
|
self.is_master = int(struct.unpack(">H", data, offset = 16)[0])
|
|
self.name = struct.unpack("32s", data, offset = 20)
|
|
self.name[31] = 0
|
|
|
|
def set_public_address(ip, port):
|
|
self.public_ip = ip
|
|
self.public_port = port
|
|
|
|
def mangle_ip(self, ip):
|
|
ip[0] = ~int(ip[0])
|
|
ip[1] = ~int(ip[1])
|
|
ip[2] = ~int(ip[2])
|
|
ip[3] = ~int(ip[3])
|
|
|
|
def marshal(self):
|
|
priv_ip = self.mangle_ip(self.private_ip)
|
|
pub_ip = self.mangle_ip(self.public_ip)
|
|
return struct.pack(">HH4B4BHH32s",
|
|
self.private_port, self.public_port, priv_ip, pub_ip,
|
|
self.key, self.is_master, self.name)
|
|
|
|
class HelloPacket(Packet):
|
|
def __init__(self, data):
|
|
Packet.__init__(self, data)
|
|
|
|
self.peer_info = PeerInfo(data[8:])
|
|
|
|
def marshal(self):
|
|
return Packet.marshal(self) + self.peer_info.marshal()
|
|
|
|
class Peer:
|
|
def __init__(self, key, srv):
|
|
self.hash_key = key
|
|
self.srv = srv
|
|
|
|
self.private_ip = [0,0,0,0]
|
|
self.public_ip = [0,0,0,0]
|
|
self.private_port = 0
|
|
self.public_port = 0
|
|
|
|
self.name = ""
|
|
self.key = 0
|
|
|
|
self.initialized = False
|
|
|
|
def get_hash_key(self):
|
|
return self.hash_key
|
|
|
|
def get_key(self):
|
|
return self.key
|
|
|
|
def get_name(self):
|
|
return self.name
|
|
|
|
def send_data(self, data):
|
|
self.srv.send_data( self.get_hash_key(), data)
|
|
|
|
def handle_packet(self, data, addr):
|
|
raw = Packet(data)
|
|
pkg_cls = packet_class_by_type[raw.get_type()]
|
|
pkg = pkg_cls(data)
|
|
|
|
if pkg.type == ACK:
|
|
pass
|
|
elif pkg.type == HELLO:
|
|
# take the public ID from the source of this message
|
|
ip = socket.gethostbyname(addr[0]).split('.')
|
|
port = addr[1]
|
|
ip = [int(ip[0]), int(ip[1]), int(ip[2]), int(ip[3])]
|
|
|
|
self.private_ip = pkg.private_ip
|
|
self.private_port = pkg.private_port
|
|
self.public_ip = ip
|
|
self.public_port = port
|
|
|
|
self.key = pkg.key
|
|
self.name = pkg.name
|
|
|
|
self.initialized = True
|
|
elif pkg.type == PEER_CONNECT:
|
|
other = src.get_peer_by_name_key(pkg.name, pkg.key)
|
|
other.send_data( self.marshal() )
|
|
self.send_data( other.marshal() )
|
|
return None
|
|
|
|
class BrokerPacketHandler(SocketServer.DatagramRequestHandler):
|
|
def handle(self):
|
|
srv = self.server
|
|
msg = self.rfile.read()
|
|
|
|
peer = srv.get_peer(self.client_addr)
|
|
try:
|
|
peer.handle_packet()
|
|
except:
|
|
# Sends crap, let's remove it
|
|
srv.remove_peer(peer)
|
|
|
|
class Broker(SocketServer.UDPServer):
|
|
|
|
def __init__(self, host, req_handler):
|
|
SocketServer.UDPServer.__init__(self, host, req_handler)
|
|
# Instead of setsockopt( ... REUSEADDR ... )
|
|
self.allow_reuse_address = True
|
|
self.peers = {}
|
|
|
|
def send_data(self, dst, data):
|
|
self.socket.sendto(data, dst)
|
|
|
|
def get_peer(self, key):
|
|
"Return the peer for a certain key, or a new one if it doesn't exist"
|
|
try:
|
|
peer = self.peers[key]
|
|
except KeyError, e:
|
|
peer = Peer(key, self)
|
|
return peer
|
|
|
|
def get_peer_by_name_key(self, name, key):
|
|
for k,v in self.peers.iteritems():
|
|
if name == v.get_name() and key == v.get_key():
|
|
return v
|
|
return None
|
|
|
|
def remove_peer(self, peer):
|
|
del self.peers[ peer.get_hash_key() ]
|
|
|
|
if __name__ == "__main__":
|
|
print "Starting Frodo network broker"
|
|
s = Broker( ("localhost", 46214), BrokerPacketHandler)
|
|
s.serve_forever()
|