mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-13 07:05:12 +01:00
lots of very broken network stuff
This commit is contained in:
parent
138854cc88
commit
b714e699fb
@ -68,6 +68,11 @@ Network::Network(int sock, bool is_master)
|
||||
|
||||
/* Assume black screen */
|
||||
memset(this->screen, 0, DISPLAY_X * DISPLAY_Y);
|
||||
|
||||
/* Peer addresses */
|
||||
memset(&this->private_addr, 0, sizeof(struct sockaddr_in));
|
||||
memset(&this->public_addr, 0, sizeof(struct sockaddr_in));
|
||||
this->connection_addr = &this->public_addr;
|
||||
}
|
||||
|
||||
Network::~Network()
|
||||
@ -487,15 +492,17 @@ bool Network::ReceiveUpdate()
|
||||
bool out;
|
||||
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
out = this->ReceiveUpdate(this->ud, &tv);
|
||||
out = this->ReceiveUpdate(this->ud, NETWORK_UPDATE_SIZE, &tv);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool Network::ReceiveUpdate(NetworkUpdate *dst, struct timeval *tv)
|
||||
bool Network::ReceiveUpdate(NetworkUpdate *dst, size_t total_sz,
|
||||
struct timeval *tv)
|
||||
{
|
||||
Uint8 *pp = (Uint8*)dst;
|
||||
NetworkUpdate *p;
|
||||
size_t sz_left = total_sz;
|
||||
|
||||
if (this->Select(this->sock, tv) == false)
|
||||
return false;
|
||||
@ -503,28 +510,25 @@ bool Network::ReceiveUpdate(NetworkUpdate *dst, struct timeval *tv)
|
||||
do
|
||||
{
|
||||
p = (NetworkUpdate*)pp;
|
||||
size_t actual_sz;
|
||||
|
||||
/* Receive the header */
|
||||
if (this->ReceiveData((void*)p, this->sock, sizeof(NetworkUpdate)) == false)
|
||||
if (sz_left <= 0)
|
||||
return false;
|
||||
|
||||
/* Receive the header */
|
||||
actual_sz = this->ReceiveFrom(pp, this->sock,
|
||||
sz_left, this->connection_addr);
|
||||
if (actual_sz < 0)
|
||||
return false;
|
||||
|
||||
pp = pp + sizeof(NetworkUpdate);
|
||||
/* Drop if the magic is wrong */
|
||||
if (ntohs(p->magic) != FRODO_NETWORK_MAGIC)
|
||||
return false;
|
||||
|
||||
/* And the rest of the update */
|
||||
size_t sz = ntohl(p->size);
|
||||
if (sz > sizeof(NetworkUpdate))
|
||||
{
|
||||
size_t sz_diff = sz - sizeof(NetworkUpdate);
|
||||
|
||||
if (this->ReceiveData((void*)pp, this->sock, sz_diff) == false)
|
||||
return false;
|
||||
pp = pp + sz_diff;
|
||||
}
|
||||
if (this->DeMarshalData(p) == false)
|
||||
return false;
|
||||
sz_left -= actual_sz;
|
||||
pp = pp + actual_sz;
|
||||
} while ( !(p->type == STOP) );
|
||||
|
||||
return true;
|
||||
@ -549,7 +553,7 @@ bool Network::SendUpdate()
|
||||
sz = this->GetNetworkUpdateSize();
|
||||
if (sz <= 0)
|
||||
return false;
|
||||
if (this->SendData((void*)src, this->sock, sz) == false)
|
||||
if (this->SendTo((void*)src, this->sock, sz, this->connection_addr) < 0)
|
||||
return false;
|
||||
this->traffic += sz;
|
||||
|
||||
@ -564,6 +568,13 @@ void Network::AddNetworkUpdate(NetworkUpdate *update)
|
||||
this->cur_ud = (NetworkUpdate*)next;
|
||||
}
|
||||
|
||||
void Network::MangleIp(uint8 *ip)
|
||||
{
|
||||
ip[0] = ~ip[0];
|
||||
ip[1] = ~ip[1];
|
||||
ip[2] = ~ip[2];
|
||||
ip[3] = ~ip[3];
|
||||
}
|
||||
|
||||
bool Network::MarshalData(NetworkUpdate *p)
|
||||
{
|
||||
@ -578,6 +589,24 @@ bool Network::MarshalData(NetworkUpdate *p)
|
||||
case DISCONNECT:
|
||||
case STOP:
|
||||
break;
|
||||
case LIST_PEERS:
|
||||
{
|
||||
NetworkUpdateListPeers *lp = (NetworkUpdateListPeers *)p->data;
|
||||
for (int i = 0; i < lp->n_peers; i++)
|
||||
{
|
||||
NetworkUpdatePeerInfo *peer = &lp->peers[i];
|
||||
|
||||
peer->key = htons(peer->key);
|
||||
peer->private_port = htons(peer->private_port);
|
||||
peer->public_port = htons(peer->public_port);
|
||||
peer->is_master = htons(peer->is_master);
|
||||
this->MangleIp(peer->private_ip);
|
||||
this->MangleIp(peer->public_ip);
|
||||
}
|
||||
lp->n_peers = htonl(lp->n_peers);
|
||||
this->MangleIp(lp->your_ip);
|
||||
lp->your_port = htons(lp->your_port);
|
||||
} break;
|
||||
default:
|
||||
/* Unknown data... */
|
||||
fprintf(stderr, "Got unknown data %d while marshalling. Something is wrong\n",
|
||||
@ -630,6 +659,25 @@ bool Network::DeMarshalData(NetworkUpdate *p)
|
||||
case STOP:
|
||||
/* Nothing to do, just bytes */
|
||||
break;
|
||||
case LIST_PEERS:
|
||||
{
|
||||
NetworkUpdateListPeers *lp = (NetworkUpdateListPeers *)p->data;
|
||||
|
||||
lp->n_peers = ntohl(lp->n_peers);
|
||||
for (int i = 0; i < lp->n_peers; i++)
|
||||
{
|
||||
NetworkUpdatePeerInfo *peer = &lp->peers[i];
|
||||
|
||||
peer->key = ntohs(peer->key);
|
||||
peer->private_port = ntohs(peer->private_port);
|
||||
peer->public_port = ntohs(peer->public_port);
|
||||
peer->is_master = ntohs(peer->is_master);
|
||||
this->MangleIp(peer->private_ip);
|
||||
this->MangleIp(peer->public_ip);
|
||||
}
|
||||
this->MangleIp(lp->your_ip);
|
||||
lp->your_port = ntohs(lp->your_port);
|
||||
} break;
|
||||
default:
|
||||
/* Unknown data... */
|
||||
return false;
|
||||
@ -664,6 +712,15 @@ bool Network::DecodeUpdate(uint8 *screen, uint8 *js)
|
||||
*js = j->val;
|
||||
}
|
||||
break;
|
||||
case LIST_PEERS:
|
||||
{
|
||||
NetworkUpdateListPeers *lp = (NetworkUpdateListPeers *)p->data;
|
||||
|
||||
} break;
|
||||
case PING:
|
||||
/* Send an ack */
|
||||
break;
|
||||
case ACK: /* Should never receive this */
|
||||
case DISCONNECT:
|
||||
out = false;
|
||||
break;
|
||||
|
@ -15,10 +15,16 @@
|
||||
#define NETWORK_SOUND_BUF_SIZE 1024
|
||||
enum
|
||||
{
|
||||
STOP = 99,
|
||||
LIST_PEERS = 88,
|
||||
DISCONNECT = 77,
|
||||
PEER_INFO = 66,
|
||||
/* Connection-related messages */
|
||||
HELLO = 99, /* Hello, broker */
|
||||
LIST_PEERS = 98, /* List of peers */
|
||||
PEER_CONNECT = 97, /* A peer wants to connect */
|
||||
DISCONNECT = 96, /* Disconnect from a peer */
|
||||
PING = 95, /* (broker) are you alive? */
|
||||
ACK = 94, /* Answer to broker */
|
||||
/* Non-data messages */
|
||||
STOP = 55, /* End of this update sequence */
|
||||
/* Data transfer of various kinds */
|
||||
DISPLAY_UPDATE_RAW = 1,
|
||||
DISPLAY_UPDATE_RLE = 2,
|
||||
DISPLAY_UPDATE_DIFF= 3,
|
||||
@ -36,20 +42,57 @@ struct NetworkUpdate
|
||||
uint32 size;
|
||||
|
||||
/* The rest is just data of some type */
|
||||
Uint8 data[];
|
||||
uint8 data[];
|
||||
};
|
||||
|
||||
struct NetworkUpdateDisplay
|
||||
{
|
||||
Uint8 square;
|
||||
Uint8 data[];
|
||||
uint8 square;
|
||||
uint8 data[];
|
||||
};
|
||||
|
||||
struct NetworkUpdateJoystick
|
||||
{
|
||||
Uint8 val;
|
||||
uint8 val;
|
||||
};
|
||||
|
||||
struct NetworkUpdatePingAck
|
||||
{
|
||||
uint8 seq;
|
||||
};
|
||||
|
||||
/*
|
||||
* Sent by the third-party broker server when someone wants to connect
|
||||
* to this machine.
|
||||
*
|
||||
* See http://www.brynosaurus.com/pub/net/p2pnat/ for how the UDP hole
|
||||
* punching actually works.
|
||||
*/
|
||||
struct NetworkUpdatePeerInfo
|
||||
{
|
||||
uint16 private_port;
|
||||
uint16 public_port;
|
||||
|
||||
uint8 private_ip[4]; /* Wii isn't ipv6 capable anyway AFAIK */
|
||||
uint8 public_ip[4];
|
||||
|
||||
uint16 key; /* Random value to separate same names */
|
||||
uint16 is_master;
|
||||
uint8 name[32]; /* "SIMON", "LINDA" etc */
|
||||
};
|
||||
|
||||
struct NetworkUpdateListPeers
|
||||
{
|
||||
uint32 n_peers;
|
||||
uint8 your_ip[4];
|
||||
uint16 your_port;
|
||||
uint8 d[2]; /* Pad to 4 bytes */
|
||||
|
||||
/* Followed by the actual peers */
|
||||
NetworkUpdatePeerInfo peers[];
|
||||
};
|
||||
|
||||
|
||||
static inline NetworkUpdate *InitNetworkUpdate(NetworkUpdate *ud, uint16 type, uint32 size)
|
||||
{
|
||||
ud->magic = FRODO_NETWORK_MAGIC;
|
||||
@ -73,7 +116,7 @@ public:
|
||||
void EncodeJoystickUpdate(Uint8 v);
|
||||
|
||||
|
||||
bool DecodeUpdate(uint8 *screen, uint8 *js = NULL);
|
||||
bool DecodeUpdate(uint8 *screen, uint8 *js);
|
||||
|
||||
void ResetNetworkUpdate(void);
|
||||
|
||||
@ -195,14 +238,23 @@ protected:
|
||||
bool DecodeDisplayRaw(Uint8 *screen, struct NetworkUpdate *src,
|
||||
int x, int y);
|
||||
|
||||
bool ReceiveUpdate(NetworkUpdate *dst, struct timeval *tv);
|
||||
bool ReceiveUpdate(NetworkUpdate *dst, size_t sz, struct timeval *tv);
|
||||
|
||||
bool ReceiveData(void *dst, int sock, size_t sz);
|
||||
|
||||
/* Simple wrapper around our friend recvfrom */
|
||||
ssize_t ReceiveFrom(void *dst, int sock, size_t sz,
|
||||
struct sockaddr_in *from);
|
||||
|
||||
ssize_t SendTo(void *src, int sock, size_t sz,
|
||||
struct sockaddr_in *to);
|
||||
|
||||
bool SendData(void *src, int sock, size_t sz);
|
||||
|
||||
virtual bool Select(int sock, struct timeval *tv);
|
||||
|
||||
void MangleIp(uint8 *ip);
|
||||
|
||||
bool MarshalData(NetworkUpdate *ud);
|
||||
|
||||
bool MarshalAllData(NetworkUpdate *p);
|
||||
@ -236,6 +288,10 @@ protected:
|
||||
/* Connection to the peer */
|
||||
int sock;
|
||||
|
||||
struct sockaddr_in private_addr;
|
||||
struct sockaddr_in public_addr;
|
||||
struct sockaddr_in *connection_addr; /* Points to either of the above */
|
||||
|
||||
/* Listener-related */
|
||||
static int listen_sock;
|
||||
|
||||
|
@ -174,6 +174,22 @@ bool Network::ReceiveData(void *dst, int sock, size_t sz)
|
||||
return sz > 0;
|
||||
}
|
||||
|
||||
ssize_t Network::ReceiveFrom(void *dst, int sock, size_t sz,
|
||||
struct sockaddr_in *from)
|
||||
{
|
||||
socklen_t from_sz = from ? sizeof(struct sockaddr_in) : 0;
|
||||
|
||||
return recvfrom(sock, dst, sz, 0, (struct sockaddr*)from, &from_sz);
|
||||
}
|
||||
|
||||
ssize_t Network::SendTo(void *src, int sock, size_t sz, struct sockaddr_in *to)
|
||||
{
|
||||
socklen_t to_sz = sizeof(struct sockaddr_in);
|
||||
|
||||
assert(to);
|
||||
return sendto(sock, src, sz, 0, (struct sockaddr*)to, to_sz);
|
||||
}
|
||||
|
||||
bool Network::SendData(void *src, int sock, size_t sz)
|
||||
{
|
||||
size_t sent_sz = 0;
|
||||
|
160
Src/network-broker/main.py
Normal file
160
Src/network-broker/main.py
Normal file
@ -0,0 +1,160 @@
|
||||
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 = struct.unpack(">H", data, offset = 0)[0]
|
||||
self.public_port = 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 = struct.unpack(">H", data, offset = 12)[0]
|
||||
self.is_master = 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
|
||||
|
||||
def get_hash_key(self):
|
||||
return self.hash_key
|
||||
|
||||
def handle_packet(self, data):
|
||||
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:
|
||||
pass
|
||||
elif pkg.type == PEER_CONNECT:
|
||||
pass
|
||||
|
||||
class BrokerPacketHandler(SocketServer.DatagramRequestHandler):
|
||||
def handle(self):
|
||||
srv = self.server
|
||||
msg = self.rfile.read()
|
||||
|
||||
peer = srv.get_peer(self.client_addr)
|
||||
try:
|
||||
reply = peer.handle_packet()
|
||||
except:
|
||||
# Sends crap, let's remove it
|
||||
srv.remove_peer(peer)
|
||||
|
||||
if reply != None:
|
||||
self.wfile.write(reply)
|
||||
|
||||
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 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 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()
|
Loading…
Reference in New Issue
Block a user