void FullyConnectedMesh2::AddParticipant( RakNetGUID rakNetGuid ) { if (rakPeerInterface->GetConnectionState(rakPeerInterface->GetSystemAddressFromGuid(rakNetGuid))!=IS_CONNECTED) { #ifdef DEBUG_FCM2 printf("AddParticipant to %s failed (not connected)\n", rakNetGuid.ToString()); #endif return; } AddParticipantInternal(rakNetGuid,0); }
void NatPunchthroughClient::SendPunchthrough(RakNetGUID destination, const SystemAddress &facilitator) { RakNet::BitStream outgoingBs; outgoingBs.Write((MessageID)ID_NAT_PUNCHTHROUGH_REQUEST); outgoingBs.Write(destination); rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,facilitator,false); // RakAssert(rakPeerInterface->GetSystemAddressFromGuid(destination)==UNASSIGNED_SYSTEM_ADDRESS); if (natPunchthroughDebugInterface) { char guidString[128]; destination.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Starting ID_NAT_PUNCHTHROUGH_REQUEST to guid %s.", guidString)); } }
// Implemented event callback from base class PluginInterface2 virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming) { // Call down to the base class in case it does anything in the future (right now it does nothing) SQLite3ServerPlugin::OnNewConnection(systemAddress, rakNetGUID, isIncoming); // Get the database index associated with the table used for this class unsigned int idx = dbHandles.GetIndexOf(connectionStateIdentifier); if (idx==(unsigned int)-1) return; // Store new system's system address and guid. rowCreationTime column is created automatically char systemAddressString[64]; systemAddress.ToString(true,systemAddressString); char guidString[128]; rakNetGUID.ToString(guidString); RakNet::RakString query( "INSERT INTO connectionState (systemAddress,rakNetGUID) VALUES ('%s','%s');", RakNet::RakString(systemAddressString).SQLEscape().C_String(), RakNet::RakString(guidString).SQLEscape().C_String()); sqlite3_exec(dbHandles[idx].dbHandle,query.C_String(),0,0,0); }
void RoomsBrowserGFx3_RakNet::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming) { if (systemAddress==lobby2Client->GetServerAddress()) { // is connected FxResponseArgs<0> rargs; FxDelegate::Invoke2(movie, "c2f_NotifyConnectionAttemptToServerSuccess", rargs); } else { FxResponseArgs<3> rargs; char saString[64]; systemAddress.ToString(true,saString); char guidString[64]; rakNetGUID.ToString(guidString); rargs.Add(saString); rargs.Add(guidString); rargs.Add(isIncoming); FxDelegate::Invoke2(movie, "c2f_NotifyNewConnection", rargs); } }
PluginReceiveResult NatPunchthroughClient::OnReceive(Packet *packet) { switch (packet->data[0]) { case ID_NAT_GET_MOST_RECENT_PORT: { OnGetMostRecentPort(packet); return RR_STOP_PROCESSING_AND_DEALLOCATE; } case ID_NAT_PUNCHTHROUGH_FAILED: case ID_NAT_PUNCHTHROUGH_SUCCEEDED: if (packet->wasGeneratedLocally==false) return RR_STOP_PROCESSING_AND_DEALLOCATE; break; case ID_NAT_RESPOND_BOUND_ADDRESSES: { RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(sizeof(MessageID)); unsigned char boundAddressCount; bs.Read(boundAddressCount); if (boundAddressCount<2) { if (natPunchthroughDebugInterface) natPunchthroughDebugInterface->OnClientMessage("INCAPABLE_PORT_STRIDE"); hasPortStride=INCAPABLE_PORT_STRIDE; SendQueuedOpenNAT(); } SystemAddress boundAddresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS]; for (int i=0; i < boundAddressCount && i < MAXIMUM_NUMBER_OF_INTERNAL_IDS; i++) { bs.Read(boundAddresses[i]); if (boundAddresses[i]!=packet->systemAddress) { RakNet::BitStream outgoingBs; outgoingBs.Write((MessageID)ID_NAT_PING); uint16_t externalPort = rakPeerInterface->GetExternalID(packet->systemAddress).GetPort(); outgoingBs.Write( externalPort ); rakPeerInterface->SendOutOfBand((const char*) boundAddresses[i].ToString(false),boundAddresses[i].GetPort(),(const char*) outgoingBs.GetData(),outgoingBs.GetNumberOfBytesUsed()); break; } } } break; case ID_OUT_OF_BAND_INTERNAL: if (packet->length>=2 && packet->data[1]==ID_NAT_PONG) { RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(sizeof(MessageID)*2); uint16_t externalPort; bs.Read(externalPort); uint16_t externalPort2; bs.Read(externalPort2); portStride = externalPort2 - externalPort; hasPortStride=HAS_PORT_STRIDE; if (natPunchthroughDebugInterface) natPunchthroughDebugInterface->OnClientMessage(RakString("HAS_PORT_STRIDE %i. Server first external port %i. Server second external port %i.", portStride, externalPort, externalPort2)); SendQueuedOpenNAT(); return RR_STOP_PROCESSING_AND_DEALLOCATE; } else if (packet->length>=2 && (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL || packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL) && sp.nextActionTime!=0) { RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(2); uint16_t sessionId; bs.Read(sessionId); // RakAssert(sessionId<100); if (sessionId!=sp.sessionId) break; char ipAddressString[32]; packet->systemAddress.ToString(true,ipAddressString); // sp.targetGuid==packet->guid is because the internal IP addresses reported may include loopbacks not reported by RakPeer::IsLocalIP() if (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL && sp.targetGuid==packet->guid) { if (natPunchthroughDebugInterface) { char guidString[128]; sp.targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Received ID_NAT_ESTABLISH_UNIDIRECTIONAL from guid %s, system address %s.", guidString, ipAddressString)); } if (sp.testMode!=SendPing::PUNCHING_FIXED_PORT) { sp.testMode=SendPing::PUNCHING_FIXED_PORT; sp.retryCount+=sp.attemptCount*pc.UDP_SENDS_PER_PORT_EXTERNAL; sp.targetAddress=packet->systemAddress; // Keeps trying until the other side gives up too, in case it is unidirectional sp.punchingFixedPortAttempts=pc.UDP_SENDS_PER_PORT_EXTERNAL*(pc.MAX_PREDICTIVE_PORT_RANGE+1); } SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL); } else if (packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL && sp.targetGuid==packet->guid) { // They send back our port unsigned short ourExternalPort; bs.Read(ourExternalPort); if (nextExternalPort==0) { nextExternalPort=ourExternalPort; } else { if (sp.testMode!=SendPing::TESTING_INTERNAL_IPS && sp.testMode!=SendPing::WAITING_FOR_INTERNAL_IPS_RESPONSE) { if (hasPortStride!=HAS_PORT_STRIDE) { portStride = ourExternalPort - nextExternalPort; hasPortStride=HAS_PORT_STRIDE; if (natPunchthroughDebugInterface) { natPunchthroughDebugInterface->OnClientMessage(RakString("Estimated port stride from incoming connection at %i", portStride)); } SendQueuedOpenNAT(); } nextExternalPort += portStride * (pc.MAX_PREDICTIVE_PORT_RANGE+1); if (natPunchthroughDebugInterface) { natPunchthroughDebugInterface->OnClientMessage(RakString("Estimated next external port %i", nextExternalPort)); } } } SendOutOfBand(packet->systemAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL); // Tell the user about the success sp.targetAddress=packet->systemAddress; PushSuccess(); //UpdateGroupPunchOnNatResult(sp.facilitator, sp.targetGuid, sp.targetAddress, 1); OnReadyForNextPunchthrough(); bool removedFromFailureQueue=RemoveFromFailureQueue(); if (natPunchthroughDebugInterface) { char guidString[128]; sp.targetGuid.ToString(guidString); if (removedFromFailureQueue) natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 2nd attempt.", guidString, ipAddressString)); else natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 1st attempt.", guidString, ipAddressString)); } } // mostRecentNewExternalPort=packet->systemAddress.GetPort(); } return RR_STOP_PROCESSING_AND_DEALLOCATE; case ID_NAT_ALREADY_IN_PROGRESS: { RakNet::BitStream incomingBs(packet->data, packet->length, false); incomingBs.IgnoreBytes(sizeof(MessageID)); RakNetGUID targetGuid; incomingBs.Read(targetGuid); // Don't update group, just use later message // UpdateGroupPunchOnNatResult(packet->systemAddress, targetGuid, UNASSIGNED_SYSTEM_ADDRESS, 2); if (natPunchthroughDebugInterface) { char guidString[128]; targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to ID_NAT_ALREADY_IN_PROGRESS. Returning failure.", guidString)); } } break; case ID_NAT_TARGET_NOT_CONNECTED: case ID_NAT_CONNECTION_TO_TARGET_LOST: case ID_NAT_TARGET_UNRESPONSIVE: { const char *reason; if (packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED) reason=(char *)"ID_NAT_TARGET_NOT_CONNECTED"; else if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST) reason=(char *)"ID_NAT_CONNECTION_TO_TARGET_LOST"; else reason=(char *)"ID_NAT_TARGET_UNRESPONSIVE"; RakNet::BitStream incomingBs(packet->data, packet->length, false); incomingBs.IgnoreBytes(sizeof(MessageID)); RakNetGUID targetGuid; incomingBs.Read(targetGuid); //UpdateGroupPunchOnNatResult(packet->systemAddress, targetGuid, UNASSIGNED_SYSTEM_ADDRESS, 2); if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST || packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE) { uint16_t sessionId; incomingBs.Read(sessionId); if (sessionId!=sp.sessionId) break; } unsigned int i; for (i=0; i < failedAttemptList.Size(); i++) { if (failedAttemptList[i].guid==targetGuid) { if (natPunchthroughDebugInterface) { char guidString[128]; targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to %s.", guidString, reason)); } // If the retry target is not connected, or loses connection, or is not responsive, then previous failures cannot be retried. // Don't need to return failed, the other messages indicate failure anyway /* Packet *p = AllocatePacketUnified(sizeof(MessageID)); p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED; p->systemAddress=failedAttemptList[i].addr; p->systemAddress.systemIndex=(SystemIndex)-1; p->guid=failedAttemptList[i].guid; rakPeerInterface->PushBackPacket(p, false); */ failedAttemptList.RemoveAtIndexFast(i); break; } } if (natPunchthroughDebugInterface) { char guidString[128]; targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough attempt to guid %s failed due to %s.", guidString, reason)); } // Stop trying punchthrough sp.nextActionTime=0; /* RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); RakNetGUID failedSystem; bs.Read(failedSystem); bool deletedFirst=false; unsigned int i=0; while (i < pendingOpenNAT.Size()) { if (pendingOpenNAT[i].destination==failedSystem) { if (i==0) deletedFirst=true; pendingOpenNAT.RemoveAtIndex(i); } else i++; } // Failed while in progress. Go to next in attempt queue if (deletedFirst && pendingOpenNAT.Size()) { SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator); sp.nextActionTime=0; } */ } break; case ID_TIMESTAMP: if (packet->data[sizeof(MessageID)+sizeof(RakNet::Time)]==ID_NAT_CONNECT_AT_TIME) { OnConnectAtTime(packet); return RR_STOP_PROCESSING_AND_DEALLOCATE; } break; } return RR_CONTINUE_PROCESSING; }
int main() { FullyConnectedMesh2 fcm2; ConnectionGraph2 cg2; rakPeer=RakNet::RakPeerInterface::GetInstance(); rakPeer->AttachPlugin(&fcm2); rakPeer->AttachPlugin(&cg2); fcm2.SetAutoparticipateConnections(true); RakNet::SocketDescriptor sd; sd.socketFamily=AF_INET; // Only IPV4 supports broadcast on 255.255.255.255 sd.port=60000; while (IRNS2_Berkley::IsPortInUse(sd.port, sd.hostAddress, sd.socketFamily, SOCK_DGRAM)==true) sd.port++; StartupResult sr = rakPeer->Startup(8,&sd,1); RakAssert(sr==RAKNET_STARTED); rakPeer->SetMaximumIncomingConnections(8); rakPeer->SetTimeoutTime(1000,RakNet::UNASSIGNED_SYSTEM_ADDRESS); printf("Our guid is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString()); printf("Started on %s\n", rakPeer->GetMyBoundAddress().ToString(true)); BitStream contextBs; contextBs.Write(RakString("Our guid is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString())); fcm2.SetMyContext(&contextBs); // PacketLogger packetLogger; // rakPeer->AttachPlugin(&packetLogger); // packetLogger.SetLogDirectMessages(false); bool quit=false; RakNet::Packet *packet; char ch; while (!quit) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { switch (packet->data[0]) { case ID_DISCONNECTION_NOTIFICATION: // Connection lost normally printf("ID_DISCONNECTION_NOTIFICATION\n"); break; case ID_NEW_INCOMING_CONNECTION: // Somebody connected. We have their IP now printf("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_REQUEST_ACCEPTED: // Somebody connected. We have their IP now printf("ID_CONNECTION_REQUEST_ACCEPTED from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_LOST: // Couldn't deliver a reliable packet - i.e. the other system was abnormally // terminated printf("ID_CONNECTION_LOST\n"); break; case ID_ADVERTISE_SYSTEM: if (packet->guid!=rakPeer->GetMyGUID()) rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0); break; case ID_FCM2_NEW_HOST: { if (packet->guid==rakPeer->GetMyGUID()) printf("Got new host (ourselves)"); else printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString()); RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(1); RakNetGUID oldHost; bs.Read(oldHost); // If oldHost is different then the current host, then we lost connection to the host if (oldHost!=UNASSIGNED_RAKNET_GUID) printf(". Oldhost Guid=%s\n", oldHost.ToString()); else printf(". (First reported host)\n"); } break; // case ID_REMOTE_NEW_INCOMING_CONNECTION: // { // uint32_t count; // RakNet::BitStream bsIn(packet->data, packet->length,false); // bsIn.IgnoreBytes(1); // bsIn.Read(count); // SystemAddress sa; // RakNetGUID guid; // printf("ID_REMOTE_NEW_INCOMING_CONNECTION from %s\n", packet->systemAddress.ToString(true)); // for (uint32_t i=0; i < count; i++) // { // bsIn.Read(sa); // bsIn.Read(guid); // // printf("%s ", sa.ToString(true)); // } // printf("\n"); // } } } if (kbhit()) { ch=getch(); if (ch==' ') { DataStructures::List<RakNetGUID> participantList; fcm2.GetParticipantList(participantList); printf("%i participants\n", participantList.Size()); for (int i=0; i < participantList.Size(); i++) { BitStream userContext; fcm2.GetParticipantContext(participantList[i], &userContext); RakString str; userContext.Read(str); printf("%i. %s: %s", i+1, participantList[i].ToString(), str.C_String()); } } if (ch=='q' || ch=='Q') { printf("Quitting.\n"); quit=true; } } RakSleep(30); for (int i=0; i < 32; i++) { if (rakPeer->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS,0).GetPort()!=60000+i) rakPeer->AdvertiseSystem("255.255.255.255", 60000+i, 0,0,0); } } RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; }
int main(void) { printf("This project demonstrates an in-game lobby using the team manager plugin.\n"); printf("Difficulty: Intermediate\n\n"); rakPeer=RakNet::RakPeerInterface::GetInstance(); fullyConnectedMesh2=FullyConnectedMesh2::GetInstance(); teamManager=TeamManager::GetInstance(); networkIDManager = NetworkIDManager::GetInstance(); replicaManager3=new SampleRM3; // test offline mode /* TM_TeamMember tmTeamMember; TM_Team tmTeam; teamManager->AddWorld(0); teamManager->GetWorldAtIndex(0)->ReferenceTeam(&tmTeam,1,false); teamManager->GetWorldAtIndex(0)->ReferenceTeamMember(&tmTeamMember,0); tmTeamMember.RequestTeam(TeamSelection::AnyAvailable()); RakAssert(tmTeam.GetTeamMembersCount()==1); tmTeam.LeaveTeam(&tmTeamMember, 255); RakAssert(tmTeam.GetTeamMembersCount()==0); */ rakPeer->AttachPlugin(fullyConnectedMesh2); rakPeer->AttachPlugin(teamManager); rakPeer->AttachPlugin(replicaManager3); rakPeer->AttachPlugin(fullyConnectedMesh2); // Make it so all new connections are registered with FullyConnectedMesh2 fullyConnectedMesh2->SetAutoparticipateConnections(true); // Allocate a world instance to be used for team operations teamManager->AddWorld(0); // Tell ReplicaManager3 which networkIDManager to use for object lookup, used for automatic serialization replicaManager3->SetNetworkIDManager(networkIDManager); // Tell ReplicaManager3 and TeamManager to not automatically add new connections, because we wait for host calculation to complete from FullyConnectedMesh2 first replicaManager3->SetAutoManageConnections(false,true); teamManager->SetAutoManageConnections(false); // Just setup user data as an example Team teams[TEAM_TYPES_COUNT]; teams[(int)PLAYER_TEAM_1].teamName="Player_Team_1"; teams[(int)PLAYER_TEAM_2].teamName="Player_Team 2"; teams[(int)REFEREE_TEAM].teamName="Referee_Team"; for (unsigned int i=0; i < TEAM_TYPES_COUNT; i++) { // Static objects require additional setup before calling reference. teams[i].SetNetworkIDManager(networkIDManager); teams[i].SetNetworkID(i); // NetworkID value doesn't matter, just needs to be unique // We serialize teams before team members, this is required by TeamManager during remote object construction. Serialization occurs in the order that Reference() is called on the object replicaManager3->Reference(&teams[i]); // Register the team with the teamManager plugin // Do not apply team balancing to the referee team bool balancingAppliesToThisTeam = i!=REFEREE_TEAM; teamManager->GetWorldAtIndex(0)->ReferenceTeam(&teams[i].tmTeam,teams[i].GetNetworkID(),balancingAppliesToThisTeam); if (i==REFEREE_TEAM) teams[i].tmTeam.SetMemberLimit(1,0); else teams[i].tmTeam.SetMemberLimit(2,0); } // Only join the referee team on specific request teams[REFEREE_TEAM].tmTeam.SetJoinPermissions(ALLOW_JOIN_SPECIFIC_TEAM); // Setup my own User *user = new User; user->userName = rakPeer->GetMyGUID().ToString(); // Inform ReplicaManager3 of my user replicaManager3->Reference(user); // Inform TeamManager of my user's team member info teamManager->GetWorldAtIndex(0)->ReferenceTeamMember(&user->tmTeamMember,user->GetNetworkID()); // Startup RakNet RakNet::SocketDescriptor sd; sd.socketFamily=AF_INET; // Only IPV4 supports broadcast on 255.255.255.255 sd.port=60000; while (SocketLayer::IsPortInUse(sd.port, sd.hostAddress, sd.socketFamily)==true) sd.port++; StartupResult sr = rakPeer->Startup(8,&sd,1); RakAssert(sr==RAKNET_STARTED); rakPeer->SetMaximumIncomingConnections(8); rakPeer->SetTimeoutTime(30000,RakNet::UNASSIGNED_SYSTEM_ADDRESS); printf("Our guid is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString()); printf("Started on %s\n", rakPeer->GetMyBoundAddress().ToString(true)); for (int i=0; i < 32; i++) { if (rakPeer->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS,0).GetPort()!=60000+i) rakPeer->AdvertiseSystem("255.255.255.255", 60000+i, 0,0,0); } PrintCommands(); bool success; bool quit=false; char ch; Packet *packet; while (!quit) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { switch (packet->data[0]) { case ID_DISCONNECTION_NOTIFICATION: printf("ID_DISCONNECTION_NOTIFICATION\n"); break; case ID_NEW_INCOMING_CONNECTION: { printf("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString()); // Add mid-game joins to ReplicaManager3 as long as we know who the host is if (fullyConnectedMesh2->GetConnectedHost()!=UNASSIGNED_RAKNET_GUID) { bool success = replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid)); RakAssert(success); teamManager->GetWorldAtIndex(0)->AddParticipant(packet->guid); } } break; case ID_CONNECTION_REQUEST_ACCEPTED: { printf("ID_CONNECTION_REQUEST_ACCEPTED from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString()); // Add mid-game joins to ReplicaManager3 as long as we know who the host is if (fullyConnectedMesh2->GetConnectedHost()!=UNASSIGNED_RAKNET_GUID) { bool success = replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid)); RakAssert(success); teamManager->GetWorldAtIndex(0)->AddParticipant(packet->guid); } } break; case ID_CONNECTION_LOST: printf("ID_CONNECTION_LOST\n"); break; case ID_ADVERTISE_SYSTEM: if (packet->guid!=rakPeer->GetMyGUID()) rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0); break; case ID_FCM2_NEW_HOST: { if (packet->guid==rakPeer->GetMyGUID()) printf("Got new host (ourselves)"); else printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString()); RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(1); RakNetGUID oldHost; bs.Read(oldHost); // If the old host is different, then this message was due to losing connection to the host. if (oldHost!=packet->guid) printf(". Oldhost Guid=%s\n", oldHost.ToString()); else printf("\n"); if (oldHost==UNASSIGNED_RAKNET_GUID) { // First time calculated host. Add existing connections to ReplicaManager3 RegisterFCM2Participants(); } } break; case ID_TEAM_BALANCER_TEAM_ASSIGNED: { printf("ID_TEAM_BALANCER_TEAM_ASSIGNED for "); TM_World *world; TM_TeamMember *teamMember; teamManager->DecodeTeamAssigned(packet, &world, &teamMember); printf("worldId=%i teamMember=%s\n", world->GetWorldId(), ((User*)teamMember->GetOwner())->userName.C_String()); } break; case ID_TEAM_BALANCER_REQUESTED_TEAM_FULL: { printf("ID_TEAM_BALANCER_REQUESTED_TEAM_FULL\n"); } break; case ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED: { printf("ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED\n"); } break; case ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED: { printf("ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED\n"); } break; } } if (kbhit()) { ch=getch(); if (ch=='A' || ch=='a') { printf("Request any team\n"); success = user->tmTeamMember.RequestTeam(TeamSelection::AnyAvailable()); printf("Success=%i\n", success); } if (ch=='B' || ch=='b') { printf("Request specific team\n"); char buff1[256]; printf("Enter team index (0-2): "); gets(buff1); if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2') { success = user->tmTeamMember.RequestTeam(TeamSelection::SpecificTeam(&(teams[buff1[0]-'0'].tmTeam))); printf("Success=%i\n", success); } else { printf("Aborted\n"); } } if (ch=='C' || ch=='c') { printf("Request team switch\n"); char buff1[256]; printf("Enter team index to join (0-2): "); gets(buff1); char buff2[256]; printf("Enter team index to leave (0-2) or leave empty for all: "); gets(buff2); if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2' && (buff2[0]==0 || (buff2[0]>='0' && buff2[0]<='2'))) { if (buff2[0]) success = user->tmTeamMember.RequestTeamSwitch(&(teams[buff1[0]-'0'].tmTeam), &teams[buff2[0]-'0'].tmTeam); else success = user->tmTeamMember.RequestTeamSwitch(&(teams[buff1[0]-'0'].tmTeam), 0); printf("Success=%i\n", success); } else { printf("Aborted\n"); } } if (ch=='D' || ch=='d') { printf("Cancel request team\n"); char buff1[256]; printf("Enter team index to cancel (0-2) or leave empty for all: "); gets(buff1); if ((buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2') || buff1[0]==0) { if (buff1[0]) success = user->tmTeamMember.CancelTeamRequest(&(teams[buff1[0]-'0'].tmTeam)); else success = user->tmTeamMember.CancelTeamRequest(0); printf("Success=%i\n", success); } else { printf("Aborted\n"); } } if (ch=='E' || ch=='e') { printf("Leave specific team\n"); char buff1[256]; printf("Enter team index to leave (0-2): "); gets(buff1); if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2') { success = user->tmTeamMember.LeaveTeam(&(teams[buff1[0]-'0'].tmTeam),0); printf("Success=%i\n", success); } else { printf("Aborted\n"); } } if (ch=='F' || ch=='f') { printf("Leave all teams\n"); success = user->tmTeamMember.LeaveAllTeams(0); printf("Success=%i\n", success); } if (ch=='G' || ch=='g') { printf("Set team member limit\n"); char buff1[256]; printf("Enter team index to operate on (0-2): "); gets(buff1); char buff2[256]; printf("Enter limit (0-9): "); gets(buff2); if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2' && buff2[0]!=0 && buff2[0]>='0' && buff2[0]<='9') { success = teams[buff1[0]-'0'].tmTeam.SetMemberLimit(buff2[0]-'0',0); printf("Success=%i\n", success); } else { printf("Aborted\n"); } } if (ch=='H' || ch=='h') { printf("Turn on balance teams setting\n"); success = teamManager->GetWorldAtIndex(0)->SetBalanceTeams(true,0); printf("Success=%i\n", success); } if (ch=='I' || ch=='i') { printf("Turn off balance teams setting\n"); success = teamManager->GetWorldAtIndex(0)->SetBalanceTeams(false,0); printf("Success=%i\n", success); } if (ch==' ') { if (teamManager->GetWorldAtIndex(0)->GetBalanceTeams()) printf("Team balancing is on\n"); else printf("Team balancing is off\n"); for (unsigned int i=0; i < TEAM_TYPES_COUNT; i++) { printf("Team %i. %s %i/%i members ", i+1, teams[i].teamName.C_String(), teams[i].tmTeam.GetTeamMembersCount(), teams[i].tmTeam.GetMemberLimit()); for (unsigned int j=0; j < teams[i].tmTeam.GetTeamMembersCount(); j++) { User *u = (User *) teams[i].tmTeam.GetTeamMemberByIndex(j)->GetOwner(); printf("%s ", u->userName.C_String()); } printf("\n"); } unsigned int numUsers = teamManager->GetWorldAtIndex(0)->GetTeamMemberCount(); for (unsigned int i=0; i < numUsers; i++) { User *u = (User *) teamManager->GetWorldAtIndex(0)->GetTeamMemberByIndex(i)->GetOwner(); printf("User %i/%i. %s ", i+1, numUsers, u->userName.C_String()); u->PrintTeamStatus(); printf("\n"); } printf("\n"); } else if (ch=='q' || ch=='Q') { printf("Quitting.\n"); quit=true; } } RakSleep(30); } rakPeer->Shutdown(100); replicaManager3->Clear(); RakNet::RakPeerInterface::DestroyInstance(rakPeer); delete replicaManager3; RakNet::FullyConnectedMesh2::DestroyInstance(fullyConnectedMesh2); RakNet::TeamManager::DestroyInstance(teamManager); RakNet::NetworkIDManager::DestroyInstance(networkIDManager); for (unsigned int i=0; i < TEAM_TYPES_COUNT; i++) { // Teams are globally deallocated after NetworkIDManager, so prevent crash on automatic dereference teams[i].SetNetworkIDManager(0); } return 1; }
int main() { FullyConnectedMesh2 fcm2[NUM_PEERS]; ConnectionGraph2 cg2[NUM_PEERS]; for (int i=0; i < NUM_PEERS; i++) { rakPeer[i]=RakNetworkFactory::GetRakPeerInterface(); rakPeer[i]->AttachPlugin(&fcm2[i]); rakPeer[i]->AttachPlugin(&cg2[i]); fcm2[i].SetAutoparticipateConnections(true); SocketDescriptor sd; sd.port=60000+i; rakPeer[i]->Startup(NUM_PEERS,0,&sd,1); rakPeer[i]->SetMaximumIncomingConnections(NUM_PEERS); rakPeer[i]->SetTimeoutTime(1000,UNASSIGNED_SYSTEM_ADDRESS); printf("Our guid is %s\n", rakPeer[i]->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString()); } for (int i=0; i < NUM_PEERS; i++) { for (int j=0; j < NUM_PEERS; j++) { if (i==j) continue; rakPeer[i]->Connect("127.0.0.1", 60000+j, 0, 0 ); } } bool quit=false; Packet *packet; char ch; while (!quit) { for (int i=0; i < NUM_PEERS; i++) { for (packet = rakPeer[i]->Receive(); packet; rakPeer[i]->DeallocatePacket(packet), packet = rakPeer[i]->Receive()) { switch (packet->data[0]) { case ID_DISCONNECTION_NOTIFICATION: // Connection lost normally printf("%i. ID_DISCONNECTION_NOTIFICATION\n", i); break; case ID_NEW_INCOMING_CONNECTION: // Somebody connected. We have their IP now printf("%i. ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", i, packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_REQUEST_ACCEPTED: // Somebody connected. We have their IP now printf("%i. ID_CONNECTION_REQUEST_ACCEPTED from %s. guid=%s.\n", i, packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_LOST: // Couldn't deliver a reliable packet - i.e. the other system was abnormally // terminated printf("%i. ID_CONNECTION_LOST\n", i); break; case ID_FCM2_NEW_HOST: if (packet->systemAddress==UNASSIGNED_SYSTEM_ADDRESS) printf("%i. Got new host (ourselves)\n", i); else printf("%i. Got new host %s\n", i, packet->systemAddress.ToString(true)); break; } } } if (kbhit()) { ch=getch(); if (ch==' ') { DataStructures::DefaultIndexType participantList; RakNetGUID hostGuid; bool weAreHost; for (int i=0; i < NUM_PEERS; i++) { if (rakPeer[i]->IsActive()==false) continue; fcm2[i].GetParticipantCount(&participantList); weAreHost=fcm2[i].IsHostSystem(); hostGuid=fcm2[i].GetHostSystem(); if (weAreHost) printf("%i. %iP myGuid=%s, hostGuid=%s (Y)\n",i, participantList, rakPeer[i]->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString(), hostGuid.ToString()); else printf("%i. %iP myGuid=%s, hostGuid=%s (N)\n",i, participantList, rakPeer[i]->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString(), hostGuid.ToString()); } } if (ch=='d' || ch=='D') { char str[32]; printf("Enter system index to disconnect.\n"); gets(str); rakPeer[atoi(str)]->Shutdown(100); printf("Done.\n"); } if (ch=='q' || ch=='Q') { printf("Quitting.\n"); quit=true; } } RakSleep(30); } for (int i=0; i < NUM_PEERS; i++) { RakNetworkFactory::DestroyRakPeerInterface(rakPeer[i]); } return 0; }
int main(int argc, char **argv) { if (argc>1) { printf("Command arguments:\n"); for (int i=1; i < argc; i++) { printf("%i. %s\n", i, argv[i]); } } SteamResults steamResults; rakPeer = RakNet::RakPeerInterface::GetInstance(); fcm2 = RakNet::FullyConnectedMesh2::GetInstance(); messageFactory = new Lobby2MessageFactory_Steam; lobby2Client = Lobby2Client_Steam::GetInstance(); lobby2Client->AddCallbackInterface(&steamResults); lobby2Client->SetMessageFactory(messageFactory); SocketDescriptor sd(1234,0); rakPeer->Startup(32,&sd,1); rakPeer->SetMaximumIncomingConnections(32); rakPeer->AttachPlugin(fcm2); rakPeer->AttachPlugin(lobby2Client); // Connect manually in Notification_Console_MemberJoinedRoom fcm2->SetConnectOnNewRemoteConnection(false, ""); RakNet::Lobby2Message* msg = messageFactory->Alloc(RakNet::L2MID_Client_Login); lobby2Client->SendMsg(msg); if (msg->resultCode!=L2RC_PROCESSING && msg->resultCode!=L2RC_SUCCESS) { printf("Steam must be running to play this game (SteamAPI_Init() failed).\n"); printf("If this fails, steam_appid.txt was probably not in the working directory.\n"); messageFactory->Dealloc(msg); return -1; } messageFactory->Dealloc(msg); PrintCommands(); bool quit=false; char ch; while(!quit) { RakNet::Packet *packet; for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { switch (packet->data[0]) { case ID_DISCONNECTION_NOTIFICATION: // Connection lost normally printf("ID_DISCONNECTION_NOTIFICATION\n"); break; case ID_ALREADY_CONNECTED: // Connection lost normally printf("ID_ALREADY_CONNECTED\n"); break; case ID_REMOTE_DISCONNECTION_NOTIFICATION: // Server telling the clients of another client disconnecting gracefully. You can manually broadcast this in a peer to peer enviroment if you want. printf("ID_REMOTE_DISCONNECTION_NOTIFICATION\n"); break; case ID_REMOTE_CONNECTION_LOST: // Server telling the clients of another client disconnecting forcefully. You can manually broadcast this in a peer to peer enviroment if you want. printf("ID_REMOTE_CONNECTION_LOST\n"); break; case ID_REMOTE_NEW_INCOMING_CONNECTION: // Server telling the clients of another client connecting. You can manually broadcast this in a peer to peer enviroment if you want. printf("ID_REMOTE_NEW_INCOMING_CONNECTION\n"); break; case ID_CONNECTION_BANNED: // Banned from this server printf("We are banned from this server.\n"); break; case ID_CONNECTION_ATTEMPT_FAILED: printf("Connection attempt failed\n"); break; case ID_NO_FREE_INCOMING_CONNECTIONS: // Sorry, the server is full. I don't do anything here but // A real app should tell the user printf("ID_NO_FREE_INCOMING_CONNECTIONS\n"); break; case ID_INVALID_PASSWORD: printf("ID_INVALID_PASSWORD\n"); break; case ID_CONNECTION_LOST: // Couldn't deliver a reliable packet - i.e. the other system was abnormally // terminated printf("ID_CONNECTION_LOST\n"); break; case ID_CONNECTION_REQUEST_ACCEPTED: // This tells the client they have connected printf("ID_CONNECTION_REQUEST_ACCEPTED to %s with GUID %s\n", packet->systemAddress.ToString(), packet->guid.ToString()); break; case ID_NEW_INCOMING_CONNECTION: printf("ID_NEW_INCOMING_CONNECTION\n"); break; case ID_FCM2_NEW_HOST: { if (packet->systemAddress==RakNet::UNASSIGNED_SYSTEM_ADDRESS) printf("Got new host (ourselves)"); else printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString()); RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(1); RakNetGUID oldHost; bs.Read(oldHost); // If the old host is different, then this message was due to losing connection to the host. if (oldHost!=packet->guid) printf(". Oldhost Guid=%s\n", oldHost.ToString()); else printf("\n"); } break; default: // It's a client, so just show the message printf("Unknown Message ID %i\n", packet->data[0]); break; } } if (kbhit()) { ch=(char)getch(); switch (ch) { case 'a': { RakNet::Lobby2Message* logoffMsg = messageFactory->Alloc(RakNet::L2MID_Console_SearchRooms); lobby2Client->SendMsg(logoffMsg); messageFactory->Dealloc(logoffMsg); } break; case 'b': { if (lobby2Client->GetRoomID()==0) { printf("Not in a room\n"); break; } RakNet::Console_LeaveRoom_Steam* msg = (RakNet::Console_LeaveRoom_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_LeaveRoom); msg->roomId=lobby2Client->GetRoomID(); lobby2Client->SendMsg(msg); messageFactory->Dealloc(msg); } break; case 'c': { if (lobby2Client->GetRoomID()!=0) { printf("Already in a room\n"); break; } RakNet::Console_CreateRoom_Steam* msg = (RakNet::Console_CreateRoom_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_CreateRoom); // set the name of the lobby if it's ours char rgchLobbyName[256]; msg->roomIsPublic=true; _snprintf( rgchLobbyName, sizeof( rgchLobbyName ), "%s's lobby", SteamFriends()->GetPersonaName() ); msg->roomName=rgchLobbyName; msg->publicSlots=8; lobby2Client->SendMsg(msg); messageFactory->Dealloc(msg); } break; case 'd': { if (lobby2Client->GetRoomID()!=0) { printf("Already in a room\n"); break; } RakNet::Console_JoinRoom_Steam* msg = (RakNet::Console_JoinRoom_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_JoinRoom); printf("Enter room id, or enter for %" PRINTF_64_BIT_MODIFIER "u: ", lastRoom); char str[256]; Gets(str, sizeof(str)); if (str[0]==0) { msg->roomId=lastRoom; } else { msg->roomId=_atoi64(str); } lobby2Client->SendMsg(msg); messageFactory->Dealloc(msg); } break; case 'e': { if (lobby2Client->GetRoomID()==0) { printf("Not in a room\n"); break; } RakNet::Console_GetRoomDetails_Steam* msg = (RakNet::Console_GetRoomDetails_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_GetRoomDetails); msg->roomId=lobby2Client->GetRoomID(); lobby2Client->SendMsg(msg); messageFactory->Dealloc(msg); } break; case 'f': { if (lobby2Client->GetRoomID()==0) { printf("Not in a room\n"); break; } RakNet::Console_SendRoomChatMessage_Steam* msg = (RakNet::Console_SendRoomChatMessage_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_SendRoomChatMessage); msg->message="Test chat message."; msg->roomId=lobby2Client->GetRoomID(); lobby2Client->SendMsg(msg); messageFactory->Dealloc(msg); } break; case 'g': { DataStructures::OrderedList<uint64_t, uint64_t> roomMembers; lobby2Client->GetRoomMembers(roomMembers); for (unsigned int i=0; i < roomMembers.Size(); i++) { printf("%i. %s ID=%" PRINTF_64_BIT_MODIFIER "u\n", i+1, lobby2Client->GetRoomMemberName(roomMembers[i]), roomMembers[i]); } } break; case '?': { PrintCommands(); } break; case 27: { quit=true; } break; } } RakSleep(30); } RakNet::Lobby2Message* logoffMsg = messageFactory->Alloc(RakNet::L2MID_Client_Logoff); lobby2Client->SendMsg(logoffMsg); messageFactory->Dealloc(logoffMsg); rakPeer->DetachPlugin(lobby2Client); rakPeer->DetachPlugin(fcm2); RakNet::RakPeerInterface::DestroyInstance(rakPeer); Lobby2Client_Steam::DestroyInstance(lobby2Client); RakNet::FullyConnectedMesh2::DestroyInstance(fcm2); return 1; }
void ReadAllPackets(void) { char str[64], str2[64]; Packet *packet; for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { packet->guid.ToString(str); packet->systemAddress.ToString(true,str2); if (packet->data[0]==ID_NEW_INCOMING_CONNECTION) { printf("ID_NEW_INCOMING_CONNECTION from %s on %s\n", str, str2); } else if (packet->data[0]==ID_CONNECTION_REQUEST_ACCEPTED) { printf("ID_CONNECTION_REQUEST_ACCEPTED from %s on %s\n", str, str2); } else if (packet->data[0]==ID_ROUTER_2_FORWARDING_NO_PATH) { printf("No path to endpoint exists. Routing failed.\n"); } else if (packet->data[0]==ID_CONNECTION_LOST) { printf("ID_CONNECTION_LOST from %s\n", str); } else if (packet->data[0]==ID_USER_PACKET_ENUM+1) { printf("Got ID_USER_PACKET_ENUM from %s\n", str); } else if (packet->data[0]==ID_ROUTER_2_FORWARDING_ESTABLISHED) { RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); bs.Read(endpointGuid); printf("Routing through %s to %s successful. Connecting.\n", str, endpointGuid.ToString()); unsigned short sourceToDestPort; bs.Read(sourceToDestPort); char ipAddressString[32]; packet->systemAddress.ToString(false, ipAddressString); rakPeer->Connect(ipAddressString, sourceToDestPort, 0,0); } else if (packet->data[0]==ID_ROUTER_2_REROUTED) { // You could read the endpointGuid and sourceToDestPoint if you wanted to RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); RakNetGUID endpointGuid2; bs.Read(endpointGuid2); endpointGuid2.ToString(str); unsigned short sourceToDestPort; SystemAddress intermediateAddress=packet->systemAddress; bs.Read(intermediateAddress.port); char str2[32]; intermediateAddress.ToString(true, str2); printf("Connection to %s rerouted through %s\n", str, str2); // Test sending a message to the endpoint RakNet::BitStream bsOut; MessageID id = ID_USER_PACKET_ENUM+1; bsOut.Write(id); rakPeer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,endpointGuid2,false); } } }
int main(void) { PortAudioStream *stream; PaError err; mute=false; bool quit; char ch; printf("A sample on how to use RakVoice. You need a microphone for this sample.\n"); printf("RakVoice relies on Speex for voice encoding and decoding.\n"); printf("See DependentExtensions/RakVoice/speex-1.1.12 for speex projects.\n"); printf("For windows, I had to define HAVE_CONFIG_H, include win32/config.h,\n"); printf("and include the files under libspeex, except those that start with test.\n"); printf("PortAudio is also included and is used to read and write audio data. You\n"); printf("can substitute whatever you want if you do not want to use portaudio.\n"); printf("Difficulty: Advanced\n\n"); // Since voice is peer to peer, we give the option to use the nat punchthrough client if desired. NatPunchthroughClient natPunchthroughClient; char port[256]; rakPeer = RakNetworkFactory::GetRakPeerInterface(); printf("Enter local port (enter for default): "); gets(port); if (port[0]==0) strcpy(port, "60000"); SocketDescriptor socketDescriptor(atoi(port),0); rakPeer->Startup(4, 30, &socketDescriptor, 1); rakPeer->SetMaximumIncomingConnections(4); rakPeer->AttachPlugin(&rakVoice); rakPeer->AttachPlugin(&natPunchthroughClient); rakVoice.Init(SAMPLE_RATE, FRAMES_PER_BUFFER*sizeof(SAMPLE)); err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), 1, // Num channels, whatever that means PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), 1, // Num channels PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ 0, /* paDitherOff, // flags */ PACallback, 0 ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Support NAT punchthrough? (y/n)? "); bool useNatPunchthrough; useNatPunchthrough=(getche()=='y'); printf("\n"); char facilitatorIP[256]; {//Linux fix. Won't compile without it. Because of the goto error above, the scope is ambigious. Make it a block to define that it will not be used after the jump. //Doesn't change current logic SystemAddress facilitator; if (useNatPunchthrough) { printf("My GUID is %s\n", rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString()); printf("Enter IP of facilitator (enter for default): "); gets(facilitatorIP); if (facilitatorIP[0]==0) strcpy(facilitatorIP, "94.198.81.195"); facilitator.SetBinaryAddress(facilitatorIP); facilitator.port=NAT_PUNCHTHROUGH_FACILITATOR_PORT; rakPeer->Connect(facilitatorIP, NAT_PUNCHTHROUGH_FACILITATOR_PORT, 0, 0); printf("Connecting to facilitator...\n"); } else { printf("Not supporting NAT punchthrough.\n"); } Packet *p; quit=false; if (useNatPunchthrough==false) printf("(Q)uit. (C)onnect. (D)isconnect. C(l)ose voice channels. (M)ute. ' ' for stats.\n"); while (!quit) { if (kbhit()) { ch=getch(); if (ch=='y') { quit=true; } else if (ch=='c') { if (useNatPunchthrough) { RakNetGUID destination; printf("Enter GUID of destination: "); char guidStr[256]; while (1) { gets(guidStr); if (!destination.FromString(guidStr)) printf("Invalid GUID format. Try again.\nEnter GUID of destination: "); else break; } printf("Starting NAT punch. Please wait...\n"); natPunchthroughClient.OpenNAT(destination,facilitator); } else { char ip[256]; printf("Enter IP of remote system: "); gets(ip); if (ip[0]==0) strcpy(ip, "127.0.0.1"); printf("Enter port of remote system: "); gets(port); if (port[0]==0) strcpy(port, "60000"); rakPeer->Connect(ip, atoi(port), 0,0); } } else if (ch=='m') { mute=!mute; if (mute) printf("Now muted.\n"); else printf("No longer muted.\n"); } else if (ch=='d') { rakPeer->Shutdown(100,0); } else if (ch=='l') { rakVoice.CloseAllChannels(); } else if (ch==' ') { char message[2048]; RakNetStatistics *rss=rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0)); StatisticsToString(rss, message, 2); printf("%s", message); } else if (ch=='q') quit=true; ch=0; } p=rakPeer->Receive(); while (p) { if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED) { if (p->systemAddress==facilitator) { printf("Connection to facilitator completed\n"); printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n"); } else { printf("ID_CONNECTION_REQUEST_ACCEPTED from %s\n", p->systemAddress.ToString()); rakVoice.RequestVoiceChannel(p->guid); } } else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED) { if (p->systemAddress==facilitator) { printf("Connection to facilitator failed. Using direct connections\n"); useNatPunchthrough=false; printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n"); } else { printf("ID_CONNECTION_ATTEMPT_FAILED\n"); } } else if (p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REQUEST || p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REPLY) { printf("Got new channel from %s\n", p->systemAddress.ToString()); } else if (p->data[0]==ID_NAT_TARGET_NOT_CONNECTED) { RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_TARGET_NOT_CONNECTED for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_TARGET_UNRESPONSIVE) { RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_TARGET_UNRESPONSIVE for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST) { RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_CONNECTION_TO_TARGET_LOST for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_ALREADY_IN_PROGRESS) { RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_ALREADY_IN_PROGRESS for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_PUNCHTHROUGH_FAILED) { printf("ID_NAT_PUNCHTHROUGH_FAILED for %s\n", p->guid.ToString()); } else if (p->data[0]==ID_NAT_PUNCHTHROUGH_SUCCEEDED) { printf("ID_NAT_PUNCHTHROUGH_SUCCEEDED for %s. Connecting...\n", p->guid.ToString()); rakPeer->Connect(p->systemAddress.ToString(false),p->systemAddress.port,0,0); } else if (p->data[0]==ID_ALREADY_CONNECTED) { printf("ID_ALREADY_CONNECTED\n"); } else if (p->data[0]==ID_RAKVOICE_CLOSE_CHANNEL) { printf("ID_RAKVOICE_CLOSE_CHANNEL\n"); } else if (p->data[0]==ID_DISCONNECTION_NOTIFICATION) { printf("ID_DISCONNECTION_NOTIFICATION\n"); } else if (p->data[0]==ID_NEW_INCOMING_CONNECTION) { printf("ID_NEW_INCOMING_CONNECTION\n"); } else { printf("Unknown packet ID %i\n", p->data[0]); } rakPeer->DeallocatePacket(p); p=rakPeer->Receive(); } Pa_Sleep( 30 ); } } err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); rakPeer->Shutdown(300); RakNetworkFactory::DestroyRakPeerInterface(rakPeer); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }
PluginReceiveResult NatPunchthroughClient::OnReceive(Packet *packet) { switch (packet->data[0]) { case ID_NAT_GET_MOST_RECENT_PORT: { OnGetMostRecentPort(packet); return RR_STOP_PROCESSING_AND_DEALLOCATE; } case ID_OUT_OF_BAND_INTERNAL: if (packet->length>=2 && (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL || packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL) && sp.nextActionTime!=0) { RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(2); uint16_t sessionId; bs.Read(sessionId); // RakAssert(sessionId<100); if (sessionId!=sp.sessionId) break; char ipAddressString[32]; packet->systemAddress.ToString(true,ipAddressString); if (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL) { if (natPunchthroughDebugInterface) { char guidString[128]; sp.targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Received ID_NAT_ESTABLISH_UNIDIRECTIONAL from guid %s, system address %s.", guidString, ipAddressString)); } if (sp.testMode!=SendPing::PUNCHING_FIXED_PORT) { sp.testMode=SendPing::PUNCHING_FIXED_PORT; sp.retryCount+=sp.attemptCount*pc.UDP_SENDS_PER_PORT_EXTERNAL; sp.targetAddress=packet->systemAddress; // Keeps trying until the other side gives up too, in case it is unidirectional sp.punchingFixedPortAttempts=pc.UDP_SENDS_PER_PORT_EXTERNAL*pc.MAX_PREDICTIVE_PORT_RANGE; } SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL); } else if (packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL && sp.targetGuid==packet->guid) { // They send back our port bs.Read(mostRecentNewExternalPort); SendOutOfBand(packet->systemAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL); // Tell the user about the success sp.targetAddress=packet->systemAddress; PushSuccess(); OnReadyForNextPunchthrough(); bool removedFromFailureQueue=RemoveFromFailureQueue(); if (natPunchthroughDebugInterface) { char guidString[128]; sp.targetGuid.ToString(guidString); if (removedFromFailureQueue) natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 2nd attempt.", guidString, ipAddressString)); else natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 1st attempt.", guidString, ipAddressString)); } } // mostRecentNewExternalPort=packet->systemAddress.port; } return RR_STOP_PROCESSING_AND_DEALLOCATE; case ID_NAT_ALREADY_IN_PROGRESS: { RakNet::BitStream incomingBs(packet->data, packet->length, false); incomingBs.IgnoreBytes(sizeof(MessageID)); RakNetGUID targetGuid; incomingBs.Read(targetGuid); if (natPunchthroughDebugInterface) { char guidString[128]; targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to ID_NAT_ALREADY_IN_PROGRESS. Returning failure.", guidString)); } } break; case ID_NAT_TARGET_NOT_CONNECTED: case ID_NAT_CONNECTION_TO_TARGET_LOST: case ID_NAT_TARGET_UNRESPONSIVE: { char *reason; if (packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED) reason=(char *)"ID_NAT_TARGET_NOT_CONNECTED"; else if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST) reason=(char *)"ID_NAT_CONNECTION_TO_TARGET_LOST"; else reason=(char *)"ID_NAT_TARGET_UNRESPONSIVE"; RakNet::BitStream incomingBs(packet->data, packet->length, false); incomingBs.IgnoreBytes(sizeof(MessageID)); RakNetGUID targetGuid; incomingBs.Read(targetGuid); if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST || packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE) { uint16_t sessionId; incomingBs.Read(sessionId); if (sessionId!=sp.sessionId) break; } unsigned int i; for (i=0; i < failedAttemptList.Size(); i++) { if (failedAttemptList[i].guid==targetGuid) { if (natPunchthroughDebugInterface) { char guidString[128]; targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to %s.", guidString, reason)); } // If the retry target is not connected, or loses connection, or is not responsive, then previous failures cannot be retried. // Don't need to return failed, the other messages indicate failure anyway /* Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID)); p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED; p->systemAddress=failedAttemptList[i].addr; p->systemAddress.systemIndex=(SystemIndex)-1; p->guid=failedAttemptList[i].guid; rakPeerInterface->PushBackPacket(p, false); */ failedAttemptList.RemoveAtIndexFast(i); break; } } if (natPunchthroughDebugInterface) { char guidString[128]; targetGuid.ToString(guidString); natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough attempt to guid %s failed due to %s.", guidString, reason)); } // Stop trying punchthrough sp.nextActionTime=0; /* RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); RakNetGUID failedSystem; bs.Read(failedSystem); bool deletedFirst=false; unsigned int i=0; while (i < pendingOpenNAT.Size()) { if (pendingOpenNAT[i].destination==failedSystem) { if (i==0) deletedFirst=true; pendingOpenNAT.RemoveAtIndex(i); } else i++; } // Failed while in progress. Go to next in attempt queue if (deletedFirst && pendingOpenNAT.Size()) { SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator); sp.nextActionTime=0; } */ } break; case ID_TIMESTAMP: if (packet->data[sizeof(MessageID)+sizeof(RakNet::Time)]==ID_NAT_CONNECT_AT_TIME) { OnConnectAtTime(packet); return RR_STOP_PROCESSING_AND_DEALLOCATE; } break; } return RR_CONTINUE_PROCESSING; }
/// RakNet stuff void CDemo::UpdateRakNet(void) { SystemAddress facilitatorSystemAddress(DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_IP, DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_PORT); Packet *packet; RakNetTime curTime = RakNet::GetTime(); RakNet::RakString targetName; for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { if (strcmp(packet->systemAddress.ToString(false),DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_IP)==0) { targetName="NATPunchthroughServer"; } else { targetName=packet->systemAddress.ToString(true); } switch (packet->data[0]) { case ID_IP_RECENTLY_CONNECTED: { PushMessage(RakNet::RakString("This IP address recently connected from ") + targetName + RakNet::RakString(".")); if (packet->systemAddress==facilitatorSystemAddress) PushMessage("Multiplayer will not work without the NAT punchthrough server!"); } break; case ID_INCOMPATIBLE_PROTOCOL_VERSION: { PushMessage(RakNet::RakString("Incompatible protocol version from ") + targetName + RakNet::RakString(".")); if (packet->systemAddress==facilitatorSystemAddress) PushMessage("Multiplayer will not work without the NAT punchthrough server!"); } break; case ID_DISCONNECTION_NOTIFICATION: { PushMessage(RakNet::RakString("Disconnected from ") + targetName + RakNet::RakString(".")); if (packet->systemAddress==facilitatorSystemAddress) isConnectedToNATPunchthroughServer=false; } break; case ID_CONNECTION_LOST: { PushMessage(RakNet::RakString("Connection to ") + targetName + RakNet::RakString(" lost.")); if (packet->systemAddress==facilitatorSystemAddress) isConnectedToNATPunchthroughServer=false; } break; case ID_NO_FREE_INCOMING_CONNECTIONS: { PushMessage(RakNet::RakString("No free incoming connections to ") + targetName + RakNet::RakString(".")); if (packet->systemAddress==facilitatorSystemAddress) PushMessage("Multiplayer will not work without the NAT punchthrough server!"); } break; case ID_NEW_INCOMING_CONNECTION: { PushMessage(RakNet::RakString("New incoming connection from ") + targetName + RakNet::RakString(".")); // Add this system as a new player replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid)); } break; case ID_CONNECTION_REQUEST_ACCEPTED: { PushMessage(RakNet::RakString("Connection request to ") + targetName + RakNet::RakString(" accepted.")); if (packet->systemAddress==facilitatorSystemAddress) { isConnectedToNATPunchthroughServer=true; } else { // Add this system as a new player replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid)); } } break; case ID_CONNECTION_ATTEMPT_FAILED: { PushMessage(RakNet::RakString("Connection attempt to ") + targetName + RakNet::RakString(" failed.")); if (packet->systemAddress==facilitatorSystemAddress) PushMessage("Multiplayer will not work without the NAT punchthrough server!"); } break; case ID_NAT_TARGET_NOT_CONNECTED: { RakNetGUID recipientGuid; RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(sizeof(MessageID)); bs.Read(recipientGuid); targetName=recipientGuid.ToString(); PushMessage(RakNet::RakString("NAT target ") + targetName + RakNet::RakString(" not connected.")); } break; case ID_NAT_TARGET_UNRESPONSIVE: { RakNetGUID recipientGuid; RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(sizeof(MessageID)); bs.Read(recipientGuid); targetName=recipientGuid.ToString(); PushMessage(RakNet::RakString("NAT target ") + targetName + RakNet::RakString(" unresponsive.")); } break; case ID_NAT_CONNECTION_TO_TARGET_LOST: { RakNetGUID recipientGuid; RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(sizeof(MessageID)); bs.Read(recipientGuid); targetName=recipientGuid.ToString(); PushMessage(RakNet::RakString("NAT target connection to ") + targetName + RakNet::RakString(" lost.")); } break; case ID_NAT_ALREADY_IN_PROGRESS: { RakNetGUID recipientGuid; RakNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(sizeof(MessageID)); bs.Read(recipientGuid); targetName=recipientGuid.ToString(); PushMessage(RakNet::RakString("NAT punchthrough to ") + targetName + RakNet::RakString(" in progress (skipping).")); } break; case ID_NAT_PUNCHTHROUGH_FAILED: { targetName=packet->guid.ToString(); unsigned char weAreSender=packet->data[1]; if (weAreSender) { PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" failed. Using proxy.")); udpProxyClient->RequestForwarding(facilitatorSystemAddress, UNASSIGNED_SYSTEM_ADDRESS, packet->guid, 7000); } else { PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" failed. Remote system should connect via proxy.")); } } break; case ID_NAT_PUNCHTHROUGH_SUCCEEDED: { unsigned char weAreSender=packet->data[1]; if (weAreSender) { PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" succeeded. Connecting.")); rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.port,0,0); } else { PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" succeeded.")); } } break; case ID_ADVERTISE_SYSTEM: if (packet->guid!=rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS)) { char hostIP[32]; packet->systemAddress.ToString(false,hostIP); rakPeer->Connect(hostIP,packet->systemAddress.port,0,0); } break; } } for (packet=tcpInterface->Receive(); packet; tcpInterface->DeallocatePacket(packet), packet=tcpInterface->Receive()) { httpConnection->ProcessTCPPacket(packet); } if (httpConnection->HasRead()) { RakNet::RakString httpResult = httpConnection->Read(); // Good response, let the PHPDirectoryServer2 class handle the data // If resultCode is not an empty string, then we got something other than a table // (such as delete row success notification, or the message is for HTTP only and not for this class). HTTPReadResult readResult = phpDirectoryServer2->ProcessHTTPRead(httpResult); if (readResult==HTTP_RESULT_GOT_TABLE) { /// Got a table which was stored internally. Print it out const DataStructures::Table *games = phpDirectoryServer2->GetLastDownloadedTable(); // __GAME_NAME is an automatic column passed to PHPDirectoryServer::UploadTable unsigned int gameNameIndex = games->ColumnIndex("__GAME_NAME"); // RakNetGUID is a column we manually added using our own GUID with PHPDirectoryServer::SetField // We need to use RakNetGUID because NAT punchthrough refers to systems by RakNetGUID, rather than by SystemAddress unsigned int guidIndex = games->ColumnIndex("RakNetGUID"); DataStructures::Table::Row *row; unsigned int i; unsigned int tableSize=0, connectionCount=0; DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = games->GetRows().GetListHead(); while (cur) { for (i=0; i < (unsigned)cur->size; i++) { RakAssert(gameNameIndex!=-1); row = cur->data[i]; // Make sure it's the same game, since the PHPDirectoryServer can return other games too if (gameNameIndex!=-1 && strcmp(row->cells[gameNameIndex]->c, "IrrlichtDemo")==0) { tableSize++; RakNet::RakString guidStr = row->cells[guidIndex]->c; RakNetGUID guid; guid.FromString(guidStr.C_String()); // Connect as long as I'm not connecting to myself if (guid!=rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS)) { connectionCount++; systemsToConnectTo.Push(guid); } } } cur=cur->next; } PushMessage(RakNet::RakString("DirectoryServer returned %i rows, of which we are connecting to %i",tableSize,connectionCount)); } } // Update our two classes so they can do time-based updates httpConnection->Update(); phpDirectoryServer2->Update(); // Start punchthrough to all pending systems, which we got from the PHP directory server code about 20 lines above if (isConnectedToNATPunchthroughServer) { while (systemsToConnectTo.GetSize()>0) { RakNetGUID g = systemsToConnectTo.Pop(__FILE__,__LINE__); natPunchthroughClient->OpenNAT(g, facilitatorSystemAddress); targetName=g.ToString(); PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" started.")); } } // Update non-plugin helper classes. // This keeps our system listed on the PHP directory server httpConnection->Update(); phpDirectoryServer2->Update(); // Call the Update function for networked game objects added to BaseIrrlichtReplica once the game is ready if (currentScene>=1) { DataStructures::DefaultIndexType idx; for (idx=0; idx < replicaManager3->GetReplicaCount(); idx++) ((BaseIrrlichtReplica*)(replicaManager3->GetReplicaAtIndex(idx)))->Update(curTime);; } }