mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-10 21:55:11 +01:00
ef79dac020
isn't really finished yet. Well, well. We'll see about that :-)
300 lines
6.4 KiB
C++
300 lines
6.4 KiB
C++
#ifndef NETWORK_H
|
|
#define NETWORK_H
|
|
|
|
#if defined(GEKKO)
|
|
# include <network.h>
|
|
#else
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#include <SDL.h>
|
|
|
|
#define FRODO_NETWORK_MAGIC 0x1976
|
|
|
|
#define NETWORK_UPDATE_SIZE (256 * 1024)
|
|
#define NETWORK_SOUND_BUF_SIZE 1024
|
|
enum
|
|
{
|
|
/* 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,
|
|
SOUND_UPDATE_RAW = 4,
|
|
SOUND_UPDATE_RLE = 5,
|
|
KEYBOARD_UPDATE = 6,
|
|
JOYSTICK_UPDATE = 7,
|
|
ENTER_MENU = 8,
|
|
};
|
|
|
|
struct NetworkUpdate
|
|
{
|
|
uint16 magic; /* Should be 0x1976 */
|
|
uint16 type; /* See above */
|
|
uint32 size;
|
|
|
|
/* The rest is just data of some type */
|
|
uint8 data[];
|
|
};
|
|
|
|
struct NetworkUpdateDisplay
|
|
{
|
|
uint8 square;
|
|
uint8 data[];
|
|
};
|
|
|
|
struct NetworkUpdateJoystick
|
|
{
|
|
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;
|
|
ud->size = size;
|
|
ud->type = type;
|
|
|
|
return ud;
|
|
}
|
|
|
|
class Network
|
|
{
|
|
public:
|
|
Network(int sock, struct sockaddr_in *peer_addr, bool is_master);
|
|
|
|
~Network();
|
|
|
|
void EncodeSound();
|
|
|
|
void EncodeDisplay(Uint8 *master, Uint8 *remote);
|
|
|
|
void EncodeJoystickUpdate(Uint8 v);
|
|
|
|
|
|
bool DecodeUpdate(uint8 *screen, uint8 *js);
|
|
|
|
void ResetNetworkUpdate(void);
|
|
|
|
void DrawTransferredBlocks(SDL_Surface *screen);
|
|
|
|
size_t GetKbps() {
|
|
return this->kbps;
|
|
}
|
|
|
|
bool ThrottleTraffic() {
|
|
return this->kbps > this->target_kbps;
|
|
}
|
|
|
|
void ResetBytesSent() {
|
|
this->traffic = 0;
|
|
}
|
|
|
|
void Tick(int ms);
|
|
|
|
void CloseSocket();
|
|
|
|
bool SendUpdate();
|
|
|
|
bool ReceiveUpdate();
|
|
|
|
static bool StartNetwork(int port);
|
|
|
|
static bool CheckNewConnection();
|
|
|
|
static bool ConnectTo(const char *hostname, int port);
|
|
|
|
Uint8 *GetScreen()
|
|
{
|
|
return this->screen;
|
|
}
|
|
|
|
/**
|
|
* Disconnect from the other end. You should delete the object
|
|
* after having done this.
|
|
*/
|
|
void Disconnect();
|
|
|
|
static void AddPeer(Network *who);
|
|
|
|
static void RemovePeer(Network *peer);
|
|
|
|
static void PushSound(uint8 vol);
|
|
|
|
/* Listener-related */
|
|
static Network *peers[1];
|
|
static int n_peers;
|
|
|
|
protected:
|
|
size_t DecodeSoundUpdate(struct NetworkUpdate *src, char *buf);
|
|
|
|
size_t EncodeSoundRLE(struct NetworkUpdate *dst,
|
|
Uint8 *buffer, size_t len);
|
|
size_t EncodeSoundRaw(struct NetworkUpdate *dst,
|
|
Uint8 *buffer, size_t len);
|
|
|
|
/** Encode part of a screen into @a dst in a single sweep
|
|
*
|
|
* @param dst the destination update structure
|
|
* @param screen the screen to encode
|
|
* @param remote the current remote screen
|
|
* @param square the square index of the screen to encode
|
|
*
|
|
* @return the size of the encoded message
|
|
*/
|
|
size_t EncodeDisplaySquare(struct NetworkUpdate *dst,
|
|
Uint8 *screen, Uint8 *remote, int square);
|
|
|
|
/**
|
|
* Encode the @a buf sound buffer into @a dst
|
|
*
|
|
* @param dst the destination update structure
|
|
* @param buf the buffer to encode
|
|
* @param len the length of the in-buffer
|
|
*
|
|
* @return the size of the encoded message
|
|
*/
|
|
size_t EncodeSoundBuffer(struct NetworkUpdate *dst,
|
|
Uint8 *buf, size_t len);
|
|
|
|
/**
|
|
* Decode a display update message onto @a screen
|
|
*
|
|
* @param screen the screen to draw to
|
|
* @param src the message to decode
|
|
*/
|
|
bool DecodeDisplayUpdate(Uint8 *screen, struct NetworkUpdate *src);
|
|
|
|
void AddNetworkUpdate(struct NetworkUpdate *update);
|
|
|
|
size_t GetNetworkUpdateSize(void)
|
|
{
|
|
return (Uint8*)this->cur_ud - (Uint8*)this->ud;
|
|
}
|
|
|
|
/**
|
|
* Compare two display squares.
|
|
*
|
|
* @param a the first square (first byte)
|
|
* @param b the second square (first byte)
|
|
*
|
|
* @return true if they are equal
|
|
*/
|
|
bool CompareSquare(Uint8 *a, Uint8 *b);
|
|
|
|
bool DecodeDisplayDiff(Uint8 *screen, struct NetworkUpdate *src,
|
|
int x, int y);
|
|
bool DecodeDisplayRLE(Uint8 *screen, struct NetworkUpdate *src,
|
|
int x, int y);
|
|
bool DecodeDisplayRaw(Uint8 *screen, struct NetworkUpdate *src,
|
|
int x, int y);
|
|
|
|
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);
|
|
|
|
bool DeMarshalAllData(NetworkUpdate *ud);
|
|
|
|
bool DeMarshalData(NetworkUpdate *ud);
|
|
|
|
NetworkUpdate *GetNext(NetworkUpdate *p)
|
|
{
|
|
return (NetworkUpdate*)((Uint8*)p + p->size);
|
|
}
|
|
|
|
NetworkUpdate *ud;
|
|
NetworkUpdate *tmp_ud;
|
|
NetworkUpdate *cur_ud;
|
|
Uint8 *raw_buf;
|
|
Uint8 *rle_buf;
|
|
Uint8 *diff_buf;
|
|
Uint8 *sound_buf;
|
|
Uint32 *square_updated;
|
|
|
|
size_t traffic, last_traffic;
|
|
int time_since_last_reset;
|
|
int target_kbps;
|
|
int kbps;
|
|
|
|
Uint8 *screen;
|
|
int joystick_port;
|
|
bool is_master; /* Some peers are more equal than others */
|
|
Uint8 cur_joystick_data;
|
|
|
|
/* 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;
|
|
|
|
/* Sound */
|
|
static uint8 sample_buf[NETWORK_SOUND_BUF_SIZE];
|
|
static int sample_head;
|
|
static int sample_tail;
|
|
};
|
|
|
|
#endif /* NETWORK_H */
|