00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <stddef.h>
00038 #include <string.h>
00039
00040 #include "stratagus.h"
00041
00042 #include "net_lowlevel.h"
00043 #include "player.h"
00044 #include "map.h"
00045 #include "network.h"
00046 #include "netconnect.h"
00047 #include "interface.h"
00048 #include "menus.h"
00049 #include "settings.h"
00050 #include "version.h"
00051
00052
00053
00054
00055
00056
00057
00058 #define CLIENT_LIVE_BEAT 60
00059 #define CLIENT_IS_DEAD 300
00060
00061
00062
00063
00064
00065 std::string NetworkArg;
00066 int NetPlayers;
00067 int NetworkPort = NetworkDefaultPort;
00068
00069 #ifdef DEBUG
00070 extern unsigned long MyHost;
00071 extern int MyPort;
00072 #endif
00073
00074 int HostsCount;
00075 CNetworkHost Hosts[PlayerMax];
00076
00077 int NetConnectRunning;
00078 NetworkState NetStates[PlayerMax];
00079 unsigned char NetLocalState;
00080 int NetLocalHostsSlot;
00081 int NetLocalPlayerNumber;
00082
00083 static int NetStateMsgCnt;
00084 static unsigned char LastStateMsgType;
00085 static unsigned long NetLastPacketSent;
00086 static unsigned long NetworkServerIP;
00087 std::string NetworkMapName;
00088
00092 static int NetworkServerPort = NetworkDefaultPort;
00093
00097 CServerSetup ServerSetupState;
00098 CServerSetup LocalSetupState;
00099
00100
00101 unsigned char *CNetworkHost::Serialize() const
00102 {
00103 unsigned char *buf = new unsigned char[CNetworkHost::Size()];
00104 unsigned char *p = buf;
00105
00106 *(Uint32 *)p = this->Host;
00107 p += 4;
00108 *(Uint16 *)p = this->Port;
00109 p += 2;
00110 *(Uint16 *)p = this->PlyNr;
00111 p += 2;
00112 memcpy(p, this->PlyName, sizeof(this->PlyName));
00113
00114 return buf;
00115 }
00116
00117 void CNetworkHost::Deserialize(const unsigned char *p)
00118 {
00119 this->Host = *(Uint32 *)p;
00120 p += 4;
00121 this->Port = *(Uint16 *)p;
00122 p += 2;
00123 this->PlyNr = *(Uint16 *)p;
00124 p += 2;
00125 memcpy(this->PlyName, p, sizeof(this->PlyName));
00126 }
00127
00128 unsigned char *CServerSetup::Serialize() const
00129 {
00130 unsigned char *buf = new unsigned char[CServerSetup::Size()];
00131 unsigned char *p = buf;
00132 int i;
00133
00134 *p++ = this->ResourcesOption;
00135 *p++ = this->UnitsOption;
00136 *p++ = this->FogOfWar;
00137 *p++ = this->RevealMap;
00138 *p++ = this->GameTypeOption;
00139 *p++ = this->Difficulty;
00140 *p++ = this->MapRichness;
00141 for (i = 0; i < PlayerMax; ++i) {
00142 *p++ = this->CompOpt[i];
00143 }
00144 for (i = 0; i < PlayerMax; ++i) {
00145 *p++ = this->Ready[i];
00146 }
00147 for (i = 0; i < PlayerMax; ++i) {
00148 *(Uint32 *)p = this->LastFrame[i];
00149 p += 4;
00150 }
00151
00152 return buf;
00153 }
00154
00155 void CServerSetup::Deserialize(const unsigned char *p)
00156 {
00157 int i;
00158
00159 this->ResourcesOption = *p++;
00160 this->UnitsOption = *p++;
00161 this->FogOfWar = *p++;
00162 this->RevealMap = *p++;
00163 this->GameTypeOption = *p++;
00164 this->Difficulty = *p++;
00165 this->MapRichness = *p++;
00166 for (i = 0; i < PlayerMax; ++i) {
00167 this->CompOpt[i] = *p++;
00168 }
00169 for (i = 0; i < PlayerMax; ++i) {
00170 this->Ready[i] = *p++;
00171 }
00172 for (i = 0; i < PlayerMax; ++i) {
00173 this->LastFrame[i] = *(Uint32 *)p;
00174 p += 4;
00175 }
00176 }
00177
00178 unsigned char *CInitMessage::Serialize() const
00179 {
00180 unsigned char *buf = new unsigned char[CInitMessage::Size()];
00181 unsigned char *p = buf;
00182 unsigned char *x;
00183
00184 *p++ = this->Type;
00185 *p++ = this->SubType;
00186 *(Sint32 *)p = this->Stratagus;
00187 p += 4;
00188 *(Sint32 *)p = this->Version;
00189 p += 4;
00190 *(Uint32 *)p = this->ConfUID;
00191 p += 4;
00192 *(Uint32 *)p = this->MapUID;
00193 p += 4;
00194 *(Sint32 *)p = this->Lag;
00195 p += 4;
00196 *(Sint32 *)p = this->Updates;
00197 p += 4;
00198 *p++ = this->HostsCount;
00199
00200 switch (this->SubType) {
00201 case ICMHello:
00202 case ICMConfig:
00203 case ICMWelcome:
00204 case ICMResync:
00205 case ICMGo:
00206 for (int i = 0; i < PlayerMax; ++i) {
00207 x = this->u.Hosts[i].Serialize();
00208 memcpy(p, x, CNetworkHost::Size());
00209 p += CNetworkHost::Size();
00210 delete[] x;
00211 }
00212 break;
00213 case ICMMap:
00214 memcpy(p, this->u.MapPath, sizeof(this->u.MapPath));
00215 p += sizeof(this->u.MapPath);
00216 break;
00217 case ICMState:
00218 x = this->u.State.Serialize();
00219 memcpy(p, x, CServerSetup::Size());
00220 p += CServerSetup::Size();
00221 delete[] x;
00222 break;
00223 }
00224
00225 return buf;
00226 }
00227
00228 void CInitMessage::Deserialize(const unsigned char *p)
00229 {
00230 this->Type = *p++;
00231 this->SubType = *p++;
00232 this->Stratagus = *(Sint32 *)p;
00233 p += 4;
00234 this->Version = *(Sint32 *)p;
00235 p += 4;
00236 this->ConfUID = *(Uint32 *)p;
00237 p += 4;
00238 this->MapUID = *(Uint32 *)p;
00239 p += 4;
00240 this->Lag = *(Sint32 *)p;
00241 p += 4;
00242 this->Updates = *(Sint32 *)p;
00243 p += 4;
00244 this->HostsCount = *p++;
00245
00246 switch (this->SubType) {
00247 case ICMHello:
00248 case ICMConfig:
00249 case ICMWelcome:
00250 case ICMResync:
00251 case ICMGo:
00252 for (int i = 0; i < PlayerMax; ++i) {
00253 this->u.Hosts[i].Deserialize(p);
00254 p += CNetworkHost::Size();
00255 }
00256 break;
00257 case ICMMap:
00258 memcpy(this->u.MapPath, p, sizeof(this->u.MapPath));
00259 p += sizeof(this->u.MapPath);
00260 break;
00261 case ICMState:
00262 this->u.State.Deserialize(p);
00263 p += CServerSetup::Size();
00264 break;
00265 }
00266 }
00267
00268
00269
00270
00271
00282 static int NetworkSendICMessage(unsigned long host, int port, CInitMessage *msg)
00283 {
00284 msg->Stratagus = htonl(StratagusVersion);
00285 msg->Version = htonl(NetworkProtocolVersion);
00286 msg->Lag = htonl(NetworkLag);
00287 msg->Updates = htonl(NetworkUpdates);
00288
00289 unsigned char *buf = msg->Serialize();
00290 int ret = NetSendUDP(NetworkFildes, host, port, buf, CInitMessage::Size());
00291 delete[] buf;
00292 return ret;
00293 }
00294
00295 #ifdef DEBUG
00296 static const char *ncconstatenames[] = {
00297 "ccs_unused",
00298 "ccs_connecting",
00299 "ccs_connected",
00300 "ccs_mapinfo",
00301 "ccs_badmap",
00302 "ccs_synced",
00303 "ccs_async",
00304 "ccs_changed",
00305 "ccs_detaching",
00306 "ccs_disconnected",
00307 "ccs_unreachable",
00308 "ccs_usercanceled",
00309 "ccs_nofreeslots",
00310 "ccs_serverquits",
00311 "ccs_goahead",
00312 "ccs_started",
00313 "ccs_incompatibleengine",
00314 "ccs_incompatiblenetwork",
00315 };
00316
00317 static const char *icmsgsubtypenames[] = {
00318 "Hello",
00319 "Config",
00320
00321 "EngineMismatch",
00322 "ProtocolMismatch",
00323 "EngineConfMismatch",
00324 "MapUidMismatch",
00325
00326 "GameFull",
00327 "Welcome",
00328
00329 "Waiting",
00330 "Map",
00331 "State",
00332 "Resync",
00333
00334 "ServerQuit",
00335 "GoodBye",
00336 "SeeYou",
00337
00338 "Go",
00339 "AreYouThere",
00340 "IAmHere",
00341 };
00342 #endif
00343
00351 static void NetworkSendRateLimitedClientMessage(CInitMessage *msg, unsigned long msecs)
00352 {
00353 unsigned long now;
00354 int n;
00355
00356 now = GetTicks();
00357 if (now - NetLastPacketSent >= msecs) {
00358 NetLastPacketSent = now;
00359 if (msg->SubType == LastStateMsgType) {
00360 ++NetStateMsgCnt;
00361 } else {
00362 NetStateMsgCnt = 0;
00363 LastStateMsgType = msg->SubType;
00364 }
00365 n = NetworkSendICMessage(NetworkServerIP, htons(NetworkServerPort),
00366 msg);
00367 if (!NetStateMsgCnt) {
00368 DebugPrint
00369 ("Sending Init Message (%s:%d): %d:%d(%d) %d.%d.%d.%d:%d\n" _C_
00370 ncconstatenames[NetLocalState] _C_ NetStateMsgCnt _C_
00371 msg->Type _C_ msg->SubType _C_ n _C_
00372 NIPQUAD(ntohl(NetworkServerIP)) _C_ NetworkServerPort);
00373 }
00374 }
00375 }
00376
00384 int NetworkSetupServerAddress(const std::string &serveraddr)
00385 {
00386 unsigned long addr;
00387
00388 addr = NetResolveHost(serveraddr);
00389 if (addr == INADDR_NONE) {
00390 return 1;
00391 }
00392 NetworkServerIP = addr;
00393
00394 DebugPrint("SELECTED SERVER: %s (%d.%d.%d.%d)\n" _C_ serveraddr.c_str() _C_
00395 NIPQUAD(ntohl(addr)));
00396
00397 return 0;
00398 }
00399
00403 void NetworkInitClientConnect(void)
00404 {
00405 int i;
00406
00407 NetConnectRunning = 2;
00408 NetLastPacketSent = GetTicks();
00409 NetLocalState = ccs_connecting;
00410 NetStateMsgCnt = 0;
00411 NetworkServerPort = NetworkPort;
00412 LastStateMsgType = ICMServerQuit;
00413 for (i = 0; i < PlayerMax; ++i) {
00414 Hosts[i].Host = 0;
00415 Hosts[i].Port = 0;
00416 Hosts[i].PlyNr = 0;
00417 memset(Hosts[i].PlyName, 0, sizeof(Hosts[i].PlyName));
00418 }
00419 ServerSetupState.Clear();
00420 LocalSetupState.Clear();
00421 }
00422
00426 void NetworkExitClientConnect(void)
00427 {
00428 NetConnectRunning = 0;
00429 NetPlayers = 0;
00430 }
00431
00435 void NetworkDetachFromServer(void)
00436 {
00437 NetLocalState = ccs_detaching;
00438 NetStateMsgCnt = 0;
00439 }
00440
00444 void NetworkInitServerConnect(int openslots)
00445 {
00446 int i;
00447
00448 NetConnectRunning = 1;
00449
00450
00451 for (i = 0; i < PlayerMax; ++i) {
00452 NetStates[i].State = ccs_unused;
00453 Hosts[i].Host = 0;
00454 Hosts[i].Port = 0;
00455 Hosts[i].PlyNr = 0;
00456 memset(Hosts[i].PlyName, 0, sizeof(Hosts[i].PlyName));
00457 }
00458
00459
00460 memcpy(Hosts[0].PlyName, LocalPlayerName.c_str(), sizeof(Hosts[0].PlyName) - 1);
00461
00462 ServerSetupState.Clear();
00463 LocalSetupState.Clear();
00464 for (i = openslots; i < PlayerMax - 1; ++i) {
00465 ServerSetupState.CompOpt[i] = 1;
00466 }
00467 }
00468
00472 void NetworkExitServerConnect(void)
00473 {
00474 int h;
00475 int i;
00476 int n;
00477 CInitMessage message;
00478
00479 message.Type = MessageInitReply;
00480 message.SubType = ICMServerQuit;
00481 for (h = 1; h < PlayerMax - 1; ++h) {
00482
00483
00484 if (Hosts[h].PlyNr) {
00485 for (i = 0; i < 5; ++i) {
00486 n = NetworkSendICMessage(Hosts[h].Host, Hosts[h].Port, &message);
00487 DebugPrint("Sending InitReply Message ServerQuit: (%d) to %d.%d.%d.%d:%d\n" _C_
00488 n _C_ NIPQUAD(ntohl(Hosts[h].Host)) _C_ ntohs(Hosts[h].Port));
00489 }
00490 }
00491 }
00492
00493 NetworkInitServerConnect(0);
00494
00495 NetConnectRunning = 0;
00496 }
00497
00501 void NetworkServerResyncClients(void)
00502 {
00503 int i;
00504
00505 if (NetConnectRunning) {
00506 for (i = 1; i < PlayerMax - 1; ++i) {
00507 if (Hosts[i].PlyNr && NetStates[i].State == ccs_synced) {
00508 NetStates[i].State = ccs_async;
00509 }
00510 }
00511 }
00512 }
00513
00517 void NetworkServerStartGame(void)
00518 {
00519 int h;
00520 int i;
00521 int j;
00522 int n;
00523 int num[PlayerMax];
00524 int org[PlayerMax];
00525 int rev[PlayerMax];
00526 unsigned char buf[1024];
00527 CInitMessage msg;
00528 CInitMessage message;
00529 CInitMessage statemsg;
00530
00531 Assert(ServerSetupState.CompOpt[0] == 0);
00532
00533
00534 LocalSetupState = ServerSetupState;
00535
00536
00537 for (h = i = 0; i < PlayerMax; ++i) {
00538 if (Map.Info.PlayerType[i] == PlayerPerson) {
00539 rev[i] = h;
00540 num[h++] = i;
00541 DebugPrint("Slot %d is available for an interactive player (%d)\n" _C_
00542 i _C_ rev[i]);
00543 }
00544 }
00545
00546 n = h;
00547 for (i = 0; i < PlayerMax; ++i) {
00548 if (Map.Info.PlayerType[i] == PlayerComputer) {
00549 rev[i] = n++;
00550 DebugPrint("Slot %d is available for an ai computer player (%d)\n" _C_
00551 i _C_ rev[i]);
00552 }
00553 }
00554
00555 for (i = 0; i < PlayerMax; ++i) {
00556 if (Map.Info.PlayerType[i] != PlayerPerson &&
00557 Map.Info.PlayerType[i] != PlayerComputer) {
00558 rev[i] = n++;
00559
00560 }
00561 }
00562
00563 #if 0
00564 printf("INITIAL ServerSetupState:\n");
00565 for (i = 0; i < PlayerMax - 1; ++i) {
00566 printf("%02d: CO: %d Host: ", i, ServerSetupState.CompOpt[i]);
00567 if (ServerSetupState.CompOpt[i] == 0) {
00568 printf(" %d.%d.%d.%d:%d %s", NIPQUAD(ntohl(Hosts[i].Host)),
00569 ntohs(Hosts[i].Port), Hosts[i].PlyName);
00570 }
00571 printf("\n");
00572 }
00573 #endif
00574
00575
00576 for (i = 0; i < PlayerMax; ++i) {
00577 org[i] = -1;
00578 for (j = 0; j < PlayerMax; ++j) {
00579 if (rev[j] == i) {
00580 org[i] = j;
00581 break;
00582 }
00583 }
00584 }
00585
00586
00587 NetPlayers = h;
00588 for (i = 1; i < h; ++i) {
00589 if (Hosts[i].PlyNr == 0 && ServerSetupState.CompOpt[i] != 0) {
00590 NetPlayers--;
00591 } else if (Hosts[i].PlyName[0] == 0) {
00592
00593 ServerSetupState.CompOpt[i] = 1;
00594 LocalSetupState.CompOpt[i] = 1;
00595 NetPlayers--;
00596 }
00597 }
00598
00599
00600 for (i = 1; i < h; ++i) {
00601 if (Hosts[i].PlyNr == 0) {
00602 for (j = i + 1; j < PlayerMax - 1; ++j) {
00603 if (Hosts[j].PlyNr) {
00604 DebugPrint("Compact: Hosts %d -> Hosts %d\n" _C_ j _C_ i);
00605 Hosts[i] = Hosts[j];
00606 Hosts[j].PlyNr = 0;
00607 Hosts[j].Host = Hosts[j].Port = 0;
00608 n = LocalSetupState.CompOpt[i];
00609 LocalSetupState.CompOpt[i] = LocalSetupState.CompOpt[j];
00610 LocalSetupState.CompOpt[j] = n;
00611 n = LocalSetupState.LastFrame[i];
00612 LocalSetupState.LastFrame[i] = LocalSetupState.LastFrame[j];
00613 LocalSetupState.LastFrame[j] = n;
00614 break;
00615 }
00616 }
00617 if (j == PlayerMax - 1) {
00618 break;
00619 }
00620 }
00621 }
00622
00623
00624
00625
00626
00627 j = h;
00628 if (NoRandomPlacementMultiplayer == 1) {
00629 for (i = 0; i < PlayerMax; ++i) {
00630 if (Map.Info.PlayerType[i] != PlayerComputer) {
00631 org[i] = Hosts[i].PlyNr;
00632 }
00633 }
00634 } else {
00635 for (i = 0; i < NetPlayers; ++i) {
00636 if (j > 0) {
00637 int k;
00638 int o;
00639 int chosen;
00640
00641 chosen = MyRand() % j;
00642
00643 n = num[chosen];
00644 Hosts[i].PlyNr = n;
00645 k = org[i];
00646 if (k != n) {
00647 for (o = 0; o < PlayerMax; ++o) {
00648 if (org[o] == n) {
00649 org[o] = k;
00650 break;
00651 }
00652 }
00653 org[i] = n;
00654 }
00655 DebugPrint("Assigning player %d to slot %d (%d)\n" _C_
00656 i _C_ n _C_ org[i]);
00657
00658 num[chosen] = num[--j];
00659 } else {
00660 Assert(0);
00661 #if 0
00662
00663
00664 Hosts[i].PlyNr = num[0];
00665 DebugPrint("Hosts[%d].PlyNr = %i\n" _C_ i _C_ num[0]);
00666 #endif
00667 }
00668 }
00669 }
00670
00671
00672 for (i = 0; i < PlayerMax; ++i) {
00673 num[i] = 1;
00674 n = org[i];
00675 ServerSetupState.CompOpt[n] = LocalSetupState.CompOpt[i];
00676 ServerSetupState.LastFrame[n] = LocalSetupState.LastFrame[i];
00677 }
00678
00679
00680
00681
00682
00683
00684
00685 NetLocalPlayerNumber = Hosts[0].PlyNr;
00686 HostsCount = NetPlayers - 1;
00687
00688
00689
00690
00691 Hosts[PlayerMax - 1] = Hosts[0];
00692 Hosts[0] = Hosts[HostsCount];
00693 Hosts[HostsCount] = Hosts[PlayerMax - 1];
00694 Hosts[PlayerMax - 1].PlyNr = 0;
00695
00696
00697 message.Type = MessageInitReply;
00698 message.SubType = ICMConfig;
00699 message.HostsCount = NetPlayers;
00700 message.MapUID = htonl(Map.Info.MapUID);
00701 for (i = 0; i < NetPlayers; ++i) {
00702 message.u.Hosts[i].Host = Hosts[i].Host;
00703 message.u.Hosts[i].Port = Hosts[i].Port;
00704 memcpy(message.u.Hosts[i].PlyName, Hosts[i].PlyName, sizeof(message.u.Hosts[i].PlyName) - 1);
00705 message.u.Hosts[i].PlyNr = htons(Hosts[i].PlyNr);
00706 }
00707
00708
00709 statemsg.Type = MessageInitReply;
00710 statemsg.SubType = ICMState;
00711 statemsg.HostsCount = NetPlayers;
00712 statemsg.u.State = ServerSetupState;
00713 statemsg.MapUID = htonl(Map.Info.MapUID);
00714
00715 DebugPrint("Ready, sending InitConfig to %d host(s)\n" _C_ HostsCount);
00716
00717
00718
00719 for (j = HostsCount; j;) {
00720
00721 breakout:
00722
00723 for (i = 0; i < HostsCount; ++i) {
00724 unsigned long host;
00725 int port;
00726
00727 if (num[Hosts[i].PlyNr] == 1) {
00728 host = message.u.Hosts[i].Host;
00729 port = message.u.Hosts[i].Port;
00730 message.u.Hosts[i].Host = message.u.Hosts[i].Port = 0;
00731 n = NetworkSendICMessage(host, port, &message);
00732 DebugPrint("Sending InitConfig Message Config (%d) to %d.%d.%d.%d:%d\n" _C_
00733 n _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
00734 message.u.Hosts[i].Host = host;
00735 message.u.Hosts[i].Port = port;
00736 } else if (num[Hosts[i].PlyNr] == 2) {
00737 host = message.u.Hosts[i].Host;
00738 port = message.u.Hosts[i].Port;
00739 n = NetworkSendICMessage(host, port, &statemsg);
00740 DebugPrint("Sending InitReply Message State: (%d) to %d.%d.%d.%d:%d\n" _C_
00741 n _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
00742 }
00743 }
00744
00745
00746 while (j && NetSocketReady(NetworkFildes, 1000)) {
00747 if ((n = NetRecvUDP(NetworkFildes, buf, sizeof(buf))) < 0) {
00748 DebugPrint("*Receive ack failed: (%d) from %d.%d.%d.%d:%d\n" _C_
00749 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
00750 continue;
00751 }
00752
00753 if (n != (int)CInitMessage::Size()) {
00754 DebugPrint("Unexpected message size\n");
00755 continue;
00756 }
00757
00758 msg.Deserialize(buf);
00759 if (msg.Type == MessageInitHello) {
00760 switch (msg.SubType) {
00761
00762 case ICMConfig:
00763 DebugPrint("Got ack for InitConfig: (%d) from %d.%d.%d.%d:%d\n" _C_
00764 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
00765
00766 for (i = 0; i < HostsCount; ++i) {
00767 if (NetLastHost == Hosts[i].Host && NetLastPort == Hosts[i].Port) {
00768 if (num[Hosts[i].PlyNr] == 1) {
00769 num[Hosts[i].PlyNr]++;
00770 }
00771 goto breakout;
00772 }
00773 }
00774 break;
00775
00776 case ICMGo:
00777 DebugPrint("Got ack for InitState: (%d) from %d.%d.%d.%d:%d\n" _C_
00778 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
00779
00780 for (i = 0; i < HostsCount; ++i) {
00781 if (NetLastHost == Hosts[i].Host && NetLastPort == Hosts[i].Port) {
00782 if (num[Hosts[i].PlyNr] == 2) {
00783 num[Hosts[i].PlyNr] = 0;
00784 --j;
00785 DebugPrint("Removing host %d from waiting list\n" _C_ j);
00786 }
00787 break;
00788 }
00789 }
00790 break;
00791
00792 default:
00793 DebugPrint("Server: Config ACK: Unhandled subtype %d\n" _C_ msg.SubType);
00794 break;
00795 }
00796 } else {
00797 DebugPrint("Unexpected Message Type %d while waiting for Config ACK\n" _C_ msg.Type);
00798 }
00799 }
00800 }
00801
00802 DebugPrint("DONE: All configs acked - Now starting..\n");
00803
00804
00805 message.SubType = ICMGo;
00806 for (i = 0; i < HostsCount; ++i) {
00807 unsigned long host;
00808 int port;
00809
00810 host = message.u.Hosts[i].Host;
00811 port = message.u.Hosts[i].Port;
00812 n = NetworkSendICMessage(host, port, &message);
00813 DebugPrint("Sending InitReply Message Go: (%d) to %d.%d.%d.%d:%d\n" _C_
00814 n _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
00815 }
00816 }
00817
00821 void NetworkGamePrepareGameSettings(void)
00822 {
00823 int c;
00824 int h;
00825 int i;
00826 int num[PlayerMax];
00827 int comp[PlayerMax];
00828
00829 DebugPrint("NetPlayers = %d\n" _C_ NetPlayers);
00830
00831 GameSettings.NetGameType = SettingsMultiPlayerGame;
00832
00833 #ifdef DEBUG
00834 for (i = 0; i < PlayerMax-1; i++) {
00835 printf("%02d: CO: %d Host: ", i, ServerSetupState.CompOpt[i]);
00836 if (ServerSetupState.CompOpt[i] == 0) {
00837 for (h = 0; h < NetPlayers; h++) {
00838 if (Hosts[h].PlyNr == i) {
00839 printf("%s", Hosts[h].PlyName);
00840 }
00841 }
00842 }
00843 printf("\n");
00844 }
00845 #endif
00846
00847
00848 for (c = h = i = 0; i < PlayerMax; i++) {
00849 if (Map.Info.PlayerType[i] == PlayerPerson) {
00850 num[h++] = i;
00851 }
00852 if (Map.Info.PlayerType[i] == PlayerComputer) {
00853 comp[c++] = i;
00854 }
00855 }
00856 for (i = 0; i < h; i++) {
00857 switch(ServerSetupState.CompOpt[num[i]]) {
00858 case 0:
00859 GameSettings.Presets[num[i]].Type = PlayerPerson;
00860 break;
00861 case 1:
00862 GameSettings.Presets[num[i]].Type = PlayerComputer;
00863 break;
00864 case 2:
00865 GameSettings.Presets[num[i]].Type = PlayerNobody;
00866 default:
00867 break;
00868 }
00869 }
00870 for (i = 0; i < c; i++) {
00871 if (ServerSetupState.CompOpt[comp[i]] == 2) {
00872 GameSettings.Presets[comp[i]].Type = PlayerNobody;
00873 DebugPrint("Settings[%d].Type == Closed\n" _C_ comp[i]);
00874 }
00875 }
00876
00877 #ifdef DEBUG
00878 for (i = 0; i < NetPlayers; i++) {
00879 Assert(GameSettings.Presets[Hosts[i].PlyNr].Type == PlayerPerson);
00880 ;
00881 }
00882 #endif
00883 }
00884
00888 void NetworkConnectSetupGame(void)
00889 {
00890 ThisPlayer->SetName(LocalPlayerName);
00891 for (int i = 0; i < HostsCount; ++i) {
00892 Players[Hosts[i].PlyNr].SetName(Hosts[i].PlyName);
00893 }
00894 }
00895
00901 void NetClientCheckLocalState(void)
00902 {
00903 if (LocalSetupState.Ready[NetLocalHostsSlot] != ServerSetupState.Ready[NetLocalHostsSlot]) {
00904 NetLocalState = ccs_changed;
00905 return;
00906 }
00907 }
00908
00912 void NetworkProcessClientRequest(void)
00913 {
00914 CInitMessage message;
00915 int i;
00916
00917 memset(&message, 0, sizeof(message));
00918 changed:
00919 switch (NetLocalState) {
00920 case ccs_disconnected:
00921 message.Type = MessageInitHello;
00922 message.SubType = ICMSeeYou;
00923
00924 for (i = 0; i < 5; ++i) {
00925 NetworkSendICMessage(NetworkServerIP, htons(NetworkServerPort), &message);
00926 }
00927 NetLocalState = ccs_usercanceled;
00928 NetConnectRunning = 0;
00929 break;
00930 case ccs_detaching:
00931 if (NetStateMsgCnt < 10) {
00932 message.Type = MessageInitHello;
00933 message.SubType = ICMGoodBye;
00934 NetworkSendRateLimitedClientMessage(&message, 100);
00935 } else {
00936
00937 NetLocalState = ccs_unreachable;
00938 NetConnectRunning = 0;
00939 DebugPrint("ccs_detaching: Above message limit %d\n" _C_ NetStateMsgCnt);
00940 }
00941 break;
00942 case ccs_connecting:
00943 if (NetStateMsgCnt < 48) {
00944 message.Type = MessageInitHello;
00945 message.SubType = ICMHello;
00946 memcpy(message.u.Hosts[0].PlyName, LocalPlayerName.c_str(), sizeof(message.u.Hosts[0].PlyName) - 1);
00947 message.MapUID = 0L;
00948 NetworkSendRateLimitedClientMessage(&message, 500);
00949 } else {
00950 NetLocalState = ccs_unreachable;
00951 NetConnectRunning = 0;
00952 DebugPrint("ccs_connecting: Above message limit %d\n" _C_ NetStateMsgCnt);
00953 }
00954 break;
00955 case ccs_connected:
00956 if (NetStateMsgCnt < 20) {
00957 message.Type = MessageInitHello;
00958 message.SubType = ICMWaiting;
00959 NetworkSendRateLimitedClientMessage(&message, 650);
00960 } else {
00961 NetLocalState = ccs_unreachable;
00962 NetConnectRunning = 0;
00963 DebugPrint("ccs_connected: Above message limit %d\n" _C_ NetStateMsgCnt);
00964 }
00965 break;
00966 case ccs_synced:
00967 NetClientCheckLocalState();
00968 if (NetLocalState != ccs_synced) {
00969 NetStateMsgCnt = 0;
00970 goto changed;
00971 }
00972 message.Type = MessageInitHello;
00973 message.SubType = ICMWaiting;
00974 NetworkSendRateLimitedClientMessage(&message, 850);
00975 break;
00976 case ccs_changed:
00977 if (NetStateMsgCnt < 20) {
00978 message.Type = MessageInitHello;
00979 message.SubType = ICMState;
00980 message.u.State = LocalSetupState;
00981 message.MapUID = htonl(Map.Info.MapUID);
00982 NetworkSendRateLimitedClientMessage(&message, 450);
00983 } else {
00984 NetLocalState = ccs_unreachable;
00985 NetConnectRunning = 0;
00986 DebugPrint("ccs_changed: Above message limit %d\n" _C_ NetStateMsgCnt);
00987 }
00988 break;
00989 case ccs_async:
00990 if (NetStateMsgCnt < 20) {
00991 message.Type = MessageInitHello;
00992 message.SubType = ICMResync;
00993 NetworkSendRateLimitedClientMessage(&message, 450);
00994 } else {
00995 NetLocalState = ccs_unreachable;
00996 NetConnectRunning = 0;
00997 DebugPrint("ccs_async: Above message limit %d\n" _C_ NetStateMsgCnt);
00998 }
00999 break;
01000 case ccs_mapinfo:
01001 if (NetStateMsgCnt < 20) {
01002 message.Type = MessageInitHello;
01003 message.SubType = ICMMap;
01004 message.MapUID = htonl(Map.Info.MapUID);
01005 NetworkSendRateLimitedClientMessage(&message, 650);
01006 } else {
01007 NetLocalState = ccs_unreachable;
01008 NetConnectRunning = 0;
01009 DebugPrint("ccs_mapinfo: Above message limit %d\n" _C_ NetStateMsgCnt);
01010 }
01011 case ccs_badmap:
01012 if (NetStateMsgCnt < 20) {
01013 message.Type = MessageInitHello;
01014 message.SubType = ICMMapUidMismatch;
01015 message.MapUID = htonl(Map.Info.MapUID);
01016 NetworkSendRateLimitedClientMessage(&message, 650);
01017 } else {
01018 NetLocalState = ccs_unreachable;
01019 NetConnectRunning = 0;
01020 DebugPrint("ccs_badmap: Above message limit %d\n" _C_ NetStateMsgCnt);
01021 }
01022 break;
01023 case ccs_goahead:
01024 if (NetStateMsgCnt < 50) {
01025 message.Type = MessageInitHello;
01026 message.SubType = ICMConfig;
01027 NetworkSendRateLimitedClientMessage(&message, 250);
01028 } else {
01029 NetLocalState = ccs_unreachable;
01030 NetConnectRunning = 0;
01031 DebugPrint("ccs_goahead: Above message limit %d\n" _C_ NetStateMsgCnt);
01032 }
01033 case ccs_started:
01034 if (NetStateMsgCnt < 20) {
01035 message.Type = MessageInitHello;
01036 message.SubType = ICMGo;
01037 NetworkSendRateLimitedClientMessage(&message, 250);
01038 } else {
01039 NetConnectRunning = 0;
01040 }
01041 break;
01042 default:
01043 break;
01044 }
01045 }
01046
01052 static void KickDeadClient(int c)
01053 {
01054 int n;
01055
01056 DebugPrint("kicking client %d\n" _C_ Hosts[c].PlyNr);
01057 NetStates[c].State = ccs_unused;
01058 Hosts[c].Host = 0;
01059 Hosts[c].Port = 0;
01060 Hosts[c].PlyNr = 0;
01061 memset(Hosts[c].PlyName, 0, sizeof(Hosts[c].PlyName));
01062 ServerSetupState.Ready[c] = 0;
01063 ServerSetupState.LastFrame[c] = 0L;
01064
01065
01066 for (n = 1; n < PlayerMax - 1; ++n) {
01067 if (n != c && Hosts[n].PlyNr) {
01068 NetStates[n].State = ccs_async;
01069 }
01070 }
01071 }
01072
01076 void NetworkProcessServerRequest(void)
01077 {
01078 int i;
01079 int n;
01080 unsigned long fcd;
01081 CInitMessage message;
01082
01083 if (GameRunning) {
01084 return;
01085
01086 }
01087
01088 for (i = 1; i < PlayerMax - 1; ++i) {
01089 if (Hosts[i].PlyNr && Hosts[i].Host && Hosts[i].Port) {
01090 fcd = FrameCounter - ServerSetupState.LastFrame[i];
01091 if (fcd >= CLIENT_LIVE_BEAT) {
01092 if (fcd > CLIENT_IS_DEAD) {
01093 KickDeadClient(i);
01094 } else if (fcd % 5 == 0) {
01095 message.Type = MessageInitReply;
01096 message.SubType = ICMAYT;
01097 message.MapUID = 0L;
01098 n = NetworkSendICMessage(Hosts[i].Host, Hosts[i].Port, &message);
01099 DebugPrint("Sending InitReply Message AreYouThere: (%d) to %d.%d.%d.%d:%d (%ld:%ld)\n" _C_
01100 n _C_ NIPQUAD(ntohl(Hosts[i].Host)) _C_ ntohs(Hosts[i].Port) _C_
01101 FrameCounter _C_ (unsigned long)ServerSetupState.LastFrame[i]);
01102 }
01103 }
01104 }
01105 }
01106 }
01107
01108 #ifdef DEBUG
01109
01114 static void ClientParseDisconnected(const CInitMessage *msg)
01115 {
01116 DebugPrint("ccs_disconnected: Server sending GoodBye dups %d\n" _C_
01117 msg->SubType);
01118 }
01119 #endif
01120
01126 static void ClientParseDetaching(const CInitMessage *msg)
01127 {
01128 switch(msg->SubType) {
01129
01130 case ICMGoodBye:
01131 NetLocalState = ccs_disconnected;
01132 NetStateMsgCnt = 0;
01133 break;
01134
01135 default:
01136 DebugPrint("ccs_detaching: Unhandled subtype %d\n" _C_ msg->SubType);
01137 break;
01138 }
01139 }
01140
01146 static void ClientParseConnecting(const CInitMessage *msg)
01147 {
01148 int i;
01149
01150 switch(msg->SubType) {
01151
01152 case ICMEngineMismatch:
01153 fprintf(stderr, "Incompatible Bos Wars version "
01154 StratagusFormatString " <-> "
01155 StratagusFormatString "\n"
01156 "from %d.%d.%d.%d:%d\n",
01157 StratagusFormatArgs((int)ntohl(msg->Stratagus)),
01158 StratagusFormatArgs(StratagusVersion),
01159 NIPQUAD(ntohl(NetLastHost)), ntohs(NetLastPort));
01160 NetLocalState = ccs_incompatibleengine;
01161 NetConnectRunning = 0;
01162 return;
01163
01164 case ICMProtocolMismatch:
01165 fprintf(stderr, "Incompatible network protocol version "
01166 NetworkProtocolFormatString " <-> "
01167 NetworkProtocolFormatString "\n"
01168 "from %d.%d.%d.%d:%d\n",
01169 NetworkProtocolFormatArgs((int)ntohl(msg->Version)),
01170 NetworkProtocolFormatArgs(NetworkProtocolVersion),
01171 NIPQUAD(ntohl(NetLastHost)), ntohs(NetLastPort));
01172 NetLocalState = ccs_incompatiblenetwork;
01173 NetConnectRunning = 0;
01174 return;
01175
01176 case ICMGameFull:
01177 fprintf(stderr, "Server at %d.%d.%d.%d:%d is full!\n",
01178 NIPQUAD(ntohl(NetLastHost)), ntohs(NetLastPort));
01179 NetLocalState = ccs_nofreeslots;
01180 NetConnectRunning = 0;
01181 return;
01182
01183 case ICMWelcome:
01184 NetLocalState = ccs_connected;
01185 NetStateMsgCnt = 0;
01186 NetLocalHostsSlot = ntohs(msg->u.Hosts[0].PlyNr);
01187 memcpy(Hosts[0].PlyName, msg->u.Hosts[0].PlyName, sizeof(Hosts[0].PlyName) - 1);
01188 NetworkLag = ntohl(msg->Lag);
01189 NetworkUpdates = ntohl(msg->Updates);
01190
01191 Hosts[0].Host = NetworkServerIP;
01192 Hosts[0].Port = htons(NetworkServerPort);
01193 for (i = 1; i < PlayerMax; ++i) {
01194 if (i != NetLocalHostsSlot) {
01195 Hosts[i].Host = msg->u.Hosts[i].Host;
01196 Hosts[i].Port = msg->u.Hosts[i].Port;
01197 Hosts[i].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
01198 if (Hosts[i].PlyNr) {
01199 memcpy(Hosts[i].PlyName, msg->u.Hosts[i].PlyName, sizeof(Hosts[i].PlyName) - 1);
01200 }
01201 } else {
01202 Hosts[i].PlyNr = i;
01203 memcpy(Hosts[i].PlyName, LocalPlayerName.c_str(), sizeof(Hosts[i].PlyName) - 1);
01204 }
01205 }
01206 break;
01207
01208 default:
01209 DebugPrint("ccs_connecting: Unhandled subtype %d\n" _C_ msg->SubType);
01210 break;
01211
01212 }
01213 }
01214
01224 static bool IsSafeMapName(const char *mapname)
01225 {
01226 char buf[256];
01227 const char *ch;
01228
01229 if (strncpy_s(buf, sizeof(buf), mapname, sizeof(buf)) != 0) {
01230 return false;
01231 }
01232 if (strstr(buf, "..")) {
01233 return false;
01234 }
01235 if (strstr(buf, "//")) {
01236 return false;
01237 }
01238 if (buf[0] == '\0') {
01239 return false;
01240 }
01241 ch = buf;
01242 while (*ch != 0) {
01243 if (!isalnum(*ch) && *ch != '/' && *ch != '.' && *ch != '-' &&
01244 *ch != '(' && *ch != ')' && *ch != '_') {
01245 return false;
01246 }
01247 ch++;
01248 }
01249
01250 return true;
01251 }
01252
01258 static void ClientParseConnected(const CInitMessage *msg)
01259 {
01260 switch (msg->SubType) {
01261
01262 case ICMMap:
01263 {
01264 if (!IsSafeMapName(msg->u.MapPath)) {
01265 fprintf(stderr, "Unsecure map name!\n");
01266 NetLocalState = ccs_badmap;
01267 break;
01268 }
01269 NetworkMapName = std::string(msg->u.MapPath, sizeof(msg->u.MapPath));
01270 std::string mappath = StratagusLibPath + "/" + NetworkMapName;
01271 LoadStratagusMapInfo(mappath);
01272 if (ntohl(msg->MapUID) != Map.Info.MapUID) {
01273 NetLocalState = ccs_badmap;
01274 fprintf(stderr, "Maps do not match (0x%08x) <-> (0x%08x)\n",
01275 (unsigned int)Map.Info.MapUID,
01276 (unsigned int)ntohl(msg->MapUID));
01277 break;
01278 }
01279 NetLocalState = ccs_mapinfo;
01280 NetStateMsgCnt = 0;
01281 break;
01282 }
01283
01284 case ICMWelcome:
01285 break;
01286
01287 default:
01288 DebugPrint("ccs_connected: Unhandled subtype %d\n" _C_ msg->SubType);
01289 break;
01290 }
01291 }
01292
01298 static void ClientParseMapInfo(const CInitMessage *msg)
01299 {
01300 switch(msg->SubType) {
01301
01302 case ICMState:
01303 ServerSetupState = msg->u.State;
01304 NetLocalState = ccs_synced;
01305 NetStateMsgCnt = 0;
01306 break;
01307
01308 default:
01309 DebugPrint("ccs_mapinfo: Unhandled subtype %d\n" _C_ msg->SubType);
01310 break;
01311 }
01312 }
01313
01319 static void ClientParseSynced(const CInitMessage *msg)
01320 {
01321 int i;
01322
01323 switch(msg->SubType) {
01324
01325 case ICMState:
01326 DebugPrint("ccs_synced: ICMState recieved\n");
01327 ServerSetupState = msg->u.State;
01328 NetLocalState = ccs_async;
01329 NetStateMsgCnt = 0;
01330 break;
01331
01332 case ICMConfig:
01333 DebugPrint("ccs_synced: Config subtype %d received - starting\n" _C_ msg->SubType);
01334 HostsCount = 0;
01335 for (i = 0; i < msg->HostsCount - 1; ++i) {
01336 if (msg->u.Hosts[i].Host || msg->u.Hosts[i].Port) {
01337 Hosts[HostsCount].Host = msg->u.Hosts[i].Host;
01338 Hosts[HostsCount].Port = msg->u.Hosts[i].Port;
01339 Hosts[HostsCount].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
01340 memcpy(Hosts[HostsCount].PlyName, msg->u.Hosts[i].PlyName, sizeof(Hosts[HostsCount].PlyName) - 1);
01341 HostsCount++;
01342 DebugPrint("Client %d = %d.%d.%d.%d:%d [%s]\n" _C_
01343 ntohs(ntohs(msg->u.Hosts[i].PlyNr)) _C_ NIPQUAD(ntohl(msg->u.Hosts[i].Host)) _C_
01344 ntohs(msg->u.Hosts[i].Port) _C_ msg->u.Hosts[i].PlyName);
01345 } else {
01346 NetLocalPlayerNumber = ntohs(msg->u.Hosts[i].PlyNr);
01347 DebugPrint("SELF %d [%s]\n" _C_ ntohs(msg->u.Hosts[i].PlyNr) _C_
01348 msg->u.Hosts[i].PlyName);
01349 }
01350 }
01351
01352 Hosts[HostsCount].Host = NetLastHost;
01353 Hosts[HostsCount].Port = NetLastPort;
01354 Hosts[HostsCount].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
01355 memcpy(Hosts[HostsCount].PlyName, msg->u.Hosts[i].PlyName, sizeof(Hosts[HostsCount].PlyName) - 1);
01356 ++HostsCount;
01357 NetPlayers = HostsCount + 1;
01358 DebugPrint("Server %d = %d.%d.%d.%d:%d [%s]\n" _C_
01359 ntohs(msg->u.Hosts[i].PlyNr) _C_ NIPQUAD(ntohl(NetLastHost)) _C_
01360 ntohs(NetLastPort) _C_ msg->u.Hosts[i].PlyName);
01361
01362
01363 Hosts[HostsCount].Host = 0;
01364 Hosts[HostsCount].Port = 0;
01365 Hosts[HostsCount].PlyNr = NetLocalPlayerNumber;
01366 memcpy(Hosts[HostsCount].PlyName, LocalPlayerName.c_str(), sizeof(Hosts[HostsCount].PlyName) - 1);
01367
01368 NetLocalState = ccs_goahead;
01369 NetStateMsgCnt = 0;
01370 break;
01371
01372 default:
01373 DebugPrint("ccs_synced: Unhandled subtype %d\n" _C_ msg->SubType);
01374 break;
01375 }
01376 }
01377
01383 static void ClientParseAsync(const CInitMessage *msg)
01384 {
01385 int i;
01386
01387 switch(msg->SubType) {
01388
01389 case ICMResync:
01390 DebugPrint("ccs_async: ICMResync\n");
01391 for (i = 1; i < PlayerMax - 1; ++i) {
01392 if (i != NetLocalHostsSlot) {
01393 Hosts[i].Host = msg->u.Hosts[i].Host;
01394 Hosts[i].Port = msg->u.Hosts[i].Port;
01395 Hosts[i].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
01396 if (Hosts[i].PlyNr) {
01397 memcpy(Hosts[i].PlyName, msg->u.Hosts[i].PlyName, sizeof(Hosts[i].PlyName) - 1);
01398 }
01399 } else {
01400 Hosts[i].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
01401 memcpy(Hosts[i].PlyName, LocalPlayerName.c_str(), sizeof(Hosts[i].PlyName) - 1);
01402 }
01403 }
01404 NetLocalState = ccs_synced;
01405 NetStateMsgCnt = 0;
01406 break;
01407
01408 default:
01409 DebugPrint("ccs_async: Unhandled subtype %d\n" _C_ msg->SubType);
01410 break;
01411 }
01412 }
01413
01419 static void ClientParseGoAhead(const CInitMessage *msg)
01420 {
01421 switch(msg->SubType) {
01422
01423 case ICMConfig:
01424 break;
01425
01426 case ICMState:
01427 DebugPrint("ccs_goahead: Final State subtype %d received - starting\n" _C_ msg->SubType);
01428 ServerSetupState = msg->u.State;
01429 NetLocalState = ccs_started;
01430 NetStateMsgCnt = 0;
01431 break;
01432
01433 default:
01434 DebugPrint("ccs_goahead: Unhandled subtype %d\n" _C_ msg->SubType);
01435 break;
01436 }
01437 }
01438
01444 static void ClientParseStarted(const CInitMessage *msg)
01445 {
01446 switch(msg->SubType) {
01447
01448 case ICMGo:
01449 DebugPrint("ClientParseStarted ICMGo !!!!!\n");
01450 NetConnectRunning = 0;
01451 break;
01452
01453 default:
01454 DebugPrint("ccs_started: Unhandled subtype %d\n" _C_ msg->SubType);
01455 break;
01456 }
01457 }
01458
01464 static void ClientParseAreYouThere(const CInitMessage *msg)
01465 {
01466 CInitMessage message;
01467
01468 message.Type = MessageInitHello;
01469 message.SubType = ICMIAH;
01470 NetworkSendICMessage(NetworkServerIP, htons(NetworkServerPort), &message);
01471 }
01472
01478 static void ClientParseBadMap(const CInitMessage *msg)
01479 {
01480 int i;
01481 CInitMessage message;
01482
01483 message.Type = MessageInitHello;
01484 message.SubType = ICMSeeYou;
01485
01486 for (i = 0; i < 5; ++i) {
01487 NetworkSendICMessage(NetworkServerIP, htons(NetworkServerPort), &message);
01488 }
01489 NetConnectRunning = 0;
01490 }
01491
01492
01499 static void ServerParseHello(int h, const CInitMessage *msg)
01500 {
01501 int i, n;
01502 CInitMessage message;
01503
01504 if (h == -1) {
01505 for (i = 1; i < PlayerMax - 1; ++i) {
01506
01507 if (ServerSetupState.CompOpt[i] == 0) {
01508 if (Hosts[i].PlyNr == 0) {
01509 h = i;
01510 break;
01511 }
01512 }
01513 }
01514 if (h != -1) {
01515 Hosts[h].Host = NetLastHost;
01516 Hosts[h].Port = NetLastPort;
01517 Hosts[h].PlyNr = h;
01518 memcpy(Hosts[h].PlyName, msg->u.Hosts[0].PlyName, sizeof(Hosts[h].PlyName) - 1);
01519 DebugPrint("New client %d.%d.%d.%d:%d [%s]\n" _C_
01520 NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort) _C_ Hosts[h].PlyName);
01521 NetStates[h].State = ccs_connecting;
01522 NetStates[h].MsgCnt = 0;
01523 } else {
01524 message.Type = MessageInitReply;
01525 message.SubType = ICMGameFull;
01526 message.MapUID = 0L;
01527 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01528 DebugPrint("Sending InitReply Message GameFull: (%d) to %d.%d.%d.%d:%d\n" _C_
01529 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01530 return;
01531 }
01532 }
01533
01534 ServerSetupState.LastFrame[h] = FrameCounter;
01535 message.Type = MessageInitReply;
01536 message.SubType = ICMWelcome;
01537 message.u.Hosts[0].PlyNr = htons(h);
01538 memcpy(message.u.Hosts[0].PlyName, LocalPlayerName.c_str(), sizeof(message.u.Hosts[0].PlyName) - 1);
01539 message.MapUID = 0L;
01540 for (i = 1; i < PlayerMax - 1; ++i) {
01541 if (i != h) {
01542 if (Hosts[i].PlyNr) {
01543 message.u.Hosts[i].Host = Hosts[i].Host;
01544 message.u.Hosts[i].Port = Hosts[i].Port;
01545 message.u.Hosts[i].PlyNr = htons(Hosts[i].PlyNr);
01546 memcpy(message.u.Hosts[i].PlyName, Hosts[i].PlyName, sizeof(message.u.Hosts[i].PlyName) - 1);
01547 } else {
01548 message.u.Hosts[i].Host = 0;
01549 message.u.Hosts[i].Port = 0;
01550 message.u.Hosts[i].PlyNr = 0;
01551 }
01552 }
01553 }
01554 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01555 DebugPrint("Sending InitReply Message Welcome: (%d) [PlyNr: %d] to %d.%d.%d.%d:%d\n" _C_
01556 n _C_ h _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01557 NetStates[h].MsgCnt++;
01558 if (NetStates[h].MsgCnt > 48) {
01559
01560
01561 KickDeadClient(h);
01562 }
01563 }
01564
01570 static void ServerParseResync(const int h)
01571 {
01572 int i;
01573 int n;
01574 CInitMessage message;
01575
01576 ServerSetupState.LastFrame[h] = FrameCounter;
01577 switch (NetStates[h].State) {
01578 case ccs_mapinfo:
01579
01580 case ccs_async:
01581
01582 NetStates[h].State = ccs_synced;
01583 NetStates[h].MsgCnt = 0;
01584
01585 case ccs_synced:
01586
01587
01588 message.Type = MessageInitReply;
01589 message.SubType = ICMResync;
01590 for (i = 1; i < PlayerMax - 1; ++i) {
01591 if (i != h) {
01592 if (Hosts[i].PlyNr) {
01593 message.u.Hosts[i].Host = Hosts[i].Host;
01594 message.u.Hosts[i].Port = Hosts[i].Port;
01595 message.u.Hosts[i].PlyNr = htons(Hosts[i].PlyNr);
01596 memcpy(message.u.Hosts[i].PlyName, Hosts[i].PlyName, sizeof(message.u.Hosts[i].PlyName) - 1);
01597 } else {
01598 message.u.Hosts[i].Host = 0;
01599 message.u.Hosts[i].Port = 0;
01600 message.u.Hosts[i].PlyNr = 0;
01601 }
01602 }
01603 }
01604 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01605 DebugPrint("Sending InitReply Message Resync: (%d) to %d.%d.%d.%d:%d\n" _C_
01606 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01607 NetStates[h].MsgCnt++;
01608 if (NetStates[h].MsgCnt > 50) {
01609
01610 ;
01611 }
01612 break;
01613
01614 default:
01615 DebugPrint("Server: ICMResync: Unhandled state %d Host %d\n" _C_
01616 NetStates[h].State _C_ h);
01617 break;
01618 }
01619 }
01620
01621
01627 static void ServerParseWaiting(const int h)
01628 {
01629 int i;
01630 int n;
01631 CInitMessage message;
01632
01633 ServerSetupState.LastFrame[h] = FrameCounter;
01634
01635 switch (NetStates[h].State) {
01636
01637 case ccs_connecting:
01638 NetStates[h].State = ccs_connected;
01639 NetStates[h].MsgCnt = 0;
01640
01641 case ccs_connected:
01642
01643 message.Type = MessageInitReply;
01644 message.SubType = ICMMap;
01645 strncpy_s(message.u.MapPath, sizeof(message.u.MapPath), NetworkMapName.c_str(), NetworkMapName.size());
01646 message.MapUID = htonl(Map.Info.MapUID);
01647 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01648 DebugPrint("Sending InitReply Message Map: (%d) to %d.%d.%d.%d:%d\n" _C_
01649 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01650 NetStates[h].MsgCnt++;
01651 if (NetStates[h].MsgCnt > 50) {
01652
01653 ;
01654 }
01655 break;
01656 case ccs_mapinfo:
01657 NetStates[h].State = ccs_synced;
01658 NetStates[h].MsgCnt = 0;
01659 for (i = 1; i < PlayerMax - 1; ++i) {
01660 if (i != h && Hosts[i].PlyNr) {
01661
01662 NetStates[i].State = ccs_async;
01663 }
01664 }
01665
01666 case ccs_synced:
01667
01668 NetStates[h].MsgCnt = 0;
01669 break;
01670
01671 case ccs_async:
01672
01673
01674
01675
01676
01677 message.Type = MessageInitReply;
01678 message.SubType = ICMState;
01679 message.u.State = ServerSetupState;
01680 message.MapUID = htonl(Map.Info.MapUID);
01681 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01682 DebugPrint("Sending InitReply Message State: (%d) to %d.%d.%d.%d:%d\n" _C_
01683 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01684 NetStates[h].MsgCnt++;
01685 if (NetStates[h].MsgCnt > 50) {
01686
01687 ;
01688 }
01689 break;
01690
01691 default:
01692 DebugPrint("Server: ICMWaiting: Unhandled state %d Host %d\n" _C_
01693 NetStates[h].State _C_ h);
01694 break;
01695 }
01696 }
01697
01703 static void ServerParseMap(const int h)
01704 {
01705 int n;
01706 CInitMessage message;
01707
01708 ServerSetupState.LastFrame[h] = FrameCounter;
01709 switch (NetStates[h].State) {
01710
01711 case ccs_connected:
01712 NetStates[h].State = ccs_mapinfo;
01713 NetStates[h].MsgCnt = 0;
01714
01715 case ccs_mapinfo:
01716
01717
01718 message.Type = MessageInitReply;
01719 message.SubType = ICMState;
01720 message.u.State = ServerSetupState;
01721 message.MapUID = htonl(Map.Info.MapUID);
01722 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01723 DebugPrint("Sending InitReply Message State: (%d) to %d.%d.%d.%d:%d\n" _C_
01724 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01725 NetStates[h].MsgCnt++;
01726 if (NetStates[h].MsgCnt > 50) {
01727
01728 ;
01729 }
01730 break;
01731 default:
01732 DebugPrint("Server: ICMMap: Unhandled state %d Host %d\n" _C_
01733 NetStates[h].State _C_ h);
01734 break;
01735 }
01736 }
01737
01744 static void ServerParseState(const int h, const CInitMessage *msg)
01745 {
01746 int i;
01747 int n;
01748 CInitMessage message;
01749
01750 ServerSetupState.LastFrame[h] = FrameCounter;
01751 switch (NetStates[h].State) {
01752 case ccs_mapinfo:
01753
01754
01755 case ccs_synced:
01756
01757
01758 NetStates[h].MsgCnt = 0;
01759
01760 ServerSetupState.Ready[h] = msg->u.State.Ready[h];
01761
01762
01763
01764 for (i = 1; i < PlayerMax - 1; ++i) {
01765 if (Hosts[i].PlyNr) {
01766 NetStates[i].State = ccs_async;
01767 }
01768 }
01769
01770 case ccs_async:
01771
01772
01773 message.Type = MessageInitReply;
01774 message.SubType = ICMState;
01775 message.u.State = ServerSetupState;
01776 message.MapUID = htonl(Map.Info.MapUID);
01777 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01778 DebugPrint("Sending InitReply Message State: (%d) to %d.%d.%d.%d:%d\n" _C_
01779 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01780 NetStates[h].MsgCnt++;
01781 if (NetStates[h].MsgCnt > 50) {
01782
01783 ;
01784 }
01785 break;
01786 default:
01787 DebugPrint("Server: ICMState: Unhandled state %d Host %d\n" _C_
01788 NetStates[h].State _C_ h);
01789 break;
01790 }
01791 }
01792
01798 static void ServerParseGoodBye(const int h)
01799 {
01800 int n;
01801 CInitMessage message;
01802
01803 ServerSetupState.LastFrame[h] = FrameCounter;
01804 switch (NetStates[h].State) {
01805 default:
01806
01807 NetStates[h].MsgCnt = 0;
01808 NetStates[h].State = ccs_detaching;
01809
01810 case ccs_detaching:
01811
01812
01813 message.Type = MessageInitReply;
01814 message.SubType = ICMGoodBye;
01815 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01816 DebugPrint("Sending InitReply Message GoodBye: (%d) to %d.%d.%d.%d:%d\n" _C_
01817 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01818 NetStates[h].MsgCnt++;
01819 if (NetStates[h].MsgCnt > 10) {
01820
01821 ;
01822 }
01823 break;
01824 }
01825 }
01826
01832 static void ServerParseSeeYou(const int h)
01833 {
01834 switch (NetStates[h].State) {
01835 case ccs_detaching:
01836 KickDeadClient(h);
01837 break;
01838
01839 default:
01840 DebugPrint("Server: ICMSeeYou: Unhandled state %d Host %d\n" _C_
01841 NetStates[h].State _C_ h);
01842 break;
01843 }
01844 }
01845
01851 static void ServerParseIAmHere(const int h)
01852 {
01853
01854 ServerSetupState.LastFrame[h] = FrameCounter;
01855 }
01856
01864 static int CheckVersions(const CInitMessage *msg)
01865 {
01866 int n;
01867 CInitMessage message;
01868
01869 if (ntohl(msg->Stratagus) != StratagusVersion) {
01870 fprintf(stderr, "Incompatible Bos Wars version "
01871 StratagusFormatString " <-> "
01872 StratagusFormatString "\n"
01873 "from %d.%d.%d.%d:%d\n",
01874 StratagusFormatArgs((int)ntohl(msg->Stratagus)),
01875 StratagusFormatArgs(StratagusVersion),
01876 NIPQUAD(ntohl(NetLastHost)),ntohs(NetLastPort));
01877
01878 message.Type = MessageInitReply;
01879 message.SubType = ICMEngineMismatch;
01880 message.MapUID = 0L;
01881 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01882 DebugPrint("Sending InitReply Message EngineMismatch: (%d) to %d.%d.%d.%d:%d\n" _C_
01883 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01884 return -1;
01885 }
01886
01887 if (ntohl(msg->Version) != NetworkProtocolVersion) {
01888 fprintf(stderr, "Incompatible network protocol version "
01889 NetworkProtocolFormatString " <-> "
01890 NetworkProtocolFormatString "\n"
01891 "from %d.%d.%d.%d:%d\n",
01892 NetworkProtocolFormatArgs((int)ntohl(msg->Version)),
01893 NetworkProtocolFormatArgs(NetworkProtocolVersion),
01894 NIPQUAD(ntohl(NetLastHost)),ntohs(NetLastPort));
01895
01896 message.Type = MessageInitReply;
01897 message.SubType = ICMProtocolMismatch;
01898 message.MapUID = 0L;
01899 n = NetworkSendICMessage(NetLastHost, NetLastPort, &message);
01900 DebugPrint("Sending InitReply Message ProtocolMismatch: (%d) to %d.%d.%d.%d:%d\n" _C_
01901 n _C_ NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
01902 return -1;
01903 }
01904
01905 return 0;
01906 }
01907
01913 static void NetworkParseMenuPacket(const CInitMessage *msg)
01914 {
01915 DebugPrint("Received %s Init Message %d:%d from %d.%d.%d.%d:%d (%ld)\n" _C_
01916 icmsgsubtypenames[msg->SubType] _C_ msg->Type _C_ msg->SubType _C_ NIPQUAD(ntohl(NetLastHost)) _C_
01917 ntohs(NetLastPort) _C_ FrameCounter);
01918
01919 if (NetConnectRunning == 2) {
01920 if (msg->Type == MessageInitReply) {
01921 if (msg->SubType == ICMServerQuit) {
01922 NetLocalState = ccs_serverquits;
01923 NetConnectRunning = 0;
01924
01925 return;
01926 }
01927 if (msg->SubType == ICMAYT) {
01928 ClientParseAreYouThere(msg);
01929 return;
01930 }
01931 switch(NetLocalState) {
01932 case ccs_disconnected:
01933 #ifdef DEBUG
01934 ClientParseDisconnected(msg);
01935 #endif
01936 break;
01937
01938 case ccs_detaching:
01939 ClientParseDetaching(msg);
01940 break;
01941
01942 case ccs_connecting:
01943 ClientParseConnecting(msg);
01944 break;
01945
01946 case ccs_connected:
01947 ClientParseConnected(msg);
01948 break;
01949
01950 case ccs_mapinfo:
01951 ClientParseMapInfo(msg);
01952 break;
01953
01954 case ccs_changed:
01955 case ccs_synced:
01956 ClientParseSynced(msg);
01957 break;
01958
01959 case ccs_async:
01960 ClientParseAsync(msg);
01961 break;
01962
01963 case ccs_goahead:
01964 ClientParseGoAhead(msg);
01965 break;
01966
01967 case ccs_badmap:
01968 ClientParseBadMap(msg);
01969 break;
01970
01971 case ccs_started:
01972 ClientParseStarted(msg);
01973 break;
01974
01975 default:
01976 DebugPrint("Client: Unhandled state %d\n" _C_ NetLocalState);
01977 break;
01978 }
01979 }
01980
01981 } else if (NetConnectRunning == 1) {
01982 int i;
01983
01984 if (CheckVersions(msg)) {
01985 return;
01986 }
01987
01988
01989 for (i = 0; i < PlayerMax - 1; ++i) {
01990 if (Hosts[i].Host == NetLastHost && Hosts[i].Port == NetLastPort) {
01991 switch(msg->SubType) {
01992 case ICMHello:
01993 ServerParseHello(i, msg);
01994 break;
01995
01996 case ICMResync:
01997 ServerParseResync(i);
01998 break;
01999
02000 case ICMWaiting:
02001 ServerParseWaiting(i);
02002 break;
02003
02004 case ICMMap:
02005 ServerParseMap(i);
02006 break;
02007
02008 case ICMState:
02009 ServerParseState(i, msg);
02010 break;
02011
02012 case ICMMapUidMismatch:
02013 case ICMGoodBye:
02014 ServerParseGoodBye(i);
02015 break;
02016
02017 case ICMSeeYou:
02018 ServerParseSeeYou(i);
02019 break;
02020
02021 case ICMIAH:
02022 ServerParseIAmHere(i);
02023 break;
02024
02025 default:
02026 DebugPrint("Server: Unhandled subtype %d from host %d\n" _C_ msg->SubType _C_ i);
02027 break;
02028 }
02029 break;
02030 }
02031 }
02032 if (i == PlayerMax - 1 && msg->SubType == ICMHello) {
02033
02034 ServerParseHello(-1, msg);
02035 }
02036 }
02037 }
02038
02047 int NetworkParseSetupEvent(const unsigned char *buf, int size)
02048 {
02049 CInitMessage msg;
02050
02051 if (size != (int)CInitMessage::Size()) {
02052
02053 if (NetConnectRunning == 2 && NetLocalState == ccs_started) {
02054
02055
02056
02057 NetConnectRunning = 0;
02058 }
02059 return 0;
02060 }
02061
02062 msg.Deserialize(buf);
02063 if (msg.Type > MessageInitConfig) {
02064 if (NetConnectRunning == 2 && NetLocalState == ccs_started) {
02065
02066
02067
02068 NetConnectRunning = 0;
02069 }
02070 return 0;
02071 }
02072
02073 if (InterfaceState == IfaceStateMenu) {
02074 NetworkParseMenuPacket(&msg);
02075 return 1;
02076 }
02077 return 0;
02078 }
02079
02080
02081