void SendAbort (void) { BYTE dis[2] = { PRE_FAKE, PRE_DISCONNECT }; int i, j; if (doomcom.numnodes > 1) { if (consoleplayer == 0) { // The host needs to let everyone know for (i = 1; i < doomcom.numnodes; ++i) { for (j = 4; j > 0; --j) { PreSend (dis, 2, &sendaddress[i]); } } } else { // Guests only need to let the host know. for (i = 4; i > 0; --i) { PreSend (dis, 2, &sendaddress[1]); } } } }
bool Guest_WaitForOthers (void *userdata) { sockaddr_in *from; PreGamePacket packet; while ( (from = PreGet (&packet, sizeof(packet), false)) ) { if (packet.Fake != PRE_FAKE || FindNode(from) != 1) { continue; } switch (packet.Message) { case PRE_CONACK: StartScreen->NetProgress (packet.NumPresent); break; case PRE_ALLHERE: if (doomcom.numnodes == 2) { int node; packet.NumNodes = packet.NumNodes; doomcom.numnodes = packet.NumNodes + 2; sendplayer[0] = packet.ConsoleNum; // My player number doomcom.consoleplayer = packet.ConsoleNum; StartScreen->NetMessage ("Console player number: %d", doomcom.consoleplayer); for (node = 0; node < packet.NumNodes; node++) { sendaddress[node+2].sin_addr.s_addr = packet.machines[node].address; sendaddress[node+2].sin_port = packet.machines[node].port; sendplayer[node+2] = packet.machines[node].player; // [JC] - fixes problem of games not starting due to // no address family being assigned to nodes stored in // sendaddress[] from the All Here packet. sendaddress[node+2].sin_family = AF_INET; } } StartScreen->NetMessage ("Received All Here, sending ACK."); packet.Fake = PRE_FAKE; packet.Message = PRE_ALLHEREACK; PreSend (&packet, 2, &sendaddress[1]); break; case PRE_GO: StartScreen->NetMessage ("Received \"Go.\""); return true; case PRE_DISCONNECT: I_FatalError ("The host cancelled the game."); break; } } return false; }
static void SendConAck (int num_connected, int num_needed) { PreGamePacket packet; packet.Fake = PRE_FAKE; packet.Message = PRE_CONACK; packet.NumNodes = num_needed; packet.NumPresent = num_connected; for (int node = 1; node < doomcom.numnodes; ++node) { PreSend (&packet, 4, &sendaddress[node]); } StartScreen->NetProgress (doomcom.numnodes); }
bool Guest_ContactHost (void *userdata) { sockaddr_in *from; PreGamePacket packet; // Let the host know we are here. packet.Fake = PRE_FAKE; packet.Message = PRE_CONNECT; PreSend (&packet, 2, &sendaddress[1]); // Listen for a reply. while ( (from = PreGet (&packet, sizeof(packet), true)) ) { if (packet.Fake == PRE_FAKE && FindNode(from) == 1) { if (packet.Message == PRE_CONACK) { StartScreen->NetMessage ("Total players: %d", packet.NumNodes); StartScreen->NetInit ("Waiting for other players", packet.NumNodes); StartScreen->NetProgress (packet.NumPresent); return true; } else if (packet.Message == PRE_DISCONNECT) { doomcom.numnodes = 0; I_FatalError ("The host cancelled the game."); } else if (packet.Message == PRE_ALLFULL) { doomcom.numnodes = 0; I_FatalError ("The game is full."); } } } // In case the progress bar could not be marqueed, bump it. StartScreen->NetProgress (0); return false; }
void HostGame (int i) { PreGamePacket packet; int numplayers; int node; int gotack[MAXNETNODES+1]; if ((i == Args->NumArgs() - 1) || !(numplayers = atoi (Args->GetArg(i+1)))) { // No player count specified, assume 2 numplayers = 2; } if (numplayers == 1) { // Special case: Only 1 player, so don't bother starting the network netgame = false; multiplayer = true; doomcom.id = DOOMCOM_ID; doomcom.numplayers = doomcom.numnodes = 1; doomcom.consoleplayer = 0; return; } StartNetwork (false); // [JC] - this computer is starting the game, therefore it should // be the Net Arbitrator. doomcom.consoleplayer = 0; Printf ("Console player number: %d\n", doomcom.consoleplayer); doomcom.numnodes = 1; atterm (SendAbort); StartScreen->NetInit ("Waiting for players", numplayers); // Wait for numplayers-1 different connections if (!StartScreen->NetLoop (Host_CheckForConnects, (void *)(intptr_t)numplayers)) { exit (0); } // Now inform everyone of all machines involved in the game memset (gotack, 0, sizeof(gotack)); StartScreen->NetMessage ("Sending all here."); StartScreen->NetInit ("Done waiting", 1); if (!StartScreen->NetLoop (Host_SendAllHere, (void *)gotack)) { exit (0); } popterm (); // Now go StartScreen->NetMessage ("Go"); packet.Fake = PRE_FAKE; packet.Message = PRE_GO; for (node = 1; node < doomcom.numnodes; node++) { // If we send the packets eight times to each guest, // hopefully at least one of them will get through. for (int i = 8; i != 0; --i) { PreSend (&packet, 2, &sendaddress[node]); } } StartScreen->NetMessage ("Total players: %d", doomcom.numnodes); doomcom.id = DOOMCOM_ID; doomcom.numplayers = doomcom.numnodes; // On the host, each player's number is the same as its node number for (i = 0; i < doomcom.numnodes; ++i) { sendplayer[i] = i; } }
bool Host_SendAllHere (void *userdata) { int *gotack = (int *)userdata; // ackcount is at gotack[MAXNETNODES] PreGamePacket packet; int node; sockaddr_in *from; // Send out address information to all guests. Guests that have already // acknowledged receipt effectively get just a heartbeat packet. packet.Fake = PRE_FAKE; packet.Message = PRE_ALLHERE; for (node = 1; node < doomcom.numnodes; node++) { int machine, spot = 0; packet.ConsoleNum = node; if (!gotack[node]) { for (spot = 0, machine = 1; machine < doomcom.numnodes; machine++) { if (node != machine) { packet.machines[spot].address = sendaddress[machine].sin_addr.s_addr; packet.machines[spot].port = sendaddress[machine].sin_port; packet.machines[spot].player = node; spot++; // fixes problem of new address replacing existing address in // array; it's supposed to increment the index before getting // and storing in the packet the next address. } } packet.NumNodes = doomcom.numnodes - 2; } else { packet.NumNodes = 0; } PreSend (&packet, 4 + spot*8, &sendaddress[node]); } // Check for replies. while ( (from = PreGet (&packet, sizeof(packet), false)) ) { if (packet.Fake == PRE_FAKE && packet.Message == PRE_ALLHEREACK) { node = FindNode (from); if (node >= 0) { if (!gotack[node]) { gotack[node] = true; gotack[MAXNETNODES]++; } } PreSend (&packet, 2, from); } } // If everybody has replied, then this loop can end. return gotack[MAXNETNODES] == doomcom.numnodes - 1; }
bool Host_CheckForConnects (void *userdata) { PreGamePacket packet; int numplayers = (int)(intptr_t)userdata; sockaddr_in *from; int node; while ( (from = PreGet (&packet, sizeof(packet), false)) ) { if (packet.Fake != PRE_FAKE) { continue; } switch (packet.Message) { case PRE_CONNECT: node = FindNode (from); if (doomcom.numnodes == numplayers) { if (node == -1) { const BYTE *s_addr_bytes = (const BYTE *)&from->sin_addr; StartScreen->NetMessage ("Got extra connect from %d.%d.%d.%d:%d", s_addr_bytes[0], s_addr_bytes[1], s_addr_bytes[2], s_addr_bytes[3], from->sin_port); packet.Message = PRE_ALLFULL; PreSend (&packet, 2, from); } } else { if (node == -1) { node = doomcom.numnodes++; sendaddress[node] = *from; StartScreen->NetMessage ("Got connect from node %d.", node); } // Let the new guest (and everyone else) know we got their message. SendConAck (doomcom.numnodes, numplayers); } break; case PRE_DISCONNECT: node = FindNode (from); if (node >= 0) { StartScreen->NetMessage ("Got disconnect from node %d.", node); doomcom.numnodes--; while (node < doomcom.numnodes) { sendaddress[node] = sendaddress[node+1]; node++; } // Let remaining guests know that somebody left. SendConAck (doomcom.numnodes, numplayers); } break; } } if (doomcom.numnodes < numplayers) { return false; } // It's possible somebody bailed out after all players were found. // Unfortunately, this isn't guaranteed to catch all of them. // Oh well. Better than nothing. while ( (from = PreGet (&packet, sizeof(packet), false)) ) { if (packet.Fake == PRE_FAKE && packet.Message == PRE_DISCONNECT) { node = FindNode (from); if (node >= 0) { doomcom.numnodes--; while (node < doomcom.numnodes) { sendaddress[node] = sendaddress[node+1]; node++; } // Let remaining guests know that somebody left. SendConAck (doomcom.numnodes, numplayers); } break; } } return doomcom.numnodes >= numplayers; }
void ClientSession::ConnectCompletion() { CRASH_ASSERT(LThreadType == THREAD_IO_WORKER); if (1 == InterlockedExchange(&mConnected, 1)) { /// already exists? CRASH_ASSERT(false); return; } bool resultOk = true; do { if ( SOCKET_ERROR == setsockopt( mSocket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0 )) { printf_s("[DEBUG] SO_UPDATE_ACCEPT_CONTEXT error: %d\n", GetLastError()); resultOk = false; break; } /* int opt = 1; if (SOCKET_ERROR == setsockopt(mSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(int))) { printf_s("[DEBUG] TCP_NODELAY error: %d\n", GetLastError()); resultOk = false; break; } opt = 0; if (SOCKET_ERROR == setsockopt(mSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(int))) { printf_s("[DEBUG] SO_RCVBUF change error: %d\n", GetLastError()); resultOk = false; break; } int addrlen = sizeof(SOCKADDR_IN); if (SOCKET_ERROR == getpeername(mSocket, (SOCKADDR*)&mClientAddr, &addrlen)) { printf_s("[DEBUG] getpeername error: %d\n", GetLastError()); resultOk = false; break; } HANDLE handle = CreateIoCompletionPort((HANDLE)mSocket, GIocpManager->GetComletionPort(), (ULONG_PTR)this, 0); if (handle != GIocpManager->GetComletionPort()) { printf_s("[DEBUG] CreateIoCompletionPort error: %d\n", GetLastError()); resultOk = false; break; } */ } while (false); if (!resultOk) { DisconnectRequest(DR_ONCONNECT_ERROR); return; } printf_s("[DEBUG] Client Connected: IP=%s, PORT=%d\n", inet_ntoa(mClientAddr.sin_addr), ntohs(mClientAddr.sin_port)); if (false == PreSend()) { printf_s("[DEBUG] PreSend error: %d\n", GetLastError()); } /// 타이머 테스트를 위해 10ms 후에 player 가동 ㄱㄱ //DoSyncAfter(10, mPlayer, &Player::Start, 1000); }