2 * $Logfile: /Freespace2/code/Network/PsNet.cpp $
7 * C file containing application level network-interface.
10 * Revision 1.4 2002/06/02 02:29:39 relnev
13 * Revision 1.3 2002/05/26 20:49:54 theoddone33
16 * Revision 1.2 2002/05/07 03:16:48 theoddone33
17 * The Great Newline Fix
19 * Revision 1.1.1.1 2002/05/03 03:28:10 root
23 * 7 7/15/99 9:20a Andsager
24 * FS2_DEMO initial checkin
26 * 6 11/19/98 4:19p Dave
27 * Put IPX sockets back in psnet. Consolidated all multiplayer config
30 * 5 11/19/98 8:04a Dave
31 * Full support for D3-style reliable sockets. Revamped packet lag/loss
32 * system, made it receiver side and at the lowest possible level.
34 * 4 11/17/98 11:12a Dave
35 * Removed player identification by address. Now assign explicit id #'s.
37 * 3 10/09/98 2:57p Dave
38 * Starting splitting up OS stuff.
40 * 2 10/07/98 10:53a Dave
43 * 1 10/07/98 10:50a Dave
45 * 107 9/15/98 4:04p Allender
46 * added back in the -ip_addr command line switch because it needs to be
47 * in the standalone server only executable
49 * 106 9/14/98 11:28a Allender
50 * support for server bashing of address when received from client. Added
51 * a cmdline.cfg file to process command line arguments from a file
53 * 105 9/08/98 2:20p Allender
54 * temporary code to force IP address to a specific value.
56 * 104 8/21/98 1:15p Dave
57 * Put in log system hooks in useful places.
59 * 103 8/12/98 4:50p Allender
60 * fix error with new write socket code
62 * 102 8/11/98 11:45a Allender
63 * fix major problem in psnet_send where select() would block until ready
64 * to send, which for slow modems could be a long time. Doesn't block,
65 * and now correctly returns when socket is not set for writing
67 * 101 8/07/98 10:40a Allender
68 * new command line flags for starting netgames. Only starting currently
69 * works, and PXO isn't implemented yet
71 * 100 7/28/98 4:43p Allender
72 * fix bug where error on receiving of reliable data would sometimes
75 * 99 7/06/98 5:05p Allender
76 * dont use default port to send UDP data to. Use port stored in address
78 * 98 6/13/98 9:32p Mike
79 * Kill last character in file which caused "Find in Files" to report the
80 * file as "not a text file."
82 * 97 6/13/98 6:01p Hoffoss
83 * Externalized all new (or forgot to be added) strings to all the code.
85 * 96 6/13/98 3:19p Hoffoss
86 * NOX()ed out a bunch of strings that shouldn't be translated.
88 * 95 6/10/98 2:56p Dave
89 * Substantial changes to reduce bandwidth and latency problems.
91 * 94 6/05/98 9:55a Lawrance
94 * 93 5/24/98 2:17p Allender
95 * make reliable socket read all data before returning
97 * 92 5/22/98 10:54a Allender
98 * new dialog information for networking to tell user if connection type
99 * doesn't match the setup specified type
101 * 91 5/21/98 3:31p Allender
102 * more RAS stuff -- fix possible problem when unable to read data on
105 * 90 5/20/98 4:34p John
106 * fixed some bugs with rasenum connections. HAd to specify ansi versions
107 * in dll. Also, my pc returned 0 connections, before that still said
108 * there was a connection.
116 #include <windowsx.h>
121 #include <raserror.h>
129 #include "multiutil.h"
130 #include "multilag.h"
131 #include "osregistry.h"
133 #include "multi_log.h"
138 // old style packet buffering
139 // #define PSNET_BUFFER_OLD_SCHOOL
141 // sockets for IPX and TCP
143 SOCKET IPX_reliable_socket;
144 SOCKET IPX_listen_socket;
147 SOCKET TCP_reliable_socket;
148 SOCKET TCP_listen_socket;
150 // the sockets that the game will use when selecting network type
151 SOCKET Unreliable_socket = INVALID_SOCKET;
152 SOCKET Reliable_socket = INVALID_SOCKET;
153 SOCKET Listen_socket = INVALID_SOCKET;
155 BOOL Psnet_my_addr_valid;
156 net_addr Psnet_my_addr;
158 ubyte Null_address[6];
161 int Can_broadcast; // can we do broadcasting on our socket?
162 int Ipx_can_broadcast = 0;
163 int Tcp_can_broadcast = 0;
166 int Tcp_failure_code = 0;
167 int Ipx_failure_code = 0;
169 int Psnet_connection;
171 ushort Psnet_default_port;
173 // specified their internet connnection type
174 #define NETWORK_CONNECTION_NONE 1
175 #define NETWORK_CONNECTION_DIALUP 2
176 #define NETWORK_CONNECTION_LAN 3
178 // defines and variables to indicate network connection status
179 #define NETWORK_STATUS_NOT_INITIALIZED 1
180 #define NETWORK_STATUS_NO_WINSOCK 2 // winsock failed to initialize
181 #define NETWORK_STATUS_NO_PROTOCOL 3 // specified protocol doesn't appear to be loaded
182 #define NETWORK_STATUS_NO_RELIABLE 4
183 #define NETWORK_STATUS_RUNNING 5 // everything should be running
185 // defintion of structures that actually leave this machine. psnet_send give us only
186 // the data that we want to send. We will add a header onto this data (packet sequence
187 // number, possibly a checksum). We must include a 2 byte flags variable into both structure
188 // since the receiving end of this packet must know whether or not to checksum the packet.
190 // use the pack pragma to pack these structures to 2 byte aligment. Really only needed for
193 #pragma pack(push, 2)
195 // packet def for a checksum'ed packet
196 #define MAX_CHECKSUM_PACKET_SIZE 1024
197 typedef struct network_checksum_packet
202 ubyte data[MAX_CHECKSUM_PACKET_SIZE];
203 } network_checksum_packet;
205 // definition for a non-checksum packet
206 typedef struct network_packet
210 ubyte data[MAX_PACKET_SIZE];
211 } network_naked_packet;
213 // structure definition for our packet buffers
214 typedef struct network_packet_buffer
219 ubyte data[MAX_PACKET_SIZE];
220 } network_packet_buffer;
224 #define MAX_PACKET_BUFFERS 96
226 #ifdef PSNET_BUFFER_OLD_SCHOOL
227 LOCAL network_packet_buffer packet_buffers[MAX_PACKET_BUFFERS]; // buffer to hold packets sent to us
228 LOCAL short packet_free_list[MAX_PACKET_BUFFERS]; // contains id's of free packet buffers
229 LOCAL Num_packet_buffers;
230 LOCAL int Largest_packet_index = 0;
236 // variables to keep track of bytes read/written during the course of network play
239 #define PSNET_FRAME_FILTER 32
240 #define MAX_NET_STATS 32
244 net_addr addr; // stats for this address
245 int total_read; // total bytes read
246 int total_written; // total bytes read.
254 net_stats Psnet_stats[MAX_NET_STATS];
255 socket_xlate Psnet_socket_addr[MAX_NET_STATS];
257 int psnet_bytes_read_frame; // running count of bytes read this frame
258 int psnet_bytes_written_frame; // running count of bytes written this frame
260 int Psnet_bytes_read; // globally available numbers for printing on the hud
261 int Psnet_bytes_written;
263 int psnet_read_sizes[PSNET_FRAME_FILTER];
264 int psnet_write_sizes[PSNET_FRAME_FILTER];
266 int psnet_read_total;
267 int psnet_write_total;
269 int psnet_frame_count;
273 #define MAXHOSTNAME 128
275 #define MAX_RECEIVE_BUFSIZE (1<<15) // 32 K, eh?
276 #define MAX_SEND_RETRIES 20 // number of retries when sending would block
277 #define MAX_LINGER_TIME 0 // in seconds -- when lingering to close a socket
281 int psnet_same_no_port( net_addr * a1, net_addr * a2 );
283 // do stats for a particular address. num_bytes is the number of bytes either read or
284 // written (depending on the read flag. read flag is true when reading, 0 when writing
285 void psnet_do_net_stats( net_addr *addr, int num_bytes, int read )
289 for ( i = 0; i < MAX_NET_STATS; i++ ) {
290 if ( !Psnet_stats[i].in_use )
292 if ( addr && psnet_same_no_port(&Psnet_stats[i].addr, addr) )
296 if ( i == MAX_NET_STATS ) {
297 // find the first NULL entry
298 for ( i = 0; i < MAX_NET_STATS; i++ ) {
299 if ( !Psnet_stats[i].in_use )
302 if ( i == MAX_NET_STATS ) {
303 Int3(); // we should always have a slot
306 Psnet_stats[i].addr = *addr;
307 Psnet_stats[i].in_use = 1;
310 Psnet_stats[i].total_read += num_bytes;
312 Psnet_stats[i].total_written += num_bytes;
315 // returns the stats for the given network address. returns 1 when (i.e. net_addr was found),
316 // 0 otherwise. total read and total written are returned in the parameters
317 int psnet_get_stats( net_addr *addr, int *tr, int *tw )
321 for ( i = 0; i < MAX_NET_STATS; i++ ) {
322 if ( !Psnet_stats[i].in_use )
325 if ( addr && psnet_same_no_port(&Psnet_stats[i].addr, addr) )
329 if ( i == MAX_NET_STATS )
332 *tr = Psnet_stats[i].total_read;
333 *tw = Psnet_stats[i].total_written;
338 void psnet_stats_init()
342 for ( i = 0; i < MAX_NET_STATS; i++ ) {
343 Psnet_stats[i].in_use = 0;
344 Psnet_stats[i].total_read = 0;
345 Psnet_stats[i].total_written = 0;
346 Psnet_socket_addr[i].socket = INVALID_SOCKET;
352 #define NETWORK_STATUS_NOT_INITIALIZED 1
353 #define NETWORK_STATUS_NO_WINSOCK 2 // winsock failed to initialize
354 #define NETWORK_STATUS_NO_TCPIP 3 // TCP/IP doesn't appear to be loaded
355 #define NETWORK_STATUS_RUNNING 4 // everything should be running
357 // function called from high level FreeSpace code to determine the status of the networking
358 // code returns one of a handful of macros
359 int psnet_get_network_status()
361 // first case is when "none" is selected
362 if ( Psnet_connection == NETWORK_CONNECTION_NONE ) {
363 return NETWORK_ERROR_NO_TYPE;
366 // first, check the connection status of the network
367 if ( Network_status == NETWORK_STATUS_NO_WINSOCK )
368 return NETWORK_ERROR_NO_WINSOCK;
370 if ( Network_status == NETWORK_STATUS_NO_TCPIP )
371 return NETWORK_ERROR_NO_TCPIP;
373 // network is running -- be sure that the RAS people know to connect if they currently cannot.
375 if ( Psnet_connection == NETWORK_CONNECTION_DIALUP ) {
376 // if on a dialup connection, be sure that RAS is active.
377 if ( !Ras_connected ) {
378 return NETWORK_ERROR_CONNECT_TO_ISP;
380 } else if ( Psnet_connection == NETWORK_CONNECTION_LAN ) {
381 // if on a LAN, and they have a dialup connection active, return error to indicate that they need
382 // to pick the right connection type
383 if ( Ras_connected ) {
384 return NETWORK_ERROR_LAN_AND_RAS;
387 return NETWORK_ERROR_NONE;
390 DWORD (__stdcall *pRasEnumConnections)(LPRASCONN lprasconn, LPDWORD lpcb, LPDWORD lpcConnections) = NULL;
391 DWORD (__stdcall *pRasGetConnectStatus)(HRASCONN hrasconn, LPRASCONNSTATUS lprasconnstatus ) = NULL;
392 DWORD (__stdcall *pRasGetProjectionInfo)(HRASCONN hrasconn, RASPROJECTION rasprojection, LPVOID lpprojection, LPDWORD lpcb ) = NULL;
394 // functions to get the status of a RAS connection
395 void psnet_ras_status()
398 unsigned long size, num_connections, i;
399 RASCONN rasbuffer[25];
400 HINSTANCE ras_handle;
404 // first, call a LoadLibrary to load the RAS api
405 ras_handle = LoadLibrary( NOX("rasapi32.dll") );
406 if ( ras_handle == NULL ) {
410 pRasEnumConnections = (DWORD (__stdcall *)(LPRASCONN, LPDWORD, LPDWORD))GetProcAddress(ras_handle, NOX("RasEnumConnectionsA"));
411 if (!pRasEnumConnections) {
412 FreeLibrary( ras_handle );
415 pRasGetConnectStatus = (DWORD (__stdcall *)(HRASCONN, LPRASCONNSTATUS))GetProcAddress(ras_handle, NOX("RasGetConnectStatusA"));
416 if (!pRasGetConnectStatus) {
417 FreeLibrary( ras_handle );
420 pRasGetProjectionInfo = (DWORD (__stdcall *)(HRASCONN, RASPROJECTION, LPVOID, LPDWORD))GetProcAddress(ras_handle, NOX("RasGetProjectionInfoA"));
421 if (!pRasGetProjectionInfo) {
422 FreeLibrary( ras_handle );
426 size = sizeof(rasbuffer);
427 rasbuffer[0].dwSize = sizeof(RASCONN);
429 rval = pRasEnumConnections( rasbuffer, &size, &num_connections );
431 FreeLibrary( ras_handle );
435 // JAS: My computer gets to this point, but I have no RAS connections,
437 if ( num_connections < 1 ) {
438 nprintf(("Network", "Found no connections\n" ));
439 FreeLibrary( ras_handle );
443 nprintf(("Network", "Found %d connections\n", num_connections));
445 for (i = 0; i < num_connections; i++ ) {
446 RASCONNSTATUS status;
450 nprintf(("Network", "Connection %d:\n", i));
451 nprintf(("Network", "Entry Name: %s\n", rasbuffer[i].szEntryName));
452 nprintf(("Network", "Device Type: %s\n", rasbuffer[i].szDeviceType));
453 nprintf(("Network", "Device Name: %s\n", rasbuffer[i].szDeviceName));
455 // get the connection status
456 status.dwSize = sizeof(RASCONNSTATUS);
457 rval = pRasGetConnectStatus(rasbuffer[i].hrasconn, &status);
459 FreeLibrary( ras_handle );
463 nprintf(("Network", "\tStatus: %s\n", (status.rasconnstate==RASCS_Connected)?"Connected":"Not Connected"));
465 // get the projection informatiom
466 size = sizeof(projection);
467 projection.dwSize = size;
468 rval = pRasGetProjectionInfo(rasbuffer[i].hrasconn, RASP_PppIp, &projection, &size );
470 FreeLibrary( ras_handle );
474 printf(("Network", "\tIP Address: %s\n", projection.szIpAddress));
479 FreeLibrary( ras_handle );
482 // -------------------------------------------------------------------------------------------------
483 // netmisc_calc_checksum() calculates the checksum of a block of memory.
486 ushort psnet_calc_checksum( void * vptr, int len )
488 ubyte * ptr = (ubyte *)vptr;
489 unsigned int sum1,sum2;
495 if (sum1 >= 255 ) sum1 -= 255;
500 return (unsigned short)((sum1<<8)+ sum2);
503 // -------------------------------------------------------------------------------------------------
504 // psnet_set_socket_mode()
508 uint psnet_set_socket_mode(SOCKET sock_id, int opt, BOOL toggle)
510 return (setsockopt(sock_id, SOL_SOCKET, opt, (LPSTR)&toggle, sizeof(toggle)));
514 // -------------------------------------------------------------------------------------------------
515 // sock_get_ip() returns the IP address of this computer.
521 char LclHost[MAXHOSTNAME];
528 // Init local address to zero
529 LclAddr.sin_addr.s_addr = INADDR_ANY;
531 // Get the local host name
532 nRet = gethostname(LclHost, MAXHOSTNAME );
533 if (nRet != SOCKET_ERROR ) {
534 // Resolve host name for local address
535 Hostent = gethostbyname((LPSTR)LclHost);
537 LclAddr.sin_addr.s_addr = *((u_long FAR *)(Hostent->h_addr));
540 return LclAddr.sin_addr.s_addr;
546 // psnet_get_ip() attempts to get the local IP address of this machine
547 // returns 0 on failure, and 1 on success
548 int psnet_get_ip( SOCKET s )
551 SOCKADDR_IN local_addr;
553 if ( Psnet_my_addr_valid ){
557 memset(&local_addr, 0, sizeof(SOCKADDR_IN));
558 len = sizeof(SOCKADDR_IN);
559 rval = getsockname(s, (SOCKADDR *)&local_addr, &len );
560 if ( rval == SOCKET_ERROR )
563 // now we should have an IP address of this machine.
564 memcpy(Psnet_my_addr.addr, &(local_addr.sin_addr), 4);
565 Psnet_my_addr.port = ntohs(local_addr.sin_port);
567 Psnet_my_addr_valid = 1;
571 // -------------------------------------------------------------------------------------------------
578 #ifndef PSNET_RELIABLE_OLD_SCHOOL
579 psnet_reliable_close();
582 if ( Network_status != NETWORK_STATUS_RUNNING )
585 WSACancelBlockingCall();
587 if ( TCP_listen_socket != INVALID_SOCKET ) {
588 shutdown( TCP_listen_socket, 1 );
589 closesocket( TCP_listen_socket );
592 if ( TCP_reliable_socket != INVALID_SOCKET ) {
593 shutdown( TCP_reliable_socket, 1 );
594 closesocket( TCP_reliable_socket );
597 if ( TCP_socket != INVALID_SOCKET ) {
598 shutdown( TCP_socket, 1 );
599 closesocket( TCP_socket );
603 //Warning( LOCATION, "Error closing wsock!\n" );
606 Network_status = NETWORK_STATUS_NOT_INITIALIZED;
609 // function to initialize a reliable socket. All it does is call the socket() command.
610 // returns 1 on success, 0 on failure.
611 int psnet_init_stream( SOCKET *s, int type )
617 sock = socket(AF_IPX,SOCK_STREAM,NSPROTO_SPX);
618 if ( sock == INVALID_SOCKET )
623 sock = socket(AF_INET,SOCK_STREAM,0);
624 if ( sock == INVALID_SOCKET )
638 // called by psnet_init to initialize the listen socket used by a host/server
639 int psnet_init_reliable(ushort port, int should_listen, int type)
641 SOCKET sock = 0; // JAS: Get rid of optimized warning
642 SOCKADDR_IN sockaddr; // UDP/TCP socket structure
643 SOCKADDR_IPX ipx_addr; // IPX socket structure
645 // set up the reliable TCP transport socket
646 if ( !psnet_init_stream(&sock, type) ) {
647 nprintf(("Network", "Unable to initialize reliable socket on port %d (%d)!\n" , port, WSAGetLastError() ));
648 return INVALID_SOCKET;
651 // bind the socket to the port
654 memset(&ipx_addr, 0, sizeof(SOCKADDR_IPX));
655 ipx_addr.sa_socket = htons( port );
656 ipx_addr.sa_family = AF_IPX;
657 if (bind(sock, (SOCKADDR *)&ipx_addr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR) {
658 nprintf(("Network", "Unable to bind reliable socket on port %d (%d)!\n" , port, WSAGetLastError() ));
659 return INVALID_SOCKET;
664 memset( &sockaddr, 0, sizeof(SOCKADDR_IN) );
665 sockaddr.sin_family = AF_INET;
666 sockaddr.sin_addr.s_addr = INADDR_ANY; //fill in with our IP
667 sockaddr.sin_port = htons( port );
668 if ( bind(sock, (SOCKADDR*)&sockaddr, sizeof (sockaddr)) == SOCKET_ERROR) {
669 nprintf(("Network", "Unable to bind reliable socket on port %d (%d)!\n" , port, WSAGetLastError() ));
670 return INVALID_SOCKET;
676 return INVALID_SOCKET;
680 // set up the listen on the Reliable_socket port
681 if ( should_listen && listen(sock, 5) ) {
682 nprintf(("Network", "Unable to listen on Listen Socket (%d)!\n" , WSAGetLastError() ));
683 return INVALID_SOCKET;
686 // make any reliable sockets which we create that aren't listening non-blocking sockets
687 if ( !should_listen ) {
692 error = ioctlsocket( sock, FIONBIO, &arg );
693 if ( error == SOCKET_ERROR ) {
694 nprintf(("Network", "Unable to make reliable socket non-blocking -- %d", WSAGetLastError() ));
695 return INVALID_SOCKET;
698 // set the reuse option
699 if ( psnet_set_socket_mode(sock, SO_REUSEADDR, 1) == SOCKET_ERROR ) {
700 error = WSAGetLastError();
701 nprintf(("Network", "Error setting socket to reuse address -- %d\n", error));
709 void psnet_socket_options( SOCKET sock )
712 int ret, cursize, cursizesize, bufsize, trysize;
714 // Set the mode of the socket to allow broadcasting. We need to be able to broadcast
715 // when a game is searched for in IPX mode.
717 if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (LPSTR)&broadcast, sizeof(broadcast) )){
723 // try and increase the size of my receive buffer
724 bufsize = MAX_RECEIVE_BUFSIZE;
726 // set the current size of the receive buffer
727 cursizesize = sizeof(int);
728 getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (LPSTR)&cursize, &cursizesize);
729 for ( trysize = bufsize; trysize >= cursize; trysize >>= 1 ) {
730 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (LPSTR)&trysize, sizeof(trysize));
731 if ( ret == SOCKET_ERROR ) {
734 wserr = WSAGetLastError();
735 if ( (wserr == WSAENOPROTOOPT) || (wserr == WSAEINVAL) )
740 getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (LPSTR)&cursize, &cursizesize);
741 nprintf(("Network", "Receive buffer set to %d\n", cursize));
743 // set the current size of the send buffer
744 cursizesize = sizeof(int);
745 getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (LPSTR)&cursize, &cursizesize);
746 for ( trysize = bufsize; trysize >= cursize; trysize >>= 1 ) {
747 ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (LPSTR)&trysize, sizeof(trysize));
748 if ( ret == SOCKET_ERROR ) {
751 wserr = WSAGetLastError();
752 if ( (wserr == WSAENOPROTOOPT) || (wserr == WSAEINVAL) )
757 getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (LPSTR)&cursize, &cursizesize);
758 nprintf(("Network", "Send buffer set to %d\n", cursize));
762 // psnet_init called at game startup time and initializes all sockets that the game might use (i.e. for both
764 void psnet_init( int protocol, int port_num )
766 char *internet_connection;
769 // UDP/TCP socket structure
770 SOCKADDR_IN sockaddr;
772 // IPX socket structure
773 //SOCKADDR_IPX ipx_addr;
775 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
779 // GAME PORT INITIALIZATION STUFF
780 if ( Network_status == NETWORK_STATUS_RUNNING )
783 internet_connection = os_config_read_string(NULL, "NetworkConnection", "none");
784 if ( !stricmp(internet_connection, NOX("dialup")) ) {
785 Psnet_connection = NETWORK_CONNECTION_DIALUP;
786 } else if ( !stricmp(internet_connection, NOX("lan")) ) {
787 Psnet_connection = NETWORK_CONNECTION_LAN;
789 Psnet_connection = NETWORK_CONNECTION_NONE;
792 Network_status = NETWORK_STATUS_NO_WINSOCK;
793 if (WSAStartup(0x101, &wsa_data )){
797 // get the port for running this game on. Be careful that it cannot be out of bounds
798 Psnet_default_port = DEFAULT_GAME_PORT;
799 if ( (port_num > 1023) && (port_num < USHRT_MAX) ) {
800 Psnet_default_port = (ushort)port_num;
803 #ifndef PSNET_RELIABLE_OLD_SCHOOL
804 if(!psnet_reliable_init()){
805 nprintf(("Network","PSNET RELIABLE : init failed - no networking available!\n"));
810 // initialize TCP now
811 TCP_socket = INVALID_SOCKET;
812 TCP_reliable_socket = INVALID_SOCKET;
813 TCP_listen_socket = INVALID_SOCKET;
815 Network_status = NETWORK_STATUS_NO_TCPIP;
816 TCP_socket = socket( AF_INET, SOCK_DGRAM, 0 );
817 if ( TCP_socket == INVALID_SOCKET ) {
818 Tcp_failure_code = WSAGetLastError();
819 nprintf(("Network", "Error on TCP startup %d\n", Tcp_failure_code));
824 memset(&sockaddr,0,sizeof(SOCKADDR_IN));
825 sockaddr.sin_family = AF_INET;
827 sockaddr.sin_addr.s_addr = INADDR_ANY; //fill in with our IP
829 sockaddr.sin_port = htons( Psnet_default_port );
830 if ( bind(TCP_socket, (SOCKADDR*)&sockaddr, sizeof (sockaddr)) == SOCKET_ERROR) {
831 Tcp_failure_code = WSAGetLastError();
832 nprintf(( "Network", "Couldn't bind TCP socket (%d)! Invalidating TCP\n", Tcp_failure_code ));
836 #ifdef PSNET_RELIABLE_OLD_SCHOOL
837 // set up reliable socket (using SPX).
838 TCP_reliable_socket = psnet_init_reliable( 0, 0, NET_TCP );
839 if ( TCP_reliable_socket == INVALID_SOCKET ) {
840 Tcp_failure_code = WSAGetLastError();
841 nprintf(( "Network", "Couldn't initialize TCP reliable socket (OLD SCHOOL) (%d)! Invalidating TCP\n", Tcp_failure_code ));
845 TCP_listen_socket = psnet_init_reliable( (u_short)(Psnet_default_port-1), 1, NET_TCP );
846 if ( TCP_listen_socket == INVALID_SOCKET ) {
847 Tcp_failure_code = WSAGetLastError();
848 nprintf(( "Network", "Couldn't initialize TCP listen socket (OLD SCHOOL) (%d)! Invalidating TCP\n", Tcp_failure_code ));
853 psnet_socket_options( TCP_socket );
854 Tcp_can_broadcast = Can_broadcast;
857 // fire up a second UDP socket for "reliable" transport
858 #ifndef PSNET_RELIABLE_OLD_SCHOOL
859 TCP_reliable_socket = socket( AF_INET, SOCK_DGRAM, 0 );
860 if ( TCP_reliable_socket != INVALID_SOCKET ) {
862 memset(&sockaddr,0,sizeof(SOCKADDR_IN));
863 sockaddr.sin_family = AF_INET;
865 sockaddr.sin_addr.s_addr = INADDR_ANY; //fill in with our IP
866 //unsigned long my_ip = sock_get_ip();
867 //memcpy(&sockaddr.sin_addr.s_addr,&my_ip,sizeof(uint));
869 sockaddr.sin_port = htons( (ushort)(port+1) );
870 if ( bind(TCP_reliable_socket, (SOCKADDR*)&sockaddr, sizeof (sockaddr)) == SOCKET_ERROR) {
871 nprintf(( "Network", "Couldn't bind TCP socket (%d)! Invalidating TCP\n", WSAGetLastError() ));
875 psnet_socket_options( TCP_reliable_socket );
882 Network_status = NETWORK_STATUS_RUNNING;
884 nprintf(("Network","TCP Initialized\n"));
886 // with TCP initialized, see if the RAS services are installed
890 psnet_frame_int = -1; // for counting bytes per frame
893 #ifdef PSNET_BUFFER_OLD_SCHOOL
897 // initialize the packet buffer stuff. We use an array (the packet_free_list) to determine
898 // which of the packet buffers we can use next.
900 for (i=0; i<MAX_PACKET_BUFFERS; i++ ) {
901 packet_buffers[i].sequence_number = -1;
902 packet_free_list[i] = (short)i;
904 Num_packet_buffers = 0;
905 Largest_packet_index = 0;
907 // initialize the new buffering system
912 #define MAX_TMPBUF_SIZE 1024
914 #ifdef PSNET_RELIABLE_OLD_SCHOOL
915 // function to shutdown and close the given socket. It takes a couple of things into consideration
916 // when closing, such as possibly reiniting reliable sockets if they are closed here.
917 void psnet_rel_close_socket( PSNET_SOCKET *p_sockp )
923 sockp = (SOCKET *)p_sockp;
925 if ( *sockp == INVALID_SOCKET )
929 if ( *sockp == IPX_reliable_socket )
930 nprintf(("Network", "Closing my reliable IPX socket\n"));
931 else if ( *sockp == TCP_reliable_socket )
932 nprintf(("network", "Closing my relibale TCP socket\n"));
934 nprintf(("Network", "Closing client's reliable socket\n"));
937 // make the socket blocking
938 //unsigned long val = 0;
939 //rval = ioctlsocket(*sockp,FIONBIO,&val);
940 //if ( rval == SOCKET_ERROR ) {
941 // error = WSAGetLastError();
942 // nprintf(("Network", "Error %d when trying to make reliable socket blocking.\n", error));
945 // set the socket to linger with a timeout of 0
949 rval = setsockopt(*sockp,SOL_SOCKET,SO_LINGER,(char*)&l_val,sizeof(linger));
950 if ( rval == SOCKET_ERROR ) {
951 error = WSAGetLastError();
952 nprintf(("Network", "Error %d when trying to set linger value.\n", error));
955 // see if this socket is my Reliable_socket. If so, I will have to reinitialize it!
957 if ( *sockp == IPX_reliable_socket )
958 reinit_type = NET_IPX;
959 else if ( *sockp == TCP_reliable_socket )
960 reinit_type = NET_TCP;
963 rval = shutdown( *sockp, 2); // shut the whole damn thing down.
964 if ( rval == SOCKET_ERROR ) {
965 error = WSAGetLastError();
966 nprintf(("Network", "Error %d on socket shutdown\n", error));
970 shutdown( *sockp, 1 );
972 while ( rval && (rval != SOCKET_ERROR) ) {
973 char tmp_buf[MAX_TMPBUF_SIZE];
975 rval = recv( *sockp, tmp_buf, MAX_TMPBUF_SIZE, 0 );
976 if ( rval == SOCKET_ERROR ) {
979 error = WSAGetLastError();
980 if ( error == WSAEWOULDBLOCK )
985 rval = closesocket( *sockp );
986 if ( rval == SOCKET_ERROR ) {
987 error = WSAGetLastError();
988 nprintf(("Network", "Error %d on closing socket\n", error ));
991 *sockp = INVALID_SOCKET;
993 // see if we need to reinitialize
994 if ( reinit_type != -1 ) {
997 port = Psnet_default_port;
998 if ( reinit_type == NET_IPX ){
999 IPX_reliable_socket = psnet_init_reliable( 0, 0, NET_IPX);
1000 Reliable_socket = IPX_reliable_socket;
1002 else if ( reinit_type == NET_TCP){
1003 TCP_reliable_socket = psnet_init_reliable( 0, 0, NET_TCP);
1004 Reliable_socket = TCP_reliable_socket;
1009 // function to shutdown and close the given socket. It takes a couple of things into consideration
1010 // when closing, such as possibly reiniting reliable sockets if they are closed here.
1011 void psnet_close_socket( PSNET_SOCKET *p_sockp )
1015 // copy the address to be removed
1016 memcpy(&remove,&((net_addr*)(*p_sockp)),sizeof(net_addr));
1018 // remove it from the reliable address list
1019 psnet_reliable_notify_drop_addr(&remove);
1021 // invalidate the passed in "socket"
1026 // function to check the status of the reliable socket and try to re-initialize it if necessary.
1027 // win95 seems to have trouble doing a reinit of the socket immediately after close, so this
1028 // function exists to check the status, and reinitialize if we need to
1029 int psnet_rel_check()
1031 // if our Reliable_socket is valid, simply return true to indicate all is well.
1032 if ( Reliable_socket != INVALID_SOCKET )
1035 // based on our protocol type, try to reinitialize the socket we need.
1036 switch( Socket_type ) {
1039 IPX_reliable_socket = psnet_init_reliable( 0, 0, NET_IPX);
1040 Reliable_socket = IPX_reliable_socket;
1044 TCP_reliable_socket = psnet_init_reliable( 0, 0, NET_TCP);
1045 Reliable_socket = TCP_reliable_socket;
1050 // return our status.
1051 if ( Reliable_socket == INVALID_SOCKET )
1057 // this function is called from a high level at FreeSpace to set the protocol that the user wishes to use
1058 int psnet_use_protocol( int protocol )
1061 SOCKADDR_IPX ipx_addr;
1063 // zero out my address
1064 Psnet_my_addr_valid = 0;
1065 memset( &Psnet_my_addr, 0, sizeof(Psnet_my_addr) );
1067 // wait until we choose a protocol to determine if we can broadcast
1070 switch ( protocol ) {
1074 // assign the IPX_* sockets to the socket values used elsewhere
1075 Unreliable_socket = IPX_socket;
1076 Reliable_socket = IPX_reliable_socket;
1077 Listen_socket = IPX_listen_socket;
1079 Can_broadcast = Ipx_can_broadcast;
1081 nprintf(("Network","Psnet : IPX broadcast\n"));
1084 // get the socket name for the IPX_socket, and put it into My_addr
1085 len = sizeof(SOCKADDR_IPX);
1086 if ( getsockname(IPX_socket, (SOCKADDR *)&ipx_addr, &len) == SOCKET_ERROR ) {
1087 nprintf(("Network", "Unable to get sock name for IPX unreliable socket (%d)\n", WSAGetLastError() ));
1091 memcpy(Psnet_my_addr.net_id, ipx_addr.sa_netnum, 4);
1092 memcpy(Psnet_my_addr.addr, ipx_addr.sa_nodenum, 6);
1093 Psnet_my_addr.port = DEFAULT_GAME_PORT;
1095 nprintf(("Network","Psnet using - NET_IPX\n"));
1099 if ( Network_status != NETWORK_STATUS_RUNNING )
1102 // assign the TCP_* sockets to the socket values used elsewhere
1103 Unreliable_socket = TCP_socket;
1104 Reliable_socket = TCP_reliable_socket;
1105 Listen_socket = TCP_listen_socket;
1107 Can_broadcast = Tcp_can_broadcast;
1109 nprintf(("Network","Psnet : TCP broadcast\n"));
1112 nprintf(("Network","Psnet using - NET_TCP\n"));
1120 Psnet_my_addr.type = protocol;
1121 Socket_type = protocol;
1126 #define MAX_CONNECT_TRIES 10
1128 // attacmpt to connect() to the server's tcp socket. socket parameter is simply assigned to the
1129 // Reliable_socket socket created in psnet_init
1130 void psnet_rel_connect_to_server( PSNET_SOCKET *psocket, net_addr *server_addr)
1132 SOCKADDR_IN sockaddr; // UDP/TCP socket structure
1133 SOCKADDR_IPX ipx_addr; // IPX socket structure
1134 SOCKADDR *addr; // pointer to SOCKADDR to make coding easier
1138 int name_length, val;
1140 memset(iaddr, 0x00, 6);
1141 memcpy(iaddr, server_addr->addr, 6);
1142 port = (u_short)(server_addr->port - 1);
1144 socket = (SOCKET *)psocket;
1146 switch( Socket_type ) {
1148 ipx_addr.sa_family = AF_IPX;
1149 memcpy(ipx_addr.sa_nodenum, iaddr, 6);
1150 memcpy(ipx_addr.sa_netnum, server_addr->net_id, 4);
1151 ipx_addr.sa_socket = htons(port);
1152 addr = (SOCKADDR *)&ipx_addr;
1153 name_length = sizeof(ipx_addr);
1157 sockaddr.sin_family = AF_INET;
1158 memcpy(&sockaddr.sin_addr.s_addr, iaddr, 4);
1159 sockaddr.sin_port = htons(port);
1160 addr = (SOCKADDR *)&sockaddr;
1161 name_length = sizeof(sockaddr);
1170 ml_string(NOX("Attempting to perform reliable TCP connect to server"));
1172 // connect this guys Reliable_socket to the socket parameter passed in
1173 *socket = INVALID_SOCKET;
1174 val = connect(Reliable_socket, addr, name_length);
1176 // I suppose that we could have a valid socket right away
1177 if ( val != SOCKET_ERROR ) {
1178 *socket = Reliable_socket;
1182 error = WSAGetLastError();
1183 if ( error == WSAEWOULDBLOCK ) { // use select to find out when socket is writeable
1184 int is_set, num_tries;
1186 struct timeval timeout;
1188 // call select -- and return if an error leaving our connection to the client invalid
1192 FD_SET( Reliable_socket, &wfds );
1194 timeout.tv_usec = 500000; //500000 micro seconds is 1/2 second
1196 is_set = select( -1, NULL, &wfds, NULL, &timeout);
1198 is_set = select( Reliable_socket+1, NULL, &wfds, NULL, &timeout);
1200 // check for error on select first
1201 if ( is_set == SOCKET_ERROR ) {
1202 nprintf(("Network", "Error on select for connect %d\n", WSAGetLastError() ));
1204 } else if (is_set) { // if set, then we have connection, move forward
1207 Sleep(10); // sleep for 10 ms and try again
1210 } while ( num_tries < MAX_CONNECT_TRIES );
1212 if ( num_tries == MAX_CONNECT_TRIES )
1215 *socket = Reliable_socket;
1218 nprintf(("Network", "Connecting with server failed %d\n", error ));
1219 *socket = INVALID_SOCKET;
1223 // if we have a connection, get my address from getsockname
1224 if ( *socket == Reliable_socket ) {
1225 if ( !psnet_get_ip(Reliable_socket) ) {
1226 *socket = INVALID_SOCKET;
1233 void psnet_calc_bytes_per_frame()
1238 // -------------------------------------------------------------------------------------------------
1243 int psnet_same_no_port( net_addr * a1, net_addr * a2 )
1245 if ( !memcmp(a1->addr, a2->addr, 6) )
1250 int psnet_same( net_addr * a1, net_addr * a2 )
1252 return psnet_same_no_port( a1, a2 );
1254 if ( !memcmp(a1->addr, a2->addr, 6) && a1->port == a2->port)
1260 // -------------------------------------------------------------------------------------------------
1265 char* psnet_addr_to_string( char * text, net_addr * address )
1268 if ( Network_status != NETWORK_STATUS_RUNNING ) {
1269 strcpy( text, XSTR("[no networking]",910) );
1275 switch ( address->type ) {
1277 sprintf(text, "%x %x %x %x: %x %x %x %x %x %x", address->net_id[0],
1290 memcpy(&temp_addr.s_addr, address->addr, 4);
1291 strcpy( text, inet_ntoa(temp_addr) );
1304 // -------------------------------------------------------------------------------------------------
1305 // psnet_undescribe()
1309 void psnet_string_to_addr( net_addr * address, char * text )
1312 char str[255], *c, *port;
1315 if ( Network_status != NETWORK_STATUS_RUNNING ) {
1316 strcpy( text, XSTR("[no networking]",910) );
1320 // copy the text string to local storage to look for ports
1321 Assert( strlen(text) < 255 );
1323 c = strrchr(str, ':');
1330 switch ( address->type ) {
1332 Int3(); // no support for this yet
1336 addr.s_addr = inet_addr(str);
1337 // if we get INADDR_NONE returns, then we need to try and resolve the host
1339 if ( addr.s_addr == INADDR_NONE ) {
1340 he = gethostbyname( str );
1341 // returns a non-null pointer if successful, so get the address
1343 addr.s_addr = ((in_addr *)(he->h_addr))->s_addr; // this is the address in network byte order
1345 addr.s_addr = INADDR_NONE;
1349 memset(address->addr, 0x00, 6);
1350 memcpy(address->addr, &addr.s_addr, 4);
1352 address->port = (ushort)(atoi(port));
1363 // psnet_get_socket_data() will get data out of the socket and stuff it into the packet_buffers
1364 // The original psnet_get() now calls this function, then determines which of the packet buffers
1365 // to package up and use
1366 void psnet_get_socket_data(SOCKET socket, int flags = PSNET_FLAG_RAW)
1368 SOCKADDR_IN ip_addr; // UDP/TCP socket structure
1369 SOCKADDR_IPX ipx_addr; // IPX socket structure
1372 int read_len, from_len;
1374 network_checksum_packet packet_read;
1375 network_checksum_packet packet_data;
1377 // clear the addresses to remove compiler warnings
1378 memset(&ip_addr, 0, sizeof(SOCKADDR_IN));
1379 memset(&ipx_addr, 0, sizeof(SOCKADDR_IPX));
1381 if ( Network_status != NETWORK_STATUS_RUNNING ) {
1382 nprintf(("Network","Network ==> socket not inited in psnet_get\n"));
1387 #ifdef PSNET_BUFFER_OLD_SCHOOL
1389 // if there are no more packet buffers that we can use, then we must bail here before reading
1391 if ( Num_packet_buffers >= MAX_PACKET_BUFFERS ) {
1392 nprintf(("Network", "Packet buffer overrun in psnet_get()\n"));
1397 // check if there is any data on the socket to be read. The amount of data that can be
1398 // atomically read is stored in len.
1401 FD_SET( socket, &rfds );
1403 timeout.tv_usec = 0;
1406 if ( select( -1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
1408 if ( select( socket+1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
1410 nprintf(("Network", "Error %d doing a socket select on read\n", WSAGetLastError()));
1414 // if the read file descriptor is not set, then bail!
1415 if ( !FD_ISSET(socket, &rfds ) )
1418 // get data off the socket and process
1419 read_len = SOCKET_ERROR;
1420 switch ( Socket_type ) {
1422 from_len = sizeof(SOCKADDR_IPX);
1423 if(flags & PSNET_FLAG_RAW){
1424 read_len = recvfrom( socket, (char*)packet_read.data, MAX_PACKET_SIZE, 0, (SOCKADDR*)&ipx_addr, &from_len );
1426 read_len = recvfrom( socket, (char *)&packet_read, sizeof(packet_data), 0, (SOCKADDR*)&ipx_addr, &from_len );
1431 from_len = sizeof(SOCKADDR_IN);
1432 if(flags & PSNET_FLAG_RAW){
1433 read_len = recvfrom( socket, (char*)packet_read.data, MAX_PACKET_SIZE, 0, (SOCKADDR*)&ip_addr, &from_len );
1435 read_len = recvfrom( socket, (char *)&packet_read, sizeof(packet_data), 0, (SOCKADDR*)&ip_addr, &from_len );
1444 // set the from_addr for storage into the packet buffer structure
1445 from_addr.type = Socket_type;
1447 switch ( Socket_type ) {
1449 if(socket == Reliable_socket){
1450 from_addr.port = Psnet_default_port;
1452 from_addr.port = ntohs( ipx_addr.sa_socket );
1454 memcpy(from_addr.addr, ipx_addr.sa_nodenum, 6 );
1455 memcpy(from_addr.net_id, ipx_addr.sa_netnum, 4 );
1459 if(socket == Reliable_socket){
1460 from_addr.port = Psnet_default_port;
1462 from_addr.port = ntohs( ip_addr.sin_port );
1464 memset(from_addr.addr, 0x00, 6);
1465 memcpy(from_addr.addr, &ip_addr.sin_addr.S_un.S_addr, 4);
1473 if ( read_len == SOCKET_ERROR ) {
1474 int x = WSAGetLastError();
1475 nprintf(("Network", "Read error on socket. Winsock error %d \n", x));
1479 #ifndef PSNET_RELIABLE_OLD_SCHOOL
1481 // now we check to see if this is a reliable packet, and act accordindly
1482 if(socket == Reliable_socket){
1483 // this function processes the incoming packet, and determines if the system should continue to process the data
1484 shave_size = psnet_reliable_should_process(&from_addr,packet_read.data,read_len);
1488 // copy in from data+2, so we skip the reliable data header
1489 memcpy(packet_data.data,packet_read.data + shave_size,read_len);
1491 // subtract out the size of the reliable header
1492 read_len -= shave_size;
1495 memcpy(packet_data.data,packet_read.data,read_len);
1498 memcpy(packet_data.data,packet_read.data,read_len);
1501 #ifdef PSNET_BUFFER_OLD_SCHOOL
1505 // if we had no error reading from the socket, then determine if we need to calculate a
1506 // checksum on the packet
1507 if ( !(flags & PSNET_FLAG_RAW) && (packet_data.flags & PSNET_FLAG_CHECKSUM) ) {
1510 // calculate the size of the data that is actual real data
1511 len = read_len - (sizeof(packet_data) - MAX_CHECKSUM_PACKET_SIZE);
1512 checksum = psnet_calc_checksum( packet_data.data, len );
1513 if ( checksum != packet_data.checksum ) {
1514 nprintf(("Network", "bad checksum on incoming packet -- discarding\n"));
1517 data = packet_data.data;
1518 packet_id = packet_data.sequence_number;
1520 network_naked_packet *packet;
1522 // just read in the raw socket data and length
1523 if(flags & PSNET_FLAG_RAW){
1524 data = packet_data.data;
1529 // we don't have a checksum packet. cast the data to the naked packet type and
1530 // copy it over to passed parameters
1531 packet = (network_naked_packet *)&packet_data;
1533 len = read_len - (sizeof(network_naked_packet) - MAX_PACKET_SIZE);
1534 data = packet->data;
1536 packet_id = packet->sequence_number;
1540 // look at the sequence number compared to what we last received
1541 if ( Last_packet_id > -1 ) {
1542 if ( packet_id != (Last_packet_id+1) ) {
1543 //if ( packet_id < Last_packet_id )
1544 // nprintf(("network", "packet %d came in delayed (last id was %d\n", packet_id, Last_packet_id));
1545 //else if ( packet_id > (Last_packet_id+1) )
1546 // nprintf(("Network", "missed %d packet(s). last id %d. This id %d\n", (packet_id - Last_packet_id), Last_packet_id, packet_id));
1549 Last_packet_id = packet_id;
1552 psnet_do_net_stats( &from_addr, read_len, 1 );
1553 psnet_bytes_read_frame += read_len;
1556 // put all of the data (length, who from, etc.) into the next available packet buffer
1557 // slot. We should be assured of a slot here because of the check at the beginning
1558 // of the while loop
1559 Assert ( Num_packet_buffers < MAX_PACKET_BUFFERS );
1560 id = packet_free_list[ Num_packet_buffers++ ];
1561 if (id > Largest_packet_index ) Largest_packet_index = id;
1562 packet_buffers[id].len = len; // use the flags field of the packet structure to hold the data length
1563 packet_buffers[id].sequence_number = packet_id;
1564 packet_buffers[id].from_addr = from_addr;
1565 memcpy( packet_buffers[id].data, data, len );
1568 psnet_do_net_stats( &from_addr, read_len, 1 );
1569 psnet_bytes_read_frame += read_len;
1572 // buffer the packet
1573 psnet_buffer_packet(packet_data.data,read_len,&from_addr);
1578 // -------------------------------------------------------------------------------------------------
1583 int psnet_send( net_addr * who_to, void * data, int len, int flags, int reliable_socket )
1587 SOCKADDR_IN sockaddr; // UDP/TCP socket structure
1588 SOCKADDR_IPX ipx_addr; // IPX socket structure
1590 ubyte iaddr[6], *send_data;
1593 struct timeval timeout;
1595 if(!reliable_socket){
1596 send_sock = Unreliable_socket;
1598 send_sock = Reliable_socket;
1601 if ( Network_status != NETWORK_STATUS_RUNNING ) {
1602 nprintf(("Network","Network ==> Socket not inited in psnet_send\n"));
1606 if ( psnet_same( who_to, &Psnet_my_addr) ){
1610 memset(iaddr, 0x00, 6);
1611 memcpy(iaddr, who_to->addr, 6);
1613 if ( memcmp(iaddr, Null_address, 6) == 0) {
1614 nprintf(("Network","Network ==> send to address is 0 in psnet_send\n"));
1618 if(send_sock == Unreliable_socket){
1619 port = who_to->port;
1620 } else if(send_sock == Reliable_socket){
1621 port = DEFAULT_GAME_PORT + 1;
1623 port = who_to->port;
1627 nprintf(("Network","Network ==> destination port %d invalid in psnet_send\n", port));
1631 #ifdef PSNET_BUFFER_OLD_SCHOOL
1632 network_checksum_packet Send_network_checksum_packet;
1633 network_naked_packet Send_network_naked_packet;
1635 // determine from the flags whether or not this packet should have a checksum.
1636 if ( flags & PSNET_FLAG_CHECKSUM ) {
1637 // can't send raw data with a checksum, dumbass!
1638 Assert(!(flags & PSNET_FLAG_RAW));
1640 Send_network_checksum_packet.sequence_number = Next_packet_id++;
1641 Send_network_checksum_packet.flags = PSNET_FLAG_CHECKSUM;
1643 Send_network_checksum_packet.checksum = psnet_calc_checksum(data, len);
1644 memcpy( Send_network_checksum_packet.data, data, len );
1645 send_len = sizeof(Send_network_checksum_packet) - MAX_CHECKSUM_PACKET_SIZE + len;
1646 send_data = (ubyte *)&Send_network_checksum_packet;
1648 // send standard psnet stuff
1649 if(!(flags & PSNET_FLAG_RAW)){
1650 Send_network_naked_packet.sequence_number = Next_packet_id++;
1651 Send_network_naked_packet.flags = 0;
1653 memcpy(Send_network_naked_packet.data, data, len);
1654 send_len = sizeof(Send_network_naked_packet) - MAX_PACKET_SIZE + len; // gets us the real size of the structure
1655 send_data = (ubyte *)&Send_network_naked_packet;
1659 send_data = (ubyte*)data;
1664 send_data = (ubyte*)data;
1670 FD_SET( send_sock, &wfds );
1672 timeout.tv_usec = 0;
1675 if ( select( -1, NULL, &wfds, NULL, &timeout) == SOCKET_ERROR ) {
1677 if ( select( send_sock+1, NULL, &wfds, NULL, &timeout) == SOCKET_ERROR ) {
1679 nprintf(("Network", "Error on blocking select for write %d\n", WSAGetLastError() ));
1683 // if the write file descriptor is not set, then bail!
1684 if ( !FD_ISSET(send_sock, &wfds ) )
1688 switch ( who_to->type ) {
1691 ipx_addr.sa_socket = htons(port);
1692 ipx_addr.sa_family = AF_IPX;
1693 memcpy(ipx_addr.sa_nodenum, iaddr, 6);
1694 memcpy(ipx_addr.sa_netnum, who_to->net_id, 4);
1696 ret = sendto(send_sock, (char *)send_data, send_len, 0, (SOCKADDR*)&ipx_addr, sizeof(ipx_addr));
1697 if ( (ret != SOCKET_ERROR) && (ret != send_len) )
1698 nprintf(("Network", "requested to send %d bytes -- sent %d instead!!!\n", send_len, ret));
1704 sockaddr.sin_family = AF_INET;
1705 memcpy(&sockaddr.sin_addr.s_addr, iaddr, 4);
1706 sockaddr.sin_port = htons(port);
1708 ret = sendto( send_sock, (char *)send_data, send_len, 0, (SOCKADDR*)&sockaddr, sizeof(sockaddr) );
1712 Assert(0); // unknown protocol
1717 if ( ret != SOCKET_ERROR ) {
1719 psnet_bytes_written_frame += send_len;
1720 psnet_do_net_stats( who_to, send_len, 0 );
1724 //Warning( LOCATION, "Couldn't send data (0x%x)!\n", WSAGetLastError() );
1728 #ifdef PSNET_BUFFER_OLD_SCHOOL
1729 // routine to "free" a packet buffer
1730 void free_packet( int id )
1732 packet_buffers[id].sequence_number = -1;
1733 packet_free_list[ --Num_packet_buffers ] = (short)id;
1734 if ( Largest_packet_index == id)
1735 while ((--Largest_packet_index>0) && (packet_buffers[Largest_packet_index].sequence_number == -1 ));
1739 #ifdef PSNET_RELIABLE_OLD_SCHOOL
1740 // psnet_send_reliable sends the given data through the given reliable socket.
1742 #define MAX_RSEND_BUFFER 2048
1743 ubyte rsend_buffer[MAX_RSEND_BUFFER];
1745 int psnet_rel_send( PSNET_SOCKET psocket, ubyte *data, int length, int flags )
1748 int num_sent, total_sent, error, retries;
1750 unsigned short s_length;
1752 socket = (SOCKET)psocket;
1755 if ( Network_status != NETWORK_STATUS_RUNNING ) {
1756 nprintf(("Network","Network ==> Socket not inited in psnet_send\n"));
1760 if ( socket == INVALID_SOCKET ) // might happen in race conditions -- should get cleaned up.
1763 Assert( length < MAX_RSEND_BUFFER );
1765 // copy the length of the data into the beginning of the buffer. then put the data into the buffer
1766 // after the length value
1767 Assert( length > 0 );
1768 s_length = (ushort)length;
1769 memcpy( &rsend_buffer[0], &s_length, sizeof(s_length) );
1770 memcpy( &rsend_buffer[2], data, length );
1776 num_sent = send( socket, (char *)rsend_buffer, length+sizeof(s_length), 0 );
1777 if ( num_sent == SOCKET_ERROR ) {
1778 error = WSAGetLastError();
1779 if ( (error != WSAEWOULDBLOCK) || (retries > MAX_SEND_RETRIES) ) { // means that we would block on send -- not really an error
1781 // if error is would block, then set error to aborted connection
1782 if ( error == WSAEWOULDBLOCK )
1783 error = WSAECONNABORTED;
1785 multi_eval_socket_error(socket, error);
1788 retries++; // keep a try count
1791 send_data += num_sent;
1792 total_sent += num_sent;
1794 } while ( length > 0 );
1797 psnet_bytes_written_frame += total_sent;
1800 //index = psnet_find_stats_loc( who_to );
1801 //if ( index != -1 )
1802 // Psnet_stats[index].total_written += send_len;
1807 // get data off the reliable socket
1808 int psnet_rel_get( PSNET_SOCKET psocket, ubyte *buffer, int max_len, int flags)
1810 int from_len, total_read, error;
1813 struct timeval timeout;
1815 ubyte rread_buffer[2];
1817 socket = (SOCKET)psocket;
1819 // see if there is data to be read
1821 FD_SET( socket, &rfds );
1823 timeout.tv_usec = 0;
1826 if ( select( -1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
1828 if ( select( socket+1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
1830 nprintf(("Network", "Error on select for read reliable: %d\n", WSAGetLastError() ));
1834 // if no data, then we can leave.
1835 if ( !FD_ISSET(socket, &rfds ) )
1838 // we know we have data to read. We must read the two byte length of the packet first
1842 from_len = recv(socket, (char *)(&rread_buffer[total_read]), read_len - total_read, 0);
1844 // from_len will be 0 when back end gracefully closes connection. We will assume that since
1845 // the close is graceful, we will info from him telling us he's left. So we'll ignore
1846 // this condition here.
1847 if ( from_len == 0 ) {
1848 nprintf(("Network", "Dumping player because recv returned 0\n"));
1849 multi_eval_socket_error( socket, WSAECONNRESET ); // this error drops player from game.
1853 // on a socket error, we need to check for WSAEWOULDBLOCK meaning that there is no more
1855 else if ( from_len == SOCKET_ERROR ) {
1856 error = WSAGetLastError();
1857 if ( error != WSAEWOULDBLOCK )
1858 multi_eval_socket_error( socket, error );
1859 return 0; // get it next frame?
1862 total_read += from_len;
1863 } while ( total_read < read_len );
1867 memcpy(&read_len, &rread_buffer[0], 2);
1868 Assert( (read_len > 0) && (read_len < max_len) );
1869 if ( read_len == 0 )
1873 from_len = recv(socket, (char *)(buffer + total_read), read_len - total_read, 0);
1875 // from_len will be 0 when back end gracefully closes connection. We will assume that since
1876 // the close is graceful, we will info from him telling us he's left. So we'll ignore
1877 // this condition here.
1878 if ( from_len == 0 ) {
1879 nprintf(("Network", "Dumping player because recv returned 0\n"));
1880 multi_eval_socket_error( socket, WSAECONNRESET ); // this error drops player from game.
1884 // on a socket error, we need to check for WSAEWOULDBLOCK meaning that there is no more
1886 else if ( from_len == SOCKET_ERROR ) {
1887 error = WSAGetLastError();
1888 if ( error != WSAEWOULDBLOCK ) {
1889 multi_eval_socket_error( socket, error );
1895 total_read += from_len;
1896 } while ( total_read < read_len );
1901 // psnet_send_reliable sends the given data through the given reliable socket.
1902 int psnet_send_reliable( PSNET_SOCKET psocket, ubyte *data, int length, int flags )
1904 // don't do anything if the socket is null
1905 if(psocket == NULL){
1909 // send a reliable data packet
1910 return psnet_reliable_send(data,length,(net_addr*)psocket);
1913 int psnet_get_reliable( PSNET_SOCKET psocket, ubyte *buffer, int max_len, int flags)
1916 int best, best_id, i, n, size;
1918 // call the routine to read data out of the socket (which stuffs it into the packet buffers)
1919 psnet_get_socket_data(Reliable_socket,flags);
1921 #ifdef PSNET_BUFFER_OLD_SCHOOL
1922 // now determine which (if any) of the packet buffers we should look at!
1927 for (i=0; i <= Largest_packet_index; i++ ) {
1928 if ( packet_buffers[i].sequence_number > -1 ) {
1930 if ( best == -1 || (packet_buffers[i].sequence_number < best) ) {
1931 best = packet_buffers[i].sequence_number;
1937 //mprintf( (0, "Best id = %d, pn = %d, last_ecb = %x, len=%x, ne = %d\n", best_id, best, last_ecb, lastlen, neterrors ));
1938 //mprintf( (1, "<%d> ", neterrors ));
1940 if ( best_id < 0 ) return 0;
1942 size = packet_buffers[best_id].len;
1943 memcpy( buffer, packet_buffers[best_id].data, size );
1944 memcpy( psocket, &packet_buffers[best_id].from_addr, sizeof(net_addr) );
1945 free_packet(best_id);
1954 // function which checks the Listen_socket for possibly incoming requests to be connected.
1955 // returns 0 on error or nothing waiting. 1 if we should try to accept
1956 int psnet_rel_check_for_listen(net_addr *from_addr)
1960 SOCKET sock; // when trying to accept, this is new socket
1961 SOCKADDR_IN ip_addr; // UDP/TCP socket structure
1962 SOCKADDR_IPX ipx_addr; // IPX socket structure
1963 int from_len, error;
1967 FD_SET( Listen_socket, &rfds );
1969 timeout.tv_usec = 0;
1972 if ( select(-1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
1974 if ( select(Listen_socket+1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
1976 nprintf(("Network", "Error %d doing select on listen socket\n", WSAGetLastError() ));
1980 // check to see if Listen_socket has something -- if not, return
1981 if ( !FD_ISSET(Listen_socket, &rfds) )
1982 return INVALID_SOCKET;
1984 sock = INVALID_SOCKET;
1985 switch ( Socket_type ) {
1987 from_len = sizeof(SOCKADDR_IPX);
1988 sock = accept( Listen_socket, (SOCKADDR*)&ipx_addr, &from_len );
1989 from_addr->port = ntohs( ipx_addr.sa_socket );
1990 memcpy(from_addr->addr, ipx_addr.sa_nodenum, 6 );
1991 memcpy(from_addr->net_id, ipx_addr.sa_netnum, 4 );
1992 nprintf(("Network","Accepted SPX connection!!\n"));
1996 from_len = sizeof(SOCKADDR_IN);
1997 sock = accept( Listen_socket, (SOCKADDR*)&ip_addr, &from_len );
1998 from_addr->port = ntohs( ip_addr.sin_port );
1999 memset(from_addr->addr, 0x00, 6);
2000 memcpy(from_addr->addr, &ip_addr.sin_addr.S_un.S_addr, 4);
2001 nprintf(("Network","Accepted TCP connected!!\n"));
2009 if ( !psnet_get_ip(sock) ) {
2010 return INVALID_SOCKET;
2013 // make the new socket non-blocking
2014 if(sock != INVALID_SOCKET){
2016 error = ioctlsocket( sock, FIONBIO, &arg );
2017 if ( error == SOCKET_ERROR ) {
2018 nprintf(("Network", "Unable to make accepted socket non-blocking -- %d", WSAGetLastError() ));
2019 return INVALID_SOCKET;
2027 // psnet_get() will call the above function to read data out of the socket. It will then determine
2028 // which of the buffers we should use and pass to the routine which called us
2029 int psnet_get( void * data, net_addr* from_addr, int flags )
2031 // USE THIS CODE TO TEST NON-BUFFERED SOCKET READS. OUT-OF-ORDER PACKETS DROP TO NEARLY 0
2036 int read_len,from_len;
2037 SOCKADDR_IN ip_addr;
2039 FD_SET( Unreliable_socket, &rfds );
2041 timeout.tv_usec = 0;
2044 if ( select( -1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
2046 if ( select( Unreliable_socket+1, &rfds, NULL, NULL, &timeout) == SOCKET_ERROR ) {
2048 nprintf(("Network", "Error %d doing a socket select on read\n", WSAGetLastError()));
2052 // if the read file descriptor is not set, then bail!
2053 if ( !FD_ISSET(Unreliable_socket, &rfds ) )
2056 // get data off the socket and process
2057 read_len = SOCKET_ERROR;
2058 from_len = sizeof(SOCKADDR_IN);
2059 read_len = recvfrom( Unreliable_socket, (char*)data, MAX_PACKET_SIZE, 0, (SOCKADDR*)&ip_addr, &from_len );
2060 from_addr->port = ntohs( ip_addr.sin_port );
2061 memset(from_addr->addr, 0x00, 6);
2062 memcpy(from_addr->addr, &ip_addr.sin_addr.S_un.S_addr, 4);
2066 // call the routine to read data out of the socket (which stuffs it into the packet buffers)
2067 psnet_get_socket_data(Unreliable_socket,flags);
2069 #ifdef PSNET_BUFFER_OLD_SCHOOL
2070 int best, best_id, i, n, size;
2072 // now determine which (if any) of the packet buffers we should look at!
2077 for (i=0; i <= Largest_packet_index; i++ ) {
2078 if ( packet_buffers[i].sequence_number > -1 ) {
2080 if ( best == -1 || (packet_buffers[i].sequence_number < best) ) {
2081 best = packet_buffers[i].sequence_number;
2087 //mprintf( (0, "Best id = %d, pn = %d, last_ecb = %x, len=%x, ne = %d\n", best_id, best, last_ecb, lastlen, neterrors ));
2088 //mprintf( (1, "<%d> ", neterrors ));
2090 if ( best_id < 0 ) return 0;
2092 size = packet_buffers[best_id].len;
2093 memcpy( data, packet_buffers[best_id].data, size );
2094 memcpy( from_addr, &packet_buffers[best_id].from_addr, sizeof(net_addr) );
2095 free_packet(best_id);
2101 // try and get a free buffer and return its size
2102 if(psnet_buffer_get_next((ubyte*)data,&buffer_size,from_addr)){
2113 // -------------------------------------------------------------------------------------------------
2114 // psnet_broadcast()
2118 int psnet_broadcast( net_addr * who_to, void * data, int len, int flags )
2120 if ( Network_status != NETWORK_STATUS_RUNNING ) {
2121 nprintf(("Network","Network ==> Socket not inited in psnet_broadcast\n"));
2125 if ( !Can_broadcast ) {
2126 nprintf(("Network", "Cannot broadcast -- returning without doing anything\n"));
2130 ubyte broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2132 // broadcasting works on a local subnet which is all we really want to do for now anyway.
2133 // we might keep this in as an option for freespace later.
2134 switch ( who_to->type ) {
2138 memcpy(who_to->addr, broadcast, 6);
2139 psnet_send(who_to, data, len, flags);
2147 // called to clear out the socket of any remaining data
2151 ubyte data[MAX_PACKET_SIZE];
2154 while ( psnet_get( data, &from_addr ) > 0 ) ;
2160 // function to keep track of bytes read/written on average during the frame
2161 void psnet_calc_socket_stats()
2163 if ( psnet_frame_int == -1 ) {
2165 for ( i = 0; i < PSNET_FRAME_FILTER; i++ ) {
2166 psnet_read_sizes[i] = 0;
2167 psnet_write_sizes[i] = 0;
2169 psnet_read_total = 0;
2170 psnet_write_total = 0;
2171 psnet_frame_int = 0;
2173 psnet_read_total -= psnet_read_sizes[psnet_frame_int];
2174 psnet_write_total -= psnet_write_sizes[psnet_frame_int];
2176 psnet_read_total += psnet_bytes_read_frame;
2177 psnet_write_total += psnet_bytes_written_frame;
2179 psnet_read_sizes[psnet_frame_int] = psnet_bytes_read_frame;
2180 psnet_write_sizes[psnet_frame_int] = psnet_bytes_written_frame;
2182 psnet_frame_int = (psnet_frame_int + 1 ) % PSNET_FRAME_FILTER;
2184 if ( psnet_frame_count > 0 ) {
2185 if ( psnet_frame_count >= PSNET_FRAME_FILTER )
2186 Psnet_bytes_read = psnet_read_total / PSNET_FRAME_FILTER;
2188 Psnet_bytes_read = psnet_read_total / psnet_frame_count;
2190 if ( psnet_frame_count >= PSNET_FRAME_FILTER )
2191 Psnet_bytes_written = psnet_write_total / PSNET_FRAME_FILTER;
2193 Psnet_bytes_written = psnet_write_total / psnet_frame_count;
2196 psnet_frame_count++;
2197 psnet_bytes_read_frame = 0;
2198 psnet_bytes_written_frame = 0;
2202 int psnet_is_valid_numeric_ip(char *ip)
2206 int val1,val2,val3,val4;
2208 // get the first ip value
2210 token = strtok(copy,".");
2214 // get the value of the token
2216 if((val1 < 0) || (val1 > 255)){
2222 token = strtok(NULL,".");
2226 // get the value of the token
2228 if((val2 < 0) || (val2 > 255)){
2234 token = strtok(NULL,".");
2238 // get the value of the token
2240 if((val3 < 0) || (val3 > 255)){
2246 token = strtok(NULL,"");
2250 // get the value of the token
2252 if((val4 < 0) || (val4 > 255)){
2257 // make sure he hasn't entered all 0's
2258 if((val1 == 0) && (val2 == 0) && (val3 == 0) && (val4 == 0)){
2267 // returns true or false if the given string is a valid ip string or not.
2268 // allow port allows us to append the port number on the end of the ip string with
2270 // so we must be sure to remove the port number
2271 int psnet_is_valid_ip_string( char *ip_string, int allow_port )
2274 struct hostent *host_ent;
2277 // our addresses may have ports, so make local copy and remove port number
2278 Assert( strlen(ip_string) < 255 );
2279 strcpy(str, ip_string);
2280 c = strrchr(str, ':');
2285 addr.s_addr = inet_addr(ip_string);
2286 if ( addr.s_addr != INADDR_NONE ){
2287 // make sure the ip string is a valid format string
2288 if(psnet_is_valid_numeric_ip(ip_string)){
2293 // try name resolution
2294 host_ent = gethostbyname( ip_string );
2299 // valid host entry so return 1;
2304 // ------------------------------------------------------------------------------------------------------
2305 // PACKET BUFFERING FUNCTIONS
2308 #ifndef PSNET_BUFFER_OLD_SCHOOL
2310 // a sequence number of -1 will indicate that this packet is not valid
2311 LOCAL network_packet_buffer Psnet_buffers[MAX_PACKET_BUFFERS];
2312 LOCAL int Psnet_seq_number = 0;
2313 LOCAL int Psnet_lowest_id = 0;
2314 LOCAL int Psnet_highest_id = 0;
2316 // initialize the buffering system
2317 void psnet_buffer_init()
2321 // blast the buffer clean
2322 memset(Psnet_buffers,0,sizeof(network_packet_buffer) * MAX_PACKET_BUFFERS);
2324 // set all buffer sequence #'s to -1
2325 for(idx=0;idx<MAX_PACKET_BUFFERS;idx++){
2326 Psnet_buffers[idx].sequence_number = -1;
2329 // initialize the sequence #
2330 Psnet_seq_number = 0;
2331 Psnet_lowest_id = -1;
2332 Psnet_highest_id = -1;
2335 // buffer a packet (maintain order!)
2336 void psnet_buffer_packet(ubyte *data, int length, net_addr *from)
2341 // find the first empty packet
2342 for(idx=0;idx<MAX_PACKET_BUFFERS;idx++){
2343 if(Psnet_buffers[idx].sequence_number == -1){
2349 // if we didn't find the buffer, report an overrun
2351 nprintf(("Network","WARNING - Buffer overrun in psnet\n"));
2354 memcpy(Psnet_buffers[idx].data,data,length);
2355 Psnet_buffers[idx].len = length;
2356 memcpy(&Psnet_buffers[idx].from_addr,from,sizeof(net_addr));
2357 Psnet_buffers[idx].sequence_number = Psnet_seq_number;
2359 // keep track of the highest id#
2360 Psnet_highest_id = Psnet_seq_number++;
2362 // set the lowest id# for the first time
2363 if(Psnet_lowest_id == -1){
2364 Psnet_lowest_id = Psnet_highest_id;
2369 // get the index of the next packet in order!
2370 int psnet_buffer_get_next(ubyte *data, int *length, net_addr *from)
2375 // if there are no buffers, do nothing
2376 if((Psnet_lowest_id == -1) || (Psnet_lowest_id > Psnet_highest_id)){
2380 // search until we find the lowest packet index id#
2381 for(idx=0;idx<MAX_PACKET_BUFFERS;idx++){
2382 // if we found the buffer
2383 if(Psnet_buffers[idx].sequence_number == Psnet_lowest_id){
2389 // at this point, we should _always_ have found the buffer
2392 // copy out the buffer data
2393 memcpy(data,Psnet_buffers[idx].data,Psnet_buffers[idx].len);
2394 *length = Psnet_buffers[idx].len;
2395 memcpy(from,&Psnet_buffers[idx].from_addr,sizeof(net_addr));
2397 // now we need to cleanup the packet list
2399 // mark the buffer as free
2400 Psnet_buffers[idx].sequence_number = -1;
2408 // initialize the buffering system
2409 void psnet_buffer_init() {}
2411 // buffer a packet (maintain order!)
2412 void psnet_buffer_packet(ubyte *data, int length) {}
2414 // get the index of the next packet in order!
2415 int psnet_buffer_get_next() { return -1; }
2419 // ------------------------------------------------------------------------------------------------------
2420 // RELIABLE UDP FUNCTIONS
2423 // verbose debug output
2424 #define PSNET_RELIABLE_VERBOSE
2426 // overall buffer space allocated to the buffers
2427 #define PSNET_RELIABLE_MAX_OUT_BUFFER_SIZE (1<<18) // 256k
2428 #define PSNET_RELIABLE_MAX_IN_BUFFER_SIZE (1<<12) // 4k
2430 // outgoing reliable packets
2431 typedef struct reliable_packet_out {
2432 ubyte data[MAX_PACKET_SIZE]; // data in the original packet
2433 ushort packet_size; // size of the original packet
2434 ushort player_flags; // bitflags indexing (1<<N) into the Psnet_reliable_addr[N] array
2435 ushort player_acks; // bitflags indexing (1<<N) into the Psnet_reliable_addr[N] array
2436 int player_stamps[MAX_PLAYERS]; // timeouts for each player
2437 ubyte num_resends[MAX_PLAYERS]; // # of times we've resent to a given player
2438 ushort out_id; // identifier of the packet
2439 fix age; // how old this packet is
2440 } reliable_packet_out;
2442 // incoming reliable packets
2443 typedef struct reliable_packet_in {
2444 ushort in_id; // identifier of the received packet
2445 fix age; // when we received the packet
2446 } reliable_packet_in;
2448 // # of outgoing and incoming buffers we'll allocate
2449 #define PSNET_RELIABLE_NUM_OUT_BUFFERS (PSNET_RELIABLE_MAX_OUT_BUFFER_SIZE / sizeof(reliable_packet_out))
2450 #define PSNET_RELIABLE_NUM_IN_BUFFERS (PSNET_RELIABLE_MAX_IN_BUFFER_SIZE / sizeof(reliable_packet_in))
2452 // timeout to be used for the packets
2453 #define PSNET_RELIABLE_TIMEOUT 1500 // in ms
2455 // # of repeats to use
2456 #define PSNET_RELIABLE_REPEAT 8 // repeat this many times max
2459 #define PSNET_RELIABLE_INVALID 0
2462 #define PSNET_RELIABLE_ACK 0xffff
2464 // the outgoing and incoming buffers themselves
2465 reliable_packet_out *Psnet_reliable_out[PSNET_RELIABLE_NUM_OUT_BUFFERS];
2466 reliable_packet_in *Psnet_reliable_in[PSNET_RELIABLE_NUM_IN_BUFFERS];
2468 // psnet reliable address list
2469 net_addr Psnet_reliable_addr[MAX_PLAYERS]; // address of registered "reliable" addrs
2470 int Psnet_reliable_addr_flags; // bitflags indicating which of the above are valid
2472 // my local identifier # (will only use lower 12 bits)
2473 ushort Psnet_reliable_local_id = 0x1;
2475 // is the reliable system initialized
2476 int Psnet_reliable_inited = 0;
2478 // # of times a packet has not been delivered
2479 int Psnet_reliable_fail_count = 0;
2481 // # of times packets have had to be resent
2482 int Psnet_reliable_resend_count = 0;
2484 // # of times we've run out of packets and had to overwrite existing ones
2485 int Psnet_reliable_overwrite_count = 0;
2487 // forward declarations ------------------------------------------------------
2489 // free up all used buffers
2490 void psnet_reliable_free_all_buffers();
2492 // get the index of the passed address or -1 if it doesn't exist
2493 int psnet_reliable_addr_index(net_addr *addr);
2495 // get the index into the address array from the passed bitflag
2496 int psnet_reliable_index_addr(int flags);
2498 // kill all outgoing packets belonging to the passed index
2499 void psnet_reliable_kill_outgoing(int index);
2501 // generate a unique id #, given the passed in value and the address it came from, return PSNET_RELIABLE_INVALID
2502 // upper 12 bytes should be valid # and the lower 4 should be free for this function to fill in
2503 ushort psnet_reliable_get_unique_id(ushort id_num,net_addr *from);
2505 // get the upper 12 bit version of my id# and increment the original
2506 ushort psnet_reliable_get_next_id();
2508 // get the index of a free outgoing relible packet buffer, killing the oldest if necessary
2509 int psnet_reliable_get_free_outgoing();
2511 // get the index of a free incoming relible packet buffer, killing the oldest if necessary
2512 int psnet_reliable_get_free_incoming();
2514 // actually send the data contained with the reliable_packet_out
2515 int psnet_reliable_send_packet(reliable_packet_out *out,int force_index = 0);
2517 // evaluate the status of a reliable packet - and free it up if the thing is _done_
2518 void psnet_reliable_evaluate_status(reliable_packet_out *out);
2520 // determine if the passed id# exists in the in-packet list, return the instance where it exists, or -1 if it doesn't
2521 int psnet_reliable_find_in_id(ushort id_num);
2523 // determine if the passed id# exists in the out-packet list, return the instance where it exists, or -1 if it doesn't
2524 int psnet_reliable_find_out_id(ushort id_num);
2526 // send an ack to the specified address
2527 void psnet_reliable_send_ack(net_addr *addr,ushort id_num);
2530 // extern functions -----------------------------------------------------------
2532 // initialize the psnet reliable system (return 0 on fail, 1 on success)
2533 int psnet_reliable_init()
2537 // if the system is already inited, do nothing
2538 if(Psnet_reliable_inited){
2542 #ifdef PSNET_RELIABLE_VERBOSE
2543 nprintf(("Network","PSNET RELIABLE SIZES : \n OUT BUFFER SIZE : %d\n OUT BUFFER COUNT %d\n IN BUFFER SIZE %d\n IN BUFFER COUNT %d\n",
2544 PSNET_RELIABLE_MAX_OUT_BUFFER_SIZE,PSNET_RELIABLE_NUM_OUT_BUFFERS,PSNET_RELIABLE_MAX_IN_BUFFER_SIZE,PSNET_RELIABLE_NUM_IN_BUFFERS));
2548 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
2549 Psnet_reliable_out[idx] = NULL;
2551 for(idx=0;idx<PSNET_RELIABLE_NUM_IN_BUFFERS;idx++){
2552 Psnet_reliable_in[idx] = NULL;
2555 // initialize all outgoing buffers
2556 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
2557 Psnet_reliable_out[idx] = NULL;
2558 Psnet_reliable_out[idx] = (reliable_packet_out*)malloc(sizeof(reliable_packet_out));
2560 // if we failed to allocate the buffer, return failure
2561 if(Psnet_reliable_out[idx] == NULL){
2562 psnet_reliable_free_all_buffers();
2565 memset(Psnet_reliable_out[idx],0,sizeof(reliable_packet_out));
2568 // initialize all incoming buffers
2569 for(idx=0;idx<PSNET_RELIABLE_NUM_IN_BUFFERS;idx++){
2570 Psnet_reliable_in[idx] = NULL;
2571 Psnet_reliable_in[idx] = (reliable_packet_in*)malloc(sizeof(reliable_packet_in));
2573 // if we failed to allocate the buffer, return failure
2574 if(Psnet_reliable_in[idx] == NULL){
2575 psnet_reliable_free_all_buffers();
2578 memset(Psnet_reliable_in[idx],0,sizeof(reliable_packet_in));
2581 // blast the reliable address list free
2582 memset(Psnet_reliable_addr,0,sizeof(net_addr) * MAX_PLAYERS);
2583 Psnet_reliable_addr_flags = 0;
2585 // set the system to be initialized
2586 Psnet_reliable_inited = 1;
2588 // initialize my local id #
2589 Psnet_reliable_local_id = 0x1;
2591 // initialize the packet delivery fail count
2592 Psnet_reliable_fail_count = 0;
2594 // intialize the packet necessary resend count
2595 Psnet_reliable_resend_count = 0;
2597 // initialize # of times we've run out of packets and had to overwrite existing ones
2598 Psnet_reliable_overwrite_count = 0;
2604 // shutdown the reliable system (free up buffers, etc)
2605 void psnet_reliable_close()
2607 // if the system is not initialized, don't do anything
2608 if(!Psnet_reliable_inited){
2612 // free up all buffers
2613 psnet_reliable_free_all_buffers();
2615 // blast all addresses clean
2616 memset(Psnet_reliable_addr,0,sizeof(net_addr) * MAX_PLAYERS);
2617 Psnet_reliable_addr_flags = 0;
2619 // set the system as being uninitialized
2620 Psnet_reliable_inited = 0;
2623 // notify the reliable system of a new address at index N
2624 void psnet_reliable_notify_new_addr(net_addr *addr,int index)
2626 // copy in the address
2627 memcpy(&Psnet_reliable_addr[index],addr,sizeof(net_addr));
2629 // set the bit indicating its validity
2630 Psnet_reliable_addr_flags |= (1<<index);
2633 // notify the reliable system of a drop at index N
2634 void psnet_reliable_notify_drop_addr(net_addr *addr)
2638 // do a lookup for the address
2639 index = psnet_reliable_addr_index(addr);
2641 // clear out all packets belonging exclusively to this address
2642 psnet_reliable_kill_outgoing(index);
2644 // clear the address and its existence bit
2645 memset(&Psnet_reliable_addr[index],0,sizeof(net_addr));
2646 Psnet_reliable_addr_flags &= ~(1<<index);
2650 // send a reliable data packet
2651 int psnet_reliable_send(ubyte *data,int packet_size,net_addr *addr)
2655 reliable_packet_out *p;
2657 // if the system is not initialized, don't do anything
2658 if(!Psnet_reliable_inited){
2662 // try and find a guy to send to
2664 to_index = psnet_reliable_addr_index(addr);
2666 nprintf(("Network","PSNET RELIABLE : could not find player for outgoing packet!\n"));
2670 // attempt to get a free buffer
2672 free_buffer = psnet_reliable_get_free_outgoing();
2673 if(free_buffer == -1){
2674 Int3(); // should never happen - we should always overwrite the oldest buffer
2677 // setup the data for the outgoing packet
2678 p = Psnet_reliable_out[free_buffer];
2679 memcpy(p->data,data,packet_size);
2680 p->packet_size = (ushort)packet_size;
2681 p->player_flags |= (1<<to_index);
2682 memset(p->player_stamps,0xf,sizeof(int) * MAX_PLAYERS);
2683 p->player_stamps[to_index] = timestamp(PSNET_RELIABLE_TIMEOUT);
2684 p->out_id = psnet_reliable_get_next_id();
2685 p->age = timer_get_fixed_seconds();
2688 return psnet_reliable_send_packet(p);
2691 // process frame for all reliable stuff (call once per frame)
2692 void psnet_reliable_process()
2695 reliable_packet_out *p;
2697 // if the system is not initialized, don't do anything
2698 if(!Psnet_reliable_inited){
2702 // go through all active packets
2703 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
2704 // if the packet is active
2705 if(Psnet_reliable_out[idx]->out_id != PSNET_RELIABLE_INVALID){
2706 p = Psnet_reliable_out[idx];
2708 // loop through all active players and see if we need to resend
2709 for(s_idx=0;s_idx<MAX_PLAYERS;s_idx++){
2710 // if the packet is active for this player and he hasn't acked
2711 if(p->player_flags & (1<<s_idx) && !(p->player_acks & (1<<s_idx))){
2712 // if the timestamp has elapsed
2713 if((p->player_stamps[s_idx] != -1) && timestamp_elapsed(p->player_stamps[s_idx])){
2714 // if we are at max resends, bomb!
2715 if(p->num_resends[s_idx] >= PSNET_RELIABLE_REPEAT){
2716 #ifdef PSNET_RELIABLE_VERBOSE
2717 nprintf(("Network","PSNET RELIABLE : packet failed to be delivered (%d retries) !!\n",PSNET_RELIABLE_REPEAT));
2719 p->player_flags &= ~(1<<s_idx);
2721 // increment the fail count
2722 Psnet_reliable_fail_count++;
2724 // otherwise resend the packet
2726 // actually send the data contained with the reliable_packet_out
2727 psnet_reliable_send_packet(p,s_idx);
2729 // increment the resend count
2730 Psnet_reliable_resend_count++;
2732 #ifdef PSNET_RELIABLE_VERBOSE
2733 nprintf(("Network","PSNET RELIABLE : resending packet\n"));
2740 // evaluate if this packet has completed
2741 psnet_reliable_evaluate_status(p);
2746 // determine if the passed in reliable data should be processed, and sends an ack if necessary
2747 // return # of bytes which should be stripped off the data (reliable data header)
2748 int psnet_reliable_should_process(net_addr *addr,ubyte *data,int packet_size)
2750 ushort id_num,ack_code,unique_id;
2754 reliable_packet_in *p;
2756 // get the reliable packet id #
2757 memcpy(&id_num,data,sizeof(ushort));
2759 // if the id# is an ack, get the id# do a lookup
2760 if(id_num == PSNET_RELIABLE_ACK){
2761 #ifdef PSNET_RELIABLE_VERBOSE
2762 nprintf(("Network","PSNET RELIABLE : ACK 1\n"));
2768 memcpy(&id_num,data+2,sizeof(ushort));
2770 // get the packet index
2771 // unique_id = psnet_reliable_get_unique_id(id_num,addr);
2773 packet_index = psnet_reliable_find_out_id(unique_id);
2774 player_index = psnet_reliable_addr_index(addr);
2775 if((packet_index != -1) && (player_index != -1)){
2776 #ifdef PSNET_RELIABLE_VERBOSE
2777 nprintf(("Network","PSNET RELIABLE : ACK 2\n"));
2780 Psnet_reliable_out[packet_index]->player_acks |= (1<<player_index);
2782 // check to see if this packet is _done_
2783 psnet_reliable_evaluate_status(Psnet_reliable_out[packet_index]);
2786 // return 4 bytes processed
2790 // otherwise - see if this is a new packet
2791 packet_index = psnet_reliable_find_in_id(id_num);
2792 if(packet_index == -1){
2795 free_index = psnet_reliable_get_free_incoming();
2796 if(free_index == -1){
2800 // setup the incoming packet
2801 p = Psnet_reliable_in[free_index];
2802 p->age = timer_get_fixed_seconds();
2803 p->in_id = psnet_reliable_get_unique_id(id_num,addr);
2806 psnet_reliable_send_ack(addr,id_num);
2808 // return 2 bytes processed
2811 // send another ack for good measure
2813 psnet_reliable_send_ack(addr,id_num);
2819 // forward definitions --------------------------------------------
2821 // free up all used buffers
2822 void psnet_reliable_free_all_buffers()
2826 // free all outgoing buffers
2827 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
2828 // if the buffer is not null, free it
2829 if(Psnet_reliable_out[idx] != NULL){
2830 free(Psnet_reliable_out[idx]);
2831 Psnet_reliable_out[idx] = NULL;
2835 // free all incoming buffers
2836 for(idx=0;idx<PSNET_RELIABLE_NUM_IN_BUFFERS;idx++){
2837 // if the buffer is not null, free it
2838 if(Psnet_reliable_in[idx] != NULL){
2839 free(Psnet_reliable_in[idx]);
2840 Psnet_reliable_in[idx] = NULL;
2845 // get the index of the passed address or -1 if it doesn't exist
2846 int psnet_reliable_addr_index(net_addr *addr)
2850 // look through all valid addresses
2851 for(idx=0;idx<MAX_PLAYERS;idx++){
2852 if((Psnet_reliable_addr_flags & (1<<idx)) && psnet_same(addr,&Psnet_reliable_addr[idx])){
2857 // couldn't find the address
2861 // get the index into the address array from the passed bitflag
2862 int psnet_reliable_index_addr(int flags)
2866 // look through all the bits in the flags
2867 for(idx=0;idx<MAX_PLAYERS;idx++){
2868 if(flags & (1<<idx)){
2873 // couldn't find any
2877 // kill all outgoing packets belonging to the passed index
2878 void psnet_reliable_kill_outgoing(int index)
2882 // go through all buffers
2883 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
2884 if(Psnet_reliable_out[idx]->out_id != PSNET_RELIABLE_INVALID){
2885 // if it is exclusively his, kill the whole packet
2886 if(Psnet_reliable_out[idx]->player_flags == (1<<index)){
2887 memset(Psnet_reliable_out[idx],0,sizeof(reliable_packet_out));
2890 // if it belongs to him and other players, kill his entry
2891 else if(Psnet_reliable_out[idx]->player_flags & (1<<index)){
2892 Psnet_reliable_out[idx]->player_flags &= ~(1<<index);
2893 Psnet_reliable_out[idx]->num_resends[index] = 0;
2899 // generate a unique id #, given the passed in value and the address it came from, return PSNET_RELIABLE_INVALID
2900 // upper 12 bytes should be valid # and the lower 4 should be free for this function to fill in
2901 ushort psnet_reliable_get_unique_id(ushort id_num,net_addr *from)
2906 // if the lower 4 bits are not clear, we've got a problem
2911 // lookup through the Psnet_reliable_addr[] list and try and find the index
2912 for(idx=0;idx<MAX_PLAYERS;idx++){
2913 if((idx == 1) /*(Psnet_reliable_addr_flags & (1<<idx)) && (psnet_same(from,&Psnet_reliable_addr[idx]))*/){
2914 // fill in the lower 4 bits
2916 id_num |= (cast & 0xf);
2921 // couldn't find an id#
2922 return PSNET_RELIABLE_INVALID;
2925 // get the upper 12 bit version of my id# and increment the original
2926 ushort psnet_reliable_get_next_id()
2928 ushort id_num = Psnet_reliable_local_id;
2930 // clear out the upper 4 bits
2933 // shift 4 bits to the left
2936 // increment the local id #
2937 if(Psnet_reliable_local_id == 0x0fff){
2938 Psnet_reliable_local_id = 0x1;
2940 Psnet_reliable_local_id++;
2943 // return the shifted value
2947 // get the index of a free outgoing relible packet buffer, killing the oldest if necessary
2948 int psnet_reliable_get_free_outgoing()
2951 int oldest_index = -1;
2954 // search through all buffers
2955 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
2956 if(Psnet_reliable_out[idx]->out_id == PSNET_RELIABLE_INVALID){
2960 // keep track of the oldest packet
2961 if((oldest_index == -1) || (Psnet_reliable_out[idx]->age < oldest)){
2963 oldest = Psnet_reliable_out[idx]->age;
2967 // if we got here, all of our buffers are full, so we should kill the oldest one
2968 memset(Psnet_reliable_out[oldest_index],0,sizeof(reliable_packet_out));
2969 Psnet_reliable_overwrite_count = 0;
2970 #ifdef PSNET_RELIABLE_VERBOSE
2971 nprintf(("Network","PSNET RELIABLE : overwriting old send buffer\n"));
2973 return oldest_index;
2976 // get the index of a free incoming relible packet buffer, killing the oldest if necessary
2977 int psnet_reliable_get_free_incoming()
2980 int oldest_index = -1;
2983 // search through all buffers
2984 for(idx=0;idx<PSNET_RELIABLE_NUM_IN_BUFFERS;idx++){
2985 if(Psnet_reliable_in[idx]->in_id == PSNET_RELIABLE_INVALID){
2989 // keep track of the oldest packet
2990 if((oldest_index == -1) || (Psnet_reliable_in[idx]->age < oldest)){
2992 oldest = Psnet_reliable_in[idx]->age;
2996 // if we got here, all of our buffers are full, so we should kill the oldest one
2997 memset(Psnet_reliable_in[oldest_index],0,sizeof(reliable_packet_in));
2998 #ifdef PSNET_RELIABLE_VERBOSE
2999 nprintf(("Network","PSNET RELIABLE : overwriting old recv buffer\n"));
3001 return oldest_index;
3004 // actually send the data contained with the reliable_packet_out
3005 int psnet_reliable_send_packet(reliable_packet_out *out,int force_index)
3007 ubyte data[MAX_PACKET_SIZE];
3009 int packet_size = 2 + out->packet_size;
3011 // stick the identifier on the front of the packet
3012 memcpy(data,&out->out_id,sizeof(ushort));
3014 // copy in the actual data
3015 memcpy(data+2,out->data,out->packet_size);
3017 // send the packet and update the timestamp for all players
3019 // send to one specified player in the packet
3021 if(force_index != 0){
3022 if(out->player_flags & (1<<force_index) && !(out->player_acks & (1<<force_index))){
3023 bytes_sent = psnet_send(&Psnet_reliable_addr[force_index],data,packet_size,PSNET_FLAG_RAW,1);
3024 out->player_stamps[force_index] = timestamp(PSNET_RELIABLE_TIMEOUT);
3025 out->num_resends[force_index]++;
3028 // send to all players contained in the packet
3030 for(idx=0;idx<MAX_PLAYERS;idx++){
3031 // if this guy is flagged and he exists and he hasn't already acked
3032 if(out->player_flags & (1<<idx) && (Psnet_reliable_addr_flags & (1<<idx)) && !(out->player_acks & (1<<idx))){
3033 bytes_sent = psnet_send(&Psnet_reliable_addr[idx],data,packet_size,PSNET_FLAG_RAW,1);
3034 out->player_stamps[idx] = timestamp(PSNET_RELIABLE_TIMEOUT);
3035 out->num_resends[idx]++;
3044 // evaluate the status of a reliable packet - and free it up if the thing is _done_
3045 void psnet_reliable_evaluate_status(reliable_packet_out *out)
3049 // check to see if all players have acked or failed miserably
3051 for(idx=0;idx<MAX_PLAYERS;idx++){
3052 // if the packet is active for this guy but he has not acked yet
3053 if((out->player_flags & (1<<idx)) && !(out->player_acks & (1<<idx))){
3059 // if its ok to annihilate this packet, do so
3061 memset(out,0,sizeof(reliable_packet_out));
3065 // determine if the passed id# exists in the in-packet list, return the instance where it exists, or -1 if it doesn't
3066 int psnet_reliable_find_in_id(ushort id_num)
3070 // if the id is 0, its invalid
3071 if(id_num == PSNET_RELIABLE_INVALID){
3075 // look through all in packets
3076 for(idx=0;idx<PSNET_RELIABLE_NUM_IN_BUFFERS;idx++){
3077 if(id_num == Psnet_reliable_in[idx]->in_id){
3086 // determine if the passed id# exists in the out-packet list, return the instance where it exists, or -1 if it doesn't
3087 int psnet_reliable_find_out_id(ushort id_num)
3091 // if the id is 0, its invalid
3092 if(id_num == PSNET_RELIABLE_INVALID){
3096 // look through all in packets
3097 for(idx=0;idx<PSNET_RELIABLE_NUM_OUT_BUFFERS;idx++){
3098 if(id_num == Psnet_reliable_out[idx]->out_id){
3107 // send an ack to the specified address
3108 void psnet_reliable_send_ack(net_addr *addr,ushort id_num)
3114 val = PSNET_RELIABLE_ACK;
3115 memcpy(data,&val,sizeof(ushort));
3118 memcpy(data+2,&id_num,sizeof(ushort));
3121 psnet_send(addr,data,4,PSNET_FLAG_RAW,Reliable_socket);
3124 #endif // #ifndef PSNET2