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