lots of very broken network stuff

This commit is contained in:
simon.kagstrom 2009-02-07 11:08:50 +00:00
parent 138854cc88
commit b714e699fb
4 changed files with 315 additions and 26 deletions

View File

@ -68,6 +68,11 @@ Network::Network(int sock, bool is_master)
/* Assume black screen */ /* Assume black screen */
memset(this->screen, 0, DISPLAY_X * DISPLAY_Y); 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() Network::~Network()
@ -487,15 +492,17 @@ bool Network::ReceiveUpdate()
bool out; bool out;
memset(&tv, 0, sizeof(tv)); memset(&tv, 0, sizeof(tv));
out = this->ReceiveUpdate(this->ud, &tv); out = this->ReceiveUpdate(this->ud, NETWORK_UPDATE_SIZE, &tv);
return out; 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; Uint8 *pp = (Uint8*)dst;
NetworkUpdate *p; NetworkUpdate *p;
size_t sz_left = total_sz;
if (this->Select(this->sock, tv) == false) if (this->Select(this->sock, tv) == false)
return false; return false;
@ -503,28 +510,25 @@ bool Network::ReceiveUpdate(NetworkUpdate *dst, struct timeval *tv)
do do
{ {
p = (NetworkUpdate*)pp; p = (NetworkUpdate*)pp;
size_t actual_sz;
/* Receive the header */ if (sz_left <= 0)
if (this->ReceiveData((void*)p, this->sock, sizeof(NetworkUpdate)) == false) return false;
/* Receive the header */
actual_sz = this->ReceiveFrom(pp, this->sock,
sz_left, this->connection_addr);
if (actual_sz < 0)
return false; return false;
pp = pp + sizeof(NetworkUpdate);
/* Drop if the magic is wrong */ /* Drop if the magic is wrong */
if (ntohs(p->magic) != FRODO_NETWORK_MAGIC) if (ntohs(p->magic) != FRODO_NETWORK_MAGIC)
return false; 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) if (this->DeMarshalData(p) == false)
return false; return false;
sz_left -= actual_sz;
pp = pp + actual_sz;
} while ( !(p->type == STOP) ); } while ( !(p->type == STOP) );
return true; return true;
@ -549,7 +553,7 @@ bool Network::SendUpdate()
sz = this->GetNetworkUpdateSize(); sz = this->GetNetworkUpdateSize();
if (sz <= 0) if (sz <= 0)
return false; 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; return false;
this->traffic += sz; this->traffic += sz;
@ -564,6 +568,13 @@ void Network::AddNetworkUpdate(NetworkUpdate *update)
this->cur_ud = (NetworkUpdate*)next; 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) bool Network::MarshalData(NetworkUpdate *p)
{ {
@ -578,6 +589,24 @@ bool Network::MarshalData(NetworkUpdate *p)
case DISCONNECT: case DISCONNECT:
case STOP: case STOP:
break; 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: default:
/* Unknown data... */ /* Unknown data... */
fprintf(stderr, "Got unknown data %d while marshalling. Something is wrong\n", fprintf(stderr, "Got unknown data %d while marshalling. Something is wrong\n",
@ -630,6 +659,25 @@ bool Network::DeMarshalData(NetworkUpdate *p)
case STOP: case STOP:
/* Nothing to do, just bytes */ /* Nothing to do, just bytes */
break; 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: default:
/* Unknown data... */ /* Unknown data... */
return false; return false;
@ -664,6 +712,15 @@ bool Network::DecodeUpdate(uint8 *screen, uint8 *js)
*js = j->val; *js = j->val;
} }
break; break;
case LIST_PEERS:
{
NetworkUpdateListPeers *lp = (NetworkUpdateListPeers *)p->data;
} break;
case PING:
/* Send an ack */
break;
case ACK: /* Should never receive this */
case DISCONNECT: case DISCONNECT:
out = false; out = false;
break; break;

View File

@ -15,10 +15,16 @@
#define NETWORK_SOUND_BUF_SIZE 1024 #define NETWORK_SOUND_BUF_SIZE 1024
enum enum
{ {
STOP = 99, /* Connection-related messages */
LIST_PEERS = 88, HELLO = 99, /* Hello, broker */
DISCONNECT = 77, LIST_PEERS = 98, /* List of peers */
PEER_INFO = 66, 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_RAW = 1,
DISPLAY_UPDATE_RLE = 2, DISPLAY_UPDATE_RLE = 2,
DISPLAY_UPDATE_DIFF= 3, DISPLAY_UPDATE_DIFF= 3,
@ -36,20 +42,57 @@ struct NetworkUpdate
uint32 size; uint32 size;
/* The rest is just data of some type */ /* The rest is just data of some type */
Uint8 data[]; uint8 data[];
}; };
struct NetworkUpdateDisplay struct NetworkUpdateDisplay
{ {
Uint8 square; uint8 square;
Uint8 data[]; uint8 data[];
}; };
struct NetworkUpdateJoystick 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) static inline NetworkUpdate *InitNetworkUpdate(NetworkUpdate *ud, uint16 type, uint32 size)
{ {
ud->magic = FRODO_NETWORK_MAGIC; ud->magic = FRODO_NETWORK_MAGIC;
@ -73,7 +116,7 @@ public:
void EncodeJoystickUpdate(Uint8 v); void EncodeJoystickUpdate(Uint8 v);
bool DecodeUpdate(uint8 *screen, uint8 *js = NULL); bool DecodeUpdate(uint8 *screen, uint8 *js);
void ResetNetworkUpdate(void); void ResetNetworkUpdate(void);
@ -195,14 +238,23 @@ protected:
bool DecodeDisplayRaw(Uint8 *screen, struct NetworkUpdate *src, bool DecodeDisplayRaw(Uint8 *screen, struct NetworkUpdate *src,
int x, int y); 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); 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); bool SendData(void *src, int sock, size_t sz);
virtual bool Select(int sock, struct timeval *tv); virtual bool Select(int sock, struct timeval *tv);
void MangleIp(uint8 *ip);
bool MarshalData(NetworkUpdate *ud); bool MarshalData(NetworkUpdate *ud);
bool MarshalAllData(NetworkUpdate *p); bool MarshalAllData(NetworkUpdate *p);
@ -236,6 +288,10 @@ protected:
/* Connection to the peer */ /* Connection to the peer */
int sock; 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 */ /* Listener-related */
static int listen_sock; static int listen_sock;

View File

@ -174,6 +174,22 @@ bool Network::ReceiveData(void *dst, int sock, size_t sz)
return sz > 0; 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) bool Network::SendData(void *src, int sock, size_t sz)
{ {
size_t sent_sz = 0; size_t sent_sz = 0;

160
Src/network-broker/main.py Normal file
View 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()