2009-01-19 07:44:19 +01:00
|
|
|
#ifndef NETWORK_H
|
|
|
|
#define NETWORK_H
|
|
|
|
|
2009-01-29 21:26:40 +01:00
|
|
|
#if defined(GEKKO)
|
|
|
|
# include <network.h>
|
|
|
|
#else
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
2009-01-19 07:44:19 +01:00
|
|
|
#include <SDL.h>
|
|
|
|
|
2009-04-09 15:42:49 +02:00
|
|
|
#include "SID.h"
|
2009-04-13 08:31:12 +02:00
|
|
|
#include "Display.h"
|
2009-04-09 15:42:49 +02:00
|
|
|
|
2009-10-28 18:49:30 +01:00
|
|
|
#define FRODO_NETWORK_PROTOCOL_VERSION 4
|
2009-04-04 09:40:17 +02:00
|
|
|
|
2009-02-03 19:10:09 +01:00
|
|
|
#define FRODO_NETWORK_MAGIC 0x1976
|
2009-02-01 20:47:21 +01:00
|
|
|
|
2009-02-02 20:51:58 +01:00
|
|
|
#define NETWORK_UPDATE_SIZE (256 * 1024)
|
2009-04-11 13:50:10 +02:00
|
|
|
#define NETWORK_SOUND_BUF_SIZE 4096
|
2009-04-13 07:45:20 +02:00
|
|
|
|
2009-11-01 09:38:13 +01:00
|
|
|
#define SCREENSHOT_FACTOR 4
|
|
|
|
#define SCREENSHOT_X (DISPLAY_X / SCREENSHOT_FACTOR)
|
|
|
|
#define SCREENSHOT_Y (DISPLAY_Y / SCREENSHOT_FACTOR)
|
|
|
|
|
2009-02-16 20:20:00 +01:00
|
|
|
typedef enum
|
2009-01-19 07:44:19 +01:00
|
|
|
{
|
2009-02-07 12:08:50 +01:00
|
|
|
/* Connection-related messages */
|
2009-02-13 08:57:40 +01:00
|
|
|
CONNECT_TO_BROKER = 99, /* Hello, broker */
|
2009-02-07 12:08:50 +01:00
|
|
|
LIST_PEERS = 98, /* List of peers */
|
2009-02-13 08:57:40 +01:00
|
|
|
CONNECT_TO_PEER = 97, /* A peer wants to connect */
|
2009-02-07 12:08:50 +01:00
|
|
|
DISCONNECT = 96, /* Disconnect from a peer */
|
2009-02-28 19:45:26 +01:00
|
|
|
SELECT_PEER = 93, /* (client) Select who to connect to */
|
2009-02-07 12:08:50 +01:00
|
|
|
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 */
|
2009-01-19 07:44:19 +01:00
|
|
|
DISPLAY_UPDATE_RAW = 1,
|
|
|
|
DISPLAY_UPDATE_RLE = 2,
|
2009-01-25 11:07:51 +01:00
|
|
|
DISPLAY_UPDATE_DIFF= 3,
|
|
|
|
SOUND_UPDATE_RAW = 4,
|
|
|
|
SOUND_UPDATE_RLE = 5,
|
|
|
|
KEYBOARD_UPDATE = 6,
|
|
|
|
JOYSTICK_UPDATE = 7,
|
2009-02-01 11:52:32 +01:00
|
|
|
ENTER_MENU = 8,
|
2009-04-13 08:31:12 +02:00
|
|
|
TEXT_MESSAGE = 9,
|
2009-02-16 20:20:00 +01:00
|
|
|
} network_message_type_t;
|
2009-01-19 07:44:19 +01:00
|
|
|
|
2009-02-13 08:57:40 +01:00
|
|
|
typedef enum
|
2009-02-11 21:07:28 +01:00
|
|
|
{
|
2009-02-16 20:20:00 +01:00
|
|
|
CONN_CONNECTED,
|
|
|
|
CONN_CONNECT_TO_BROKER,
|
|
|
|
CONN_WAIT_FOR_PEER_ADDRESS,
|
|
|
|
CONN_CONNECT_TO_PEER,
|
2009-02-28 19:45:26 +01:00
|
|
|
CONN_SELECT_PEER,
|
2009-02-16 20:20:00 +01:00
|
|
|
CONN_WAIT_FOR_PEER_REPLY,
|
2009-02-11 21:07:28 +01:00
|
|
|
|
|
|
|
/* Client-only */
|
2009-02-16 20:20:00 +01:00
|
|
|
CONN_WAIT_FOR_PEER_LIST,
|
2009-04-04 09:40:17 +02:00
|
|
|
|
|
|
|
FAILED,
|
2009-02-13 08:57:40 +01:00
|
|
|
} network_connection_state_t;
|
2009-02-11 21:07:28 +01:00
|
|
|
|
2009-04-04 09:40:17 +02:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
OK = 0,
|
|
|
|
AGAIN_ERROR,
|
|
|
|
VERSION_ERROR,
|
|
|
|
SERVER_GARBAGE_ERROR,
|
2009-04-04 13:18:03 +02:00
|
|
|
NO_PEERS_ERROR,
|
2009-04-04 09:40:17 +02:00
|
|
|
} network_connection_error_t;
|
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
struct NetworkUpdate
|
2009-01-19 07:44:19 +01:00
|
|
|
{
|
2009-02-03 19:10:09 +01:00
|
|
|
uint16 magic; /* Should be 0x1976 */
|
|
|
|
uint16 type; /* See above */
|
|
|
|
uint32 size;
|
2009-01-19 07:44:19 +01:00
|
|
|
|
|
|
|
/* The rest is just data of some type */
|
2009-02-07 12:08:50 +01:00
|
|
|
uint8 data[];
|
2009-01-19 07:44:19 +01:00
|
|
|
};
|
|
|
|
|
2009-02-03 19:10:09 +01:00
|
|
|
struct NetworkUpdateDisplay
|
|
|
|
{
|
2009-02-07 12:08:50 +01:00
|
|
|
uint8 square;
|
|
|
|
uint8 data[];
|
2009-02-03 19:10:09 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct NetworkUpdateJoystick
|
|
|
|
{
|
2009-02-07 12:08:50 +01:00
|
|
|
uint8 val;
|
2009-02-03 19:10:09 +01:00
|
|
|
};
|
|
|
|
|
2009-02-28 19:45:26 +01:00
|
|
|
struct NetworkUpdateSelectPeer
|
|
|
|
{
|
|
|
|
uint32 server_id;
|
|
|
|
};
|
|
|
|
|
2009-02-07 12:08:50 +01:00
|
|
|
struct NetworkUpdatePingAck
|
|
|
|
{
|
2009-03-28 16:18:50 +01:00
|
|
|
uint32 seq;
|
2009-02-07 12:08:50 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2009-02-13 08:57:40 +01:00
|
|
|
/* Encoded as hex numbers in a string - c0a80a02\0 -> 192.168.10.2.
|
|
|
|
* Some more space to fit IPv6 stuff */
|
|
|
|
uint8 private_ip[16];
|
|
|
|
uint8 public_ip[16];
|
2009-02-07 12:08:50 +01:00
|
|
|
|
|
|
|
uint16 key; /* Random value to separate same names */
|
|
|
|
uint16 is_master;
|
|
|
|
uint8 name[32]; /* "SIMON", "LINDA" etc */
|
2009-02-28 19:45:26 +01:00
|
|
|
uint32 server_id; /* Used by the server */
|
2009-04-04 09:40:17 +02:00
|
|
|
uint32 version; /* Version number */
|
2009-11-01 09:38:13 +01:00
|
|
|
|
|
|
|
uint32 avatar; /* Hash of the avatar */
|
|
|
|
/* RAW-encoded screenshot of how the display looks like */
|
|
|
|
uint8 screenshot[(SCREENSHOT_X * SCREENSHOT_Y) / 2];
|
2009-02-07 12:08:50 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct NetworkUpdateListPeers
|
|
|
|
{
|
|
|
|
uint32 n_peers;
|
2009-02-13 08:57:40 +01:00
|
|
|
uint8 your_ip[16];
|
2009-02-07 12:08:50 +01:00
|
|
|
uint16 your_port;
|
|
|
|
uint8 d[2]; /* Pad to 4 bytes */
|
|
|
|
|
|
|
|
/* Followed by the actual peers */
|
|
|
|
NetworkUpdatePeerInfo peers[];
|
|
|
|
};
|
|
|
|
|
2009-02-03 19:10:09 +01:00
|
|
|
static inline NetworkUpdate *InitNetworkUpdate(NetworkUpdate *ud, uint16 type, uint32 size)
|
|
|
|
{
|
|
|
|
ud->magic = FRODO_NETWORK_MAGIC;
|
|
|
|
ud->size = size;
|
|
|
|
ud->type = type;
|
|
|
|
|
|
|
|
return ud;
|
|
|
|
}
|
2009-01-26 22:00:23 +01:00
|
|
|
|
2009-01-19 07:44:19 +01:00
|
|
|
class Network
|
|
|
|
{
|
|
|
|
public:
|
2009-10-28 19:04:30 +01:00
|
|
|
Network(const char *remote_host, int port);
|
2009-01-24 16:48:43 +01:00
|
|
|
|
|
|
|
~Network();
|
|
|
|
|
2009-02-02 20:51:58 +01:00
|
|
|
void EncodeSound();
|
|
|
|
|
2009-11-01 09:38:13 +01:00
|
|
|
void EncodeScreenshot(Uint8 *dst, Uint8 *master);
|
|
|
|
|
2009-02-01 20:47:21 +01:00
|
|
|
void EncodeDisplay(Uint8 *master, Uint8 *remote);
|
2009-01-25 11:07:51 +01:00
|
|
|
|
2009-01-29 22:11:04 +01:00
|
|
|
void EncodeJoystickUpdate(Uint8 v);
|
|
|
|
|
2009-04-13 08:31:12 +02:00
|
|
|
void EncodeTextMessage(char *str);
|
2009-01-29 22:11:04 +01:00
|
|
|
|
2009-04-13 08:31:12 +02:00
|
|
|
|
|
|
|
bool DecodeUpdate(C64Display *display, uint8 *js, MOS6581 *dst);
|
2009-01-25 11:07:51 +01:00
|
|
|
|
|
|
|
void ResetNetworkUpdate(void);
|
|
|
|
|
|
|
|
void DrawTransferredBlocks(SDL_Surface *screen);
|
|
|
|
|
2009-01-30 18:49:47 +01:00
|
|
|
size_t GetKbps() {
|
|
|
|
return this->kbps;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThrottleTraffic() {
|
|
|
|
return this->kbps > this->target_kbps;
|
2009-01-25 11:07:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ResetBytesSent() {
|
2009-01-30 18:49:47 +01:00
|
|
|
this->traffic = 0;
|
2009-01-25 11:07:51 +01:00
|
|
|
}
|
|
|
|
|
2009-01-30 18:49:47 +01:00
|
|
|
void Tick(int ms);
|
|
|
|
|
2009-02-01 20:47:21 +01:00
|
|
|
void CloseSocket();
|
|
|
|
|
|
|
|
bool SendUpdate();
|
|
|
|
|
|
|
|
bool ReceiveUpdate();
|
|
|
|
|
2009-02-08 12:52:09 +01:00
|
|
|
bool ReceiveUpdate(struct timeval *tv);
|
2009-02-08 12:27:56 +01:00
|
|
|
|
2009-02-08 09:22:15 +01:00
|
|
|
static bool StartNetworkServer(int port);
|
2009-01-29 21:35:06 +01:00
|
|
|
|
2009-02-01 20:47:21 +01:00
|
|
|
static bool CheckNewConnection();
|
2009-01-25 11:07:51 +01:00
|
|
|
|
2009-02-01 20:47:21 +01:00
|
|
|
Uint8 *GetScreen()
|
|
|
|
{
|
|
|
|
return this->screen;
|
|
|
|
}
|
|
|
|
|
2009-02-13 08:57:40 +01:00
|
|
|
bool Connect();
|
|
|
|
|
2009-04-04 09:40:17 +02:00
|
|
|
network_connection_error_t ConnectFSM();
|
|
|
|
|
2009-02-01 20:47:21 +01:00
|
|
|
/**
|
|
|
|
* Disconnect from the other end. You should delete the object
|
|
|
|
* after having done this.
|
|
|
|
*/
|
|
|
|
void Disconnect();
|
|
|
|
|
2009-02-02 20:51:58 +01:00
|
|
|
static void PushSound(uint8 vol);
|
|
|
|
|
2009-04-09 15:42:49 +02:00
|
|
|
static bool is_master; /* Some peers are more equal than others */
|
2009-01-25 11:07:51 +01:00
|
|
|
protected:
|
2009-03-08 20:02:19 +01:00
|
|
|
void InitNetwork();
|
|
|
|
|
2009-03-28 10:34:31 +01:00
|
|
|
void ShutdownNetwork();
|
|
|
|
|
2009-04-10 13:39:46 +02:00
|
|
|
size_t DecodeSoundRLE(struct NetworkUpdate *src, MOS6581 *dst);
|
|
|
|
|
2009-04-09 15:42:49 +02:00
|
|
|
size_t DecodeSoundUpdate(struct NetworkUpdate *src, MOS6581 *dst);
|
2009-01-25 11:07:51 +01:00
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
size_t EncodeSoundRLE(struct NetworkUpdate *dst,
|
2009-01-25 11:07:51 +01:00
|
|
|
Uint8 *buffer, size_t len);
|
2009-01-26 22:00:23 +01:00
|
|
|
size_t EncodeSoundRaw(struct NetworkUpdate *dst,
|
2009-01-25 11:07:51 +01:00
|
|
|
Uint8 *buffer, size_t len);
|
2009-01-24 16:48:43 +01:00
|
|
|
|
2009-04-11 13:50:10 +02:00
|
|
|
size_t GetSoundBufferSize();
|
|
|
|
|
2009-01-28 21:57:48 +01:00
|
|
|
/** 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,
|
2009-03-28 13:37:06 +01:00
|
|
|
Uint8 *screen, Uint8 *remote, int square,
|
|
|
|
bool use_diff = true);
|
2009-01-28 21:57:48 +01:00
|
|
|
|
2009-01-19 07:44:19 +01:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2009-01-26 22:00:23 +01:00
|
|
|
size_t EncodeSoundBuffer(struct NetworkUpdate *dst,
|
2009-01-19 07:44:19 +01:00
|
|
|
Uint8 *buf, size_t len);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decode a display update message onto @a screen
|
|
|
|
*
|
|
|
|
* @param src the message to decode
|
|
|
|
*/
|
2009-04-13 08:31:12 +02:00
|
|
|
bool DecodeDisplayUpdate(struct NetworkUpdate *src);
|
2009-01-24 16:48:43 +01:00
|
|
|
|
2009-01-24 21:57:23 +01:00
|
|
|
void AddNetworkUpdate(struct NetworkUpdate *update);
|
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
size_t GetNetworkUpdateSize(void)
|
|
|
|
{
|
|
|
|
return (Uint8*)this->cur_ud - (Uint8*)this->ud;
|
|
|
|
}
|
|
|
|
|
2009-01-24 16:48:43 +01:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2009-04-13 08:31:12 +02:00
|
|
|
bool DecodeDisplayDiff(struct NetworkUpdate *src,
|
2009-01-25 11:07:51 +01:00
|
|
|
int x, int y);
|
2009-04-13 08:31:12 +02:00
|
|
|
bool DecodeDisplayRLE(struct NetworkUpdate *src,
|
2009-01-19 07:44:19 +01:00
|
|
|
int x, int y);
|
2009-04-13 08:31:12 +02:00
|
|
|
bool DecodeDisplayRaw(struct NetworkUpdate *src,
|
2009-01-19 07:44:19 +01:00
|
|
|
int x, int y);
|
|
|
|
|
2009-03-28 16:18:50 +01:00
|
|
|
void SendPingAck(int seq);
|
|
|
|
|
2009-02-07 12:08:50 +01:00
|
|
|
bool ReceiveUpdate(NetworkUpdate *dst, size_t sz, struct timeval *tv);
|
2009-01-19 07:44:19 +01:00
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
bool ReceiveData(void *dst, int sock, size_t sz);
|
|
|
|
|
2009-02-08 12:27:56 +01:00
|
|
|
bool InitSocket(const char *remote_host, int port);
|
|
|
|
|
2009-02-07 12:08:50 +01:00
|
|
|
/* 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);
|
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
bool SendData(void *src, int sock, size_t sz);
|
|
|
|
|
|
|
|
virtual bool Select(int sock, struct timeval *tv);
|
2009-01-19 07:44:19 +01:00
|
|
|
|
2009-02-13 08:57:40 +01:00
|
|
|
bool IpToStr(char *dst, uint8 *ip);
|
|
|
|
|
|
|
|
bool InitSockaddr (struct sockaddr_in *name,
|
|
|
|
const char *hostname, uint16_t port);
|
2009-02-07 12:08:50 +01:00
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
bool MarshalData(NetworkUpdate *ud);
|
2009-01-24 16:48:43 +01:00
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
bool MarshalAllData(NetworkUpdate *p);
|
|
|
|
|
2009-03-16 21:56:04 +01:00
|
|
|
bool DeMarshalAllData(NetworkUpdate *ud, size_t max_size,
|
|
|
|
bool *has_stop);
|
2009-02-07 19:24:50 +01:00
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
bool DeMarshalData(NetworkUpdate *ud);
|
|
|
|
|
2009-02-13 08:57:40 +01:00
|
|
|
bool ConnectToBroker();
|
|
|
|
|
|
|
|
bool ConnectToPeer();
|
|
|
|
|
|
|
|
bool WaitForPeerReply();
|
|
|
|
|
2009-04-04 09:40:17 +02:00
|
|
|
network_connection_error_t WaitForPeerList();
|
2009-02-13 08:57:40 +01:00
|
|
|
|
2009-04-04 09:40:17 +02:00
|
|
|
network_connection_error_t WaitForPeerAddress();
|
2009-02-13 08:57:40 +01:00
|
|
|
|
2009-02-28 19:45:26 +01:00
|
|
|
bool SelectPeer(uint32 id);
|
|
|
|
|
2009-03-16 21:56:04 +01:00
|
|
|
size_t FillNetworkBuffer(NetworkUpdate *p);
|
|
|
|
|
2009-01-26 22:00:23 +01:00
|
|
|
NetworkUpdate *GetNext(NetworkUpdate *p)
|
|
|
|
{
|
|
|
|
return (NetworkUpdate*)((Uint8*)p + p->size);
|
|
|
|
}
|
|
|
|
|
2009-01-24 16:48:43 +01:00
|
|
|
NetworkUpdate *ud;
|
2009-01-26 22:00:23 +01:00
|
|
|
NetworkUpdate *cur_ud;
|
2009-01-28 21:57:48 +01:00
|
|
|
Uint8 *raw_buf;
|
|
|
|
Uint8 *rle_buf;
|
|
|
|
Uint8 *diff_buf;
|
2009-02-02 20:51:58 +01:00
|
|
|
Uint8 *sound_buf;
|
2009-11-01 09:38:13 +01:00
|
|
|
Uint8 screenshot[SCREENSHOT_X * SCREENSHOT_Y / 2];
|
2009-01-25 11:07:51 +01:00
|
|
|
Uint32 *square_updated;
|
2009-01-30 18:49:47 +01:00
|
|
|
|
|
|
|
size_t traffic, last_traffic;
|
|
|
|
int time_since_last_reset;
|
|
|
|
int target_kbps;
|
|
|
|
int kbps;
|
2009-01-29 19:04:31 +01:00
|
|
|
|
2009-03-28 13:37:06 +01:00
|
|
|
/* The current square to refresh */
|
|
|
|
int refresh_square;
|
|
|
|
|
2009-01-19 07:44:19 +01:00
|
|
|
Uint8 *screen;
|
|
|
|
int joystick_port;
|
2009-02-08 12:27:56 +01:00
|
|
|
bool connected;
|
2009-01-30 16:37:15 +01:00
|
|
|
Uint8 cur_joystick_data;
|
|
|
|
|
2009-02-01 20:47:21 +01:00
|
|
|
/* Connection to the peer */
|
2009-01-19 07:44:19 +01:00
|
|
|
int sock;
|
2009-02-13 08:57:40 +01:00
|
|
|
struct sockaddr_in connection_addr;
|
|
|
|
|
2009-04-04 09:40:17 +02:00
|
|
|
const char *connection_error_message;
|
|
|
|
|
2009-02-13 08:57:40 +01:00
|
|
|
network_connection_state_t network_connection_state;
|
2009-02-02 20:51:58 +01:00
|
|
|
|
|
|
|
/* Sound */
|
|
|
|
static uint8 sample_buf[NETWORK_SOUND_BUF_SIZE];
|
|
|
|
static int sample_head;
|
|
|
|
static int sample_tail;
|
2009-04-26 08:02:57 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
static bool networking_started;
|
2009-01-19 07:44:19 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* NETWORK_H */
|