mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-11-22 04:12:09 +00:00
423 lines
11 KiB
C++
423 lines
11 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "Precompiled.h"
|
|
#include "globaldata.h"
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <string>
|
|
|
|
#include <errno.h>
|
|
|
|
// Sockets
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <netex/errno.h>
|
|
#include <netex/net.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "i_system.h"
|
|
#include "d_event.h"
|
|
#include "d_net.h"
|
|
#include "m_argv.h"
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "i_net.h"
|
|
|
|
#include "doomlib.h"
|
|
#include "../Main/Main.h"
|
|
|
|
void NetSend (void);
|
|
qboolean NetListen (void);
|
|
|
|
namespace {
|
|
bool IsValidSocket( int socketDescriptor );
|
|
int GetLastSocketError();
|
|
|
|
|
|
|
|
/*
|
|
========================
|
|
Returns true if the socket is valid. I made this function to help abstract the differences
|
|
between WinSock (used on Xbox) and BSD sockets, which the PS3 follows more closely.
|
|
========================
|
|
*/
|
|
bool IsValidSocket( int socketDescriptor ) {
|
|
return socketDescriptor >= 0;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
Returns the last error reported by the platform's socket library.
|
|
========================
|
|
*/
|
|
int GetLastSocketError() {
|
|
return sys_net_errno;
|
|
}
|
|
}
|
|
|
|
//
|
|
// NETWORKING
|
|
//
|
|
int DOOMPORT = 1002; // DHM - Nerve :: On original XBox, ports 1000 - 1255 saved you a byte on every packet. 360 too?
|
|
|
|
|
|
unsigned long GetServerIP() {
|
|
return ::g->sendaddress[::g->doomcom.consoleplayer].sin_addr.s_addr;
|
|
}
|
|
|
|
void (*netget) (void);
|
|
void (*netsend) (void);
|
|
|
|
|
|
//
|
|
// UDPsocket
|
|
//
|
|
int UDPsocket (void)
|
|
{
|
|
int s;
|
|
|
|
// allocate a socket
|
|
s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
if ( !IsValidSocket( s ) ) {
|
|
int err = GetLastSocketError();
|
|
I_Error( "can't create socket, error %d", err );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
//
|
|
// BindToLocalPort
|
|
//
|
|
void BindToLocalPort( int s, int port )
|
|
{
|
|
int v;
|
|
struct sockaddr_in address;
|
|
|
|
memset (&address, 0, sizeof(address));
|
|
address.sin_family = AF_INET;
|
|
address.sin_addr.s_addr = INADDR_ANY;
|
|
address.sin_port = port;
|
|
|
|
v = bind (s, (sockaddr*)&address, sizeof(address));
|
|
//if (v == -1)
|
|
//I_Error ("BindToPort: bind: %s", strerror(errno));
|
|
}
|
|
|
|
|
|
//
|
|
// PacketSend
|
|
//
|
|
void PacketSend (void)
|
|
{
|
|
int c;
|
|
doomdata_t sw;
|
|
|
|
// byte swap
|
|
sw.checksum = htonl(::g->netbuffer->checksum);
|
|
sw.sourceDest = DoomLib::BuildSourceDest(::g->doomcom.remotenode);
|
|
sw.player = ::g->netbuffer->player;
|
|
sw.retransmitfrom = ::g->netbuffer->retransmitfrom;
|
|
sw.starttic = ::g->netbuffer->starttic;
|
|
sw.numtics = ::g->netbuffer->numtics;
|
|
for (c=0 ; c< ::g->netbuffer->numtics ; c++)
|
|
{
|
|
sw.cmds[c].forwardmove = ::g->netbuffer->cmds[c].forwardmove;
|
|
sw.cmds[c].sidemove = ::g->netbuffer->cmds[c].sidemove;
|
|
sw.cmds[c].angleturn = htons(::g->netbuffer->cmds[c].angleturn);
|
|
sw.cmds[c].consistancy = htons(::g->netbuffer->cmds[c].consistancy);
|
|
sw.cmds[c].buttons = ::g->netbuffer->cmds[c].buttons;
|
|
}
|
|
|
|
// Send Socket
|
|
{
|
|
//DWORD num_sent;
|
|
|
|
//if ( globalNetworking ) {
|
|
// c = WSASendTo(::g->sendsocket, &buffer, 1, &num_sent, 0, (sockaddr*)&::g->sendaddress[::g->doomcom.remotenode],
|
|
// sizeof(::g->sendaddress[::g->doomcom.remotenode]), 0, 0);
|
|
//} else {
|
|
c = DoomLib::Send( (char*)&sw, ::g->doomcom.datalength, (sockaddr_in*)&::g->sendaddress[::g->doomcom.remotenode], ::g->doomcom.remotenode );
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// PacketGet
|
|
//
|
|
void PacketGet (void)
|
|
{
|
|
int i;
|
|
int c;
|
|
struct sockaddr_in fromaddress;
|
|
int fromlen;
|
|
doomdata_t sw;
|
|
DWORD num_recieved; //, flags = 0;
|
|
|
|
// Try and read a socket
|
|
//buffer.buf = (char*)&sw;
|
|
//buffer.len = sizeof(sw);
|
|
fromlen = sizeof(fromaddress);
|
|
|
|
//if ( globalNetworking ) {
|
|
// c = WSARecvFrom(::g->insocket, &buffer, 1, &num_recieved, &flags, (struct sockaddr*)&fromaddress, &fromlen, 0, 0);
|
|
//} else {
|
|
c = DoomLib::Recv( (char*)&sw, &num_recieved );
|
|
//}
|
|
if ( c < 0 )
|
|
{
|
|
/*if ( globalNetworking ) {
|
|
int err = WSAGetLastError();
|
|
if (err != WSAEWOULDBLOCK)
|
|
I_Error ("GetPacket: %s",strerror(errno));
|
|
}*/
|
|
|
|
::g->doomcom.remotenode = -1; // no packet
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// find remote node number
|
|
/*for (i=0 ; i<::g->doomcom.numnodes ; i++)
|
|
if ( fromaddress.sin_addr.s_addr == ::g->sendaddress[i].sin_addr.s_addr )
|
|
break;
|
|
|
|
if (i == ::g->doomcom.numnodes)
|
|
{
|
|
// packet is not from one of the ::g->players (new game broadcast)
|
|
::g->doomcom.remotenode = -1; // no packet
|
|
return;
|
|
}*/
|
|
|
|
//if ( ::g->consoleplayer == 1 ) {
|
|
//int x = 0;
|
|
//}
|
|
|
|
int source;
|
|
int dest;
|
|
DoomLib::GetSourceDest( sw.sourceDest, &source, &dest );
|
|
|
|
i = source;
|
|
|
|
//if ( ::g->consoleplayer == 1 ) {
|
|
//if ( i == 2 ) {
|
|
//int suck = 0;
|
|
//}
|
|
//}
|
|
|
|
::g->doomcom.remotenode = i; // good packet from a game player
|
|
::g->doomcom.datalength = (short)num_recieved;
|
|
|
|
// byte swap
|
|
::g->netbuffer->checksum = ntohl(sw.checksum);
|
|
::g->netbuffer->player = sw.player;
|
|
::g->netbuffer->retransmitfrom = sw.retransmitfrom;
|
|
::g->netbuffer->starttic = sw.starttic;
|
|
::g->netbuffer->numtics = sw.numtics;
|
|
|
|
for ( c = 0; c < ::g->netbuffer->numtics; c++ )
|
|
{
|
|
::g->netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
|
|
::g->netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
|
|
::g->netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
|
|
::g->netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
|
|
::g->netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
|
|
}
|
|
}
|
|
|
|
static int I_TrySetupNetwork(void)
|
|
{
|
|
// DHM - Moved to Session
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// I_InitNetwork
|
|
//
|
|
void I_InitNetwork (void)
|
|
{
|
|
|
|
//qboolean trueval = true;
|
|
int i;
|
|
int p;
|
|
//int a = 0;
|
|
// struct hostent* hostentry; // host information entry
|
|
|
|
memset (&::g->doomcom, 0, sizeof(::g->doomcom) );
|
|
|
|
// set up for network
|
|
i = M_CheckParm ("-dup");
|
|
if (i && i< ::g->myargc-1)
|
|
{
|
|
::g->doomcom.ticdup = ::g->myargv[i+1][0]-'0';
|
|
if (::g->doomcom.ticdup < 1)
|
|
::g->doomcom.ticdup = 1;
|
|
if (::g->doomcom.ticdup > 9)
|
|
::g->doomcom.ticdup = 9;
|
|
}
|
|
else
|
|
::g->doomcom.ticdup = 1;
|
|
|
|
if (M_CheckParm ("-extratic"))
|
|
::g->doomcom.extratics = 1;
|
|
else
|
|
::g->doomcom.extratics = 0;
|
|
|
|
p = M_CheckParm ("-port");
|
|
if (p && p < ::g->myargc-1)
|
|
{
|
|
DOOMPORT = atoi (::g->myargv[p+1]);
|
|
I_Printf ("using alternate port %i\n",DOOMPORT);
|
|
}
|
|
|
|
// parse network game options,
|
|
// -net <::g->consoleplayer> <host> <host> ...
|
|
i = M_CheckParm ("-net");
|
|
if (!i || !I_TrySetupNetwork())
|
|
{
|
|
// single player game
|
|
::g->netgame = false;
|
|
::g->doomcom.id = DOOMCOM_ID;
|
|
::g->doomcom.numplayers = ::g->doomcom.numnodes = 1;
|
|
::g->doomcom.deathmatch = false;
|
|
::g->doomcom.consoleplayer = 0;
|
|
return;
|
|
}
|
|
|
|
netsend = PacketSend;
|
|
netget = PacketGet;
|
|
|
|
::g->netgame = true;
|
|
|
|
{
|
|
++i; // skip the '-net'
|
|
::g->doomcom.numnodes = 0;
|
|
::g->doomcom.consoleplayer = atoi( ::g->myargv[i] );
|
|
// skip the console number
|
|
++i;
|
|
::g->doomcom.numnodes = 0;
|
|
for (; i < ::g->myargc; ++i)
|
|
{
|
|
::g->sendaddress[::g->doomcom.numnodes].sin_family = AF_INET;
|
|
::g->sendaddress[::g->doomcom.numnodes].sin_port = htons(DOOMPORT);
|
|
|
|
// Pull out the port number.
|
|
const std::string ipAddressWithPort( ::g->myargv[i] );
|
|
const std::size_t colonPosition = ipAddressWithPort.find_last_of(':');
|
|
std::string ipOnly;
|
|
|
|
if( colonPosition != std::string::npos && colonPosition + 1 < ipAddressWithPort.size() ) {
|
|
const std::string portOnly( ipAddressWithPort.substr( colonPosition + 1 ) );
|
|
|
|
::g->sendaddress[::g->doomcom.numnodes].sin_port = htons( atoi( portOnly.c_str() ) );
|
|
|
|
ipOnly = ipAddressWithPort.substr( 0, colonPosition );
|
|
} else {
|
|
// Assume the address doesn't include a port.
|
|
ipOnly = ipAddressWithPort;
|
|
}
|
|
|
|
in_addr_t ipAddress = inet_addr( ipOnly.c_str() );
|
|
|
|
if ( ipAddress == INADDR_NONE ) {
|
|
I_Error( "Invalid IP Address: %s\n", ipOnly.c_str() );
|
|
session->QuitMatch();
|
|
common->AddDialog( GDM_OPPONENT_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, false );
|
|
}
|
|
::g->sendaddress[::g->doomcom.numnodes].sin_addr.s_addr = ipAddress;
|
|
::g->doomcom.numnodes++;
|
|
}
|
|
|
|
::g->doomcom.id = DOOMCOM_ID;
|
|
::g->doomcom.numplayers = ::g->doomcom.numnodes;
|
|
}
|
|
|
|
if ( globalNetworking ) {
|
|
// Setup sockets
|
|
::g->insocket = UDPsocket ();
|
|
BindToLocalPort (::g->insocket,htons(DOOMPORT));
|
|
|
|
// PS3 call to enable non-blocking mode
|
|
int nonblocking = 1; // Non-zero is nonblocking mode.
|
|
setsockopt( ::g->insocket, SOL_SOCKET, SO_NBIO, &nonblocking, sizeof(nonblocking));
|
|
|
|
::g->sendsocket = UDPsocket ();
|
|
|
|
I_Printf( "[+] Setting up sockets for player %d\n", DoomLib::GetPlayer() );
|
|
}
|
|
}
|
|
|
|
// DHM - Nerve
|
|
void I_ShutdownNetwork( void ) {
|
|
if ( globalNetworking && gameLocal != NULL ) {
|
|
|
|
int curPlayer = DoomLib::GetPlayer();
|
|
|
|
for (int player = 0; player < gameLocal->Interface.GetNumPlayers(); ++player)
|
|
{
|
|
DoomLib::SetPlayer( player );
|
|
|
|
if ( IsValidSocket( ::g->insocket ) ) {
|
|
I_Printf( "[-] Shut down insocket for player %d\n", DoomLib::GetPlayer() );
|
|
shutdown( ::g->insocket, SHUT_RDWR );
|
|
socketclose( ::g->insocket );
|
|
}
|
|
if ( IsValidSocket( ::g->sendsocket ) ) {
|
|
I_Printf( "[-] Shut down sendsocket for player %d\n", DoomLib::GetPlayer() );
|
|
shutdown( ::g->sendsocket, SHUT_RDWR );
|
|
socketclose( ::g->sendsocket );
|
|
}
|
|
}
|
|
|
|
DoomLib::SetPlayer(curPlayer);
|
|
|
|
globalNetworking = false;
|
|
}
|
|
}
|
|
|
|
void I_NetCmd (void)
|
|
{
|
|
if (::g->doomcom.command == CMD_SEND)
|
|
{
|
|
netsend ();
|
|
}
|
|
else if (::g->doomcom.command == CMD_GET)
|
|
{
|
|
netget ();
|
|
}
|
|
else
|
|
I_Error ("Bad net cmd: %i\n",::g->doomcom.command);
|
|
}
|
|
|