/* * 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 . --- 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 #if defined(WIN32) // Windows includes #include // 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(POSIX) // Linux includes/defines #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // rcg06212000 my SDL adds. #include "SDL.h" #include "SDL_thread.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); // 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); // Copies my address into the passed argument void nw_GetMyAddress(network_address *addr); 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... #if defined(POSIX) SDL_Thread *threadId; #endif }; #ifdef WIN32 #define CDECLCALL __cdecl #else #define CDECLCALL #endif #if defined(POSIX) // 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