Files
Descent3/mac/MACNETWORKING.CPP
Kevin Bentley df209742fc Initial import
2024-04-15 21:43:29 -06:00

2424 lines
68 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
}