mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
2134 lines
72 KiB
C++
2134 lines
72 KiB
C++
/*
|
|
* $Logfile: /DescentIII/Main/mac/MACNETWORKING.CPP $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003/08/26 03:58:15 $
|
|
* $Author: kevinb $
|
|
*
|
|
*
|
|
*
|
|
* $Log: MACNETWORKING.CPP,v $
|
|
* Revision 1.1.1.1 2003/08/26 03:58:15 kevinb
|
|
* initial 1.5 import
|
|
*
|
|
*
|
|
* 2 10/21/99 1:55p Kevin
|
|
* Mac Merge!
|
|
*
|
|
* 1 7/28/99 2:31p Kevin
|
|
* Mac only stuff
|
|
*
|
|
*
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "descent.h"
|
|
#include "shippage.h"
|
|
#include "appdatabase.h"
|
|
#include "pstypes.h"
|
|
#include "pserror.h"
|
|
#include "mono.h"
|
|
#include "networking.h"
|
|
#include "ddio.h"
|
|
#include "mem.h"
|
|
#include "game.h"
|
|
#include "args.h"
|
|
#include "pstring.h"
|
|
#include "module.h" //for some nice defines to use below
|
|
#ifndef WIN32
|
|
bool Use_DirectPlay = false;
|
|
#endif
|
|
BOOL TCP_active = FALSE;
|
|
BOOL IPX_active = FALSE;
|
|
BOOL DP_active = FALSE; // Direct Play active
|
|
#ifdef FIXED
|
|
#define MAX_CONNECT_TRIES 50
|
|
#define MAX_RECEIVE_BUFSIZE (1 << 16) // 32 K, eh?
|
|
int Dialup_connection = 0;
|
|
int nw_ServerSocket = -1;
|
|
int nw_ClientSocket = -1;
|
|
network_protocol NetworkProtocol = NP_NONE;
|
|
int Sockets_initted = 0;
|
|
int Network_initted = 0;
|
|
unsigned long Net_fixed_ip = INADDR_NONE;
|
|
// sockets for IPX and TCP
|
|
SOCKET IPX_socket;
|
|
SOCKET IPX_reliable_socket;
|
|
SOCKET IPX_listen_socket;
|
|
SOCKET TCP_socket;
|
|
SOCKET TCP_reliable_socket;
|
|
SOCKET TCP_listen_socket;
|
|
// the sockets that the game will use when selecting network type
|
|
static SOCKET *Unreliable_socket;
|
|
static SOCKET *Reliable_socket;
|
|
static SOCKET *Listen_socket;
|
|
BOOL TCP_active = FALSE;
|
|
BOOL IPX_active = FALSE;
|
|
BOOL DP_active = FALSE; // Direct Play active
|
|
// BOOL TCP_MT_active = FALSE;
|
|
// This structure contains the local computer info
|
|
network_address My_addr;
|
|
typedef struct network_checksum_packet {
|
|
int sequence_number;
|
|
ushort flags;
|
|
ushort checksum;
|
|
ubyte data[MAX_PACKET_SIZE];
|
|
} network_checksum_packet;
|
|
// definition for a non-checksum packet
|
|
typedef struct network_packet {
|
|
int sequence_number;
|
|
ushort flags;
|
|
ubyte data[MAX_PACKET_SIZE];
|
|
} network_naked_packet;
|
|
// structure definition for our packet buffers
|
|
typedef struct network_packet_buffer {
|
|
int sequence_number;
|
|
int len;
|
|
network_address from_addr;
|
|
ubyte data[MAX_PACKET_SIZE];
|
|
} network_packet_buffer;
|
|
#define MAX_PACKET_BUFFERS 96
|
|
static network_packet_buffer Packet_buffers[MAX_PACKET_BUFFERS]; // buffer to hold packets sent to us
|
|
static short Packet_free_list[MAX_PACKET_BUFFERS]; // contains id's of free packet buffers
|
|
static Num_packet_buffers;
|
|
static int Largest_packet_index = 0;
|
|
int Uncompressed_outgoing_data_len = 0;
|
|
int Compressed_outgoing_data_len = 0;
|
|
int Next_packet_id;
|
|
int Last_packet_id;
|
|
// An array of callbacks
|
|
NetworkReceiveCallback Netcallbacks[16];
|
|
#define R_NET_SEQUENCE_NONE 0
|
|
#define R_NET_SEQUENCE_CONNECTING 1
|
|
#define R_NET_SEQUENCE_CONNECTED 2
|
|
#define R_NET_SEQUENCE_FAILED 3
|
|
#define R_NET_PACKET_QUEUE_TIME .1f
|
|
int Net_connect_socket_id = INVALID_SOCKET;
|
|
int Net_connect_sequence = R_NET_SEQUENCE_NONE;
|
|
// ------------------------------------------------------------------------------------------------------
|
|
// PACKET BUFFERING FUNCTIONS
|
|
//
|
|
// a sequence number of -1 will indicate that this packet is not valid
|
|
network_packet_buffer Psnet_buffers[MAX_PACKET_BUFFERS];
|
|
int Psnet_seq_number = 0;
|
|
int Psnet_lowest_id = 0;
|
|
int Psnet_highest_id = 0;
|
|
// Reliable UDP stuff
|
|
//*******************************
|
|
#ifdef WIN32
|
|
#pragma pack(push, r_udp)
|
|
#endif
|
|
#pragma pack(1)
|
|
typedef struct {
|
|
ubyte type; // packet type
|
|
ubyte compressed; //
|
|
ushort seq; // sequence packet 0-65535 used for ACKing also
|
|
ushort data_len; // length of data
|
|
float send_time; // Time the packet was sent, if an ACK the time the packet being ACK'd was sent.
|
|
ubyte data[NETBUFFERSIZE]; // Packet data
|
|
} reliable_header;
|
|
#define RELIABLE_PACKET_HEADER_ONLY_SIZE (sizeof(reliable_header) - NETBUFFERSIZE)
|
|
#define MAX_PING_HISTORY 10
|
|
typedef struct {
|
|
ubyte buffer[NETBUFFERSIZE];
|
|
} reliable_net_sendbuffer;
|
|
typedef struct {
|
|
ubyte buffer[NETBUFFERSIZE];
|
|
} reliable_net_rcvbuffer;
|
|
SOCKET Reliable_UDP_socket = INVALID_SOCKET;
|
|
SOCKET Reliable_IPX_socket = INVALID_SOCKET;
|
|
float first_sent_iamhere = 0;
|
|
float last_sent_iamhere = 0;
|
|
unsigned int serverconn = 0xFFFFFFFF;
|
|
#ifdef WIN32
|
|
#pragma pack(pop, r_udp)
|
|
#elif defined(__LINUX__)
|
|
#pragma pack()
|
|
#endif
|
|
typedef struct {
|
|
|
|
float timesent[MAXNETBUFFERS];
|
|
int send_len[MAXNETBUFFERS];
|
|
int recv_len[MAXNETBUFFERS];
|
|
float last_packet_received; // For a given connection, this is the last packet we received
|
|
float last_packet_sent;
|
|
float pings[MAX_PING_HISTORY];
|
|
unsigned int num_ping_samples;
|
|
float mean_ping;
|
|
float last_sent; // The last time we sent a packet (used for NAGLE emulation)
|
|
int waiting_packet_number; // Which packet has data in it that is waiting for the interval to send
|
|
ushort status; // Status of this connection
|
|
unsigned short oursequence; // This is the next sequence number the application is expecting
|
|
unsigned short theirsequence; // This is the next sequence number the peer is expecting
|
|
unsigned short rsequence[MAXNETBUFFERS]; // This is the sequence number of the given packet
|
|
ubyte ping_pos;
|
|
|
|
network_address net_addr; // A D3 network address structure
|
|
network_protocol connection_type; // IPX, IP, modem, etc.
|
|
reliable_net_rcvbuffer *rbuffers[MAXNETBUFFERS];
|
|
SOCKADDR addr; // SOCKADDR of our peer
|
|
reliable_net_sendbuffer *sbuffers[MAXNETBUFFERS]; // This is an array of pointers for quick sorting
|
|
unsigned short ssequence[MAXNETBUFFERS]; // This is the sequence number of the given packet
|
|
ubyte send_urgent;
|
|
} reliable_socket;
|
|
reliable_socket reliable_sockets[MAXRELIABLESOCKETS];
|
|
#endif // FIXED
|
|
//*******************************
|
|
void CloseNetworking() {
|
|
#ifdef FIXED
|
|
ASSERT(Network_initted == 1);
|
|
ASSERT(Sockets_initted == 1);
|
|
mprintf((0, "Shutting down networking...\n"));
|
|
if (IPX_socket != INVALID_SOCKET) {
|
|
shutdown(IPX_socket, 1);
|
|
#ifdef WIN32
|
|
closesocket(IPX_socket);
|
|
#else
|
|
close(IPX_socket);
|
|
#endif
|
|
}
|
|
if (TCP_socket != INVALID_SOCKET) {
|
|
shutdown(TCP_socket, 1);
|
|
#ifdef WIN32
|
|
closesocket(TCP_socket);
|
|
#else
|
|
close(TCP_socket);
|
|
#endif
|
|
}
|
|
|
|
Network_initted = 0;
|
|
Sockets_initted = 0;
|
|
NetworkProtocol = NP_NONE;
|
|
|
|
#endif // FIXED
|
|
}
|
|
// Inits the sockets layer to activity
|
|
void nw_InitNetworking() {
|
|
#ifdef FIXED
|
|
static char exewithpath[_MAX_PATH * 2];
|
|
static char exefile[_MAX_PATH * 2];
|
|
static char ourargs[_MAX_PATH * 2];
|
|
static char exedir[_MAX_PATH * 2];
|
|
static char exeext[_MAX_PATH];
|
|
static char *fixdir;
|
|
static char szconntype[100];
|
|
int parmlen;
|
|
int len = 99;
|
|
Database->read("NetworkConnection", szconntype, &len);
|
|
if (strcmpi(szconntype, "DIALUP") == 0) {
|
|
Dialup_connection = 1;
|
|
} else {
|
|
Dialup_connection = 0;
|
|
}
|
|
int iparg;
|
|
iparg = FindArg("-useip");
|
|
if (!iparg) {
|
|
iparg = FindArg("+ip");
|
|
}
|
|
if (iparg) {
|
|
Net_fixed_ip = inet_addr(GameArgs[iparg + 1]);
|
|
if (Net_fixed_ip == INADDR_NONE) {
|
|
Net_fixed_ip = INADDR_NONE;
|
|
}
|
|
}
|
|
#ifdef WIN32
|
|
if (!dp_DidLobbyLaunchGame()) {
|
|
// Tell direct play about this game
|
|
char *p = GetCommandLine();
|
|
mprintf((0, "Command line: %s\n", p));
|
|
parmlen = strlen(p);
|
|
for (int a = 0; a < parmlen; a++) {
|
|
if (p[a] == ' ') {
|
|
break;
|
|
}
|
|
}
|
|
if (a < parmlen) {
|
|
strcpy(ourargs, p + a + 1);
|
|
} else
|
|
strcpy(ourargs, "");
|
|
strncpy(exewithpath, p, a);
|
|
exewithpath[a] = NULL;
|
|
ddio_SplitPath(exewithpath, exedir, exefile, exeext);
|
|
if (exedir[0] == '\"')
|
|
fixdir = exedir + 1;
|
|
else
|
|
fixdir = exedir;
|
|
if (exeext[strlen(exeext) - 1] == '\"')
|
|
exeext[strlen(exeext) - 1] = NULL;
|
|
strcat(exefile, exeext);
|
|
// dp_RegisterLobbyApplication("Descent 3",exefile,fixdir,ourargs,Base_directory,"Descent 3");
|
|
}
|
|
#endif
|
|
#ifdef WIN32
|
|
int error = WSAStartup(ver, &ws_data);
|
|
#else
|
|
int error = 0;
|
|
#endif
|
|
if (error != 0) {
|
|
mprintf((0, "There was an error initializing networking! Error=%d\n", error));
|
|
return;
|
|
} else {
|
|
mprintf((0, "Network initted successfully!\n"));
|
|
Network_initted = 1;
|
|
atexit(CloseNetworking);
|
|
}
|
|
#endif // FIXED
|
|
}
|
|
// Sets the size of buffers
|
|
void nw_SetSocketOptions(SOCKET sock) {
|
|
#ifdef FIXED
|
|
int broadcast;
|
|
int ret, cursize, cursizesize, bufsize, trysize;
|
|
// Set the mode of the socket to allow broadcasting. We need to be able to broadcast
|
|
// when a game is searched for in IPX mode.
|
|
broadcast = 1;
|
|
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (LPSTR)&broadcast, sizeof(broadcast));
|
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (LPSTR)&broadcast, sizeof(broadcast));
|
|
|
|
int error;
|
|
unsigned long arg;
|
|
arg = TRUE;
|
|
#ifdef WIN32
|
|
error = ioctlsocket(sock, FIONBIO, &arg);
|
|
#elif defined(__LINUX__)
|
|
error = ioctl(sock, FIONBIO, &arg);
|
|
#endif
|
|
if (error == SOCKET_ERROR) {
|
|
mprintf((0, "Unable to make socket non-blocking -- %d", WSAGetLastError()));
|
|
}
|
|
|
|
// try and increase the size of my receive buffer
|
|
bufsize = MAX_RECEIVE_BUFSIZE;
|
|
|
|
// set the current size of the receive buffer
|
|
cursizesize = sizeof(int);
|
|
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (LPSTR)&cursize, &cursizesize);
|
|
for (trysize = bufsize; trysize >= cursize; trysize >>= 1) {
|
|
ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (LPSTR)&trysize, sizeof(trysize));
|
|
if (ret == SOCKET_ERROR) {
|
|
int wserr;
|
|
wserr = WSAGetLastError();
|
|
if ((wserr == WSAENOPROTOOPT) || (wserr == WSAEINVAL))
|
|
break;
|
|
} else
|
|
break;
|
|
}
|
|
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (LPSTR)&cursize, &cursizesize);
|
|
mprintf((0, "Receive buffer set to %d\n", cursize));
|
|
/*
|
|
// set the current size of the send buffer
|
|
bufsize = MAX_RECEIVE_BUFSIZE/4;
|
|
cursizesize = sizeof(int);
|
|
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (LPSTR)&cursize, &cursizesize);
|
|
for ( trysize = bufsize; trysize >= cursize; trysize >>= 1 )
|
|
{
|
|
ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (LPSTR)&trysize, sizeof(trysize));
|
|
if ( ret == SOCKET_ERROR )
|
|
{
|
|
int wserr;
|
|
wserr = WSAGetLastError();
|
|
if ( (wserr == WSAENOPROTOOPT) || (wserr == WSAEINVAL) )
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (LPSTR)&cursize, &cursizesize);
|
|
mprintf((0, "Send buffer set to %d\n", cursize));
|
|
*/
|
|
#endif // FIXED
|
|
}
|
|
unsigned short nw_ListenPort = 0;
|
|
// Inits the sockets that the application will be using
|
|
void nw_InitSockets(ushort port) {
|
|
#ifdef FIXED
|
|
|
|
nw_ListenPort = port;
|
|
// UDP/TCP socket structure
|
|
SOCKADDR_IN sock_addr;
|
|
// IPX socket structure
|
|
SOCKADDR_IPX ipx_addr;
|
|
|
|
// Initialize IPX stuff first
|
|
IPX_active = 0;
|
|
IPX_socket = INVALID_SOCKET;
|
|
IPX_reliable_socket = INVALID_SOCKET;
|
|
IPX_listen_socket = INVALID_SOCKET;
|
|
IPX_socket = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
|
if (IPX_socket != INVALID_SOCKET) {
|
|
memset(&ipx_addr, 0, sizeof(SOCKADDR_IPX));
|
|
#ifdef WIN32
|
|
ipx_addr.sa_socket = htons(port);
|
|
ipx_addr.sa_family = AF_IPX;
|
|
#else
|
|
ipx_addr.sipx_port = htons(port);
|
|
ipx_addr.sipx_family = AF_IPX;
|
|
#endif
|
|
if (bind(IPX_socket, (SOCKADDR *)&ipx_addr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR) {
|
|
mprintf((0, "Couldn't bind IPX socket (%d)! Invalidating IPX\n", WSAGetLastError()));
|
|
goto init_tcp;
|
|
}
|
|
nw_SetSocketOptions(IPX_socket);
|
|
IPX_active = 1;
|
|
} else {
|
|
mprintf((0, "Cannot create IPX socket (%d)!\n", WSAGetLastError()));
|
|
}
|
|
init_tcp:
|
|
// Now do tcp!
|
|
TCP_active = 0;
|
|
TCP_socket = INVALID_SOCKET;
|
|
// TCP_reliable_socket = INVALID_SOCKET;
|
|
TCP_listen_socket = INVALID_SOCKET;
|
|
// Initialize the UDP socket
|
|
TCP_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
// Initialize all reliable sockets, IPX and TCP
|
|
nw_InitReliableSocket();
|
|
|
|
if (TCP_socket != INVALID_SOCKET) {
|
|
// bind the socket
|
|
memset(&sock_addr, 0, sizeof(SOCKADDR_IN));
|
|
sock_addr.sin_family = AF_INET;
|
|
|
|
unsigned int my_ip;
|
|
|
|
my_ip = nw_GetThisIP();
|
|
memcpy(&sock_addr.sin_addr.s_addr, &my_ip, sizeof(uint));
|
|
sock_addr.sin_port = htons(port);
|
|
if (bind(TCP_socket, (SOCKADDR *)&sock_addr, sizeof(sock_addr)) == SOCKET_ERROR) {
|
|
mprintf((0, "Couldn't bind TCP socket (%d)! Invalidating TCP\n", WSAGetLastError()));
|
|
goto tcp_done;
|
|
}
|
|
nw_SetSocketOptions(TCP_socket);
|
|
TCP_active = 1;
|
|
} else {
|
|
mprintf((0, "Cannot create TCP socket (%d)!\n", WSAGetLastError()));
|
|
}
|
|
|
|
tcp_done:
|
|
int ret;
|
|
unsigned int isocktrue = 1;
|
|
setsockopt(IPX_socket, SOL_SOCKET, SO_REUSEADDR, (LPSTR)&isocktrue, sizeof(isocktrue));
|
|
ret = setsockopt(IPX_socket, SOL_SOCKET, SO_BROADCAST, (LPSTR)&isocktrue, sizeof(unsigned int));
|
|
if (ret == SOCKET_ERROR) {
|
|
int wserr;
|
|
wserr = WSAGetLastError();
|
|
if ((wserr == WSAENOPROTOOPT) || (wserr == WSAEINVAL)) {
|
|
mprintf((0, "Unable to make socket broadcastable!"));
|
|
Int3(); // Get Kevin
|
|
}
|
|
}
|
|
setsockopt(TCP_socket, SOL_SOCKET, SO_REUSEADDR, (LPSTR)&isocktrue, sizeof(isocktrue));
|
|
ret = setsockopt(TCP_socket, SOL_SOCKET, SO_BROADCAST, (LPSTR)&isocktrue, sizeof(unsigned int));
|
|
if (ret == SOCKET_ERROR) {
|
|
int wserr;
|
|
wserr = WSAGetLastError();
|
|
if ((wserr == WSAENOPROTOOPT) || (wserr == WSAEINVAL)) {
|
|
mprintf((0, "Unable to make socket broadcastable!"));
|
|
Int3(); // Get Kevin
|
|
}
|
|
}
|
|
Sockets_initted = 1;
|
|
if (TCP_active)
|
|
mprintf((0, "TCP Initialized\n"));
|
|
if (IPX_active)
|
|
mprintf((0, "IPX Initialized\n"));
|
|
|
|
nw_psnet_buffer_init();
|
|
nw_RegisterCallback((NetworkReceiveCallback)nw_HandleUnreliableData, NWT_UNRELIABLE);
|
|
#endif // FIXED
|
|
}
|
|
// Copies my address into the passed argument
|
|
void nw_GetMyAddress(network_address *addr) {
|
|
#ifdef FIXED
|
|
int len;
|
|
SOCKADDR_IN in_addr;
|
|
SOCKADDR_IPX ipx_addr;
|
|
memset(&My_addr, 0, sizeof(network_address));
|
|
if (TCP_active) {
|
|
// assign the TCP_* sockets to the socket values used elsewhere
|
|
Unreliable_socket = &TCP_socket;
|
|
Reliable_socket = &TCP_reliable_socket;
|
|
Listen_socket = &TCP_listen_socket;
|
|
// get the socket name for the TCP_socket, and put it into My_addr
|
|
len = sizeof(SOCKADDR_IN);
|
|
if (getsockname(*Unreliable_socket, (SOCKADDR *)&in_addr, &len) == SOCKET_ERROR) {
|
|
mprintf((0, "Unable to get sock name for TCP unreliable socket (%s)\n", WSAGetLastError()));
|
|
return;
|
|
}
|
|
memcpy(My_addr.address, &in_addr.sin_addr, 4);
|
|
// My_addr.port = in_addr.sin_port;
|
|
My_addr.port = ntohs(in_addr.sin_port);
|
|
} else if (IPX_active) {
|
|
// assign the IPX_* sockets to the socket values used elsewhere
|
|
Unreliable_socket = &IPX_socket;
|
|
Reliable_socket = &IPX_reliable_socket;
|
|
Listen_socket = &IPX_listen_socket;
|
|
// get the socket name for the IPX_socket, and put it into My_addr
|
|
len = sizeof(SOCKADDR_IPX);
|
|
if (getsockname(IPX_socket, (SOCKADDR *)&ipx_addr, &len) == SOCKET_ERROR) {
|
|
mprintf((0, "Unable to get sock name for IPX unreliable socket (%d)\n", WSAGetLastError()));
|
|
return;
|
|
}
|
|
#ifdef WIN32
|
|
memcpy(My_addr.net_id, ipx_addr.sa_netnum, 4);
|
|
memcpy(My_addr.address, ipx_addr.sa_nodenum, 6);
|
|
#else
|
|
memcpy(My_addr.net_id, &ipx_addr.sipx_network, 4);
|
|
memcpy(My_addr.address, ipx_addr.sipx_node, 6);
|
|
#endif
|
|
My_addr.port = DEFAULT_GAME_PORT;
|
|
}
|
|
*addr = My_addr;
|
|
#endif // FIXED
|
|
}
|
|
// Returns internet address format from string address format...ie "204.243.217.14"
|
|
// turns into 1414829242
|
|
unsigned long nw_GetHostAddressFromNumbers(char *str) {
|
|
#ifdef FIXED
|
|
// ASSERT (NetworkProtocol==NP_TCP);
|
|
return inet_addr(str);
|
|
#endif // FIXED
|
|
}
|
|
// Fills in the string with the string address from the internet address
|
|
void nw_GetNumbersFromHostAddress(network_address *address, char *str) {
|
|
#ifdef FIXED
|
|
// ASSERT(NetworkProtocol==NP_TCP);
|
|
ASSERT(str);
|
|
struct in_addr addr;
|
|
if (address->connection_type == NP_TCP) {
|
|
memcpy(&addr, address->address, sizeof(struct in_addr));
|
|
sprintf(str, "IP: %s:%d", inet_ntoa(addr), address->port);
|
|
} else if (address->connection_type == NP_IPX) {
|
|
char sznet[10] = "";
|
|
char sznode[20] = "";
|
|
char sztmp[4];
|
|
int i;
|
|
for (i = 0; i < 4; i++) {
|
|
sprintf(sztmp, "%.2X", address->net_id[i]);
|
|
strcat(sznet, sztmp);
|
|
}
|
|
for (i = 0; i < 6; i++) {
|
|
sprintf(sztmp, "%.2X", address->address[i]);
|
|
strcat(sznode, sztmp);
|
|
}
|
|
sprintf(str, "IPX: %s:%s:%d", sznet, sznode, address->port);
|
|
}
|
|
#ifdef WIN32
|
|
else if (Use_DirectPlay && (address->connection_type == NP_DIRECTPLAY)) {
|
|
DPID id;
|
|
memcpy(&id, address->address, sizeof(DPID));
|
|
sprintf(str, "DirectPlay: 0x%x", id);
|
|
}
|
|
#endif
|
|
#endif // FIXED
|
|
}
|
|
#define CLOSE_TIMEOUT_TIME 3 // 3 seconds
|
|
// returns the ip address of this computer
|
|
unsigned int nw_GetThisIP() {
|
|
#ifdef FIXED
|
|
SOCKADDR_IN local_address;
|
|
int address_size = sizeof(SOCKADDR);
|
|
|
|
if (Net_fixed_ip != INADDR_NONE) {
|
|
return Net_fixed_ip;
|
|
}
|
|
// Init local address to zero
|
|
local_address.sin_addr.s_addr = INADDR_ANY;
|
|
if (Dialup_connection) {
|
|
#ifdef WIN32
|
|
local_address.sin_addr.s_addr = psnet_ras_status();
|
|
#else
|
|
local_address.sin_addr.s_addr = INADDR_ANY;
|
|
#endif
|
|
}
|
|
if ((!Dialup_connection) || (!local_address.sin_addr.s_addr)) {
|
|
// Removed the fancy way, it worked worse than the easy way (some adsl/cable people had problems.
|
|
/*
|
|
// Get the local host name
|
|
ret = gethostname(local, 255 );
|
|
if (ret != SOCKET_ERROR )
|
|
{
|
|
// Resolve host name for local address
|
|
hostent = gethostbyname((LPSTR)local);
|
|
if ( hostent )
|
|
local_address.sin_addr.s_addr = *((u_long FAR *)(hostent->h_addr));
|
|
}
|
|
*/
|
|
local_address.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
return local_address.sin_addr.s_addr;
|
|
|
|
#endif // FIXED
|
|
}
|
|
// Calculates a unique ushort checksum for a stream of data
|
|
ushort nw_CalculateChecksum(void *vptr, int len) {
|
|
ubyte *ptr = (ubyte *)vptr;
|
|
unsigned int sum1, sum2;
|
|
sum1 = sum2 = 0;
|
|
while (len--) {
|
|
sum1 += *ptr++;
|
|
if (sum1 >= 255)
|
|
sum1 -= 255;
|
|
sum2 += sum1;
|
|
}
|
|
sum2 %= 255;
|
|
|
|
return (unsigned short)((sum1 << 8) + sum2);
|
|
}
|
|
// Sends data on an unreliable socket
|
|
int nw_Send(network_address *who_to, void *data, int len, int flags) {
|
|
#ifdef FIXED
|
|
if (len == 0) {
|
|
mprintf((0, "Attempting to send 0 byte network packet in nw_Send()\n"));
|
|
Int3();
|
|
}
|
|
return nw_SendWithID(NWT_UNRELIABLE, (ubyte *)data, len, who_to);
|
|
#endif // FIXED
|
|
}
|
|
void nw_HandleUnreliableData(ubyte *data, int len, network_address *from_addr) {
|
|
#ifdef FIXED
|
|
nw_psnet_buffer_packet((ubyte *)data, len, from_addr);
|
|
#endif // FIXED
|
|
}
|
|
// routine to "free" a packet buffer
|
|
void nw_FreePacket(int id) {
|
|
#ifdef FIXED
|
|
Packet_buffers[id].sequence_number = -1;
|
|
Packet_free_list[--Num_packet_buffers] = (short)id;
|
|
if (Largest_packet_index == id)
|
|
while ((--Largest_packet_index > 0) && (Packet_buffers[Largest_packet_index].sequence_number == -1))
|
|
;
|
|
#endif // FIXED
|
|
}
|
|
// 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) {
|
|
#ifdef FIXED
|
|
// call the routine to read data out of the socket (which stuffs it into the packet buffers)
|
|
if (Use_DirectPlay) {
|
|
#ifdef WIN32
|
|
dp_DirectPlayDispatch();
|
|
#endif
|
|
} else {
|
|
// nw_ReceiveFromSocket();
|
|
nw_DoReceiveCallbacks();
|
|
}
|
|
|
|
int buffer_size;
|
|
// try and get a free buffer and return its size
|
|
if (nw_psnet_buffer_get_next((ubyte *)data, &buffer_size, from_addr)) {
|
|
return buffer_size;
|
|
}
|
|
return 0;
|
|
#endif // FIXED
|
|
}
|
|
int ExtraBufferTempHack = 0;
|
|
// Temp hack to figure out this buffer overflow thing
|
|
// Return codes:
|
|
//-1 socket not connected
|
|
// 0 No packet ready to receive
|
|
// >0 Buffer filled with the number of bytes recieved
|
|
int nw_ReceiveReliable(unsigned int socketid, ubyte *buffer, int max_len) {
|
|
#ifdef FIXED
|
|
|
|
int i;
|
|
if (Use_DirectPlay) {
|
|
#ifdef WIN32
|
|
dp_DirectPlayDispatch();
|
|
|
|
// try and get a free buffer and return its size
|
|
if (nw_psnet_buffer_get_next_by_dpid((ubyte *)buffer, &max_len, socketid)) {
|
|
return max_len;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
reliable_socket *rsocket = NULL;
|
|
// nw_WorkReliable();
|
|
nw_DoReceiveCallbacks();
|
|
if (socketid >= MAXRELIABLESOCKETS) {
|
|
mprintf((0, "Invalid socket id passed to nw_NewReceiveReliable() -- %d\n", socketid));
|
|
return -1;
|
|
}
|
|
rsocket = &reliable_sockets[socketid];
|
|
if ((RNF_CONNECTED != rsocket->status) && (RNF_LIMBO != rsocket->status)) {
|
|
mprintf((0, "Can't receive packet because it isn't connected in nw_ReceiveReliable(). socket = %d\n", socketid));
|
|
return 0;
|
|
}
|
|
// If the buffer position is the position we are waiting for, fill in
|
|
// the buffer we received in the call to this function and return true
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
if ((rsocket->rsequence[i] == rsocket->oursequence) && (rsocket->rbuffers[i])) {
|
|
memcpy(buffer, rsocket->rbuffers[i]->buffer, rsocket->recv_len[i]);
|
|
mem_free(rsocket->rbuffers[i]);
|
|
rsocket->rbuffers[i] = NULL;
|
|
rsocket->rsequence[i] = 0;
|
|
// mprintf((0,"Found packet for upper layer in nw_ReceiveReliable() %d bytes.
|
|
// seq:%d.\n",rsocket->recv_len[i],rsocket->oursequence));
|
|
rsocket->oursequence++;
|
|
return rsocket->recv_len[i];
|
|
}
|
|
}
|
|
#endif // FIXED
|
|
return 0;
|
|
}
|
|
// This function will look for a control packet, indicating a
|
|
// desire to establish a reliable link.
|
|
// When is makes a link, it will return a SOCKET, and fill in from_addr.
|
|
// if there is no waiting line, it returns -1
|
|
int nw_CheckListenSocket(network_address *from_addr) {
|
|
#ifdef FIXED
|
|
SOCKADDR_IN *ip_addr; // UDP/TCP socket structure
|
|
SOCKADDR_IPX *ipx_addr; // IPX socket structure
|
|
#ifdef WIN32
|
|
DPID id;
|
|
#endif
|
|
if (Use_DirectPlay) {
|
|
#ifdef WIN32
|
|
// look for a pending connection
|
|
for (int i = 0; i < MAX_PENDING_NEW_CONNECTIONS; i++) {
|
|
if (Pending_dp_conn[i] != DPID_UNKNOWN) {
|
|
memset(from_addr, 0, sizeof(network_address));
|
|
memcpy(from_addr->address, &Pending_dp_conn[i], sizeof(DPID));
|
|
from_addr->connection_type = NP_DIRECTPLAY;
|
|
id = Pending_dp_conn[i];
|
|
Pending_dp_conn[i] = DPID_UNKNOWN;
|
|
mprintf((0, "New DirectPlay connection in nw_CheckListenSocket().\n"));
|
|
return id;
|
|
}
|
|
}
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
// nw_WorkReliable();
|
|
nw_DoReceiveCallbacks();
|
|
int i;
|
|
for (i = 1; i < MAXRELIABLESOCKETS; i++) {
|
|
if (reliable_sockets[i].status == RNF_CONNECTING) {
|
|
reliable_sockets[i].status = RNF_CONNECTED;
|
|
// memcpy(from_addr,&reliable_sockets[i].addr,sizeof(SOCKADDR));
|
|
mprintf((0, "New reliable connection in nw_CheckListenSocket().\n"));
|
|
|
|
switch (reliable_sockets[i].connection_type) {
|
|
case NP_IPX:
|
|
ipx_addr = (SOCKADDR_IPX *)&reliable_sockets[i].addr;
|
|
memset(from_addr, 0x00, sizeof(network_address));
|
|
#ifdef WIN32
|
|
from_addr->port = ntohs(ipx_addr->sa_socket);
|
|
from_addr->connection_type = NP_IPX;
|
|
memcpy(from_addr->address, ipx_addr->sa_nodenum, 6);
|
|
memcpy(from_addr->net_id, ipx_addr->sa_netnum, 4);
|
|
#else
|
|
from_addr->port = ntohs(ipx_addr->sipx_port);
|
|
from_addr->connection_type = NP_IPX;
|
|
memcpy(from_addr->address, ipx_addr->sipx_node, 6);
|
|
memcpy(from_addr->net_id, &ipx_addr->sipx_network, 4);
|
|
#endif
|
|
break;
|
|
case NP_TCP:
|
|
ip_addr = (SOCKADDR_IN *)&reliable_sockets[i].addr;
|
|
memset(from_addr, 0x00, sizeof(network_address));
|
|
from_addr->port = ntohs(ip_addr->sin_port);
|
|
from_addr->connection_type = NP_TCP;
|
|
#ifdef WIN32
|
|
memcpy(from_addr->address, &ip_addr->sin_addr.S_un.S_addr, 4);
|
|
#else
|
|
memcpy(from_addr->address, &ip_addr->sin_addr.s_addr, 4);
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
Int3();
|
|
break;
|
|
}
|
|
char dbg_output[50];
|
|
nw_GetNumbersFromHostAddress(from_addr, dbg_output);
|
|
mprintf((0, "Got address from: %s\n", dbg_output));
|
|
return i;
|
|
}
|
|
}
|
|
#endif // FIXED
|
|
return INVALID_SOCKET;
|
|
}
|
|
int nw_SendReliable(unsigned int socketid, ubyte *data, int length, bool urgent) {
|
|
#ifdef FIXED
|
|
int i;
|
|
int bytesout;
|
|
int use_buffer = -1;
|
|
reliable_socket *rsocket;
|
|
reliable_header send_header;
|
|
int send_this_packet = 1;
|
|
|
|
if (length == 0) {
|
|
mprintf((0, "Attempting to send 0 byte network packet in nw_SendReliable()\n"));
|
|
Int3();
|
|
}
|
|
// mprintf((0,"Socket id passed to nw_NewSendReliable() -- %d\n",socketid));
|
|
if (Use_DirectPlay) {
|
|
#ifdef WIN32
|
|
network_address who_to;
|
|
who_to.connection_type = NP_DIRECTPLAY;
|
|
memcpy(&who_to.address, &socketid, sizeof(DPID));
|
|
return dp_DirectPlaySend(&who_to, data, length, true);
|
|
#endif
|
|
}
|
|
ASSERT(length < sizeof(reliable_header));
|
|
// nw_WorkReliable();
|
|
nw_DoReceiveCallbacks();
|
|
|
|
if (socketid >= MAXRELIABLESOCKETS) {
|
|
mprintf((0, "Invalid socket id passed to nw_NewSendReliable() -- %d\n", socketid));
|
|
return -1;
|
|
}
|
|
rsocket = &reliable_sockets[socketid];
|
|
if (rsocket->status != RNF_CONNECTED) {
|
|
// We can't send because this isn't a connected reliable socket.
|
|
mprintf(
|
|
(0, "Can't send packet because of status %d in nw_SendReliable(). socket = %d\n", rsocket->status, socketid));
|
|
return -1;
|
|
}
|
|
if (urgent)
|
|
rsocket->send_urgent = 1;
|
|
// See if there is a packet waiting to be sent
|
|
if (-1 != rsocket->waiting_packet_number) {
|
|
int pnum = rsocket->waiting_packet_number;
|
|
ASSERT(rsocket->sbuffers[pnum]);
|
|
// See if there's room for this data
|
|
if (sizeof(reliable_net_sendbuffer) < (rsocket->send_len[pnum] + length)) {
|
|
// Send the previous packet, then use the normal code to generate a new packet
|
|
mprintf((0, "Pending reliable packet buffer full, sending packet now.\n"));
|
|
rsocket->waiting_packet_number = -1;
|
|
use_buffer = pnum;
|
|
network_address send_address;
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
|
|
memcpy(send_header.data, rsocket->sbuffers[pnum], rsocket->send_len[pnum]);
|
|
send_header.data_len = rsocket->send_len[pnum];
|
|
send_header.type = RNT_DATA;
|
|
send_header.send_time = timer_GetTime();
|
|
send_address.connection_type = rsocket->connection_type;
|
|
if (NP_IPX == rsocket->connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&rsocket->addr;
|
|
#ifdef WIN32
|
|
memcpy(send_address.address, ipxaddr->sa_nodenum, 6);
|
|
memcpy(send_address.net_id, ipxaddr->sa_netnum, 4);
|
|
send_address.port = htons(ipxaddr->sa_socket);
|
|
#else
|
|
memcpy(send_address.address, ipxaddr->sipx_node, 6);
|
|
memcpy(send_address.net_id, &ipxaddr->sipx_network, 4);
|
|
send_address.port = htons(ipxaddr->sipx_port);
|
|
#endif
|
|
send_address.connection_type = NP_IPX;
|
|
} else if (NP_TCP == rsocket->connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&rsocket->addr;
|
|
memcpy(send_address.address, &inaddr->sin_addr, 4);
|
|
send_address.port = htons(inaddr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
}
|
|
bytesout = nw_SendWithID(NWT_RELIABLE, (ubyte *)&send_header,
|
|
RELIABLE_PACKET_HEADER_ONLY_SIZE + rsocket->send_len[use_buffer], &send_address);
|
|
|
|
if ((bytesout == SOCKET_ERROR) && (WSAEWOULDBLOCK == WSAGetLastError())) {
|
|
// This will cause it to try to send again next frame. (or sooner)
|
|
rsocket->timesent[use_buffer] = timer_GetTime() - (NETRETRYTIME * 4);
|
|
} else {
|
|
rsocket->timesent[use_buffer] = timer_GetTime();
|
|
}
|
|
} else {
|
|
// tack this data on the end of the previous packet
|
|
// mprintf((0,"Appending to delayed packet...\n"));
|
|
ASSERT(rsocket->sbuffers[pnum]);
|
|
memcpy(rsocket->sbuffers[pnum]->buffer + rsocket->send_len[pnum], data, length);
|
|
int msize = mem_size(rsocket->sbuffers[pnum]);
|
|
rsocket->send_len[pnum] += length;
|
|
return length;
|
|
}
|
|
}
|
|
|
|
// Add the new packet to the sending list and send it.
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
use_buffer = -1;
|
|
if (NULL == rsocket->sbuffers[i]) {
|
|
// mprintf((0,"Sending in nw_SendReliable() %d bytes seq=%d.\n",length,rsocket->theirsequence));
|
|
|
|
rsocket->send_len[i] = length;
|
|
rsocket->sbuffers[i] = (reliable_net_sendbuffer *)mem_malloc(sizeof(reliable_net_sendbuffer));
|
|
|
|
memcpy(rsocket->sbuffers[i]->buffer, data, length);
|
|
send_header.seq = rsocket->theirsequence;
|
|
rsocket->ssequence[i] = rsocket->theirsequence;
|
|
|
|
use_buffer = i;
|
|
rsocket->waiting_packet_number = i;
|
|
|
|
rsocket->theirsequence++;
|
|
return length;
|
|
}
|
|
}
|
|
mprintf((0, "Can't send packet because a buffer overflow nw_SendReliable(). socket = %d\n", socketid));
|
|
rsocket->status = RNF_BROKEN;
|
|
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
if (rsocket->sbuffers[i]) {
|
|
mprintf((0, "Buffer %d: %d,%d,%d,%d,%d,%d\n", i, rsocket->sbuffers[i]->buffer[0], rsocket->sbuffers[i]->buffer[1],
|
|
rsocket->sbuffers[i]->buffer[2], rsocket->sbuffers[i]->buffer[3], rsocket->sbuffers[i]->buffer[4],
|
|
rsocket->sbuffers[i]->buffer[5]));
|
|
}
|
|
}
|
|
|
|
// Error ("Couldn't send packet because of buffer overflow!");
|
|
// Int3();
|
|
#endif // FIXED
|
|
return 0;
|
|
}
|
|
int nw_InitReliableSocket() {
|
|
#ifdef FIXED
|
|
nw_RegisterCallback((NetworkReceiveCallback)nw_WorkReliable, NWT_RELIABLE);
|
|
#endif // FIXED
|
|
return 1;
|
|
}
|
|
void nw_SendReliableAck(SOCKADDR *raddr, unsigned int sig, network_protocol link_type, float time_sent) {
|
|
#ifdef FIXED
|
|
int ret;
|
|
reliable_header ack_header;
|
|
ack_header.type = RNT_ACK;
|
|
// mprintf((0,"Sending ACK for sig %d.\n",sig));
|
|
ack_header.data_len = sizeof(unsigned int);
|
|
ack_header.send_time = time_sent;
|
|
memcpy(&ack_header.data, &sig, sizeof(unsigned int));
|
|
|
|
network_address send_address;
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
|
|
send_address.connection_type = reliable_sockets[serverconn].connection_type;
|
|
if (NP_IPX == link_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)raddr;
|
|
#ifdef WIN32
|
|
memcpy(send_address.address, ipxaddr->sa_nodenum, 6);
|
|
memcpy(send_address.net_id, ipxaddr->sa_netnum, 4);
|
|
send_address.port = htons(ipxaddr->sa_socket);
|
|
#else
|
|
memcpy(send_address.address, ipxaddr->sipx_node, 6);
|
|
memcpy(send_address.net_id, &ipxaddr->sipx_network, 4);
|
|
send_address.port = htons(ipxaddr->sipx_port);
|
|
#endif
|
|
send_address.connection_type = NP_IPX;
|
|
} else if (NP_TCP == link_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)raddr;
|
|
memcpy(send_address.address, &inaddr->sin_addr, 4);
|
|
send_address.port = htons(inaddr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
}
|
|
ret = nw_SendWithID(NWT_RELIABLE, (ubyte *)&ack_header, RELIABLE_PACKET_HEADER_ONLY_SIZE + sizeof(unsigned int),
|
|
&send_address);
|
|
#endif // FIXED
|
|
}
|
|
void nw_DoNetworkIdle(void) {
|
|
#ifdef FIXED
|
|
if (!Use_DirectPlay) {
|
|
nw_DoReceiveCallbacks();
|
|
nw_ReliableResend();
|
|
}
|
|
#endif // FIXED
|
|
}
|
|
#define CONNECTSEQ 0x142 // Magic number for starting a connection, just so it isn't 0
|
|
void nw_WorkReliable(ubyte *data, int len, network_address *naddr) {
|
|
#ifdef FIXED
|
|
int i;
|
|
int rcode = -1;
|
|
int max_len = NETBUFFERSIZE;
|
|
static reliable_header rcv_buff;
|
|
static SOCKADDR rcv_addr;
|
|
int bytesin = 0;
|
|
int addrlen = sizeof(SOCKADDR);
|
|
unsigned int rcvid; // The id of who we actually received a packet from, as opposed to socketid parm
|
|
if (NP_IPX == naddr->connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&rcv_addr;
|
|
#ifdef WIN32
|
|
memcpy(&ipxaddr->sa_nodenum, &naddr->address, 6);
|
|
memcpy(&ipxaddr->sa_netnum, &naddr->net_id, 4);
|
|
ipxaddr->sa_socket = htons(naddr->port);
|
|
#else
|
|
memcpy(ipxaddr->sipx_node, &naddr->address, 6);
|
|
memcpy(&ipxaddr->sipx_network, &naddr->net_id, 4);
|
|
ipxaddr->sipx_port = htons(naddr->port);
|
|
#endif
|
|
} else if (NP_TCP == naddr->connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&rcv_addr;
|
|
memcpy(&inaddr->sin_addr, &naddr->address, 4);
|
|
inaddr->sin_port = htons(naddr->port);
|
|
}
|
|
|
|
// memcpy(&rcv_addr,&naddr->address,sizeof(SOCKADDR));
|
|
if (Net_connect_sequence == R_NET_SEQUENCE_CONNECTING) {
|
|
nw_HandleConnectResponse(data, len, naddr);
|
|
return;
|
|
}
|
|
// Check for incoming data
|
|
|
|
reliable_socket *rsocket = NULL;
|
|
// Check to see if we need to send a packet out.
|
|
if ((reliable_sockets[serverconn].status == RNF_LIMBO) &&
|
|
((serverconn != -1) && (timer_GetTime() - last_sent_iamhere) > NETRETRYTIME)) {
|
|
reliable_header conn_header;
|
|
// Now send I_AM_HERE packet
|
|
conn_header.type = RNT_I_AM_HERE;
|
|
conn_header.seq = ~CONNECTSEQ;
|
|
conn_header.data_len = 0;
|
|
last_sent_iamhere = timer_GetTime();
|
|
network_address send_address;
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
|
|
send_address.connection_type = reliable_sockets[serverconn].connection_type;
|
|
if (NP_IPX == send_address.connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&reliable_sockets[serverconn].addr;
|
|
#ifdef WIN32
|
|
memcpy(send_address.address, ipxaddr->sa_nodenum, 6);
|
|
memcpy(send_address.net_id, ipxaddr->sa_netnum, 4);
|
|
send_address.port = htons(ipxaddr->sa_socket);
|
|
#else
|
|
memcpy(send_address.address, ipxaddr->sipx_node, 6);
|
|
memcpy(send_address.net_id, &ipxaddr->sipx_network, 4);
|
|
send_address.port = htons(ipxaddr->sipx_port);
|
|
#endif
|
|
send_address.connection_type = NP_IPX;
|
|
} else if (NP_TCP == send_address.connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&reliable_sockets[serverconn].addr;
|
|
memcpy(send_address.address, &inaddr->sin_addr, 4);
|
|
send_address.port = htons(inaddr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
}
|
|
int ret = nw_SendWithID(NWT_RELIABLE, (ubyte *)&conn_header, RELIABLE_PACKET_HEADER_ONLY_SIZE, &send_address);
|
|
|
|
if ((ret == SOCKET_ERROR) && (WSAEWOULDBLOCK == WSAGetLastError())) {
|
|
reliable_sockets[serverconn].last_packet_sent = timer_GetTime() - NETRETRYTIME;
|
|
} else {
|
|
reliable_sockets[serverconn].last_packet_sent = timer_GetTime();
|
|
}
|
|
}
|
|
network_protocol link_type = naddr->connection_type;
|
|
network_address d3_rcv_addr;
|
|
memcpy(&d3_rcv_addr, naddr, sizeof(network_address));
|
|
memcpy((ubyte *)&rcv_buff, data, len);
|
|
SOCKADDR_IN *rcvaddr, *rsockaddr;
|
|
do {
|
|
rsocket = NULL;
|
|
if (len) {
|
|
// Someone wants to connect, so find a slot
|
|
if (rcv_buff.type == RNT_REQ_CONN) {
|
|
for (i = 1; i < MAXRELIABLESOCKETS; i++) {
|
|
if ((reliable_sockets[i].status == RNF_CONNECTED) || (reliable_sockets[i].status == RNF_LIMBO))
|
|
// if(memcmp(&rcv_addr,&reliable_sockets[i].addr,sizeof(SOCKADDR))==0)
|
|
if (memcmp(&d3_rcv_addr, &reliable_sockets[i].net_addr, sizeof(network_address)) == 0)
|
|
// d3_rcv_addr
|
|
{
|
|
// We already have a reliable link to this user, so we will ignore it...
|
|
mprintf((0, "Received duplicate connection request. %d\n", i));
|
|
// reliable_sockets[i].last_packet_received = timer_GetTime();
|
|
nw_SendReliableAck(&reliable_sockets[i].addr, rcv_buff.seq, link_type, rcv_buff.send_time);
|
|
// We will change this as a hack to prevent later code from hooking us up
|
|
rcv_buff.type = 0xff;
|
|
continue;
|
|
}
|
|
}
|
|
for (i = 1; i < MAXRELIABLESOCKETS; i++) {
|
|
if (reliable_sockets[i].status == RNF_UNUSED) {
|
|
// Add the new connection here.
|
|
reliable_sockets[i].connection_type = link_type;
|
|
memcpy(&reliable_sockets[i].net_addr, naddr, sizeof(network_address));
|
|
memcpy(&reliable_sockets[i].addr, &rcv_addr, sizeof(SOCKADDR));
|
|
reliable_sockets[i].ping_pos = 0;
|
|
reliable_sockets[i].num_ping_samples = 0;
|
|
reliable_sockets[i].status = RNF_LIMBO;
|
|
reliable_sockets[i].last_packet_received = timer_GetTime();
|
|
reliable_sockets[i].last_sent = timer_GetTime();
|
|
reliable_sockets[i].waiting_packet_number = -1;
|
|
reliable_sockets[i].send_urgent = 0;
|
|
rsocket = &reliable_sockets[i];
|
|
rcvaddr = (SOCKADDR_IN *)&rcv_addr;
|
|
// Int3();
|
|
mprintf((0, "Connect from %s:%d\n", inet_ntoa(rcvaddr->sin_addr), htons(rcvaddr->sin_port)));
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAXRELIABLESOCKETS) {
|
|
// No more connections!
|
|
mprintf((0, "Out of incoming reliable connection sockets\n"));
|
|
// Int3();//See Kevin
|
|
continue;
|
|
}
|
|
nw_SendReliableAck(&rsocket->addr, rcv_buff.seq, link_type, rcv_buff.send_time);
|
|
}
|
|
|
|
// Find out if this is a packet from someone we were expecting a packet.
|
|
rcvaddr = (SOCKADDR_IN *)&rcv_addr;
|
|
for (i = 1; i < MAXRELIABLESOCKETS; i++) {
|
|
|
|
rsockaddr = (SOCKADDR_IN *)&reliable_sockets[i].addr;
|
|
if (memcmp(&d3_rcv_addr, &reliable_sockets[i].net_addr, sizeof(network_address)) == 0) {
|
|
rsocket = &reliable_sockets[i];
|
|
rcvid = i;
|
|
break;
|
|
}
|
|
}
|
|
if (NULL == rsocket) {
|
|
mprintf((0, "Received reliable data from unconnected client.\n"));
|
|
char addrstr[200];
|
|
nw_GetNumbersFromHostAddress(&d3_rcv_addr, addrstr);
|
|
mprintf((0, "Received from %s\n", addrstr));
|
|
continue;
|
|
}
|
|
rsocket->last_packet_received = timer_GetTime();
|
|
|
|
if (rsocket->status != RNF_CONNECTED) {
|
|
// Get out of limbo
|
|
if (rsocket->status == RNF_LIMBO) {
|
|
// this is our connection to the server
|
|
if ((serverconn != -1)) {
|
|
if (rcv_buff.type == RNT_ACK) {
|
|
int *acknum = (int *)&rcv_buff.data;
|
|
if (*acknum == (~CONNECTSEQ & 0xffff)) {
|
|
rsocket->status = RNF_CONNECTED;
|
|
mprintf((0, "Got ACK for IAMHERE!\n"));
|
|
}
|
|
continue;
|
|
}
|
|
} else if (rcv_buff.type == RNT_I_AM_HERE) {
|
|
rsocket->status = RNF_CONNECTING;
|
|
nw_SendReliableAck(&rsocket->addr, rcv_buff.seq, link_type, rcv_buff.send_time);
|
|
mprintf((0, "Got IAMHERE!\n"));
|
|
continue;
|
|
}
|
|
}
|
|
if ((rcv_buff.type == RNT_DATA) && (serverconn != -1)) {
|
|
rsocket->status = RNF_CONNECTED;
|
|
} else {
|
|
// mprintf((0,"Packet from nonconnected socket -- seq: %d status: %d\n",rcv_buff.seq,rsocket->status));
|
|
rsocket->last_packet_received = timer_GetTime();
|
|
continue;
|
|
}
|
|
}
|
|
// Update the last recv variable so we don't need a heartbeat
|
|
rsocket->last_packet_received = timer_GetTime();
|
|
if (rcv_buff.type == RNT_HEARTBEAT) {
|
|
continue;
|
|
}
|
|
if (rcv_buff.type == RNT_ACK) {
|
|
// Update ping time
|
|
rsocket->num_ping_samples++;
|
|
|
|
rsocket->pings[rsocket->ping_pos] = rsocket->last_packet_received - rcv_buff.send_time;
|
|
// mprintf((0,"ping time: %f\n",rsocket->pings[rsocket->ping_pos]));
|
|
if (rsocket->num_ping_samples >= MAX_PING_HISTORY) {
|
|
float sort_ping[MAX_PING_HISTORY];
|
|
for (int a = 0; a < MAX_PING_HISTORY; a++)
|
|
sort_ping[a] = rsocket->pings[a];
|
|
qsort(sort_ping, MAX_PING_HISTORY, sizeof(float), nw_PingCompare);
|
|
rsocket->mean_ping = ((sort_ping[MAX_PING_HISTORY / 2] + sort_ping[(MAX_PING_HISTORY / 2) + 1])) / 2;
|
|
// mprintf_at((2,i+1,0,"Ping: %f ",rsocket->mean_ping));
|
|
}
|
|
rsocket->ping_pos++;
|
|
if (rsocket->ping_pos >= MAX_PING_HISTORY) {
|
|
rsocket->ping_pos = 0;
|
|
}
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
unsigned int *acksig = (unsigned int *)&rcv_buff.data;
|
|
if (rsocket)
|
|
if (rsocket->sbuffers[i])
|
|
if (rsocket->ssequence[i] == *acksig) {
|
|
// mprintf((0,"Received ACK %d\n",*acksig));
|
|
mem_free(rsocket->sbuffers[i]);
|
|
rsocket->sbuffers[i] = NULL;
|
|
rsocket->ssequence[i] = 0;
|
|
}
|
|
}
|
|
// remove that packet from the send buffer
|
|
rsocket->last_packet_received = timer_GetTime();
|
|
continue;
|
|
}
|
|
if (rcv_buff.type == RNT_DATA_COMP) {
|
|
// More2Come
|
|
// Decompress it. Put it back in the buffer. Process it as RNT_DATA
|
|
rcv_buff.type = RNT_DATA;
|
|
}
|
|
if (rcv_buff.type == RNT_DATA) {
|
|
|
|
// If the data is out of order by >= MAXNETBUFFERS-1 ignore that packet for now
|
|
int seqdelta;
|
|
seqdelta = rcv_buff.seq - rsocket->oursequence;
|
|
if (seqdelta < 0)
|
|
seqdelta = seqdelta * -1;
|
|
if (seqdelta >= MAXNETBUFFERS - 1) {
|
|
mprintf((0, "Received reliable packet out of order!\n"));
|
|
// It's out of order, so we won't ack it, which will mean we will get it again soon.
|
|
continue;
|
|
}
|
|
// else move data into the proper buffer position
|
|
int savepacket = 1;
|
|
|
|
if (rsocket->oursequence < (0xffff - (MAXNETBUFFERS - 1))) {
|
|
if (rsocket->oursequence > rcv_buff.seq) {
|
|
savepacket = 0;
|
|
}
|
|
} else {
|
|
// Sequence is high, so prepare for wrap around
|
|
if (((unsigned short)(rcv_buff.seq + rsocket->oursequence)) > (MAXNETBUFFERS - 1)) {
|
|
savepacket = 0;
|
|
}
|
|
}
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
if ((NULL != rsocket->rbuffers[i]) && (rsocket->rsequence[i] == rcv_buff.seq)) {
|
|
// Received duplicate packet!
|
|
// mprintf((0,"Received duplicate packet!\n"));
|
|
savepacket = 0;
|
|
}
|
|
}
|
|
if (savepacket) {
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
if (NULL == rsocket->rbuffers[i]) {
|
|
// mprintf((0,"Got good data seq: %d\n",rcv_buff.seq));
|
|
if (rcv_buff.data_len > max_len)
|
|
rsocket->recv_len[i] = rcv_buff.data_len;
|
|
else
|
|
rsocket->recv_len[i] = rcv_buff.data_len;
|
|
rsocket->rbuffers[i] = (reliable_net_rcvbuffer *)mem_malloc(sizeof(reliable_net_rcvbuffer));
|
|
memcpy(rsocket->rbuffers[i]->buffer, rcv_buff.data, rsocket->recv_len[i]);
|
|
rsocket->rsequence[i] = rcv_buff.seq;
|
|
// mprintf((0,"Adding packet to receive buffer in nw_ReceiveReliable().\n"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
nw_SendReliableAck(&rsocket->addr, rcv_buff.seq, link_type, rcv_buff.send_time);
|
|
}
|
|
}
|
|
} while (0); // while((IPX_has_data>0) || (UDP_has_data>0));
|
|
|
|
#endif // FIXED
|
|
}
|
|
void nw_HandleConnectResponse(ubyte *data, int len, network_address *server_addr) {
|
|
#ifdef FIXED
|
|
int i;
|
|
static reliable_header ack_header;
|
|
static reliable_header conn_header;
|
|
SOCKADDR rcv_addr;
|
|
|
|
memcpy(&ack_header, data, len);
|
|
if (NP_IPX == server_addr->connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&rcv_addr;
|
|
#ifdef WIN32
|
|
memcpy(&ipxaddr->sa_nodenum, &server_addr->address, 6);
|
|
memcpy(&ipxaddr->sa_netnum, &server_addr->net_id, 4);
|
|
ipxaddr->sa_socket = htons(server_addr->port);
|
|
#else
|
|
memcpy(&ipxaddr->sipx_node, &server_addr->address, 6);
|
|
memcpy(&ipxaddr->sipx_network, &server_addr->net_id, 4);
|
|
ipxaddr->sipx_port = htons(server_addr->port);
|
|
#endif
|
|
} else if (NP_TCP == server_addr->connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&rcv_addr;
|
|
memcpy(&inaddr->sin_addr, &server_addr->address, 4);
|
|
inaddr->sin_port = htons(server_addr->port);
|
|
}
|
|
mprintf((0, "Got a connect response!\n"));
|
|
if (ack_header.type == RNT_ACK) {
|
|
int *acknum = (int *)&ack_header.data;
|
|
if (*acknum == CONNECTSEQ) {
|
|
// if(memcmp(&rcv_addr,&sockaddr,sizeof(SOCKADDR))==0)
|
|
{
|
|
for (i = 1; i < MAXRELIABLESOCKETS; i++) {
|
|
if (reliable_sockets[i].status == RNF_UNUSED) {
|
|
// Add the new connection here.
|
|
memset(&reliable_sockets[i], 0, sizeof(reliable_socket));
|
|
reliable_sockets[i].connection_type = server_addr->connection_type;
|
|
memcpy(&reliable_sockets[i].net_addr, server_addr, sizeof(network_address));
|
|
reliable_sockets[i].last_packet_received = timer_GetTime();
|
|
memcpy(&reliable_sockets[i].addr, &rcv_addr, sizeof(SOCKADDR));
|
|
reliable_sockets[i].status = RNF_LIMBO;
|
|
Net_connect_socket_id = i;
|
|
reliable_sockets[i].last_sent = timer_GetTime();
|
|
reliable_sockets[i].waiting_packet_number = -1;
|
|
mprintf((0, "Succesfully connected to server in nw_ConnectToServer().\n"));
|
|
// Now send I_AM_HERE packet
|
|
conn_header.type = RNT_I_AM_HERE;
|
|
conn_header.seq = ~CONNECTSEQ;
|
|
conn_header.data_len = 0;
|
|
serverconn = i;
|
|
first_sent_iamhere = timer_GetTime();
|
|
last_sent_iamhere = timer_GetTime();
|
|
|
|
int rcode =
|
|
nw_SendWithID(NWT_RELIABLE, (ubyte *)&conn_header, RELIABLE_PACKET_HEADER_ONLY_SIZE, server_addr);
|
|
// int rcode = sendto(typeless_sock,(char
|
|
// *)&conn_header,RELIABLE_PACKET_HEADER_ONLY_SIZE,0,addr,sizeof(SOCKADDR));
|
|
if (rcode == SOCKET_ERROR) {
|
|
Net_connect_socket_id = INVALID_SOCKET;
|
|
reliable_sockets[i].status = RNF_UNUSED;
|
|
memset(&reliable_sockets[i], 0, sizeof(reliable_socket));
|
|
mprintf((0, "Unable to send packet in nw_ConnectToServer()\n"));
|
|
Net_connect_sequence = R_NET_SEQUENCE_FAILED;
|
|
return;
|
|
}
|
|
reliable_sockets[i].last_packet_sent = timer_GetTime();
|
|
/*
|
|
float f;
|
|
f = timer_GetTime();
|
|
while(((timer_GetTime() - f)<2) && (reliable_sockets[i].status!=RNF_CONNECTING))
|
|
{
|
|
//nw_WorkReliable();
|
|
nw_DoReceiveCallbacks();
|
|
}
|
|
*/
|
|
Net_connect_sequence = R_NET_SEQUENCE_CONNECTED;
|
|
return;
|
|
}
|
|
}
|
|
mprintf((0, "Out of reliable socket space in nw_ConnectToServer().\n"));
|
|
Net_connect_sequence = R_NET_SEQUENCE_FAILED;
|
|
return;
|
|
}
|
|
// else
|
|
//{
|
|
// mprintf((0,"Received a reliable packet from a server other than the current server\n"));
|
|
//}
|
|
} else {
|
|
mprintf((0, "Received out of sequence ACK in nw_ConnectToServer().\n"));
|
|
}
|
|
} else {
|
|
mprintf((0, "Received something that isn't an ACK in nw_ConnectToServer().\n"));
|
|
}
|
|
#endif // FIXED
|
|
}
|
|
void nw_ConnectToServer(uint *socket, network_address *server_addr) {
|
|
#ifdef FIXED
|
|
// Send out a RNT_REQ_CONN packet, and wait for it to be acked.
|
|
float time_sent_req = 0;
|
|
float first_sent_req = 0;
|
|
static reliable_header conn_header;
|
|
static reliable_header ack_header;
|
|
int bytesin;
|
|
struct timeval timeout;
|
|
*socket = INVALID_SOCKET;
|
|
if (Use_DirectPlay) {
|
|
// We need a session description to do this, so we don't use this function
|
|
return;
|
|
}
|
|
|
|
conn_header.type = RNT_REQ_CONN;
|
|
conn_header.seq = CONNECTSEQ;
|
|
conn_header.data_len = 0;
|
|
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 0;
|
|
if ((server_addr->connection_type == NP_IPX) && (!IPX_active)) {
|
|
return;
|
|
}
|
|
if ((server_addr->connection_type == NP_TCP) && (!TCP_active)) {
|
|
return;
|
|
}
|
|
|
|
Net_connect_sequence = R_NET_SEQUENCE_CONNECTING;
|
|
memset(&ack_header, 0, sizeof(reliable_header));
|
|
bytesin = 0;
|
|
network_address d3_rcv_addr;
|
|
memset(&d3_rcv_addr, 0, sizeof(network_address));
|
|
int ret = nw_SendWithID(NWT_RELIABLE, (ubyte *)&conn_header, RELIABLE_PACKET_HEADER_ONLY_SIZE, server_addr);
|
|
if (SOCKET_ERROR == ret) {
|
|
mprintf((0, "Unable to send IPX packet in nw_ConnectToServer()! -- %d\n", WSAGetLastError()));
|
|
return;
|
|
}
|
|
|
|
first_sent_req = timer_GetTime();
|
|
time_sent_req = timer_GetTime();
|
|
|
|
// Wait until we get a response from the server or we timeout
|
|
|
|
do {
|
|
nw_DoReceiveCallbacks();
|
|
// Now we wait for the connection to be made....
|
|
if (Net_connect_sequence == R_NET_SEQUENCE_CONNECTED) {
|
|
*socket = Net_connect_socket_id;
|
|
return;
|
|
}
|
|
if ((timer_GetTime() - time_sent_req) > 2) {
|
|
mprintf((0, "Resending connect request.\n"));
|
|
int ret = nw_SendWithID(NWT_RELIABLE, (ubyte *)&conn_header, RELIABLE_PACKET_HEADER_ONLY_SIZE, server_addr);
|
|
if (ret != SOCKET_ERROR) {
|
|
time_sent_req = timer_GetTime();
|
|
} else {
|
|
mprintf((0, "Error sending connection request! -- %d\n", WSAGetLastError()));
|
|
}
|
|
}
|
|
} while ((timer_GetTime() - first_sent_req) < NETTIMEOUT);
|
|
return;
|
|
#endif // FIXED
|
|
}
|
|
void nw_CloseSocket(uint *sockp) {
|
|
#ifdef FIXED
|
|
reliable_header diss_conn_header;
|
|
#ifdef WIN32
|
|
if (DP_active) {
|
|
dp_DirectPlayDestroyPlayer(*sockp);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (*sockp >= MAXRELIABLESOCKETS) {
|
|
mprintf((0, "Invalid socket id passed to nw_NewCloseSocket() -- %d\n", *sockp));
|
|
return;
|
|
}
|
|
if (reliable_sockets[*sockp].status == RNF_UNUSED) {
|
|
mprintf((0, "Trying to close an unused socket (%d) -- ignoring request.\n", *sockp));
|
|
}
|
|
mprintf((0, "Closing socket %d\n", *sockp));
|
|
// Go through every buffer and "free it up(tm)"
|
|
int i;
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
if (reliable_sockets[*sockp].rbuffers[i]) {
|
|
mem_free(reliable_sockets[*sockp].rbuffers[i]);
|
|
reliable_sockets[*sockp].rbuffers[i] = NULL;
|
|
reliable_sockets[*sockp].rsequence[i] = 0;
|
|
}
|
|
if (reliable_sockets[*sockp].sbuffers[i]) {
|
|
mem_free(reliable_sockets[*sockp].sbuffers[i]);
|
|
reliable_sockets[*sockp].sbuffers[i] = NULL;
|
|
reliable_sockets[*sockp].rsequence[i] = 0;
|
|
}
|
|
}
|
|
diss_conn_header.type = RNT_DISCONNECT;
|
|
diss_conn_header.seq = CONNECTSEQ;
|
|
diss_conn_header.data_len = 0;
|
|
if (*sockp == serverconn)
|
|
serverconn = -1;
|
|
network_address send_address;
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
|
|
send_address.connection_type = reliable_sockets[*sockp].connection_type;
|
|
if (NP_IPX == reliable_sockets[*sockp].connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&reliable_sockets[*sockp].addr;
|
|
#ifdef WIN32
|
|
memcpy(send_address.address, ipxaddr->sa_nodenum, 6);
|
|
memcpy(send_address.net_id, ipxaddr->sa_netnum, 4);
|
|
send_address.port = htons(ipxaddr->sa_socket);
|
|
#else
|
|
memcpy(send_address.address, ipxaddr->sipx_node, 6);
|
|
memcpy(send_address.net_id, &ipxaddr->sipx_network, 4);
|
|
send_address.port = htons(ipxaddr->sipx_port);
|
|
#endif
|
|
send_address.connection_type = NP_IPX;
|
|
} else if (NP_TCP == reliable_sockets[*sockp].connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&reliable_sockets[*sockp].addr;
|
|
memcpy(send_address.address, &inaddr->sin_addr, 4);
|
|
send_address.port = htons(inaddr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
}
|
|
nw_SendWithID(NWT_RELIABLE, (ubyte *)&diss_conn_header, RELIABLE_PACKET_HEADER_ONLY_SIZE, &send_address);
|
|
|
|
memset(&reliable_sockets[*sockp], 0, sizeof(reliable_socket));
|
|
reliable_sockets[*sockp].status = RNF_UNUSED;
|
|
|
|
#endif // FIXED
|
|
}
|
|
int nw_CheckReliableSocket(int socknum) {
|
|
#ifdef FIXED
|
|
// Checks to see if a socket is connected or not.
|
|
if (Use_DirectPlay) {
|
|
return true;
|
|
}
|
|
if (socknum >= MAXRELIABLESOCKETS) {
|
|
mprintf((0, "Invalid socket id passed to nw_CheckReliableSocket() -- %d\n", socknum));
|
|
return 0;
|
|
}
|
|
switch (reliable_sockets[socknum].status) {
|
|
case RNF_UNUSED:
|
|
case RNF_BROKEN:
|
|
case RNF_DISCONNECTED:
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
#endif // FIXED
|
|
return 1;
|
|
}
|
|
int nw_PingCompare(const void *arg1, const void *arg2) {
|
|
#ifdef FIXED
|
|
float *ping1 = (float *)arg1;
|
|
float *ping2 = (float *)arg2;
|
|
|
|
if (*ping1 == *ping2)
|
|
return 0;
|
|
else if (*ping1 > *ping2)
|
|
return 1;
|
|
else if (*ping1 < *ping2)
|
|
return -1;
|
|
#endif // FIXED
|
|
return 0;
|
|
}
|
|
// Warning, experimental compression below, if you want to use it, talk to Kevin. Doesn't do much currently, only
|
|
// reduces 0's
|
|
#define COMPRESS_KEY 0xfd
|
|
int nw_Compress(void *srcdata, void *destdata, int count) {
|
|
#ifdef FIXED
|
|
int i;
|
|
ubyte *curr_src = (ubyte *)srcdata;
|
|
ubyte *currp = (ubyte *)destdata;
|
|
for (i = 0; i < count; i++) {
|
|
// Woops, we have a char that matches our compress key, so add it as it's own type
|
|
if (curr_src[i] == COMPRESS_KEY) {
|
|
*currp = COMPRESS_KEY;
|
|
currp++;
|
|
//*currp = 1;
|
|
// currp++;
|
|
*currp = COMPRESS_KEY;
|
|
currp++;
|
|
}
|
|
// Look for 3 in a row
|
|
else if ((curr_src[i] == 0) && (curr_src[i + 1] == 0) && (curr_src[i + 2] == 0) && (i + 3 < count)) {
|
|
int repeat_count = 3;
|
|
*currp = COMPRESS_KEY;
|
|
currp++;
|
|
while ((curr_src[i] == curr_src[i + repeat_count]) && (repeat_count < 250) && (i + repeat_count < count)) {
|
|
repeat_count++;
|
|
}
|
|
*currp = repeat_count;
|
|
currp++;
|
|
//*currp = curr_src[i];
|
|
// currp++;
|
|
i += (repeat_count - 1);
|
|
} else {
|
|
*currp = curr_src[i];
|
|
currp++;
|
|
}
|
|
}
|
|
return currp - (ubyte *)destdata;
|
|
#endif // FIXED
|
|
}
|
|
int nw_Uncompress(void *compdata, void *uncompdata, int count) {
|
|
#ifdef FIXED
|
|
int i;
|
|
int destlen = 0;
|
|
ubyte *comp_src = (ubyte *)compdata;
|
|
ubyte *currp = (ubyte *)uncompdata;
|
|
for (i = 0; i < count; i++) {
|
|
if (*comp_src == COMPRESS_KEY) {
|
|
comp_src++;
|
|
if (*comp_src == COMPRESS_KEY) {
|
|
currp[destlen] = COMPRESS_KEY;
|
|
destlen++;
|
|
} else {
|
|
for (int a = 0; a < (*comp_src); a++) {
|
|
currp[destlen] = 0; //*(comp_src+1);
|
|
destlen++;
|
|
}
|
|
}
|
|
i++;
|
|
// comp_src++;
|
|
comp_src++;
|
|
} else {
|
|
currp[destlen] = *comp_src;
|
|
destlen++;
|
|
comp_src++;
|
|
}
|
|
}
|
|
return destlen;
|
|
#endif // FIXED
|
|
}
|
|
// initialize the buffering system
|
|
void nw_psnet_buffer_init() {
|
|
#ifdef FIXED
|
|
int idx;
|
|
|
|
// blast the buffer clean
|
|
memset(Psnet_buffers, 0, sizeof(network_packet_buffer) * MAX_PACKET_BUFFERS);
|
|
|
|
// set all buffer sequence #'s to -1
|
|
for (idx = 0; idx < MAX_PACKET_BUFFERS; idx++) {
|
|
Psnet_buffers[idx].sequence_number = -1;
|
|
}
|
|
// initialize the sequence #
|
|
Psnet_seq_number = 0;
|
|
Psnet_lowest_id = -1;
|
|
Psnet_highest_id = -1;
|
|
#endif // FIXED
|
|
}
|
|
// buffer a packet (maintain order!)
|
|
void nw_psnet_buffer_packet(ubyte *data, int length, network_address *from) {
|
|
#ifdef FIXED
|
|
int idx;
|
|
int found_buf = 0;
|
|
|
|
// find the first empty packet
|
|
for (idx = 0; idx < MAX_PACKET_BUFFERS; idx++) {
|
|
if (Psnet_buffers[idx].sequence_number == -1) {
|
|
found_buf = 1;
|
|
break;
|
|
}
|
|
}
|
|
// if we didn't find the buffer, report an overrun
|
|
if (!found_buf) {
|
|
mprintf((0, "WARNING - Buffer overrun in psnet\n"));
|
|
} else {
|
|
// copy in the data
|
|
memcpy(Psnet_buffers[idx].data, data, length);
|
|
Psnet_buffers[idx].len = length;
|
|
memcpy(&Psnet_buffers[idx].from_addr, from, sizeof(network_address));
|
|
Psnet_buffers[idx].sequence_number = Psnet_seq_number;
|
|
|
|
// keep track of the highest id#
|
|
Psnet_highest_id = Psnet_seq_number++;
|
|
// set the lowest id# for the first time
|
|
if (Psnet_lowest_id == -1) {
|
|
Psnet_lowest_id = Psnet_highest_id;
|
|
}
|
|
}
|
|
#endif // FIXED
|
|
}
|
|
// get the index of the next packet in order!
|
|
int nw_psnet_buffer_get_next_by_dpid(ubyte *data, int *length, unsigned long dpid) {
|
|
#ifdef FIXED
|
|
int idx;
|
|
int found_buf = 0;
|
|
// if there are no buffers, do nothing
|
|
if ((Psnet_lowest_id == -1) || (Psnet_lowest_id > Psnet_highest_id)) {
|
|
return 0;
|
|
}
|
|
// search until we find the lowest packet index id#
|
|
for (idx = 0; idx < MAX_PACKET_BUFFERS; idx++) {
|
|
unsigned long *thisid;
|
|
thisid = (unsigned long *)&Psnet_buffers[idx].from_addr.address;
|
|
// if we found the buffer
|
|
if ((Psnet_buffers[idx].sequence_number == Psnet_lowest_id) && (dpid == *thisid)) {
|
|
found_buf = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found_buf)
|
|
return 0;
|
|
|
|
// copy out the buffer data
|
|
memcpy(data, Psnet_buffers[idx].data, Psnet_buffers[idx].len);
|
|
*length = Psnet_buffers[idx].len;
|
|
|
|
// now we need to cleanup the packet list
|
|
// mark the buffer as free
|
|
Psnet_buffers[idx].sequence_number = -1;
|
|
Psnet_lowest_id++;
|
|
#endif // FIXED
|
|
return 1;
|
|
}
|
|
// get the index of the next packet in order!
|
|
int nw_psnet_buffer_get_next(ubyte *data, int *length, network_address *from) {
|
|
#ifdef FIXED
|
|
int idx;
|
|
int found_buf = 0;
|
|
// if there are no buffers, do nothing
|
|
if ((Psnet_lowest_id == -1) || (Psnet_lowest_id > Psnet_highest_id)) {
|
|
return 0;
|
|
}
|
|
// search until we find the lowest packet index id#
|
|
for (idx = 0; idx < MAX_PACKET_BUFFERS; idx++) {
|
|
// if we found the buffer
|
|
if (Psnet_buffers[idx].sequence_number == Psnet_lowest_id) {
|
|
found_buf = 1;
|
|
break;
|
|
}
|
|
}
|
|
// at this point, we should _always_ have found the buffer
|
|
ASSERT(found_buf);
|
|
|
|
// copy out the buffer data
|
|
memcpy(data, Psnet_buffers[idx].data, Psnet_buffers[idx].len);
|
|
*length = Psnet_buffers[idx].len;
|
|
memcpy(from, &Psnet_buffers[idx].from_addr, sizeof(network_address));
|
|
// now we need to cleanup the packet list
|
|
// mark the buffer as free
|
|
Psnet_buffers[idx].sequence_number = -1;
|
|
Psnet_lowest_id++;
|
|
#endif // FIXED
|
|
return 1;
|
|
}
|
|
async_dns_lookup aslu;
|
|
async_dns_lookup *lastaslu = NULL;
|
|
void __cdecl gethostbynameworker(void *parm);
|
|
int nw_Asyncgethostbyname(unsigned int *ip, int command, char *hostname) {
|
|
#ifdef FIXED
|
|
|
|
if (command == NW_AGHBN_LOOKUP) {
|
|
if (lastaslu)
|
|
lastaslu->abort = true;
|
|
async_dns_lookup *newaslu;
|
|
newaslu = (async_dns_lookup *)mem_malloc(sizeof(async_dns_lookup));
|
|
memset(&newaslu->ip, 0, sizeof(unsigned int));
|
|
newaslu->host = hostname;
|
|
newaslu->done = false;
|
|
newaslu->error = false;
|
|
newaslu->abort = false;
|
|
lastaslu = newaslu;
|
|
aslu.done = false;
|
|
#ifdef WIN32
|
|
_beginthread(gethostbynameworker, 0, newaslu);
|
|
#else
|
|
HOSTENT *he = gethostbyname(lastaslu->host);
|
|
if (he == NULL) {
|
|
lastaslu->error = true;
|
|
} else {
|
|
memcpy(&lastaslu->ip, he->h_addr_list[0], sizeof(unsigned int));
|
|
lastaslu->done = true;
|
|
memcpy(&aslu, lastaslu, sizeof(async_dns_lookup));
|
|
}
|
|
#endif
|
|
return 1;
|
|
} else if (command == NW_AGHBN_CANCEL) {
|
|
if (lastaslu)
|
|
lastaslu->abort = true;
|
|
lastaslu = NULL;
|
|
} else if (command == NW_AGHBN_READ) {
|
|
if (!lastaslu)
|
|
return -1;
|
|
if (aslu.done) {
|
|
lastaslu = NULL;
|
|
memcpy(ip, &aslu.ip, sizeof(unsigned int));
|
|
return 1;
|
|
} else if (aslu.error) {
|
|
mem_free(lastaslu);
|
|
lastaslu = NULL;
|
|
return -1;
|
|
} else
|
|
return 0;
|
|
}
|
|
#endif // FIXED
|
|
return -2;
|
|
}
|
|
// This is the worker thread which does the lookup.
|
|
void __cdecl gethostbynameworker(void *parm) {
|
|
#ifdef FIXED
|
|
async_dns_lookup *lookup = (async_dns_lookup *)parm;
|
|
HOSTENT *he = gethostbyname(lookup->host);
|
|
if (he == NULL) {
|
|
lookup->error = true;
|
|
return;
|
|
} else if (!lookup->abort) {
|
|
memcpy(&lookup->ip, he->h_addr_list[0], sizeof(unsigned int));
|
|
lookup->done = true;
|
|
memcpy(&aslu, lookup, sizeof(async_dns_lookup));
|
|
}
|
|
mem_free(lookup);
|
|
#endif // FIXED
|
|
}
|
|
int nw_ReccomendPPS() {
|
|
#ifdef FIXED
|
|
static char szconnspeed[100];
|
|
int len = 99;
|
|
strcpy(szconnspeed, "");
|
|
Database->read("ConnectionSpeed", szconnspeed, &len);
|
|
if (strcmpi(szconnspeed, "28K") == 0)
|
|
return 5;
|
|
else if (strcmpi(szconnspeed, "33K") == 0)
|
|
return 6;
|
|
else if (strcmpi(szconnspeed, "56K") == 0)
|
|
return 7;
|
|
else if (strcmpi(szconnspeed, "ISDN") == 0)
|
|
return 8;
|
|
else if (strcmpi(szconnspeed, "Cable") == 0)
|
|
return 9;
|
|
else if (strcmpi(szconnspeed, "Fast") == 0)
|
|
return 12;
|
|
else
|
|
return 7;
|
|
#endif // FIXED
|
|
}
|
|
// Register the networking library to call your function back
|
|
// When data containing your ID is found
|
|
// Returns non-zero if succesfull, Zero if this ID is already registered
|
|
int nw_RegisterCallback(NetworkReceiveCallback nfp, ubyte id) {
|
|
#ifdef FIXED
|
|
ASSERT(id < 16);
|
|
if (Netcallbacks[id]) {
|
|
mprintf((0, "Trying to reregister a callback!\n"));
|
|
Int3(); // Get Kevin!
|
|
}
|
|
|
|
Netcallbacks[id] = nfp;
|
|
#endif // FIXED
|
|
return 0;
|
|
}
|
|
NetworkReceiveCallback nw_UnRegisterCallback(ubyte id) {
|
|
#ifdef FIXED
|
|
NetworkReceiveCallback nfp;
|
|
ASSERT(id < 16);
|
|
nfp = Netcallbacks[id];
|
|
Netcallbacks[id] = NULL;
|
|
return nfp;
|
|
#endif // FIXED
|
|
}
|
|
int nw_SendWithID(ubyte id, ubyte *data, int len, network_address *who_to) {
|
|
#ifdef FIXED
|
|
ubyte packet_data[1500];
|
|
int send_this_packet = 1;
|
|
SOCKET send_sock;
|
|
SOCKADDR_IN sock_addr; // UDP/TCP socket structure
|
|
SOCKADDR_IPX ipx_addr; // IPX socket structure
|
|
int ret, send_len;
|
|
ubyte iaddr[6], *send_data;
|
|
short port;
|
|
fd_set wfds;
|
|
|
|
ASSERT(data);
|
|
ASSERT(len);
|
|
ASSERT(who_to);
|
|
timeval timeout = {0, 0};
|
|
|
|
packet_data[0] = id;
|
|
memcpy(packet_data + 1, data, len);
|
|
len++; // Account for the added byte
|
|
// mprintf((0,"Sending packet for id %d.\n",id));
|
|
#ifdef WIN32
|
|
if (Use_DirectPlay)
|
|
return dp_DirectPlaySend(who_to, (ubyte *)data, len, false);
|
|
#endif
|
|
// send_sock = *Unreliable_socket;
|
|
switch (who_to->connection_type) {
|
|
case NP_IPX:
|
|
send_sock = IPX_socket;
|
|
if (!IPX_active)
|
|
return 0;
|
|
break;
|
|
case NP_TCP:
|
|
send_sock = TCP_socket;
|
|
if (!TCP_active)
|
|
return 0;
|
|
break;
|
|
default:
|
|
mprintf((0, "Unknown protocol type in nw_Send()\n"));
|
|
Int3();
|
|
return 0;
|
|
}
|
|
/*
|
|
ubyte compdata[MAX_PACKET_SIZE*3];
|
|
ubyte testdata[MAX_PACKET_SIZE*3];
|
|
int uncompsize;
|
|
////Int3();
|
|
Uncompressed_outgoing_data_len += len;
|
|
int compsize = nw_Compress(data,compdata,len);
|
|
Compressed_outgoing_data_len += compsize;
|
|
uncompsize = nw_Uncompress(compdata,testdata,compsize);
|
|
|
|
ASSERT(uncompsize==len);
|
|
ASSERT(memcmp(data,testdata,uncompsize)==0);
|
|
|
|
int my_comp_ratio = (float) ((float)Uncompressed_outgoing_data_len/(float)Compressed_outgoing_data_len);
|
|
|
|
mprintf_at((2,1,0,"Compression: %d%% ",my_comp_ratio));
|
|
*/
|
|
if (!Sockets_initted) {
|
|
mprintf((0, "Network ==> Socket not inited in nw_Send\n"));
|
|
return 0;
|
|
}
|
|
|
|
memset(iaddr, 0x00, 6);
|
|
memcpy(iaddr, who_to->address, 6);
|
|
port = who_to->port;
|
|
|
|
if (port == 0) {
|
|
mprintf((0, "Network ==> destination port %d invalid in psnet_send\n", port));
|
|
Int3();
|
|
return 0;
|
|
}
|
|
|
|
send_len = len;
|
|
send_data = (ubyte *)packet_data;
|
|
FD_ZERO(&wfds);
|
|
FD_SET(send_sock, &wfds);
|
|
int sock_writable = select(send_sock + 1, NULL, &wfds, NULL, &timeout);
|
|
if (sock_writable == SOCKET_ERROR) {
|
|
mprintf((0, "Error on blocking select for write %d\n", WSAGetLastError()));
|
|
return 0;
|
|
}
|
|
if (!sock_writable) {
|
|
// This packet gets dropped.
|
|
return 0;
|
|
}
|
|
|
|
if (send_this_packet) {
|
|
switch (who_to->connection_type) {
|
|
|
|
case NP_IPX:
|
|
#ifdef WIN32
|
|
ipx_addr.sa_family = AF_IPX;
|
|
ipx_addr.sa_socket = htons(port);
|
|
memcpy(ipx_addr.sa_nodenum, iaddr, 6);
|
|
memcpy(ipx_addr.sa_netnum, who_to->net_id, 4);
|
|
#else
|
|
ipx_addr.sipx_family = AF_IPX;
|
|
ipx_addr.sipx_port = htons(port);
|
|
memcpy(ipx_addr.sipx_node, iaddr, 6);
|
|
memcpy(&ipx_addr.sipx_network, who_to->net_id, 4);
|
|
#endif
|
|
|
|
ret = sendto(IPX_socket, (char *)send_data, send_len, 0, (SOCKADDR *)&ipx_addr, sizeof(ipx_addr));
|
|
break;
|
|
case NP_TCP:
|
|
sock_addr.sin_family = AF_INET;
|
|
memcpy(&sock_addr.sin_addr.s_addr, iaddr, 4);
|
|
sock_addr.sin_port = htons(port);
|
|
ret = sendto(TCP_socket, (char *)send_data, send_len, 0, (SOCKADDR *)&sock_addr, sizeof(sock_addr));
|
|
break;
|
|
|
|
default:
|
|
Int3(); // Unknown protocol
|
|
break;
|
|
} // end switch
|
|
}
|
|
int lasterr;
|
|
if (ret != SOCKET_ERROR) {
|
|
return 1;
|
|
}
|
|
lasterr = WSAGetLastError();
|
|
if (lasterr == WSAEWOULDBLOCK) {
|
|
return 0;
|
|
}
|
|
mprintf((0, "Couldn't send data (%d)!\n", lasterr));
|
|
#endif // FIXED
|
|
return 0;
|
|
}
|
|
int nw_DoReceiveCallbacks(void) {
|
|
#ifdef FIXED
|
|
|
|
SOCKADDR_IN ip_addr; // UDP/TCP socket structure
|
|
SOCKADDR_IPX ipx_addr; // IPX socket structure
|
|
fd_set rfds;
|
|
timeval timeout;
|
|
int read_len, from_len;
|
|
network_address from_addr;
|
|
ubyte packet_data[1500];
|
|
nw_ReliableResend();
|
|
while (TCP_active) {
|
|
// check if there is any data on the socket to be read. The amount of data that can be
|
|
// atomically read is stored in len.
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(TCP_socket, &rfds);
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 0;
|
|
if (select(TCP_socket + 1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR) {
|
|
mprintf((0, "Error %d doing a socket select on IP read\n", WSAGetLastError()));
|
|
break;
|
|
}
|
|
// if the read file descriptor is not set, then bail!
|
|
if (!FD_ISSET(TCP_socket, &rfds))
|
|
break;
|
|
// get data off the socket and process
|
|
from_len = sizeof(SOCKADDR_IN);
|
|
read_len = recvfrom(TCP_socket, (char *)packet_data, 1500, 0, (SOCKADDR *)&ip_addr, &from_len);
|
|
|
|
if (read_len == SOCKET_ERROR) {
|
|
int x = WSAGetLastError();
|
|
mprintf((0, "Read error on IP socket. Winsock error %d \n", x));
|
|
break;
|
|
}
|
|
memset(&from_addr, 0x00, sizeof(network_address));
|
|
from_addr.connection_type = NP_TCP;
|
|
from_addr.port = ntohs(ip_addr.sin_port);
|
|
|
|
#ifdef WIN32
|
|
memcpy(from_addr.address, &ip_addr.sin_addr.S_un.S_addr, 4);
|
|
#else
|
|
memcpy(from_addr.address, &ip_addr.sin_addr.s_addr, 4);
|
|
#endif
|
|
ubyte packet_id = (packet_data[0] & 0x0f);
|
|
if (Netcallbacks[packet_id]) {
|
|
// mprintf((0,"Calling network callback for id %d.\n",packet_id));
|
|
Netcallbacks[packet_id](packet_data + 1, read_len - 1, &from_addr);
|
|
}
|
|
}
|
|
while (IPX_active) {
|
|
// check if there is any data on the socket to be read. The amount of data that can be
|
|
// atomically read is stored in len.
|
|
FD_ZERO(&rfds);
|
|
FD_SET(IPX_socket, &rfds);
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 0;
|
|
if (select(IPX_socket + 1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR) {
|
|
mprintf((0, "Error %d doing a socket select on IPX read\n", WSAGetLastError()));
|
|
break;
|
|
}
|
|
// if the read file descriptor is not set, then bail!
|
|
if (!FD_ISSET(IPX_socket, &rfds))
|
|
break;
|
|
// get data off the socket and process
|
|
from_len = sizeof(SOCKADDR_IPX);
|
|
read_len = recvfrom(IPX_socket, (char *)packet_data, 1500, 0, (SOCKADDR *)&ipx_addr, &from_len);
|
|
|
|
if (read_len == SOCKET_ERROR) {
|
|
int x = WSAGetLastError();
|
|
mprintf((0, "Read error on IPX socket. Winsock error %d \n", x));
|
|
break;
|
|
}
|
|
memset(&from_addr, 0x00, sizeof(network_address));
|
|
from_addr.connection_type = NP_IPX;
|
|
#ifdef WIN32
|
|
from_addr.port = ntohs(ipx_addr.sa_socket);
|
|
memcpy(from_addr.address, &ipx_addr.sa_nodenum, 6);
|
|
memcpy(from_addr.net_id, &ipx_addr.sa_netnum, 4);
|
|
#else
|
|
from_addr.port = ntohs(ipx_addr.sipx_port);
|
|
memcpy(from_addr.address, &ipx_addr.sipx_node, 6);
|
|
memcpy(from_addr.net_id, &ipx_addr.sipx_network, 4);
|
|
#endif
|
|
|
|
ubyte packet_id = (packet_data[0] & 0x0f);
|
|
if (Netcallbacks[packet_id]) {
|
|
// mprintf((0,"Calling network callback for id %d.\n",packet_id));
|
|
Netcallbacks[packet_id](packet_data + 1, read_len - 1, &from_addr);
|
|
}
|
|
}
|
|
#endif // FIXED
|
|
return 0;
|
|
}
|
|
// Resend any unack'd packets and send any buffered packets, heartbeats, etc.
|
|
void nw_ReliableResend(void) {
|
|
#ifdef FIXED
|
|
int i, j;
|
|
int rcode = -1;
|
|
int max_len = NETBUFFERSIZE;
|
|
static reliable_header rcv_buff;
|
|
static SOCKADDR rcv_addr;
|
|
int bytesin = 0;
|
|
int addrlen = sizeof(SOCKADDR);
|
|
reliable_socket *rsocket = NULL;
|
|
// Go through each reliable socket that is connected and do any needed work.
|
|
for (j = 0; j < MAXRELIABLESOCKETS; j++) {
|
|
rsocket = &reliable_sockets[j];
|
|
if (serverconn == -1) {
|
|
if (rsocket->status == RNF_LIMBO)
|
|
if ((timer_GetTime() - rsocket->last_packet_received) > NETTIMEOUT) {
|
|
mprintf((0, "Reliable (but in limbo) socket (%d) timed out in nw_WorkReliable().\n", j));
|
|
memset(rsocket, 0, sizeof(reliable_socket));
|
|
rsocket->status = RNF_UNUSED; // Won't work if this is an outgoing connection.
|
|
}
|
|
} else {
|
|
if ((rsocket->status == RNF_LIMBO) && ((timer_GetTime() - first_sent_iamhere) > NETTIMEOUT)) {
|
|
rsocket->status = RNF_BROKEN;
|
|
mprintf((0, "Reliable socket (%d) timed out in nw_WorkReliable().\n", j));
|
|
}
|
|
}
|
|
|
|
if (rsocket->status == RNF_CONNECTED) {
|
|
float retry_packet_time;
|
|
if ((rsocket->mean_ping == 0) || (rsocket->mean_ping > (NETRETRYTIME * 4))) {
|
|
retry_packet_time = NETRETRYTIME;
|
|
} else {
|
|
if (rsocket->mean_ping < MIN_NET_RETRYTIME) {
|
|
retry_packet_time = (float)MIN_NET_RETRYTIME;
|
|
// mprintf((0,"Using retransmission time of %f\n",retry_packet_time));
|
|
} else {
|
|
retry_packet_time = ((float)(float)rsocket->mean_ping * (float)1.25);
|
|
// mprintf((0,"Using retransmission time of %f\n",retry_packet_time));
|
|
}
|
|
}
|
|
// Iterate through send buffers.
|
|
for (i = 0; i < MAXNETBUFFERS; i++) {
|
|
if (((i == rsocket->waiting_packet_number) &&
|
|
((((timer_GetTime() - rsocket->last_sent) > R_NET_PACKET_QUEUE_TIME)) ||
|
|
((rsocket->mean_ping > 0) && (rsocket->mean_ping < R_NET_PACKET_QUEUE_TIME)) || rsocket->send_urgent)) ||
|
|
((rsocket->sbuffers[i]) && ((timer_GetTime() - rsocket->timesent[i]) >= retry_packet_time))) // Send again
|
|
{
|
|
|
|
if (i == rsocket->waiting_packet_number) {
|
|
rsocket->waiting_packet_number = -1;
|
|
rsocket->last_sent = timer_GetTime();
|
|
// mprintf((0,"Sending delayed packet...\n"));
|
|
}
|
|
reliable_header send_header;
|
|
// mprintf((0,"Resending reliable packet in nw_WorkReliable().\n"));
|
|
send_header.send_time = timer_GetTime();
|
|
send_header.seq = rsocket->ssequence[i];
|
|
memcpy(send_header.data, rsocket->sbuffers[i]->buffer, rsocket->send_len[i]);
|
|
send_header.data_len = rsocket->send_len[i];
|
|
send_header.type = RNT_DATA;
|
|
|
|
network_address send_address;
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
|
|
send_address.connection_type = rsocket->connection_type;
|
|
|
|
if (NP_IPX == send_address.connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&rsocket->addr;
|
|
#ifdef WIN32
|
|
memcpy(send_address.address, ipxaddr->sa_nodenum, 6);
|
|
memcpy(send_address.net_id, ipxaddr->sa_netnum, 4);
|
|
send_address.port = htons(ipxaddr->sa_socket);
|
|
#else
|
|
memcpy(send_address.address, ipxaddr->sipx_node, 6);
|
|
memcpy(send_address.net_id, &ipxaddr->sipx_network, 4);
|
|
send_address.port = htons(ipxaddr->sipx_port);
|
|
#endif
|
|
send_address.connection_type = NP_IPX;
|
|
} else if (NP_TCP == send_address.connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&rsocket->addr;
|
|
memcpy(send_address.address, &inaddr->sin_addr, 4);
|
|
send_address.port = htons(inaddr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
}
|
|
rcode = nw_SendWithID(NWT_RELIABLE, (ubyte *)&send_header,
|
|
RELIABLE_PACKET_HEADER_ONLY_SIZE + rsocket->send_len[i], &send_address);
|
|
|
|
if ((rcode == SOCKET_ERROR) && (WSAEWOULDBLOCK == WSAGetLastError())) {
|
|
// The packet didn't get sent, flag it to try again next frame
|
|
rsocket->timesent[i] = timer_GetTime() - (NETRETRYTIME * 4);
|
|
} else {
|
|
rsocket->last_packet_sent = timer_GetTime();
|
|
rsocket->timesent[i] = timer_GetTime();
|
|
}
|
|
}
|
|
}
|
|
// We've sent all the packets, now we go out of urgent mode.
|
|
rsocket->send_urgent = 0;
|
|
if ((rsocket->status == RNF_CONNECTED) && ((timer_GetTime() - rsocket->last_packet_sent) > NETHEARTBEATTIME)) {
|
|
reliable_header send_header;
|
|
// mprintf((0,"Resending reliable packet in nw_WorkReliable().\n"));
|
|
send_header.send_time = timer_GetTime();
|
|
send_header.seq = 0;
|
|
send_header.data_len = 0;
|
|
send_header.type = RNT_HEARTBEAT;
|
|
rcode = -1;
|
|
network_address send_address;
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
|
|
send_address.connection_type = rsocket->connection_type;
|
|
|
|
if (NP_IPX == send_address.connection_type) {
|
|
SOCKADDR_IPX *ipxaddr = (SOCKADDR_IPX *)&rsocket->addr;
|
|
#ifdef WIN32
|
|
memcpy(send_address.address, ipxaddr->sa_nodenum, 6);
|
|
memcpy(send_address.net_id, ipxaddr->sa_netnum, 4);
|
|
send_address.port = htons(ipxaddr->sa_socket);
|
|
#else
|
|
memcpy(send_address.address, ipxaddr->sipx_node, 6);
|
|
memcpy(send_address.net_id, &ipxaddr->sipx_network, 4);
|
|
send_address.port = htons(ipxaddr->sipx_port);
|
|
#endif
|
|
send_address.connection_type = NP_IPX;
|
|
} else if (NP_TCP == send_address.connection_type) {
|
|
SOCKADDR_IN *inaddr = (SOCKADDR_IN *)&rsocket->addr;
|
|
memcpy(send_address.address, &inaddr->sin_addr, 4);
|
|
send_address.port = htons(inaddr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
}
|
|
rcode = nw_SendWithID(NWT_RELIABLE, (ubyte *)&send_header, RELIABLE_PACKET_HEADER_ONLY_SIZE, &send_address);
|
|
|
|
if ((rcode != SOCKET_ERROR) && (WSAEWOULDBLOCK != WSAGetLastError())) {
|
|
// It must have been sent
|
|
rsocket->last_packet_sent = timer_GetTime();
|
|
}
|
|
}
|
|
if ((rsocket->status == RNF_CONNECTED) && ((timer_GetTime() - rsocket->last_packet_received) > NETTIMEOUT)) {
|
|
// This socket is hosed.....inform someone?
|
|
mprintf((0, "Reliable Socket (%d) timed out in nw_WorkReliable().\n", j));
|
|
rsocket->status = RNF_BROKEN;
|
|
}
|
|
}
|
|
}
|
|
#endif // FIXED
|
|
} |