Descent3/lib/networking.h

558 lines
18 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/Main/lib/networking.h $
* $Revision: 1.9 $
* $Date: 2004/12/05 04:00:20 $
* $Author: ryan $
*
*
*
* $Log: networking.h,v $
* Revision 1.10 2004/12/05 04:38:23 ryan
* Disable IPX support.
*
* Revision 1.9 2004/12/05 04:00:20 ryan
* MacOS X patches.
*
* Revision 1.8 2004/03/21 17:11:39 kevinb
* Fixes so linux will compile again. Tested with gcc-2.96
*
* Revision 1.7 2004/02/25 00:04:06 ryan
* Removed loki_utils dependency and ported to MacOS X (runs, but incomplete).
*
* Revision 1.6 2004/02/09 04:14:51 kevinb
* Added newlines to all headers to reduce number of warnings printed
*
* Made some small changes to get everything compiling.
*
* All Ready to merge the 1.5 tree.
*
* Revision 1.5 2001/01/13 21:48:46 icculus
* patched to (re)compile on win32.
*
* Revision 1.4 2000/09/22 19:05:40 icculus
* updated
*
* Revision 1.3 2000/06/24 01:15:15 icculus
* patched to compile.
*
* Revision 1.2 2000/06/03 14:33:51 icculus
* Merge with Outrage 1.4 tree...
*
* Revision 1.1.1.1 2000/04/18 00:00:38 icculus
* initial checkin
*
*
* 49 8/31/99 5:30p Jason
* network statistics code
*
* 48 8/21/99 3:14a Jeff
* real async lookup in linux
*
* 47 7/29/99 10:33a Kevin
* Macintosh Updates
*
* 45 7/28/99 ????? Kevin
* Mac Stuff
*
* 44 5/22/99 1:57a Kevin
* increased timeout in reliable code
*
* 43 5/19/99 5:21p Kevin
* changed return value of nw_GetHostAddressFromNumbers()
*
* 42 5/10/99 10:53p Ardussi
* changes to compile on Mac
*
* 41 4/30/99 5:06p Kevin
* misc dedicated server, networking and low memory enhancements
*
* 40 4/17/99 3:44p Kevin
* Demo2 changes & fixes
*
* 39 4/17/99 6:14a Jeff
* fixed errors compiling due to typos
*
* 38 4/17/99 5:50a Jeff
* added defines and macros for Linux port
*
* 37 4/16/99 6:00p Kevin
* Bunches of Demo stuff
*
* 36 4/15/99 2:57a Jeff
* added some defines and includes needed for linux ipx
*
* 35 4/12/99 3:16p Kevin
* Added a bunch of stuff for the linux version
*
* 34 2/24/99 12:48p Kevin
* Added urgent flag to nw_SendReliable. It causes the packet to go out
* that frame.
*
* 33 2/05/99 7:24p Kevin
* Added NAGLE type packet buffering to reliable networking code
*
* 32 1/26/99 9:44p Jeff
* moved tcplog functions to mono library
*
* 31 1/13/99 6:48a Jeff
* made linux friendly with some #ifdef's
*
* 29 1/08/99 2:58p Kevin
* Added TCP mprintf support so you can log to a remote machine.
*
* 28 12/23/98 6:38p Kevin
* All UDP data (except gamespy) now uses one (registered) port number
*
* 27 12/03/98 9:29a Kevin
* Added better ip selection code
*
* 26 11/02/98 6:41p Jason
* changed demo port number
*
* 25 10/12/98 8:39p Kevin
* removed mprintf's and fixed some smallish bugs
*
* 24 10/01/98 11:37a Kevin
* UI fixes and stuff
*
* 23 9/28/98 11:02a Kevin
* added Networking defer, and fixed some UI issues
*
* 22 9/22/98 2:29p Kevin
* moved ships allowed code out of dll and into main app. Also added
* powerup exclusions
*
* 21 9/21/98 11:19a Kevin
* check protocol before entering multiplayer screens
*
* 20 9/04/98 1:51p Kevin
* implemented asyncronous gethostbyname
*
* 19 8/14/98 4:54p Kevin
* More directplay stuff
*
* 18 8/13/98 6:32p Kevin
* Initial implementation of directplay API
*
*/
#ifndef NETWORKING_H
#define NETWORKING_H
#include "pstypes.h"
#include <cstdint>
#if defined(WIN32)
// Windows includes
#include <winsock.h>
// helper macros for working with SOCKADDR_IN to make it look nicer between windows and Linux
static inline void INADDR_SET_SUN_SADDR(struct in_addr *st, uint32_t value) { st->S_un.S_addr = value; }
static inline void INADDR_GET_SUN_SADDR(struct in_addr *st, uint32_t *value) { *value = st->S_un.S_addr; }
static inline void INADDR_SET_SUN_SUNW(struct in_addr *st, uint16_t s_w1, uint16_t s_w2) {
st->S_un.S_un_w.s_w1 = s_w1;
st->S_un.S_un_w.s_w2 = s_w2;
}
static inline void INADDR_GET_SUN_SUNW(struct in_addr *st, uint16_t *s_w1, uint16_t *s_w2) {
*s_w1 = st->S_un.S_un_w.s_w1;
*s_w2 = st->S_un.S_un_w.s_w2;
}
static inline void INADDR_SET_SUN_SUNB(struct in_addr *st, uint8_t s_b1, uint8_t s_b2, uint8_t s_b3,
uint8_t s_b4) {
st->S_un.S_un_b.s_b1 = s_b1;
st->S_un.S_un_b.s_b2 = s_b2;
st->S_un.S_un_b.s_b3 = s_b3;
st->S_un.S_un_b.s_b4 = s_b4;
}
static inline void INADDR_GET_SUN_SUNB(struct in_addr *st, uint8_t *s_b1, uint8_t *s_b2, uint8_t *s_b3,
uint8_t *s_b4) {
*s_b1 = st->S_un.S_un_b.s_b1;
*s_b2 = st->S_un.S_un_b.s_b2;
*s_b3 = st->S_un.S_un_b.s_b3;
*s_b4 = st->S_un.S_un_b.s_b4;
}
#elif defined(__LINUX__)
// Linux includes/defines
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>
// rcg06212000 my SDL adds.
#include "SDL.h"
#include "SDL_thread.h"
#include "linux_fix.h"
#define SOCKET int
#define BOOL bool
#define SOCKADDR_IN sockaddr_in
#define SOCKADDR sockaddr
#define INVALID_SOCKET -1
#ifdef TRUE
#undef TRUE
#endif
#define TRUE true
#ifdef FALSE
#undef FALSE
#endif
#define FALSE false
#define HOSTENT struct hostent
#define SOCKET_ERROR -1
// Winsock = sockets error translation
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEINVAL EINVAL
#define WSAENOPROTOOPT ENOPROTOOPT
#ifndef WSAGetLastError
#define WSAGetLastError() errno
#endif
extern bool Use_DirectPlay;
// helper macros for working with SOCKADDR_IN to make it look nicer between windows and Linux
static inline void INADDR_SET_SUN_SADDR(struct in_addr *st, uint32_t value) { st->s_addr = value; }
static inline void INADDR_GET_SUN_SADDR(struct in_addr *st, uint32_t *value) { *value = st->s_addr; }
static inline void INADDR_SET_SUN_SUNW(struct in_addr *st, uint16_t s_w1, uint16_t s_w2) {
union {
struct {
uint8_t s_b1, s_b2, s_b3, s_b4;
} S_un_b;
struct {
uint16_t s_w1, s_w2;
} S_un_w;
uint32_t S_addr;
} S_un;
S_un.S_un_w.s_w1 = s_w1;
S_un.S_un_w.s_w2 = s_w2;
st->s_addr = S_un.S_addr;
}
static inline void INADDR_GET_SUN_SUNW(struct in_addr *st, uint16_t *s_w1, uint16_t *s_w2) {
union {
struct {
uint8_t s_b1, s_b2, s_b3, s_b4;
} S_un_b;
struct {
uint16_t s_w1, s_w2;
} S_un_w;
uint32_t S_addr;
} S_un;
S_un.S_addr = st->s_addr;
*s_w1 = S_un.S_un_w.s_w1;
*s_w2 = S_un.S_un_w.s_w2;
}
static inline void INADDR_SET_SUN_SUNB(struct in_addr *st, uint8_t s_b1, uint8_t s_b2, uint8_t s_b3,
uint8_t s_b4) {
union {
struct {
uint8_t s_b1, s_b2, s_b3, s_b4;
} S_un_b;
struct {
uint16_t s_w1, s_w2;
} S_un_w;
uint32_t S_addr;
} S_un;
S_un.S_un_b.s_b1 = s_b1;
S_un.S_un_b.s_b2 = s_b2;
S_un.S_un_b.s_b3 = s_b3;
S_un.S_un_b.s_b4 = s_b4;
st->s_addr = S_un.S_addr;
}
static inline void INADDR_GET_SUN_SUNB(struct in_addr *st, uint8_t *s_b1, uint8_t *s_b2, uint8_t *s_b3,
uint8_t *s_b4) {
union {
struct {
uint8_t s_b1, s_b2, s_b3, s_b4;
} S_un_b;
struct {
uint16_t s_w1, s_w2;
} S_un_w;
uint32_t S_addr;
} S_un;
S_un.S_addr = st->s_addr;
*s_b1 = S_un.S_un_b.s_b1;
*s_b2 = S_un.S_un_b.s_b2;
*s_b3 = S_un.S_un_b.s_b3;
*s_b4 = S_un.S_un_b.s_b4;
}
#endif // OS
#define NWT_UNRELIABLE 1
#define NWT_RELIABLE 2
// This is the max size of a packet - DO NOT INCREASE THIS NUMBER ABOVE 512!
#define MAX_PACKET_SIZE 512
#if 1 // ndef DEMO
#define DEFAULT_GAME_PORT D3_DEFAULT_PORT
#else
#define DEFAULT_GAME_PORT 6250
#endif
// Network flags
#define NF_CHECKSUM 1
#define NF_NOSEQINC 2
enum network_protocol : uint32_t
{
NP_NONE,
NP_TCP,
NP_IPX,
NP_DIRECTPLAY
};
struct network_address {
uint8_t address[6];
uint16_t port;
uint8_t net_id[4];
network_protocol connection_type; // IPX, IP, modem, etc.
};
extern BOOL DP_active;
extern BOOL TCP_active;
extern BOOL IPX_active;
// create a new non-blocking socket
int make_nonblocking(SOCKET sock);
// Get the info from RAS
uint32_t psnet_ras_status();
// function to shutdown and close the given socket. It takes a couple of things into consideration
// when closing, such as possibly reiniting reliable sockets if they are closed here.
void nw_CloseSocket(SOCKET *sockp);
// Inits the sockets layer to activity
void nw_InitNetworking(int iReadBufSizeOverride = -1);
// called by psnet_init to initialize the listen socket used by a host/server
int nw_InitReliableSocket();
// function which checks the Listen_socket for possibly incoming requests to be connected.
// returns 0 on error or nothing waiting. 1 if we should try to accept
int nw_CheckListenSocket(network_address *from_addr);
// Inits the sockets that the application will be using
void nw_InitSockets(uint16_t port);
// Connects a client to a server
void nw_ConnectToServer(SOCKET *socket, network_address *server_addr);
// Returns internet address format from string address format...ie "204.243.217.14"
// turns into 1414829242
uint32_t nw_GetHostAddressFromNumbers(char *str);
// Fills in the string with the string address from the internet address
void nw_GetNumbersFromHostAddress(network_address *address, char *str);
// returns the ip address of this computer
uint32_t nw_GetThisIP();
// function which checks the Listen_socket for possibly incoming requests to be connected.
// returns 0 on error or nothing waiting. 1 if we should try to accept
int nw_CheckListenSocket(network_address *from_addr);
// Calculates a unique uint16_t checksum for a stream of data
uint16_t nw_CalculateChecksum(void *vptr, int len);
// Sends data on an unreliable socket
int nw_Send(network_address *who_to, void *data, int len, int flags);
// nw_ReceiveFromSocket will get data out of the socket and stuff it into the packet_buffers
// nw_Receive now calls this function, then determines which of the packet buffers
// to package up and use
void nw_ReceiveFromSocket();
// routine to "free" a packet buffer
void nw_FreePacket(int id);
// nw_Recieve will call the above function to read data out of the socket. It will then determine
// which of the buffers we should use and pass to the routine which called us
int nw_Receive(void *data, network_address *from_addr);
// nw_SendReliable sends the given data through the given reliable socket.
int nw_SendReliable(uint32_t socketid, uint8_t *data, int length, bool urgent = false);
// function which reads data off of a reliable socket. recv() should read the totaly amount of data
// available I believe. (i.e. we shouldn't read only part of a message with one call....I may be wrong
// and this may be a source of bugs).
int nw_ReceiveReliable(SOCKET socket, uint8_t *buffer, int max_len);
// Returns the current protocol in use
int nw_GetProtocolType();
// Copies my address into the passed argument
void nw_GetMyAddress(network_address *addr);
// Sends a packet to the game tracker
int nw_SendGameTrackerPacker(void *packet);
// Checks for an incoming game tracker packet.
int nw_ReceiveGameTracker(void *packet);
// Send a packet to the pilot tracker
int nw_SendPilotTrackerPacket(void *packet);
// Checks for an incoming pilot tracker packet.
int nw_ReceivePilotTracker(void *packet);
int nw_PingCompare(const void *arg1, const void *arg2);
// initialize the buffering system
void nw_psnet_buffer_init();
// buffer a packet (maintain order!)
void nw_psnet_buffer_packet(uint8_t *data, int length, network_address *from);
// get the index of the next packet in order!
int nw_psnet_buffer_get_next(uint8_t *data, int *length, network_address *from);
// get the index of the next packet in order!
int nw_psnet_buffer_get_next_by_packet_id(uint8_t *data, int *length, uint32_t packet_id);
// This is all the reliable UDP stuff...
#define MAXNETBUFFERS \
150 // Maximum network buffers (For between network and upper level functions, which is
// required in case of out of order packets
#define NETRETRYTIME .75 // Time after sending before we resend
#define MIN_NET_RETRYTIME .2
#define NETTIMEOUT 300 // Time after receiving the last packet before we drop that user
#define NETHEARTBEATTIME 10 // How often to send a heartbeat
#define MAXRELIABLESOCKETS 40 // Max reliable sockets to open at once...
#define NETBUFFERSIZE 600 // Max size of a network packet
// Network Types
#define RNT_ACK 1 // ACK Packet
#define RNT_DATA 2 // Data Packet
#define RNT_DATA_COMP 3 // Compressed Data Packet
#define RNT_REQ_CONN 4 // Requesting a connection
#define RNT_DISCONNECT 5 // Disconnecting a connection
#define RNT_HEARTBEAT 6 // Heartbeat -- send every NETHEARTBEATTIME
#define RNT_I_AM_HERE 7
// Reliable socket states
#define RNF_UNUSED 0 // Completely clean socket..
#define RNF_CONNECTED 1 // Connected and running fine
#define RNF_BROKEN 2 // Broken - disconnected abnormally
#define RNF_DISCONNECTED 3 // Disconnected cleanly
#define RNF_CONNECTING 4 // We received the connecting message, but haven't told the game yet.
#define RNF_LIMBO 5 // between connecting and connected
void nw_SendReliableAck(SOCKADDR *raddr, uint32_t sig, network_protocol link_type, float time_sent);
void nw_WorkReliable(uint8_t *data, int len, network_address *naddr);
int nw_Compress(void *srcdata, void *destdata, int count);
int nw_Uncompress(void *compdata, void *uncompdata, int count);
#define NW_AGHBN_CANCEL 1
#define NW_AGHBN_LOOKUP 2
#define NW_AGHBN_READ 3
struct async_dns_lookup {
uint32_t ip; // resolved host. Write only to worker thread.
char *host; // host name to resolve. read only to worker thread
bool done; // write only to the worker thread. Signals that the operation is complete
bool error; // write only to worker thread. Thread sets this if the name doesn't resolve
bool abort; // read only to worker thread. If this is set, don't fill in the struct.
// rcg06212000 added to let us join the thread at completion...
#ifdef __LINUX__
SDL_Thread *threadId;
#endif
};
#ifdef WIN32
#define CDECLCALL __cdecl
#else
#define CDECLCALL
#endif
#ifdef __LINUX__
// rcg06192000 used to return void *.
int CDECLCALL gethostbynameworker(void *parm);
#else
void CDECLCALL gethostbynameworker(void *parm);
#endif
int nw_Asyncgethostbyname(uint32_t *ip, int command, char *hostname);
int nw_ReccomendPPS();
void nw_DoNetworkIdle(void);
typedef void *(*NetworkReceiveCallback)(uint8_t *data, int len, network_address *from);
int nw_RegisterCallback(NetworkReceiveCallback nfp, uint8_t id);
NetworkReceiveCallback nw_UnRegisterCallback(uint8_t id);
int nw_SendWithID(uint8_t id, uint8_t *data, int len, network_address *who_to);
int nw_DoReceiveCallbacks(void);
void nw_HandleConnectResponse(uint8_t *data, int len, network_address *server_addr);
int nw_RegisterCallback(NetworkReceiveCallback nfp, uint8_t id);
void nw_HandleUnreliableData(uint8_t *data, int len, network_address *from_addr);
void nw_ReliableResend(void);
int nw_CheckReliableSocket(int socknum);
struct tNetworkStatus {
// TCP/IP Status lines
int udp_total_packets_sent; // total number of packets sent out on the network (unreliable)
int udp_total_packets_rec; // total number of packets recieved on the network (unrealiable)
int udp_total_bytes_sent; // total number of bytes sent (unreliable)
int udp_total_bytes_rec; // total number of bytes recieved (unreliable)
int tcp_total_packets_sent; // total number of packets sent out on the network (reliable)
int tcp_total_packets_rec; // total number of packets recieved on the network (reliable)
int tcp_total_bytes_sent; // total number of bytes sent (reliable)
int tcp_total_bytes_rec; // total number of bytes recieved (reliable)
int tcp_total_packets_resent; // total number of packets resent (reliable)
int tcp_total_bytes_resent; // total number of bytes resent (reliable)
// IPX Status lines
int ipx_total_packets_sent; // total number of packets sent out on the network (unreliable)
int ipx_total_packets_rec; // total number of packets recieved on the network (unrealiable)
int ipx_total_bytes_sent; // total number of bytes sent (unreliable)
int ipx_total_bytes_rec; // total number of bytes recieved (unreliable)
int spx_total_packets_sent; // total number of packets sent out on the network (reliable)
int spx_total_packets_rec; // total number of packets recieved on the network (reliable)
int spx_total_bytes_sent; // total number of bytes sent (reliable)
int spx_total_bytes_rec; // total number of bytes recieved (reliable)
int spx_total_packets_resent; // total number of packets resent (reliable)
int spx_total_bytes_resent; // total number of bytes resent (reliable)
}; // network status information
// fills in the buffer with network stats
// pass NULL to reset the stats
void nw_GetNetworkStats(tNetworkStatus *stats);
#endif