hostile-takeover/game/xtransport.cpp
Nathan Fulton d6b301c3e7 Track client platform version
Client platform version can be retrieved live with /ids and is also
recorded in the playerdetail module.
2016-08-31 23:54:48 -04:00

970 lines
25 KiB
C++

#include "base/log.h"
#include "base/thread.h"
#include "game/xtransport.h"
#include "game/serviceurls.h"
#include "game/chooseserverform.h"
#include "mpshared/xpump.h"
#include "mpshared/mpht.h"
namespace wi {
//---------------------------------------------------------------------------
// XTransport implementation
XTransport::XTransport(const base::SocketAddress& address) : Transport(),
address_(address), state_(XTS_CLOSED),
waiting_(false),
error_(false), id_(0), roomidCreate_(0), gameidCreate_(0),
resultLogin_(knLoginResultFail),
resultSignOut_(knSignOutResultSuccess),
resultLobbyJoin_(knLobbyJoinResultFail),
resultRoomJoin_(knRoomJoinResultFail),
resultRoomCreate_(knLobbyCreateRoomResultFail),
resultGameJoin_(knGameJoinResultFail),
resultGameCreate_(knRoomCreateGameResultFail) {
}
XTransport::~XTransport() {
}
int XTransport::GetTransportDescriptions(TransportDescription *atrad,
int ctradMax) {
// This transport is opened directly, currently
#if 0
TransportDescription *ptrad = atrad;
ptrad->trat = ktratX;
strcpy(ptrad->szName, "Connection");
ptrad->pfnOpen = XTransport::Open;
ptrad->dwTransportSpecific = 0;
return 1;
#else
return 0;
#endif
}
dword XTransport::Open(TransportDescription *ptrad, Transport **pptra) {
// This transport is opened directly, currently
#if 0
Transport *ptra = new XTransport(ptrad->dwTransportSpecific);
if (ptra == NULL) {
return knTransportOpenResultFail;
}
dword result = ptra->Open();
if (result == knTransportOpenResultSuccess) {
*pptra = ptra;
return result;
}
delete ptra;
return result;
#else
return knTransportOpenResultFail;
#endif
}
void XTransport::SetState(State state) {
LOG() << "From: " << XtsLabels.Find(state_)
<< " To: " << XtsLabels.Find(state);
state_ = state;
// If waiting for a state change, wake up
if (waiting_) {
base::Thread::current().Post(base::kidmNullEvent, NULL);
}
}
bool XTransport::CheckState(State state0, State state1) {
Assert(state0 == state_ || state1 == state_);
if (state0 != state_ && state1 != state_) {
LOG() << "Error! Current: " << XtsLabels.Find(state_);
if (state1 == XTS_INVALID) {
LOG() << " Expected: " << XtsLabels.Find(state0);
} else {
LOG() << " Expected: " << XtsLabels.Find(state0)
<< " or " << XtsLabels.Find(state1);
}
return false;
}
return true;
}
dword XTransport::Open() {
// The caller of Transport::Open expects a synchronous Open,
// yet the connect and handshake need to stay responsive to UI
// needs (like exit application, and timeout).
error_ = false;
base::Socket *sock = base::Thread::current().ss().CreateSocket(SOCK_STREAM,
this);
if (sock == NULL) {
LOG() << "CreateSocket() failed";
return knTransportOpenResultNoNetwork;
}
// Synchronous Connect to the server! There is "connecting..." UI
// showing during this.
if (sock->Connect(address_) < 0) {
if (error_ || !sock->IsBlocking()) {
LOG() << "Connect() failed";
delete sock;
return knTransportOpenResultCantConnect;
}
}
SetState(XTS_CONNECTING);
// Wait for the connect to occur with a modal loop that dispatches
// nothing. If there is no connect after the timeout, assume error.
LOG() << "Waiting to connect to " << address_.ToString();
if (!WaitForStateChange()) {
LOG() << "Timed out waiting for connect";
}
if (state_ != XTS_CONNECTED) {
LOG() << "Could not connect, closing socket";
delete sock;
SetState(XTS_CLOSED);
return knTransportOpenResultNotResponding;
}
// From here on, the socket is owned by xpump.
xpump_.Attach(sock, this);
// Now send a handshake message, and await a reply before
// returning
if (!Handshake() || error_) {
LOG() << "Handshake error";
xpump_.Close();
SetState(XTS_CLOSED);
return knTransportOpenResultCantConnect;
}
// Await a proper reply.
LOG() << "Waiting for handshake reply";
if (!WaitForStateChange()) {
LOG() << "Timed out Waiting for handshake reply";
xpump_.Close();
SetState(XTS_CLOSED);
return knTransportOpenResultNotResponding;
}
if (state_ == XTS_HANDSHAKEERROR) {
LOG() << "Received handshake error";
xpump_.Close();
SetState(XTS_CLOSED);
return knTransportOpenResultProtocolMismatch;
}
if (state_ == XTS_HANDSHAKESERVERFULL) {
LOG() << "Received handshake server full.";
xpump_.Close();
SetState(XTS_CLOSED);
return knTransportOpenResultServerFull;
}
// Now in opened state
SetState(XTS_OPEN);
LOG() << "XTransport successfully opened!";
return knTransportOpenResultSuccess;
}
void XTransport::Close() {
SetState(XTS_CLOSED);
xpump_.Close();
}
bool XTransport::IsClosed() {
return state_ == XTS_CLOSED;
}
bool XTransport::WaitForStateChange(long ctWait) {
waiting_ = true;
gtimm.Enable(false);
long t = HostGetTickCount();
int state = state_;
while (state == state_) {
if (error_) {
return false;
}
if (HostGetTickCount() - t >= ctWait) {
gtimm.Enable(true);
waiting_ = false;
return false;
}
Event evt;
if (gevm.GetEvent(&evt, 50, false)) {
if (gevm.IsAppStopping()) {
gtimm.Enable(true);
waiting_ = false;
return false;
}
}
OnEvent(&evt);
}
gtimm.Enable(true);
waiting_ = false;
return true;
}
bool XTransport::Handshake() {
if (!CheckState(XTS_CONNECTED)) {
return false;
}
xpump_.Send(XMsgHandshake::ToBuffer(kdwClientID, kdwProtocolCurrent));
SetState(XTS_HANDSHAKING);
return true;
}
void XTransport::OnHandshakeResult(dword result, dword id) {
LOG() << HandshakeResults.Find(result);
if (!CheckState(XTS_HANDSHAKING)) {
return;
}
// These should be results not states, but not changing now...
switch (result) {
case knHandshakeResultSuccess:
id_ = id;
SetState(XTS_HANDSHAKESUCCESS);
return;
case knHandshakeResultServerFull:
SetState(XTS_HANDSHAKESERVERFULL);
return;
default:
SetState(XTS_HANDSHAKEERROR);
return;
}
}
void XTransport::OnShowMessage(const char *message, dword ipRedirect,
bool disconnect) {
if (error_ || xpump_.IsClosed()) {
return;
}
// The server is asking to show a message. This is allowed during
// any state.
// TODO: show message
// TODO: handle ipRedirect, disconnect
if (m_ptcb != NULL) {
if (strlen(message) != 0) {
m_ptcb->OnShowMessage(message);
}
}
}
void XTransport::OnEcho() {
xpump_.Send(XMsgEcho::ToBuffer());
}
dword XTransport::Login(const char *username, const char *token) {
LOG() << "Logging in...";
if (error_ || xpump_.IsClosed()) {
return knLoginResultFail;
}
if (!CheckState(XTS_OPEN)) {
return knLoginResultFail;
}
// Login and wait synchronously for reply.
SetState(XTS_LOGGINGIN);
xpump_.Send(XMsgLogin::ToBuffer(username, token, gszDeviceId, HostGetPlatformString()));
if (!WaitForStateChange()) {
LOG() << "Timed out waiting for Login";
resultLogin_ = knLoginResultFail;
}
if (state_ != XTS_LOGGEDIN) {
LOG() << LoginResults.Find(resultLogin_);
SetState(XTS_OPEN);
return resultLogin_;
}
// Login successful. Keep state XTS_LOGGEDIN.
return resultLogin_;
}
void XTransport::OnLoginResult(dword resultLogin) {
LOG() << LoginResults.Find(resultLogin);
if (!CheckState(XTS_LOGGINGIN)) {
resultLogin_ = knLoginResultFail;
return;
}
if (error_ || xpump_.IsClosed()) {
resultLogin_ = knLoginResultFail;
return;
}
resultLogin_ = resultLogin;
if (resultLogin_ != knLoginResultSuccess &&
resultLogin_ != knLoginResultAnonymousSuccess) {
SetState(XTS_LOGINFAILED);
return;
}
SetState(XTS_LOGGEDIN);
}
dword XTransport::SignOut() {
LOG() << "Signing Out...";
if (error_ || xpump_.IsClosed()) {
return knSignOutResultFail;
}
// Only know how to do this from XTS_LOGGEDIN state, currently.
if (!CheckState(XTS_LOGGEDIN)) {
return knSignOutResultFail;
}
// Sign out and wait synchronously for reply.
SetState(XTS_SIGNINGOUT);
xpump_.Send(XMsgSignOut::ToBuffer());
if (!WaitForStateChange()) {
LOG() << "Timed out waiting for sign out";
resultSignOut_ = knSignOutResultFail;
}
if (state_ != XTS_SIGNEDOUT) {
LOG() << SignOutResults.Find(resultSignOut_);
SetState(XTS_LOGGEDIN);
return resultSignOut_;
}
// Sign Out successful.
SetState(XTS_OPEN);
return resultSignOut_;
}
void XTransport::OnSignOutResult(dword result) {
LOG() << SignOutResults.Find(result);
if (!CheckState(XTS_SIGNINGOUT)) {
resultSignOut_ = knSignOutResultFail;
return;
}
if (error_ || xpump_.IsClosed()) {
resultSignOut_ = knSignOutResultFail;
return;
}
resultSignOut_ = result;
if (resultSignOut_ != knSignOutResultSuccess) {
SetState(XTS_SIGNOUTFAILED);
return;
}
SetState(XTS_SIGNEDOUT);
}
const char *XTransport::GetAnonymousUsername() {
return base::Format::ToString("anon%d", id_);
}
dword XTransport::JoinLobby(ILobbyCallback *plcb) {
if (error_ || xpump_.IsClosed()) {
return knLobbyJoinResultFail;
}
if (!CheckState(XTS_LOGGEDIN)) {
return knLobbyJoinResultFail;
}
xpump_.Send(XMsgLobbyJoin::ToBuffer());
SetState(XTS_JOINLOBBY);
LOG() << "Waiting for LobbyJoinResult";
if (!WaitForStateChange()) {
LOG() << "Timed out waiting for LobbyJoinResult";
}
if (state_ != XTS_JOINLOBBYSUCCESS) {
LOG() << "Could not enter lobby reason: "
<< LobbyJoinResults.Find(resultLobbyJoin_);
SetState(XTS_LOGGEDIN);
return resultLobbyJoin_;
}
SetState(XTS_LOBBY);
m_plcb = plcb;
return resultLobbyJoin_;
}
void XTransport::OnLobbyJoinResult(dword result) {
LOG() << LobbyJoinResults.Find(result);
if (error_ || xpump_.IsClosed()) {
return;
}
if (!CheckState(XTS_JOINLOBBY)) {
return;
}
resultLobbyJoin_ = result;
if (result == knLobbyJoinResultSuccess) {
SetState(XTS_JOINLOBBYSUCCESS);
return;
}
SetState(XTS_JOINLOBBYFAILED);
}
void XTransport::OnLobbyAddRoom(const char *room, dword roomid, bool priv,
dword cPlayers, dword cGames) {
if (m_plcb != NULL) {
m_plcb->OnAddRoom(room, roomid, priv, cPlayers, cGames);
}
}
void XTransport::OnLobbyRemoveRoom(dword roomid) {
if (m_plcb != NULL) {
m_plcb->OnRemoveRoom(roomid);
}
}
void XTransport::OnLobbyUpdateRoom(dword roomid, dword cPlayers, dword cGames) {
if (m_plcb != NULL) {
m_plcb->OnUpdateRoom(roomid, cPlayers, cGames);
}
}
bool XTransport::LeaveLobby() {
m_plcb = NULL;
if (error_ || xpump_.IsClosed()) {
return false;
}
if (!CheckState(XTS_LOBBY)) {
return false;
}
xpump_.Send(XMsgLobbyLeave::ToBuffer());
SetState(XTS_LOGGEDIN);
return true;
}
void XTransport::OnLobbyLeaveResult(dword result) {
}
dword XTransport::CreateRoom(const char *roomname, const char *password,
dword *roomid) {
LOG() << base::Format::ToString("CreateRoom: %s %s", roomname, password);
if (error_ || xpump_.IsClosed()) {
return knLobbyCreateRoomResultFail;
}
if (!CheckState(XTS_LOBBY)) {
return knLobbyCreateRoomResultFail;
}
SetState(XTS_CREATINGROOM);
xpump_.Send(XMsgLobbyCreateRoom::ToBuffer(roomname, password));
// Wait for reply
if (!WaitForStateChange()) {
LOG() << "Timed out waiting room create";
resultRoomCreate_ = knLobbyCreateRoomResultFail;
}
if (state_ != XTS_CREATEROOMSUCCESS) {
LOG() << LobbyCreateRoomResults.Find(resultRoomCreate_);
SetState(XTS_LOBBY);
return resultRoomCreate_;
}
*roomid = roomidCreate_;
SetState(XTS_LOBBY);
return resultRoomCreate_;
}
void XTransport::OnLobbyCreateRoomResult(dword result, dword roomid) {
LOG() << LobbyCreateRoomResults.Find(result);
if (!CheckState(XTS_CREATINGROOM)) {
resultRoomCreate_ = knLobbyCreateRoomResultFail;
return;
}
if (error_ || xpump_.IsClosed()) {
resultRoomCreate_ = knLobbyCreateRoomResultFail;
return;
}
resultRoomCreate_ = result;
roomidCreate_ = roomid;
if (resultRoomCreate_ != knLobbyCreateRoomResultSuccess) {
SetState(XTS_CREATEROOMERROR);
return;
}
SetState(XTS_CREATEROOMSUCCESS);
}
dword XTransport::CanJoinRoom(dword roomid, const char *password) {
if (error_ || xpump_.IsClosed()) {
return knRoomJoinResultFail;
}
if (!CheckState(XTS_LOBBY)) {
return knRoomJoinResultFail;
}
SetState(XTS_CANJOINROOM);
xpump_.Send(XMsgLobbyCanJoinRoom::ToBuffer(roomid, password));
// Wait for the reply
if (!WaitForStateChange()) {
LOG() << "Timed out can wait joining room";
resultRoomJoin_ = knRoomJoinResultFail;
}
SetState(XTS_LOBBY);
return resultRoomJoin_;
}
void XTransport::OnLobbyCanJoinRoomResult(dword result) {
if (!CheckState(XTS_CANJOINROOM)) {
return;
}
resultRoomJoin_ = result;
SetState(XTS_LOBBY);
}
void XTransport::OnLobbyLurkerCount(dword count) {
if (m_plcb != NULL) {
m_plcb->OnLurkerCount(count);
}
}
void XTransport::OnLobbyReceiveChat(const char *player, const char *chat) {
if (m_plcb != NULL) {
m_plcb->OnReceiveChat(player, chat);
}
}
dword XTransport::JoinRoom(dword roomid, const char *password,
IRoomCallback *prcb) {
// Synchronously join a room. It may fail.
if (error_ || xpump_.IsClosed()) {
return knRoomJoinResultFail;
}
if (!CheckState(XTS_LOGGEDIN)) {
return knRoomJoinResultFail;
}
SetState(XTS_JOININGROOM);
xpump_.Send(XMsgRoomJoin::ToBuffer(roomid, password));
// Wait for the reply
if (!WaitForStateChange()) {
LOG() << "Timed out waiting room join";
resultRoomJoin_ = knRoomJoinResultFail;
}
if (state_ != XTS_JOINROOMSUCCESS) {
LOG() << RoomJoinResults.Find(resultRoomJoin_);
SetState(XTS_LOGGEDIN);
return resultRoomJoin_;
}
// Entering a new room; clear the games being tracked
m_prcb = prcb;
SetState(XTS_ROOM);
return resultRoomJoin_;
}
void XTransport::OnRoomJoinResult(dword result) {
LOG() << RoomJoinResults.Find(result);
if (!CheckState(XTS_JOININGROOM)) {
resultRoomJoin_ = knRoomJoinResultFail;
return;
}
if (error_ || xpump_.IsClosed()) {
resultRoomJoin_ = knRoomJoinResultFail;
return;
}
resultRoomJoin_ = result;
if (resultRoomJoin_ != knRoomJoinResultSuccess) {
SetState(XTS_JOINROOMERROR);
return;
}
SetState(XTS_JOINROOMSUCCESS);
}
void XTransport::OnRoomAddPlayer(const char *player) {
if (m_prcb != NULL) {
m_prcb->OnAddPlayer(player);
}
}
void XTransport::OnRoomRemovePlayer(dword hint, const char *player) {
if (m_prcb != NULL) {
m_prcb->OnRemovePlayer(hint, player);
}
}
bool XTransport::SendChat(const char *chat) {
if (error_ || xpump_.IsClosed()) {
return false;
}
if (state_ == XTS_ROOM) {
xpump_.Send(XMsgRoomSendChat::ToBuffer(chat));
return true;
}
if (state_ == XTS_GAME) {
xpump_.Send(XMsgGameSendChat::ToBuffer(chat));
return true;
}
Assert();
return false;
}
void XTransport::OnRoomReceiveChat(const char *player, const char *chat) {
if (m_prcb != NULL) {
m_prcb->OnReceiveChat(player, chat);
}
}
void XTransport::OnRoomAddGame(const char *player, dword gameid,
const GameParams& params, dword minplayers, dword maxplayers,
const char *title, dword ctotal) {
if (m_prcb != NULL) {
m_prcb->OnAddGame(player, gameid, params, minplayers, maxplayers,
title, ctotal);
}
}
void XTransport::OnRoomRemoveGame(dword gameid, dword ctotal) {
if (m_prcb != NULL) {
m_prcb->OnRemoveGame(gameid, ctotal);
}
}
void XTransport::OnRoomGameInProgress(dword gameid) {
if (m_prcb != NULL) {
m_prcb->OnGameInProgress(gameid);
}
}
void XTransport::OnRoomGamePlayerNames(dword gameid, dword cnames,
const PlayerName *anames) {
if (m_prcb != NULL) {
m_prcb->OnGamePlayerNames(gameid, cnames, anames);
}
}
void XTransport::OnRoomStatusComplete() {
if (m_prcb != NULL) {
m_prcb->OnStatusComplete();
}
}
dword XTransport::CanJoinGame(dword gameid) {
if (error_ || xpump_.IsClosed()) {
return knRoomJoinResultFail;
}
if (!CheckState(XTS_ROOM)) {
return knGameJoinResultFail;
}
SetState(XTS_CANJOINGAME);
xpump_.Send(XMsgRoomCanJoinGame::ToBuffer(gameid));
// Wait for the reply
if (!WaitForStateChange()) {
LOG() << "Timed out can wait joining game";
resultGameJoin_ = knGameJoinResultFail;
}
SetState(XTS_ROOM);
return resultRoomJoin_;
}
void XTransport::OnRoomCanJoinGameResult(dword result) {
if (!CheckState(XTS_CANJOINGAME)) {
return;
}
resultGameJoin_ = result;
SetState(XTS_ROOM);
}
void XTransport::SetGameCountStatus(dword ctotal) {
if (m_ptcb != NULL) {
char szT[64];
if (ctotal == 1) {
sprintf(szT, "%d game.", (int)ctotal);
} else {
sprintf(szT, "%d games.", (int)ctotal);
}
m_ptcb->OnStatusUpdate(szT);
}
}
dword XTransport::CreateGame(GameParams *params, PackId *ppackidUpgrade,
dword *gameid) {
if (error_ || xpump_.IsClosed()) {
LOG() << "Error or closed";
return knRoomCreateGameResultFail;
}
if (!CheckState(XTS_ROOM)) {
return knRoomCreateGameResultFail;
}
xpump_.Send(XMsgRoomCreateGame::ToBuffer(params));
// Wait synchronously for the result, since the UI needs it.
SetState(XTS_CREATINGGAME);
if (!WaitForStateChange()) {
LOG() << "timed out waiting for XMsgRoomCreateGameResult";
SetState(XTS_ROOM);
return knRoomCreateGameResultFail;
}
if (!CheckState(XTS_CREATEGAMEERROR, XTS_CREATEGAMESUCCESS)) {
// Don't know what state it is, so don't state transition
LOG() << "expected CREATEGAMESUCCESS or ERROR state";
return knRoomCreateGameResultFail;
}
if (state_ == XTS_CREATEGAMEERROR) {
*ppackidUpgrade = packidCreate_;
SetState(XTS_ROOM);
return resultGameCreate_;
}
SetState(XTS_ROOM);
*gameid = gameidCreate_;
return resultGameCreate_;
}
void XTransport::OnRoomCreateGameResult(dword gameid, dword result,
const PackId *ppackid) {
LOG() << CreateGameResults.Find(result);
if (!CheckState(XTS_CREATINGGAME)) {
resultGameCreate_ = knRoomCreateGameResultFail;
return;
}
if (error_ || xpump_.IsClosed()) {
resultGameCreate_ = knRoomCreateGameResultFail;
return;
}
// Remember these for later
resultGameCreate_ = result;
packidCreate_ = *ppackid;
gameidCreate_ = gameid;
if (result != knRoomCreateGameResultSuccess) {
SetState(XTS_CREATEGAMEERROR);
return;
}
SetState(XTS_CREATEGAMESUCCESS);
}
void XTransport::LeaveRoom(dword hint) {
m_prcb = NULL;
if (error_ || xpump_.IsClosed()) {
return;
}
if (!CheckState(XTS_ROOM)) {
return;
}
SetState(XTS_LEAVINGROOM);
xpump_.Send(XMsgRoomLeave::ToBuffer(hint));
WaitForStateChange();
SetState(XTS_LOGGEDIN);
}
void XTransport::OnRoomLeaveResult() {
if (error_ || xpump_.IsClosed()) {
return;
}
if (!CheckState(XTS_LEAVINGROOM)) {
return;
}
SetState(XTS_LOGGEDIN);
}
dword XTransport::JoinGame(dword gameid, dword roomid) {
if (error_ || xpump_.IsClosed()) {
LOG() << "Error or closed";
return knGameJoinResultFail;
}
// Must be in XTS_LOGGEDIN state, not in room, lobby, or game.
if (!CheckState(XTS_LOGGEDIN)) {
return knGameJoinResultFail;
}
// Wait synchronously for the result
SetState(XTS_JOININGGAME);
xpump_.Send(XMsgGameJoin::ToBuffer(gameid, roomid));
if (!WaitForStateChange()) {
LOG() << "timed out waiting for XMsgGameJoinResult";
SetState(XTS_LOGGEDIN);
return knGameJoinResultFail;
}
if (!CheckState(XTS_JOINGAMEERROR, XTS_JOINGAMESUCCESS)) {
// Don't know what state it is, so don't state transition
LOG() << "expected JOINGAMESUCCESS or ERROR state";
return knGameJoinResultFail;
}
if (state_ == XTS_JOINGAMEERROR) {
SetState(XTS_LOGGEDIN);
return resultGameJoin_;
}
SetState(XTS_GAME);
return resultGameJoin_;
}
void XTransport::OnGameJoinResult(dword result) {
LOG() << GameJoinResults.Find(result);
if (!CheckState(XTS_JOININGGAME)) {
return;
}
if (error_ || xpump_.IsClosed()) {
resultGameJoin_ = knGameJoinResultFail;
return;
}
resultGameJoin_ = result;
if (result != knGameJoinResultSuccess) {
LOG() << "Error connecting to game.";
SetState(XTS_JOINGAMEERROR);
return;
}
SetState(XTS_JOINGAMESUCCESS);
}
void XTransport::OnGameReceiveChat(const char *player, const char *chat) {
if (m_pgcb != NULL) {
m_pgcb->OnReceiveChat(player, chat);
}
}
bool XTransport::SendNetMessage(NetMessage *pnm) {
if (error_ || xpump_.IsClosed()) {
return false;
}
if (!CheckState(XTS_GAME)) {
return false;
}
return xpump_.Send(XMsgGameNetMessage::ToBuffer(pnm));
}
void XTransport::OnGameNetMessage(NetMessage **ppnm) {
if (!CheckState(XTS_GAME)) {
return;
}
if (m_pgcb != NULL) {
m_pgcb->OnNetMessage(ppnm);
}
}
void XTransport::OnGameKilled(dword gameid) {
if (!CheckState(XTS_GAME)) {
return;
}
// The server removed this client from the game, so this client's
// state is no longer GAME.
SetState(XTS_LOGGEDIN);
if (m_pgcb != NULL) {
m_pgcb->OnGameDisconnect();
}
}
void XTransport::LeaveGame() {
if (error_ || xpump_.IsClosed()) {
LOG() << "Error or closed";
return;
}
// If the game was killed by the server, the state gets reverted to
// XTS_LOGGEDIN. In this case, the client may call LeaveGame anyway,
// so ignore this case without an assert.
if (state_ == XTS_LOGGEDIN) {
return;
}
// The client should bin the game
if (!CheckState(XTS_GAME)) {
LOG() << "Not in game state!";
return;
}
// Disconnect this game synchronously. This is so that a game
// in progress doesn't continue to send updates when the client
// thinks it is disconnected.
xpump_.Send(XMsgGameLeave::ToBuffer());
if (!WaitForStateChange()) {
LOG() << "timed out waiting for disconnect game result";
}
// Go to XTS_LOGGEDIN, whether it was successful or not
SetState(XTS_LOGGEDIN);
}
void XTransport::OnGameLeaveResult(dword result) {
LOG() << GameLeaveResults.Find(result);
SetState(XTS_LOGGEDIN);
}
void XTransport::OnEvent(Event *pevt) {
if (xpump_.Dispatch()) {
OnMessages();
}
}
bool XTransport::OnMessages() {
// Pump the message loop for each xmsg. Important since xmsg's change
// state, and message loops evaluate state.
base::Thread::current().Post(base::kidmTransportEvent, NULL);
return true;
}
void XTransport::OnError(int error) {
LOG() << base::Socket::GetErrorString(error);
error_ = true;
OnClose(0);
}
void XTransport::OnClose(int error) {
LOG() << error;
if (m_ptcb != NULL) {
m_ptcb->OnConnectionClose();
}
SetState(XTS_CLOSED);
// Cause a message to be pumped through the game input loop to cause it
// to wake up, since processing here was done in MessageQueue dispatch.
base::Thread::current().Post(base::kidmNullEvent, NULL);
}
void XTransport::OnConnectEvent(base::Socket *socket) {
SetState(XTS_CONNECTED);
}
void XTransport::OnReadEvent(base::Socket *socket) {
}
void XTransport::OnWriteEvent(base::Socket *socket) {
}
void XTransport::OnCloseEvent(base::Socket *socket) {
}
void XTransport::UpdateAllies(Side side, SideMask sidmAllies) {
if (error_ || xpump_.IsClosed()) {
return;
}
if (state_ == XTS_ROOM) {
return;
}
if (state_ == XTS_GAME) {
xpump_.Send(XMsgGameUpdateAllies::ToBuffer(dword(side), dword(sidmAllies)));
return;
}
}
void XTransport::DisconnectSharedAccounts() {
xpump_.Send(XMsgDisconnectSharedAccounts::ToBuffer());
}
} // namespace wi