frodo-wii/Src/network-broker/main.py

202 lines
5.6 KiB
Python
Raw Normal View History

2009-02-07 12:08:50 +01:00
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])
2009-02-07 12:08:50 +01:00
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])
2009-02-07 12:08:50 +01:00
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
2009-02-07 12:08:50 +01:00
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):
2009-02-07 12:08:50 +01:00
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
2009-02-07 12:08:50 +01:00
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
2009-02-07 12:08:50 +01:00
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()
2009-02-07 12:08:50 +01:00
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)
2009-02-07 12:08:50 +01:00
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
2009-02-07 12:08:50 +01:00
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()