DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

i_net_ps3.cpp (10877B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "Precompiled.h"
     30 #include "globaldata.h"
     31 
     32 
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <stdio.h>
     36 #include <string>
     37 
     38 #include <errno.h>
     39 
     40 // Sockets
     41 #include <sys/socket.h>
     42 #include <sys/types.h>
     43 #include <netex/errno.h>
     44 #include <netex/net.h>
     45 #include <arpa/inet.h>
     46 
     47 #include "i_system.h"
     48 #include "d_event.h"
     49 #include "d_net.h"
     50 #include "m_argv.h"
     51 
     52 #include "doomstat.h"
     53 
     54 #include "i_net.h"
     55 
     56 #include "doomlib.h"
     57 #include "../Main/Main.h"
     58 
     59 void	NetSend (void);
     60 qboolean NetListen (void);
     61 
     62 namespace {
     63 	bool IsValidSocket( int socketDescriptor );
     64 	int GetLastSocketError();
     65 
     66 
     67 
     68 	/*
     69 	========================
     70 	Returns true if the socket is valid. I made this function to help abstract the differences
     71 	between WinSock (used on Xbox) and BSD sockets, which the PS3 follows more closely.
     72 	========================
     73 	*/
     74 	bool IsValidSocket( int socketDescriptor ) {
     75 		return socketDescriptor >= 0;
     76 	}
     77 
     78 	/*
     79 	========================
     80 	Returns the last error reported by the platform's socket library.
     81 	========================
     82 	*/
     83 	int GetLastSocketError() {
     84 		return sys_net_errno;
     85 	}
     86 }
     87 
     88 //
     89 // NETWORKING
     90 //
     91 int	DOOMPORT = 1002;	// DHM - Nerve :: On original XBox, ports 1000 - 1255 saved you a byte on every packet.  360 too?
     92 
     93 
     94 unsigned long GetServerIP() {
     95 	return ::g->sendaddress[::g->doomcom.consoleplayer].sin_addr.s_addr;
     96 }
     97 
     98 void	(*netget) (void);
     99 void	(*netsend) (void);
    100 
    101 
    102 //
    103 // UDPsocket
    104 //
    105 int UDPsocket (void)
    106 {
    107 	int	s;
    108 
    109 	// allocate a socket
    110 	s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    111 	if ( !IsValidSocket( s ) ) {
    112 		int err = GetLastSocketError();
    113 		I_Error( "can't create socket, error %d", err );
    114 	}
    115 
    116 	return s;
    117 }
    118 
    119 //
    120 // BindToLocalPort
    121 //
    122 void BindToLocalPort( int	s, int	port )
    123 {
    124 	int			v;
    125 	struct sockaddr_in	address;
    126 
    127 	memset (&address, 0, sizeof(address));
    128 	address.sin_family = AF_INET;
    129 	address.sin_addr.s_addr = INADDR_ANY;
    130 	address.sin_port = port;
    131 
    132 	v = bind (s, (sockaddr*)&address, sizeof(address));
    133 	//if (v == -1)
    134 		//I_Error ("BindToPort: bind: %s", strerror(errno));
    135 }
    136 
    137 
    138 //
    139 // PacketSend
    140 //
    141 void PacketSend (void)
    142 {
    143 	int		c;
    144 	doomdata_t	sw;
    145 
    146 	// byte swap
    147 	sw.checksum = htonl(::g->netbuffer->checksum);
    148 	sw.sourceDest = DoomLib::BuildSourceDest(::g->doomcom.remotenode);
    149 	sw.player = ::g->netbuffer->player;
    150 	sw.retransmitfrom = ::g->netbuffer->retransmitfrom;
    151 	sw.starttic = ::g->netbuffer->starttic;
    152 	sw.numtics = ::g->netbuffer->numtics;
    153 	for (c=0 ; c< ::g->netbuffer->numtics ; c++)
    154 	{
    155 		sw.cmds[c].forwardmove = ::g->netbuffer->cmds[c].forwardmove;
    156 		sw.cmds[c].sidemove = ::g->netbuffer->cmds[c].sidemove;
    157 		sw.cmds[c].angleturn = htons(::g->netbuffer->cmds[c].angleturn);
    158 		sw.cmds[c].consistancy = htons(::g->netbuffer->cmds[c].consistancy);
    159 		sw.cmds[c].buttons = ::g->netbuffer->cmds[c].buttons;
    160 	}
    161 
    162 	// Send Socket
    163 	{
    164 		//DWORD num_sent;
    165 		
    166 		//if ( globalNetworking ) {
    167 		//	c = WSASendTo(::g->sendsocket, &buffer, 1, &num_sent, 0, (sockaddr*)&::g->sendaddress[::g->doomcom.remotenode],
    168 		//					sizeof(::g->sendaddress[::g->doomcom.remotenode]), 0, 0);
    169 		//} else {
    170 			c = DoomLib::Send( (char*)&sw, ::g->doomcom.datalength, (sockaddr_in*)&::g->sendaddress[::g->doomcom.remotenode], ::g->doomcom.remotenode ); 
    171 		//}
    172 	}
    173 }
    174 
    175 
    176 //
    177 // PacketGet
    178 //
    179 void PacketGet (void)
    180 {
    181 	int			i;
    182 	int			c;
    183 	struct sockaddr_in	fromaddress;
    184 	int			fromlen;
    185 	doomdata_t		sw;
    186 	DWORD num_recieved; //, flags = 0;
    187 
    188 	// Try and read a socket
    189 	//buffer.buf = (char*)&sw;
    190 	//buffer.len = sizeof(sw);
    191 	fromlen = sizeof(fromaddress);
    192 
    193 	//if ( globalNetworking ) {
    194 	//	c = WSARecvFrom(::g->insocket, &buffer, 1, &num_recieved, &flags, (struct sockaddr*)&fromaddress, &fromlen, 0, 0);
    195 	//} else {
    196 		c = DoomLib::Recv( (char*)&sw, &num_recieved );
    197 	//}
    198 	if ( c < 0 )
    199 	{
    200 		/*if ( globalNetworking ) {
    201 			int err = WSAGetLastError();
    202 			if (err != WSAEWOULDBLOCK)
    203 				I_Error ("GetPacket: %s",strerror(errno));
    204 		}*/
    205 
    206 		::g->doomcom.remotenode = -1;		// no packet
    207 		return;
    208 	}
    209 
    210 	
    211 
    212 	// find remote node number
    213 	/*for (i=0 ; i<::g->doomcom.numnodes ; i++)
    214 		if ( fromaddress.sin_addr.s_addr == ::g->sendaddress[i].sin_addr.s_addr )
    215 			break;
    216 
    217 	if (i == ::g->doomcom.numnodes)
    218 	{
    219 		// packet is not from one of the ::g->players (new game broadcast)
    220 		::g->doomcom.remotenode = -1;		// no packet
    221 		return;
    222 	}*/
    223 
    224 	//if ( ::g->consoleplayer == 1 ) {
    225 		//int x = 0;
    226 	//}
    227 
    228 	int source;
    229 	int dest;
    230 	DoomLib::GetSourceDest( sw.sourceDest, &source, &dest );
    231 
    232 	i = source;
    233 
    234 	//if ( ::g->consoleplayer == 1 ) {
    235 		//if ( i == 2 ) {
    236 			//int suck = 0;
    237 		//}
    238 	//}
    239 
    240 	::g->doomcom.remotenode = i;			// good packet from a game player
    241 	::g->doomcom.datalength = (short)num_recieved;
    242 
    243 	// byte swap
    244 	::g->netbuffer->checksum = ntohl(sw.checksum);
    245 	::g->netbuffer->player = sw.player;
    246 	::g->netbuffer->retransmitfrom = sw.retransmitfrom;
    247 	::g->netbuffer->starttic = sw.starttic;
    248 	::g->netbuffer->numtics = sw.numtics;
    249 
    250 	for ( c = 0; c < ::g->netbuffer->numtics; c++ )
    251 	{
    252 		::g->netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
    253 		::g->netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
    254 		::g->netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
    255 		::g->netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
    256 		::g->netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
    257 	}
    258 }
    259 
    260 static int I_TrySetupNetwork(void)
    261 {
    262 	// DHM - Moved to Session
    263 	return 1;
    264 }
    265 
    266 //
    267 // I_InitNetwork
    268 //
    269 void I_InitNetwork (void)
    270 {
    271 
    272 	//qboolean		trueval = true;
    273 	int			i;
    274 	int			p;
    275 	//int a = 0;
    276 	//    struct hostent*	hostentry;	// host information entry
    277 
    278 	memset (&::g->doomcom, 0, sizeof(::g->doomcom) );
    279 
    280 	// set up for network
    281 	i = M_CheckParm ("-dup");
    282 	if (i && i< ::g->myargc-1)
    283 	{
    284 		::g->doomcom.ticdup = ::g->myargv[i+1][0]-'0';
    285 		if (::g->doomcom.ticdup < 1)
    286 			::g->doomcom.ticdup = 1;
    287 		if (::g->doomcom.ticdup > 9)
    288 			::g->doomcom.ticdup = 9;
    289 	}
    290 	else
    291 		::g->doomcom.ticdup = 1;
    292 
    293 	if (M_CheckParm ("-extratic"))
    294 		::g->doomcom.extratics = 1;
    295 	else
    296 		::g->doomcom.extratics = 0;
    297 
    298 	p = M_CheckParm ("-port");
    299 	if (p && p < ::g->myargc-1)
    300 	{
    301 		DOOMPORT = atoi (::g->myargv[p+1]);
    302 		I_Printf ("using alternate port %i\n",DOOMPORT);
    303 	}
    304 
    305 	// parse network game options,
    306 	//  -net <::g->consoleplayer> <host> <host> ...
    307 	i = M_CheckParm ("-net");
    308 	if (!i || !I_TrySetupNetwork())
    309 	{
    310 		// single player game
    311 		::g->netgame = false;
    312 		::g->doomcom.id = DOOMCOM_ID;
    313 		::g->doomcom.numplayers = ::g->doomcom.numnodes = 1;
    314 		::g->doomcom.deathmatch = false;
    315 		::g->doomcom.consoleplayer = 0;
    316 		return;
    317 	}
    318 
    319 	netsend = PacketSend;
    320 	netget = PacketGet;
    321 
    322 	::g->netgame = true;
    323 
    324 	{
    325 		++i; // skip the '-net'
    326 		::g->doomcom.numnodes = 0;
    327 		::g->doomcom.consoleplayer = atoi( ::g->myargv[i] );
    328 		// skip the console number
    329 		++i;
    330 		::g->doomcom.numnodes = 0;
    331 		for (; i < ::g->myargc; ++i)
    332 		{
    333 			::g->sendaddress[::g->doomcom.numnodes].sin_family = AF_INET;
    334 			::g->sendaddress[::g->doomcom.numnodes].sin_port = htons(DOOMPORT);
    335 			
    336 			// Pull out the port number.
    337 			const std::string ipAddressWithPort( ::g->myargv[i] );
    338 			const std::size_t colonPosition = ipAddressWithPort.find_last_of(':');
    339 			std::string ipOnly;
    340 
    341 			if( colonPosition != std::string::npos && colonPosition + 1 < ipAddressWithPort.size() ) {
    342 				const std::string portOnly( ipAddressWithPort.substr( colonPosition + 1 ) );
    343 
    344 				::g->sendaddress[::g->doomcom.numnodes].sin_port = htons( atoi( portOnly.c_str() ) );
    345 
    346 				ipOnly = ipAddressWithPort.substr( 0, colonPosition );
    347 			} else {
    348 				// Assume the address doesn't include a port.
    349 				ipOnly = ipAddressWithPort;
    350 			}
    351 
    352 			in_addr_t ipAddress = inet_addr( ipOnly.c_str() );
    353 
    354 			if ( ipAddress == INADDR_NONE ) {
    355 				I_Error( "Invalid IP Address: %s\n", ipOnly.c_str() );
    356 				session->QuitMatch();
    357 				common->AddDialog( GDM_OPPONENT_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, false );
    358 			}
    359 			::g->sendaddress[::g->doomcom.numnodes].sin_addr.s_addr = ipAddress;
    360 			::g->doomcom.numnodes++;
    361 		}
    362 		
    363 		::g->doomcom.id = DOOMCOM_ID;
    364 		::g->doomcom.numplayers = ::g->doomcom.numnodes;
    365 	}
    366 
    367 	if ( globalNetworking ) {
    368 		// Setup sockets
    369 		::g->insocket = UDPsocket ();
    370 		BindToLocalPort (::g->insocket,htons(DOOMPORT));
    371 		
    372 		// PS3 call to enable non-blocking mode
    373 		int nonblocking = 1; // Non-zero is nonblocking mode.
    374 		setsockopt( ::g->insocket, SOL_SOCKET, SO_NBIO, &nonblocking, sizeof(nonblocking));
    375 
    376 		::g->sendsocket = UDPsocket ();
    377 
    378 		I_Printf( "[+] Setting up sockets for player %d\n", DoomLib::GetPlayer() );
    379 	}
    380 }
    381 
    382 // DHM - Nerve
    383 void I_ShutdownNetwork( void ) {
    384 	if ( globalNetworking && gameLocal != NULL ) {
    385 		
    386 		int curPlayer = DoomLib::GetPlayer();
    387 
    388 		for (int player = 0; player < gameLocal->Interface.GetNumPlayers(); ++player)
    389 		{
    390 			DoomLib::SetPlayer( player );
    391 
    392 			if ( IsValidSocket( ::g->insocket ) ) {
    393 				I_Printf( "[-] Shut down insocket for player %d\n", DoomLib::GetPlayer() );
    394 				shutdown( ::g->insocket, SHUT_RDWR );
    395 				socketclose( ::g->insocket );
    396 			}
    397 			if ( IsValidSocket( ::g->sendsocket ) ) {
    398 				I_Printf( "[-] Shut down sendsocket for player %d\n", DoomLib::GetPlayer() );
    399 				shutdown( ::g->sendsocket, SHUT_RDWR );
    400 				socketclose( ::g->sendsocket );
    401 			}
    402 		}
    403 
    404 		DoomLib::SetPlayer(curPlayer);
    405 
    406 		globalNetworking = false;
    407 	}
    408 }
    409 
    410 void I_NetCmd (void)
    411 {
    412 	if (::g->doomcom.command == CMD_SEND)
    413 	{
    414 		netsend ();
    415 	}
    416 	else if (::g->doomcom.command == CMD_GET)
    417 	{
    418 		netget ();
    419 	}
    420 	else
    421 		I_Error ("Bad net cmd: %i\n",::g->doomcom.command); 
    422 }
    423