Bugfix for multiplayer binary and data checksum checking.
This commit is contained in:
parent
b2128e69a7
commit
b9172acc5c
527
source/glest_game/network/client_interface.cpp
Executable file
527
source/glest_game/network/client_interface.cpp
Executable file
|
@ -0,0 +1,527 @@
|
||||||
|
// ==============================================================
|
||||||
|
// This file is part of Glest (www.glest.org)
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||||
|
//
|
||||||
|
// You can redistribute this code and/or modify it under
|
||||||
|
// the terms of the GNU General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
#include "client_interface.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "platform_util.h"
|
||||||
|
#include "game_util.h"
|
||||||
|
#include "conversion.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include "leak_dumper.h"
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Shared::Platform;
|
||||||
|
using namespace Shared::Util;
|
||||||
|
|
||||||
|
namespace Glest{ namespace Game{
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ClientInterface
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
const int ClientInterface::messageWaitTimeout= 10000; //10 seconds
|
||||||
|
const int ClientInterface::waitSleepTime= 50;
|
||||||
|
|
||||||
|
ClientInterface::ClientInterface(){
|
||||||
|
clientSocket= NULL;
|
||||||
|
launchGame= false;
|
||||||
|
introDone= false;
|
||||||
|
playerIndex= -1;
|
||||||
|
|
||||||
|
networkGameDataSynchCheckOkMap = false;
|
||||||
|
networkGameDataSynchCheckOkTile = false;
|
||||||
|
networkGameDataSynchCheckOkTech = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientInterface::~ClientInterface()
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
if(clientSocket != NULL && clientSocket->isConnected() == true)
|
||||||
|
{
|
||||||
|
string sQuitText = getHostName() + " has chosen to leave the game!";
|
||||||
|
sendTextMessage(sQuitText,-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete clientSocket;
|
||||||
|
clientSocket = NULL;
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::connect(const Ip &ip, int port)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
delete clientSocket;
|
||||||
|
|
||||||
|
this->ip = ip;
|
||||||
|
this->port = port;
|
||||||
|
|
||||||
|
clientSocket= new ClientSocket();
|
||||||
|
clientSocket->setBlock(false);
|
||||||
|
clientSocket->connect(ip, port);
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END - socket = %d\n",__FILE__,__FUNCTION__,clientSocket->getSocketId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::reset()
|
||||||
|
{
|
||||||
|
if(getSocket() != NULL)
|
||||||
|
{
|
||||||
|
string sQuitText = getHostName() + " has chosen to leave the game!";
|
||||||
|
sendTextMessage(sQuitText,-1);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::update()
|
||||||
|
{
|
||||||
|
NetworkMessageCommandList networkMessageCommandList;
|
||||||
|
|
||||||
|
//send as many commands as we can
|
||||||
|
while(!requestedCommands.empty()){
|
||||||
|
if(networkMessageCommandList.addCommand(&requestedCommands.back())){
|
||||||
|
requestedCommands.pop_back();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(networkMessageCommandList.getCommandCount()>0){
|
||||||
|
sendMessage(&networkMessageCommandList);
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear chat variables
|
||||||
|
chatText.clear();
|
||||||
|
chatSender.clear();
|
||||||
|
chatTeamIndex= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::updateLobby()
|
||||||
|
{
|
||||||
|
//clear chat variables
|
||||||
|
chatText.clear();
|
||||||
|
chatSender.clear();
|
||||||
|
chatTeamIndex= -1;
|
||||||
|
|
||||||
|
NetworkMessageType networkMessageType = getNextMessageType(true);
|
||||||
|
|
||||||
|
switch(networkMessageType)
|
||||||
|
{
|
||||||
|
case nmtInvalid:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtIntro:
|
||||||
|
{
|
||||||
|
NetworkMessageIntro networkMessageIntro;
|
||||||
|
|
||||||
|
if(receiveMessage(&networkMessageIntro))
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got NetworkMessageIntro\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
//check consistency
|
||||||
|
if(Config::getInstance().getBool("NetworkConsistencyChecks"))
|
||||||
|
{
|
||||||
|
if(networkMessageIntro.getVersionString()!=getNetworkVersionString())
|
||||||
|
{
|
||||||
|
string sErr = "Server and client versions do not match (" + networkMessageIntro.getVersionString() + "). You have to use the same binaries.";
|
||||||
|
printf("%s\n",sErr.c_str());
|
||||||
|
throw runtime_error(sErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//send intro message
|
||||||
|
NetworkMessageIntro sendNetworkMessageIntro(getNetworkVersionString(), getHostName(), -1);
|
||||||
|
|
||||||
|
playerIndex= networkMessageIntro.getPlayerIndex();
|
||||||
|
serverName= networkMessageIntro.getName();
|
||||||
|
sendMessage(&sendNetworkMessageIntro);
|
||||||
|
|
||||||
|
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
|
||||||
|
introDone= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtSynchNetworkGameData:
|
||||||
|
{
|
||||||
|
NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData;
|
||||||
|
|
||||||
|
if(receiveMessage(&networkMessageSynchNetworkGameData))
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got NetworkMessageSynchNetworkGameData\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
// check the checksum's
|
||||||
|
int32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_tilesets) + "/" +
|
||||||
|
networkMessageSynchNetworkGameData.getTileset() + "/*", ".xml", NULL);
|
||||||
|
|
||||||
|
this->setNetworkGameDataSynchCheckOkTile((tilesetCRC == networkMessageSynchNetworkGameData.getTilesetCRC()));
|
||||||
|
if(this->getNetworkGameDataSynchCheckOkTile() == false)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] tilesetCRC mismatch, local = %d, remote = %d\n",
|
||||||
|
__FILE__,__FUNCTION__,tilesetCRC,networkMessageSynchNetworkGameData.getTilesetCRC());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//tech, load before map because of resources
|
||||||
|
int32 techCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_techs) + "/" +
|
||||||
|
networkMessageSynchNetworkGameData.getTech() + "/*", ".xml", NULL);
|
||||||
|
|
||||||
|
this->setNetworkGameDataSynchCheckOkTech((techCRC == networkMessageSynchNetworkGameData.getTechCRC()));
|
||||||
|
|
||||||
|
if(this->getNetworkGameDataSynchCheckOkTech() == false)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] techCRC mismatch, local = %d, remote = %d\n",
|
||||||
|
__FILE__,__FUNCTION__,techCRC,networkMessageSynchNetworkGameData.getTechCRC());
|
||||||
|
}
|
||||||
|
|
||||||
|
//map
|
||||||
|
Checksum checksum;
|
||||||
|
string file = Map::getMapPath(networkMessageSynchNetworkGameData.getMap());
|
||||||
|
checksum.addFile(file);
|
||||||
|
int32 mapCRC = checksum.getSum();
|
||||||
|
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] file = [%s] checksum = %d\n",__FILE__,__FUNCTION__,file.c_str(),mapCRC);
|
||||||
|
|
||||||
|
this->setNetworkGameDataSynchCheckOkMap((mapCRC == networkMessageSynchNetworkGameData.getMapCRC()));
|
||||||
|
|
||||||
|
if(this->getNetworkGameDataSynchCheckOkMap() == false)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] mapCRC mismatch, local = %d, remote = %d\n",
|
||||||
|
__FILE__,__FUNCTION__,mapCRC,networkMessageSynchNetworkGameData.getMapCRC());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this->setNetworkGameDataSynchCheckOkFogOfWar((getFogOfWar() == networkMessageSynchNetworkGameData.getFogOfWar()));
|
||||||
|
|
||||||
|
if(this->getNetworkGameDataSynchCheckOkFogOfWar() == false)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] getFogOfWar mismatch, local = %d, remote = %d\n",
|
||||||
|
__FILE__,__FUNCTION__,getFogOfWar(),networkMessageSynchNetworkGameData.getFogOfWar());
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkMessageSynchNetworkGameDataStatus sendNetworkMessageSynchNetworkGameDataStatus(mapCRC,tilesetCRC,techCRC,getFogOfWar());
|
||||||
|
sendMessage(&sendNetworkMessageSynchNetworkGameDataStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtSynchNetworkGameDataFileCRCCheck:
|
||||||
|
{
|
||||||
|
NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck;
|
||||||
|
if(receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck totalfiles = %d, fileindex = %d, crc = %d, file [%s]\n",
|
||||||
|
__FILE__,__FUNCTION__,networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount(),
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex(),
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC(),
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getFileName().c_str());
|
||||||
|
*/
|
||||||
|
Checksum checksum;
|
||||||
|
string file = networkMessageSynchNetworkGameDataFileCRCCheck.getFileName();
|
||||||
|
checksum.addFile(file);
|
||||||
|
int32 fileCRC = checksum.getSum();
|
||||||
|
|
||||||
|
if(fileCRC != networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC())
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck localCRC = %d, remoteCRC = %d, file [%s]\n",
|
||||||
|
__FILE__,__FUNCTION__,fileCRC,
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC(),
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getFileName().c_str());
|
||||||
|
|
||||||
|
// Here we initiate a download of missing or mismatched content
|
||||||
|
|
||||||
|
NetworkMessageSynchNetworkGameDataFileGet sendNetworkMessageSynchNetworkGameDataFileGet(networkMessageSynchNetworkGameDataFileCRCCheck.getFileName());
|
||||||
|
sendMessage(&sendNetworkMessageSynchNetworkGameDataFileGet);
|
||||||
|
|
||||||
|
FileTransferInfo fileInfo;
|
||||||
|
fileInfo.hostType = eClient;
|
||||||
|
fileInfo.serverIP = this->ip.getString();
|
||||||
|
fileInfo.serverPort = this->port;
|
||||||
|
fileInfo.fileName = networkMessageSynchNetworkGameDataFileCRCCheck.getFileName();
|
||||||
|
|
||||||
|
FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo);
|
||||||
|
fileXferThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex() < networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount())
|
||||||
|
{
|
||||||
|
NetworkMessageSynchNetworkGameDataFileCRCCheck sendNetworkMessageSynchNetworkGameDataFileCRCCheck(
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount(),
|
||||||
|
networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex() + 1,
|
||||||
|
0,
|
||||||
|
"");
|
||||||
|
sendMessage(&sendNetworkMessageSynchNetworkGameDataFileCRCCheck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtText:
|
||||||
|
{
|
||||||
|
NetworkMessageText networkMessageText;
|
||||||
|
if(receiveMessage(&networkMessageText))
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtText\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
chatText = networkMessageText.getText();
|
||||||
|
chatSender = networkMessageText.getSender();
|
||||||
|
chatTeamIndex = networkMessageText.getTeamIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtLaunch:
|
||||||
|
{
|
||||||
|
NetworkMessageLaunch networkMessageLaunch;
|
||||||
|
|
||||||
|
if(receiveMessage(&networkMessageLaunch))
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got NetworkMessageLaunch\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
networkMessageLaunch.buildGameSettings(&gameSettings);
|
||||||
|
|
||||||
|
//replace server player by network
|
||||||
|
for(int i= 0; i<gameSettings.getFactionCount(); ++i)
|
||||||
|
{
|
||||||
|
//replace by network
|
||||||
|
if(gameSettings.getFactionControl(i)==ctHuman)
|
||||||
|
{
|
||||||
|
gameSettings.setFactionControl(i, ctNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
//set the faction index
|
||||||
|
if(gameSettings.getStartLocationIndex(i)==playerIndex)
|
||||||
|
{
|
||||||
|
gameSettings.setThisFactionIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
launchGame= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::updateKeyframe(int frameCount)
|
||||||
|
{
|
||||||
|
bool done= false;
|
||||||
|
|
||||||
|
while(!done)
|
||||||
|
{
|
||||||
|
//wait for the next message
|
||||||
|
waitForMessage();
|
||||||
|
|
||||||
|
//check we have an expected message
|
||||||
|
NetworkMessageType networkMessageType= getNextMessageType(true);
|
||||||
|
|
||||||
|
switch(networkMessageType)
|
||||||
|
{
|
||||||
|
case nmtCommandList:
|
||||||
|
{
|
||||||
|
//make sure we read the message
|
||||||
|
NetworkMessageCommandList networkMessageCommandList;
|
||||||
|
while(!receiveMessage(&networkMessageCommandList))
|
||||||
|
{
|
||||||
|
sleep(waitSleepTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
//check that we are in the right frame
|
||||||
|
if(networkMessageCommandList.getFrameCount()!=frameCount)
|
||||||
|
{
|
||||||
|
throw runtime_error("Network synchronization error, frame counts do not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
// give all commands
|
||||||
|
for(int i= 0; i<networkMessageCommandList.getCommandCount(); ++i)
|
||||||
|
{
|
||||||
|
pendingCommands.push_back(*networkMessageCommandList.getCommand(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
done= true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtQuit:
|
||||||
|
{
|
||||||
|
NetworkMessageQuit networkMessageQuit;
|
||||||
|
if(receiveMessage(&networkMessageQuit))
|
||||||
|
{
|
||||||
|
quit= true;
|
||||||
|
}
|
||||||
|
done= true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nmtText:
|
||||||
|
{
|
||||||
|
NetworkMessageText networkMessageText;
|
||||||
|
if(receiveMessage(&networkMessageText))
|
||||||
|
{
|
||||||
|
chatText = networkMessageText.getText();
|
||||||
|
chatSender = networkMessageText.getSender();
|
||||||
|
chatTeamIndex = networkMessageText.getTeamIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nmtInvalid:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected message in client interface: " + intToStr(networkMessageType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::waitUntilReady(Checksum* checksum)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
Logger &logger= Logger::getInstance();
|
||||||
|
|
||||||
|
Chrono chrono;
|
||||||
|
chrono.start();
|
||||||
|
|
||||||
|
// FOR TESTING ONLY - delay to see the client count up while waiting
|
||||||
|
//sleep(5000);
|
||||||
|
|
||||||
|
//send ready message
|
||||||
|
NetworkMessageReady networkMessageReady;
|
||||||
|
sendMessage(&networkMessageReady);
|
||||||
|
|
||||||
|
int64 lastMillisCheck = 0;
|
||||||
|
//wait until we get a ready message from the server
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
NetworkMessageType networkMessageType = getNextMessageType(true);
|
||||||
|
|
||||||
|
if(networkMessageType == nmtReady)
|
||||||
|
{
|
||||||
|
if(receiveMessage(&networkMessageReady))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(networkMessageType == nmtInvalid)
|
||||||
|
{
|
||||||
|
if(chrono.getMillis() > readyWaitTimeout)
|
||||||
|
{
|
||||||
|
throw runtime_error("Timeout waiting for server");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(chrono.getMillis() / 1000 > lastMillisCheck)
|
||||||
|
{
|
||||||
|
lastMillisCheck = (chrono.getMillis() / 1000);
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"Waiting for network: %llu seconds elapsed (maximum wait time: %d seconds)",lastMillisCheck,int(readyWaitTimeout / 1000));
|
||||||
|
logger.add(szBuf, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleep a bit
|
||||||
|
sleep(waitSleepTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
//check checksum
|
||||||
|
if(Config::getInstance().getBool("NetworkConsistencyChecks"))
|
||||||
|
{
|
||||||
|
if(networkMessageReady.getChecksum() != checksum->getSum())
|
||||||
|
{
|
||||||
|
string sErr = "Checksum error, you don't have the same data as the server";
|
||||||
|
//throw runtime_error("Checksum error, you don't have the same data as the server");
|
||||||
|
printf("%s\n",sErr.c_str());
|
||||||
|
throw runtime_error(sErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//delay the start a bit, so clients have nore room to get messages
|
||||||
|
sleep(GameConstants::networkExtraLatency);
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::sendTextMessage(const string &text, int teamIndex){
|
||||||
|
NetworkMessageText networkMessageText(text, getHostName(), teamIndex);
|
||||||
|
sendMessage(&networkMessageText);
|
||||||
|
}
|
||||||
|
|
||||||
|
string ClientInterface::getNetworkStatus() const{
|
||||||
|
return Lang::getInstance().get("Server") + ": " + serverName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::waitForMessage()
|
||||||
|
{
|
||||||
|
Chrono chrono;
|
||||||
|
chrono.start();
|
||||||
|
|
||||||
|
while(getNextMessageType(true) == nmtInvalid)
|
||||||
|
{
|
||||||
|
if(!isConnected())
|
||||||
|
{
|
||||||
|
throw runtime_error("Disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(chrono.getMillis()>messageWaitTimeout)
|
||||||
|
{
|
||||||
|
throw runtime_error("Timeout waiting for message");
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(waitSleepTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::quitGame(bool userManuallyQuit)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
if(clientSocket != NULL && userManuallyQuit == true)
|
||||||
|
{
|
||||||
|
string sQuitText = getHostName() + " has chosen to leave the game!";
|
||||||
|
sendTextMessage(sQuitText,-1);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::close()
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
delete clientSocket;
|
||||||
|
clientSocket= NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientInterface::getFogOfWar()
|
||||||
|
{
|
||||||
|
return Config::getInstance().getBool("FogOfWar");
|
||||||
|
}
|
||||||
|
|
||||||
|
}}//end namespace
|
112
source/shared_lib/include/platform/posix/socket.h
Normal file
112
source/shared_lib/include/platform/posix/socket.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
// ==============================================================
|
||||||
|
// This file is part of Glest Shared Library (www.glest.org)
|
||||||
|
//
|
||||||
|
// Copyright (C) 2005 Matthias Braun <matze@braunis.de>
|
||||||
|
//
|
||||||
|
// You can redistribute this code and/or modify it under
|
||||||
|
// the terms of the GNU General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
#ifndef _SHARED_PLATFORM_SOCKET_H_
|
||||||
|
#define _SHARED_PLATFORM_SOCKET_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
namespace Shared{ namespace Platform{
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class IP
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class Ip{
|
||||||
|
private:
|
||||||
|
unsigned char bytes[4];
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ip();
|
||||||
|
Ip(unsigned char byte0, unsigned char byte1, unsigned char byte2, unsigned char byte3);
|
||||||
|
Ip(const string& ipString);
|
||||||
|
|
||||||
|
unsigned char getByte(int byteIndex) {return bytes[byteIndex];}
|
||||||
|
string getString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Socket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class Socket {
|
||||||
|
protected:
|
||||||
|
int sock;
|
||||||
|
long lastDebugEvent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Socket(int sock);
|
||||||
|
Socket();
|
||||||
|
~Socket();
|
||||||
|
|
||||||
|
static bool enableDebugText;
|
||||||
|
static bool enableNetworkDebugInfo;
|
||||||
|
|
||||||
|
// Int lookup is socket fd while bool result is whether or not that socket was signalled for reading
|
||||||
|
static bool hasDataToRead(std::map<int,bool> &socketTriggeredList);
|
||||||
|
static bool hasDataToRead(int socket);
|
||||||
|
bool hasDataToRead();
|
||||||
|
void disconnectSocket();
|
||||||
|
|
||||||
|
int getSocketId() const { return sock; }
|
||||||
|
|
||||||
|
int getDataToRead();
|
||||||
|
int send(const void *data, int dataSize);
|
||||||
|
int receive(void *data, int dataSize);
|
||||||
|
int peek(void *data, int dataSize);
|
||||||
|
|
||||||
|
void setBlock(bool block);
|
||||||
|
bool isReadable();
|
||||||
|
bool isWritable(bool waitOnDelayedResponse);
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
string getHostName() const;
|
||||||
|
string getIp() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void throwException(const string &str);
|
||||||
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ClientSocket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class ClientSocket: public Socket{
|
||||||
|
public:
|
||||||
|
void connect(const Ip &ip, int port);
|
||||||
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ServerSocket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class ServerSocket: public Socket{
|
||||||
|
public:
|
||||||
|
void bind(int port);
|
||||||
|
void listen(int connectionQueueSize= SOMAXCONN);
|
||||||
|
Socket *accept();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}//end namespace
|
||||||
|
|
||||||
|
#endif
|
114
source/shared_lib/include/platform/win32/socket.h
Normal file
114
source/shared_lib/include/platform/win32/socket.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// ==============================================================
|
||||||
|
// This file is part of Glest Shared Library (www.glest.org)
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001-2008 Marti<74>o Figueroa
|
||||||
|
//
|
||||||
|
// You can redistribute this code and/or modify it under
|
||||||
|
// the terms of the GNU General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
#ifndef _SHARED_PLATFORM_SOCKET_H_
|
||||||
|
#define _SHARED_PLATFORM_SOCKET_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <winsock.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
const char* WSAGetLastErrorMessage(const char* pcMessagePrefix,int nErrorID = 0);
|
||||||
|
|
||||||
|
namespace Shared{ namespace Platform{
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class IP
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class Ip{
|
||||||
|
private:
|
||||||
|
unsigned char bytes[4];
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ip();
|
||||||
|
Ip(unsigned char byte0, unsigned char byte1, unsigned char byte2, unsigned char byte3);
|
||||||
|
Ip(const string& ipString);
|
||||||
|
|
||||||
|
unsigned char getByte(int byteIndex) {return bytes[byteIndex];}
|
||||||
|
string getString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Socket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class Socket{
|
||||||
|
private:
|
||||||
|
class SocketManager{
|
||||||
|
public:
|
||||||
|
SocketManager();
|
||||||
|
~SocketManager();
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static SocketManager socketManager;
|
||||||
|
SOCKET sock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Socket(SOCKET sock);
|
||||||
|
Socket();
|
||||||
|
~Socket();
|
||||||
|
|
||||||
|
static bool enableDebugText;
|
||||||
|
static bool enableNetworkDebugInfo;
|
||||||
|
|
||||||
|
// Int lookup is socket fd while bool result is whether or not that socket was signalled for reading
|
||||||
|
static bool hasDataToRead(std::map<int,bool> &socketTriggeredList);
|
||||||
|
static bool hasDataToRead(int socket);
|
||||||
|
bool hasDataToRead();
|
||||||
|
void disconnectSocket();
|
||||||
|
|
||||||
|
int getSocketId() const { return sock; }
|
||||||
|
|
||||||
|
int getDataToRead();
|
||||||
|
int send(const void *data, int dataSize);
|
||||||
|
int receive(void *data, int dataSize);
|
||||||
|
int peek(void *data, int dataSize);
|
||||||
|
|
||||||
|
void setBlock(bool block);
|
||||||
|
bool isReadable();
|
||||||
|
bool isWritable(bool waitOnDelayedResponse);
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
string getHostName() const;
|
||||||
|
string getIp() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void throwException(const string &str);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ClientSocket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class ClientSocket: public Socket{
|
||||||
|
public:
|
||||||
|
void connect(const Ip &ip, int port);
|
||||||
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ServerSocket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class ServerSocket: public Socket{
|
||||||
|
public:
|
||||||
|
void bind(int port);
|
||||||
|
void listen(int connectionQueueSize= SOMAXCONN);
|
||||||
|
Socket *accept();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}//end namespace
|
||||||
|
|
||||||
|
#endif
|
704
source/shared_lib/sources/platform/posix/socket.cpp
Normal file
704
source/shared_lib/sources/platform/posix/socket.cpp
Normal file
|
@ -0,0 +1,704 @@
|
||||||
|
//This file is part of Glest Shared Library (www.glest.org)
|
||||||
|
//Copyright (C) 2005 Matthias Braun <matze@braunis.de>
|
||||||
|
|
||||||
|
//You can redistribute this code and/or modify it under
|
||||||
|
//the terms of the GNU General Public License as published by the Free Software
|
||||||
|
//Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
//version.
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
#if defined(HAVE_SYS_IOCTL_H)
|
||||||
|
#define BSD_COMP /* needed for FIONREAD on Solaris2 */
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_SYS_FILIO_H) /* needed for FIONREAD on Solaris 2.5 */
|
||||||
|
#include <sys/filio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "conversion.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Shared::Util;
|
||||||
|
|
||||||
|
namespace Shared{ namespace Platform{
|
||||||
|
|
||||||
|
bool Socket::enableDebugText = true;
|
||||||
|
bool Socket::enableNetworkDebugInfo = true;
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Ip
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
Ip::Ip(){
|
||||||
|
bytes[0]= 0;
|
||||||
|
bytes[1]= 0;
|
||||||
|
bytes[2]= 0;
|
||||||
|
bytes[3]= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ip::Ip(unsigned char byte0, unsigned char byte1, unsigned char byte2, unsigned char byte3){
|
||||||
|
bytes[0]= byte0;
|
||||||
|
bytes[1]= byte1;
|
||||||
|
bytes[2]= byte2;
|
||||||
|
bytes[3]= byte3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ip::Ip(const string& ipString){
|
||||||
|
int offset= 0;
|
||||||
|
int byteIndex= 0;
|
||||||
|
|
||||||
|
for(byteIndex= 0; byteIndex<4; ++byteIndex){
|
||||||
|
int dotPos= ipString.find_first_of('.', offset);
|
||||||
|
|
||||||
|
bytes[byteIndex]= atoi(ipString.substr(offset, dotPos-offset).c_str());
|
||||||
|
offset= dotPos+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string Ip::getString() const{
|
||||||
|
return intToStr(bytes[0]) + "." + intToStr(bytes[1]) + "." + intToStr(bytes[2]) + "." + intToStr(bytes[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// class Socket
|
||||||
|
// ===============================================
|
||||||
|
|
||||||
|
Socket::Socket(int sock){
|
||||||
|
this->sock= sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::Socket()
|
||||||
|
{
|
||||||
|
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if(sock < 0)
|
||||||
|
{
|
||||||
|
throwException("Error creating socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::~Socket()
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::disconnectSocket()
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] calling shutdown and close for socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
::shutdown(sock,2);
|
||||||
|
::close(sock);
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int lookup is socket fd while bool result is whether or not that socket was signalled for reading
|
||||||
|
bool Socket::hasDataToRead(std::map<int,bool> &socketTriggeredList)
|
||||||
|
{
|
||||||
|
bool bResult = false;
|
||||||
|
|
||||||
|
if(socketTriggeredList.size() > 0)
|
||||||
|
{
|
||||||
|
/* Watch stdin (fd 0) to see when it has input. */
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
|
||||||
|
int imaxsocket = 0;
|
||||||
|
for(std::map<int,bool>::iterator itermap = socketTriggeredList.begin();
|
||||||
|
itermap != socketTriggeredList.end(); itermap++)
|
||||||
|
{
|
||||||
|
int socket = itermap->first;
|
||||||
|
if(socket > 0)
|
||||||
|
{
|
||||||
|
FD_SET(socket, &rfds);
|
||||||
|
imaxsocket = max(socket,imaxsocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(imaxsocket > 0)
|
||||||
|
{
|
||||||
|
/* Wait up to 0 seconds. */
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] ERROR SELECTING SOCKET DATA retval = %d errno = %d [%s]",__FILE__,__FUNCTION__,retval,errno,strerror(errno));
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(retval)
|
||||||
|
{
|
||||||
|
bResult = true;
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] select detected data imaxsocket = %d...\n",__FILE__,__FUNCTION__,imaxsocket);
|
||||||
|
|
||||||
|
for(std::map<int,bool>::iterator itermap = socketTriggeredList.begin();
|
||||||
|
itermap != socketTriggeredList.end(); itermap++)
|
||||||
|
{
|
||||||
|
int socket = itermap->first;
|
||||||
|
if (FD_ISSET(socket, &rfds))
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s] FD_ISSET true for socket %d...\n",__FUNCTION__,socket);
|
||||||
|
|
||||||
|
itermap->second = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
itermap->second = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socketTriggeredList->size() = %d\n",__FILE__,__FUNCTION__,socketTriggeredList.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::hasDataToRead()
|
||||||
|
{
|
||||||
|
return Socket::hasDataToRead(sock) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::hasDataToRead(int socket)
|
||||||
|
{
|
||||||
|
bool bResult = false;
|
||||||
|
|
||||||
|
if(socket > 0)
|
||||||
|
{
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
/* Watch stdin (fd 0) to see when it has input. */
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(socket, &rfds);
|
||||||
|
|
||||||
|
/* Wait up to 0 seconds. */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int retval = select(socket + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
if(retval)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(socket, &rfds))
|
||||||
|
{
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::getDataToRead(){
|
||||||
|
unsigned long size = 0;
|
||||||
|
|
||||||
|
//fd_set rfds;
|
||||||
|
//struct timeval tv;
|
||||||
|
//int retval;
|
||||||
|
|
||||||
|
/* Watch stdin (fd 0) to see when it has input. */
|
||||||
|
//FD_ZERO(&rfds);
|
||||||
|
//FD_SET(sock, &rfds);
|
||||||
|
|
||||||
|
/* Wait up to 0 seconds. */
|
||||||
|
//tv.tv_sec = 0;
|
||||||
|
//tv.tv_usec = 0;
|
||||||
|
|
||||||
|
//retval = select(sock + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
//if(retval)
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
/* ioctl isn't posix, but the following seems to work on all modern
|
||||||
|
* unixes */
|
||||||
|
int err= ioctl(sock, FIONREAD, &size);
|
||||||
|
|
||||||
|
if(err < 0 && errno != EAGAIN)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] ERROR PEEKING SOCKET DATA, err = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,err,errno,strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
else if(err == 0)
|
||||||
|
{
|
||||||
|
//if(Socket::enableNetworkDebugInfo) printf("In [%s] ioctl returned = %d, size = %ld\n",__FUNCTION__,err,size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<int>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::send(const void *data, int dataSize) {
|
||||||
|
ssize_t bytesSent= 0;
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
|
||||||
|
}
|
||||||
|
if(bytesSent < 0 && errno != EAGAIN)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] ERROR WRITING SOCKET DATA, err = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesSent,errno,strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
else if(bytesSent < 0 && errno == EAGAIN)
|
||||||
|
{
|
||||||
|
printf("In [%s::%s] #1 EAGAIN during send, trying again...\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
time_t tStartTimer = time(NULL);
|
||||||
|
while((bytesSent < 0 && errno == EAGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
|
||||||
|
{
|
||||||
|
if(Socket::isWritable(true) == true)
|
||||||
|
{
|
||||||
|
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
|
||||||
|
|
||||||
|
printf("In [%s::%s] #2 EAGAIN during send, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesSent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bytesSent <= 0)
|
||||||
|
{
|
||||||
|
int iErr = errno;
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while sending socket data, bytesSent = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesSent,iErr,strerror(iErr));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] sock = %d, bytesSent = %d\n",__FILE__,__FUNCTION__,sock,bytesSent);
|
||||||
|
|
||||||
|
return static_cast<int>(bytesSent);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::receive(void *data, int dataSize)
|
||||||
|
{
|
||||||
|
ssize_t bytesReceived = 0;
|
||||||
|
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
|
||||||
|
}
|
||||||
|
if(bytesReceived < 0 && errno != EAGAIN)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] ERROR READING SOCKET DATA error while sending socket data, bytesSent = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesReceived,errno,strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
else if(bytesReceived < 0 && errno == EAGAIN)
|
||||||
|
{
|
||||||
|
printf("In [%s::%s] #1 EAGAIN during receive, trying again...\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
time_t tStartTimer = time(NULL);
|
||||||
|
while((bytesReceived < 0 && errno == EAGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
|
||||||
|
{
|
||||||
|
if(Socket::isReadable() == true)
|
||||||
|
{
|
||||||
|
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
|
||||||
|
|
||||||
|
printf("In [%s::%s] #2 EAGAIN during receive, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesReceived);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bytesReceived <= 0)
|
||||||
|
{
|
||||||
|
int iErr = errno;
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while receiving socket data, bytesReceived = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesReceived,iErr,strerror(iErr));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
return static_cast<int>(bytesReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::peek(void *data, int dataSize){
|
||||||
|
ssize_t err = 0;
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
|
||||||
|
}
|
||||||
|
if(err < 0 && errno != EAGAIN)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] ERROR PEEKING SOCKET DATA error while sending socket data, bytesSent = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,err,errno,strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
|
||||||
|
disconnectSocket();
|
||||||
|
}
|
||||||
|
else if(err < 0 && errno == EAGAIN)
|
||||||
|
{
|
||||||
|
printf("In [%s::%s] #1 EAGAIN during peek, trying again...\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
time_t tStartTimer = time(NULL);
|
||||||
|
while((err < 0 && errno == EAGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
|
||||||
|
{
|
||||||
|
if(Socket::isReadable() == true)
|
||||||
|
{
|
||||||
|
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
|
||||||
|
|
||||||
|
printf("In [%s::%s] #2 EAGAIN during peek, trying again returned: %d\n",__FILE__,__FUNCTION__,err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err <= 0)
|
||||||
|
{
|
||||||
|
int iErr = errno;
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while peeking socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,err,iErr,strerror(iErr));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<int>(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::setBlock(bool block){
|
||||||
|
int err= fcntl(sock, F_SETFL, block ? 0 : O_NONBLOCK);
|
||||||
|
if(err<0){
|
||||||
|
throwException("Error setting I/O mode for socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::isReadable()
|
||||||
|
{
|
||||||
|
if(sock <= 0) return false;
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec= 0;
|
||||||
|
tv.tv_usec= 1;
|
||||||
|
|
||||||
|
fd_set set;
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(sock, &set);
|
||||||
|
|
||||||
|
int i= select(sock+1, &set, NULL, NULL, &tv);
|
||||||
|
if(i < 0)
|
||||||
|
{
|
||||||
|
if(difftime(time(NULL),lastDebugEvent) >= 1)
|
||||||
|
{
|
||||||
|
lastDebugEvent = time(NULL);
|
||||||
|
|
||||||
|
//throwException("Error selecting socket");
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] error while selecting socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,i,errno,strerror(errno));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return (i == 1 && FD_ISSET(sock, &set));
|
||||||
|
return (i == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::isWritable(bool waitOnDelayedResponse)
|
||||||
|
{
|
||||||
|
if(sock <= 0) return false;
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec= 0;
|
||||||
|
tv.tv_usec= 1;
|
||||||
|
|
||||||
|
fd_set set;
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(sock, &set);
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int i = select(sock+1, NULL, &set, NULL, &tv);
|
||||||
|
if(i < 0 )
|
||||||
|
{
|
||||||
|
if(difftime(time(NULL),lastDebugEvent) >= 1)
|
||||||
|
{
|
||||||
|
lastDebugEvent = time(NULL);
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] error while selecting socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,i,errno,strerror(errno));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
waitOnDelayedResponse = false;
|
||||||
|
|
||||||
|
//throwException("Error selecting socket");
|
||||||
|
}
|
||||||
|
else if(i == 0)
|
||||||
|
{
|
||||||
|
if(difftime(time(NULL),lastDebugEvent) >= 1)
|
||||||
|
{
|
||||||
|
lastDebugEvent = time(NULL);
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] TIMEOUT while selecting socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,i,errno,strerror(errno));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(waitOnDelayedResponse == false)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
} while(waitOnDelayedResponse == true && result == false);
|
||||||
|
|
||||||
|
//return (i == 1 && FD_ISSET(sock, &set));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::isConnected()
|
||||||
|
{
|
||||||
|
//if the socket is not writable then it is not conencted
|
||||||
|
if(isWritable(false) == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the socket is readable it is connected if we can read a byte from it
|
||||||
|
if(isReadable())
|
||||||
|
{
|
||||||
|
char tmp;
|
||||||
|
int err = peek(&tmp, sizeof(tmp));
|
||||||
|
return (err > 0);
|
||||||
|
/*
|
||||||
|
int err = recv(sock, &tmp, sizeof(tmp), MSG_PEEK);
|
||||||
|
|
||||||
|
if(err <= 0 && errno != EAGAIN)
|
||||||
|
{
|
||||||
|
int iErr = errno;
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while peeking isconnected socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,err,iErr,strerror(iErr));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if(err <= 0)
|
||||||
|
{
|
||||||
|
int iErr = errno;
|
||||||
|
//disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] #2 DISCONNECTED SOCKET error while peeking isconnected socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,err,iErr,strerror(iErr));
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise the socket is connected
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Socket::getHostName() const {
|
||||||
|
const int strSize= 256;
|
||||||
|
char hostname[strSize];
|
||||||
|
gethostname(hostname, strSize);
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Socket::getIp() const{
|
||||||
|
hostent* info= gethostbyname(getHostName().c_str());
|
||||||
|
unsigned char* address;
|
||||||
|
|
||||||
|
if(info==NULL){
|
||||||
|
throw runtime_error("Error getting host by name");
|
||||||
|
}
|
||||||
|
|
||||||
|
address= reinterpret_cast<unsigned char*>(info->h_addr_list[0]);
|
||||||
|
|
||||||
|
if(address==NULL){
|
||||||
|
throw runtime_error("Error getting host ip");
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
intToStr(address[0]) + "." +
|
||||||
|
intToStr(address[1]) + "." +
|
||||||
|
intToStr(address[2]) + "." +
|
||||||
|
intToStr(address[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::throwException(const string &str){
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << str << " (Error: " << strerror(errno) << ")";
|
||||||
|
throw runtime_error(msg.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// class ClientSocket
|
||||||
|
// ===============================================
|
||||||
|
|
||||||
|
void ClientSocket::connect(const Ip &ip, int port)
|
||||||
|
{
|
||||||
|
sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
|
||||||
|
addr.sin_family= AF_INET;
|
||||||
|
addr.sin_addr.s_addr= inet_addr(ip.getString().c_str());
|
||||||
|
addr.sin_port= htons(port);
|
||||||
|
|
||||||
|
int err= ::connect(sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr));
|
||||||
|
if(err < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] #2 Error connecting socket for IP: %s for Port: %d err = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,ip.getString().c_str(),port,err,errno,strerror(errno));
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
|
||||||
|
if (errno == EINPROGRESS)
|
||||||
|
{
|
||||||
|
fd_set myset;
|
||||||
|
struct timeval tv;
|
||||||
|
int valopt;
|
||||||
|
socklen_t lon;
|
||||||
|
|
||||||
|
fprintf(stderr, "In [%s::%s] EINPROGRESS in connect() - selecting\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tv.tv_sec = 10;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
FD_ZERO(&myset);
|
||||||
|
FD_SET(sock, &myset);
|
||||||
|
|
||||||
|
err = select(sock+1, NULL, &myset, NULL, &tv);
|
||||||
|
|
||||||
|
if (err < 0 && errno != EINTR)
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "In [%s::%s] Error connecting %d - [%s]\n",__FILE__,__FUNCTION__,errno, strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (err > 0)
|
||||||
|
{
|
||||||
|
// Socket selected for write
|
||||||
|
lon = sizeof(int);
|
||||||
|
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0)
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "In [%s::%s] Error in getsockopt() %d - [%s]\n",__FILE__,__FUNCTION__,errno, strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Check the value returned...
|
||||||
|
if (valopt)
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "In [%s::%s] Error in delayed connection() %d - [%s]\n",__FILE__,__FUNCTION__,valopt, strerror(valopt));
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
fprintf(stderr, "In [%s::%s] Apparent recovery for connection sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "In [%s::%s] Timeout in select() - Cancelling!\n",__FILE__,__FUNCTION__);
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
|
||||||
|
disconnectSocket();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "In [%s::%s] Before END sock = %d, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,sock,err,errno,strerror(errno));
|
||||||
|
//throwException(szBuf);
|
||||||
|
disconnectSocket();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "In [%s::%s] Valid recovery for connection sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// class ServerSocket
|
||||||
|
// ===============================================
|
||||||
|
|
||||||
|
void ServerSocket::bind(int port)
|
||||||
|
{
|
||||||
|
//sockaddr structure
|
||||||
|
sockaddr_in addr;
|
||||||
|
addr.sin_family= AF_INET;
|
||||||
|
addr.sin_addr.s_addr= INADDR_ANY;
|
||||||
|
addr.sin_port= htons(port);
|
||||||
|
|
||||||
|
int val = 1;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||||
|
|
||||||
|
int err= ::bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
|
||||||
|
if(err < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf, "In [%s::%s] Error binding socket sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
|
||||||
|
throwException(szBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerSocket::listen(int connectionQueueSize)
|
||||||
|
{
|
||||||
|
int err= ::listen(sock, connectionQueueSize);
|
||||||
|
if(err < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf, "In [%s::%s] Error listening socket sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
|
||||||
|
throwException(szBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket *ServerSocket::accept()
|
||||||
|
{
|
||||||
|
int newSock= ::accept(sock, NULL, NULL);
|
||||||
|
if(newSock < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf(szBuf, "In [%s::%s] Error accepting socket connection sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,newSock,errno);
|
||||||
|
|
||||||
|
if(errno == EAGAIN)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
throwException(szBuf);
|
||||||
|
|
||||||
|
}
|
||||||
|
return new Socket(newSock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}}//end namespace
|
||||||
|
|
797
source/shared_lib/sources/platform/win32/socket.cpp
Normal file
797
source/shared_lib/sources/platform/win32/socket.cpp
Normal file
|
@ -0,0 +1,797 @@
|
||||||
|
// ==============================================================
|
||||||
|
// This file is part of Glest Shared Library (www.glest.org)
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001-2007 Marti<74>o Figueroa
|
||||||
|
//
|
||||||
|
// You can redistribute this code and/or modify it under
|
||||||
|
// the terms of the GNU General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "conversion.h"
|
||||||
|
|
||||||
|
#include "leak_dumper.h"
|
||||||
|
#include <time.h>
|
||||||
|
#include <strstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#define socklen_t int
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Shared::Util;
|
||||||
|
|
||||||
|
#define MAXHOSTNAME 254
|
||||||
|
//// Constants /////////////////////////////////////////////////////////
|
||||||
|
const int kBufferSize = 1024;
|
||||||
|
|
||||||
|
//// Statics ///////////////////////////////////////////////////////////
|
||||||
|
// List of Winsock error constants mapped to an interpretation string.
|
||||||
|
// Note that this list must remain sorted by the error constants'
|
||||||
|
// values, because we do a binary search on the list when looking up
|
||||||
|
// items.
|
||||||
|
|
||||||
|
static class ErrorEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int nID;
|
||||||
|
const char* pcMessage;
|
||||||
|
|
||||||
|
ErrorEntry(int id, const char* pc = 0) : nID(id), pcMessage(pc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const ErrorEntry& rhs)
|
||||||
|
{
|
||||||
|
return nID < rhs.nID;
|
||||||
|
}
|
||||||
|
|
||||||
|
} gaErrorList[] =
|
||||||
|
{
|
||||||
|
ErrorEntry(0, "No error"),
|
||||||
|
ErrorEntry(WSAEINTR, "Interrupted system call"),
|
||||||
|
ErrorEntry(WSAEBADF, "Bad file number"),
|
||||||
|
ErrorEntry(WSAEACCES, "Permission denied"),
|
||||||
|
ErrorEntry(WSAEFAULT, "Bad address"),
|
||||||
|
ErrorEntry(WSAEINVAL, "Invalid argument"),
|
||||||
|
ErrorEntry(WSAEMFILE, "Too many open sockets"),
|
||||||
|
ErrorEntry(WSAEWOULDBLOCK, "Operation would block"),
|
||||||
|
ErrorEntry(WSAEINPROGRESS, "Operation now in progress"),
|
||||||
|
ErrorEntry(WSAEALREADY, "Operation already in progress"),
|
||||||
|
ErrorEntry(WSAENOTSOCK, "Socket operation on non-socket"),
|
||||||
|
ErrorEntry(WSAEDESTADDRREQ, "Destination address required"),
|
||||||
|
ErrorEntry(WSAEMSGSIZE, "Message too long"),
|
||||||
|
ErrorEntry(WSAEPROTOTYPE, "Protocol wrong type for socket"),
|
||||||
|
ErrorEntry(WSAENOPROTOOPT, "Bad protocol option"),
|
||||||
|
ErrorEntry(WSAEPROTONOSUPPORT, "Protocol not supported"),
|
||||||
|
ErrorEntry(WSAESOCKTNOSUPPORT, "Socket type not supported"),
|
||||||
|
ErrorEntry(WSAEOPNOTSUPP, "Operation not supported on socket"),
|
||||||
|
ErrorEntry(WSAEPFNOSUPPORT, "Protocol family not supported"),
|
||||||
|
ErrorEntry(WSAEAFNOSUPPORT, "Address family not supported"),
|
||||||
|
ErrorEntry(WSAEADDRINUSE, "Address already in use"),
|
||||||
|
ErrorEntry(WSAEADDRNOTAVAIL, "Can't assign requested address"),
|
||||||
|
ErrorEntry(WSAENETDOWN, "Network is down"),
|
||||||
|
ErrorEntry(WSAENETUNREACH, "Network is unreachable"),
|
||||||
|
ErrorEntry(WSAENETRESET, "Net connection reset"),
|
||||||
|
ErrorEntry(WSAECONNABORTED, "Software caused connection abort"),
|
||||||
|
ErrorEntry(WSAECONNRESET, "Connection reset by peer"),
|
||||||
|
ErrorEntry(WSAENOBUFS, "No buffer space available"),
|
||||||
|
ErrorEntry(WSAEISCONN, "Socket is already connected"),
|
||||||
|
ErrorEntry(WSAENOTCONN, "Socket is not connected"),
|
||||||
|
ErrorEntry(WSAESHUTDOWN, "Can't send after socket shutdown"),
|
||||||
|
ErrorEntry(WSAETOOMANYREFS, "Too many references, can't splice"),
|
||||||
|
ErrorEntry(WSAETIMEDOUT, "Connection timed out"),
|
||||||
|
ErrorEntry(WSAECONNREFUSED, "Connection refused"),
|
||||||
|
ErrorEntry(WSAELOOP, "Too many levels of symbolic links"),
|
||||||
|
ErrorEntry(WSAENAMETOOLONG, "File name too long"),
|
||||||
|
ErrorEntry(WSAEHOSTDOWN, "Host is down"),
|
||||||
|
ErrorEntry(WSAEHOSTUNREACH, "No route to host"),
|
||||||
|
ErrorEntry(WSAENOTEMPTY, "Directory not empty"),
|
||||||
|
ErrorEntry(WSAEPROCLIM, "Too many processes"),
|
||||||
|
ErrorEntry(WSAEUSERS, "Too many users"),
|
||||||
|
ErrorEntry(WSAEDQUOT, "Disc quota exceeded"),
|
||||||
|
ErrorEntry(WSAESTALE, "Stale NFS file handle"),
|
||||||
|
ErrorEntry(WSAEREMOTE, "Too many levels of remote in path"),
|
||||||
|
ErrorEntry(WSASYSNOTREADY, "Network system is unavailable"),
|
||||||
|
ErrorEntry(WSAVERNOTSUPPORTED, "Winsock version out of range"),
|
||||||
|
ErrorEntry(WSANOTINITIALISED, "WSAStartup not yet called"),
|
||||||
|
ErrorEntry(WSAEDISCON, "Graceful shutdown in progress"),
|
||||||
|
ErrorEntry(WSAHOST_NOT_FOUND, "Host not found"),
|
||||||
|
ErrorEntry(WSANO_DATA, "No host data of that type was found")
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator<(const ErrorEntry& rhs1,const ErrorEntry& rhs2)
|
||||||
|
{
|
||||||
|
return rhs1.nID < rhs2.nID;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int kNumMessages = sizeof(gaErrorList) / sizeof(ErrorEntry);
|
||||||
|
|
||||||
|
//// WSAGetLastErrorMessage ////////////////////////////////////////////
|
||||||
|
// A function similar in spirit to Unix's perror() that tacks a canned
|
||||||
|
// interpretation of the value of WSAGetLastError() onto the end of a
|
||||||
|
// passed string, separated by a ": ". Generally, you should implement
|
||||||
|
// smarter error handling than this, but for default cases and simple
|
||||||
|
// programs, this function is sufficient.
|
||||||
|
//
|
||||||
|
// This function returns a pointer to an internal static buffer, so you
|
||||||
|
// must copy the data from this function before you call it again. It
|
||||||
|
// follows that this function is also not thread-safe.
|
||||||
|
const char* WSAGetLastErrorMessage(const char* pcMessagePrefix,
|
||||||
|
int nErrorID /* = 0 */)
|
||||||
|
{
|
||||||
|
// Build basic error string
|
||||||
|
static char acErrorBuffer[256];
|
||||||
|
std::ostrstream outs(acErrorBuffer, sizeof(acErrorBuffer));
|
||||||
|
outs << pcMessagePrefix << ": ";
|
||||||
|
|
||||||
|
// Tack appropriate canned message onto end of supplied message
|
||||||
|
// prefix. Note that we do a binary search here: gaErrorList must be
|
||||||
|
// sorted by the error constant's value.
|
||||||
|
ErrorEntry* pEnd = gaErrorList + kNumMessages;
|
||||||
|
ErrorEntry Target(nErrorID ? nErrorID : WSAGetLastError());
|
||||||
|
ErrorEntry* it = std::lower_bound(gaErrorList, pEnd, Target);
|
||||||
|
if ((it != pEnd) && (it->nID == Target.nID))
|
||||||
|
{
|
||||||
|
outs << it->pcMessage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Didn't find error in list, so make up a generic one
|
||||||
|
outs << "unknown error";
|
||||||
|
}
|
||||||
|
outs << " (" << Target.nID << ")";
|
||||||
|
|
||||||
|
// Finish error message off and return it.
|
||||||
|
outs << std::ends;
|
||||||
|
acErrorBuffer[sizeof(acErrorBuffer) - 1] = '\0';
|
||||||
|
return acErrorBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Shared{ namespace Platform{
|
||||||
|
|
||||||
|
bool Socket::enableDebugText = true;
|
||||||
|
bool Socket::enableNetworkDebugInfo = true;
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Ip
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
Ip::Ip(){
|
||||||
|
bytes[0]= 0;
|
||||||
|
bytes[1]= 0;
|
||||||
|
bytes[2]= 0;
|
||||||
|
bytes[3]= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ip::Ip(unsigned char byte0, unsigned char byte1, unsigned char byte2, unsigned char byte3){
|
||||||
|
bytes[0]= byte0;
|
||||||
|
bytes[1]= byte1;
|
||||||
|
bytes[2]= byte2;
|
||||||
|
bytes[3]= byte3;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ip::Ip(const string& ipString){
|
||||||
|
int offset= 0;
|
||||||
|
int byteIndex= 0;
|
||||||
|
|
||||||
|
for(byteIndex= 0; byteIndex<4; ++byteIndex){
|
||||||
|
int dotPos= ipString.find_first_of('.', offset);
|
||||||
|
|
||||||
|
bytes[byteIndex]= atoi(ipString.substr(offset, dotPos-offset).c_str());
|
||||||
|
offset= dotPos+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string Ip::getString() const{
|
||||||
|
return intToStr(bytes[0]) + "." + intToStr(bytes[1]) + "." + intToStr(bytes[2]) + "." + intToStr(bytes[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Socket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
Socket::SocketManager Socket::socketManager;
|
||||||
|
|
||||||
|
Socket::SocketManager::SocketManager(){
|
||||||
|
WSADATA wsaData;
|
||||||
|
WORD wVersionRequested = MAKEWORD(2, 0);
|
||||||
|
WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
//dont throw exceptions here, this is a static initializacion
|
||||||
|
printf("Winsock initialized.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::SocketManager::~SocketManager(){
|
||||||
|
WSACleanup();
|
||||||
|
printf("Winsock cleanup complete.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::Socket(SOCKET sock){
|
||||||
|
this->sock= sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::Socket(){
|
||||||
|
sock= socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||||
|
if(sock==INVALID_SOCKET){
|
||||||
|
throwException("Error creating socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::~Socket()
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::disconnectSocket()
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
::shutdown(sock,2);
|
||||||
|
::closesocket(sock);
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int lookup is socket fd while bool result is whether or not that socket was signalled for reading
|
||||||
|
bool Socket::hasDataToRead(std::map<int,bool> &socketTriggeredList)
|
||||||
|
{
|
||||||
|
bool bResult = false;
|
||||||
|
|
||||||
|
if(socketTriggeredList.size() > 0)
|
||||||
|
{
|
||||||
|
/* Watch stdin (fd 0) to see when it has input. */
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
|
||||||
|
int imaxsocket = 0;
|
||||||
|
for(std::map<int,bool>::iterator itermap = socketTriggeredList.begin();
|
||||||
|
itermap != socketTriggeredList.end(); itermap++)
|
||||||
|
{
|
||||||
|
int socket = itermap->first;
|
||||||
|
if(socket > 0)
|
||||||
|
{
|
||||||
|
FD_SET(socket, &rfds);
|
||||||
|
imaxsocket = max(socket,imaxsocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(imaxsocket > 0)
|
||||||
|
{
|
||||||
|
/* Wait up to 0 seconds. */
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] ERROR SELECTING SOCKET DATA retval = %d WSAGetLastError() = %d",__FILE__,__FUNCTION__,retval,WSAGetLastError());
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
}
|
||||||
|
else if(retval)
|
||||||
|
{
|
||||||
|
bResult = true;
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] select detected data imaxsocket = %d...\n",__FILE__,__FUNCTION__,imaxsocket);
|
||||||
|
|
||||||
|
for(std::map<int,bool>::iterator itermap = socketTriggeredList.begin();
|
||||||
|
itermap != socketTriggeredList.end(); itermap++)
|
||||||
|
{
|
||||||
|
int socket = itermap->first;
|
||||||
|
if (FD_ISSET(socket, &rfds))
|
||||||
|
{
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s] FD_ISSET true for socket %d...\n",__FUNCTION__,socket);
|
||||||
|
|
||||||
|
itermap->second = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
itermap->second = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socketTriggeredList->size() = %d\n",__FILE__,__FUNCTION__,socketTriggeredList.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::hasDataToRead()
|
||||||
|
{
|
||||||
|
return Socket::hasDataToRead(sock) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::hasDataToRead(int socket)
|
||||||
|
{
|
||||||
|
bool bResult = false;
|
||||||
|
|
||||||
|
if(socket > 0)
|
||||||
|
{
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
/* Watch stdin (fd 0) to see when it has input. */
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(socket, &rfds);
|
||||||
|
|
||||||
|
/* Wait up to 0 seconds. */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int retval = select(socket + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
if(retval)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(socket, &rfds))
|
||||||
|
{
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::getDataToRead(){
|
||||||
|
unsigned long size = 0;
|
||||||
|
|
||||||
|
//fd_set rfds;
|
||||||
|
//struct timeval tv;
|
||||||
|
//int retval;
|
||||||
|
|
||||||
|
/* Watch stdin (fd 0) to see when it has input. */
|
||||||
|
//FD_ZERO(&rfds);
|
||||||
|
//FD_SET(sock, &rfds);
|
||||||
|
|
||||||
|
/* Wait up to 0 seconds. */
|
||||||
|
//tv.tv_sec = 0;
|
||||||
|
//tv.tv_usec = 0;
|
||||||
|
|
||||||
|
//retval = select(sock + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
//if(retval)
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
/* ioctl isn't posix, but the following seems to work on all modern
|
||||||
|
* unixes */
|
||||||
|
int err= ioctlsocket(sock, FIONREAD, &size);
|
||||||
|
|
||||||
|
if(err < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] ERROR PEEKING SOCKET DATA, err = %d WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,err,WSAGetLastError());
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
else if(err == 0)
|
||||||
|
{
|
||||||
|
//if(Socket::enableNetworkDebugInfo) printf("In [%s] ioctl returned = %d, size = %ld\n",__FUNCTION__,err,size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<int>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::send(const void *data, int dataSize) {
|
||||||
|
int bytesSent= 0;
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
|
||||||
|
}
|
||||||
|
if(bytesSent < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"In [%s::%s] ERROR WRITING SOCKET DATA, err = %d WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,bytesSent,WSAGetLastError());
|
||||||
|
//throwException(szBuf);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
else if(bytesSent < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
printf("In [%s::%s] #1 WSAEWOULDBLOCK during send, trying again...\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
time_t tStartTimer = time(NULL);
|
||||||
|
while((bytesSent < 0 && WSAGetLastError() == WSAEWOULDBLOCK) && (difftime(time(NULL),tStartTimer) <= 5))
|
||||||
|
{
|
||||||
|
if(Socket::isWritable(true) == true)
|
||||||
|
{
|
||||||
|
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
|
||||||
|
|
||||||
|
printf("In [%s::%s] #2 WSAEWOULDBLOCK during send, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesSent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bytesSent <= 0)
|
||||||
|
{
|
||||||
|
int iErr = WSAGetLastError();
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while sending socket data, bytesSent = %d, WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,bytesSent,iErr);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] sock = %d, bytesSent = %d\n",__FILE__,__FUNCTION__,sock,bytesSent);
|
||||||
|
|
||||||
|
return static_cast<int>(bytesSent);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::receive(void *data, int dataSize)
|
||||||
|
{
|
||||||
|
int bytesReceived = 0;
|
||||||
|
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
|
||||||
|
}
|
||||||
|
if(bytesReceived < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] ERROR READING SOCKET DATA error while sending socket data, bytesSent = %d, WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,bytesReceived,WSAGetLastError());
|
||||||
|
//throwException(szBuf);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
else if(bytesReceived < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
printf("In [%s::%s] #1 WSAEWOULDBLOCK during receive, trying again...\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
time_t tStartTimer = time(NULL);
|
||||||
|
while((bytesReceived < 0 && WSAGetLastError() == WSAEWOULDBLOCK) && (difftime(time(NULL),tStartTimer) <= 5))
|
||||||
|
{
|
||||||
|
if(Socket::isReadable() == true)
|
||||||
|
{
|
||||||
|
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
|
||||||
|
|
||||||
|
printf("In [%s::%s] #2 WSAEWOULDBLOCK during receive, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesReceived);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bytesReceived <= 0)
|
||||||
|
{
|
||||||
|
int iErr = WSAGetLastError();
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while receiving socket data, bytesReceived = %d, WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,bytesReceived,iErr);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
return static_cast<int>(bytesReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Socket::peek(void *data, int dataSize){
|
||||||
|
int err = 0;
|
||||||
|
if(sock > 0)
|
||||||
|
{
|
||||||
|
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
|
||||||
|
}
|
||||||
|
if(err < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] ERROR PEEKING SOCKET DATA error while sending socket data, bytesSent = %d, WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,err,WSAGetLastError());
|
||||||
|
//throwException(szBuf);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
else if(err < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
printf("In [%s::%s] #1 WSAEWOULDBLOCK during peek, trying again...\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
time_t tStartTimer = time(NULL);
|
||||||
|
while((err < 0 && WSAGetLastError() == WSAEWOULDBLOCK) && (difftime(time(NULL),tStartTimer) <= 5))
|
||||||
|
{
|
||||||
|
if(Socket::isReadable() == true)
|
||||||
|
{
|
||||||
|
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
|
||||||
|
|
||||||
|
printf("In [%s::%s] #2 WSAEWOULDBLOCK during peek, trying again returned: %d\n",__FILE__,__FUNCTION__,err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err <= 0)
|
||||||
|
{
|
||||||
|
int iErr = WSAGetLastError();
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while peeking socket data, err = %d, WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,err,iErr);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
//throwException(szBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<int>(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::setBlock(bool block){
|
||||||
|
u_long iMode= !
|
||||||
|
block;
|
||||||
|
int err= ioctlsocket(sock, FIONBIO, &iMode);
|
||||||
|
if(err==SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
throwException("Error setting I/O mode for socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::isReadable()
|
||||||
|
{
|
||||||
|
if(sock <= 0) return false;
|
||||||
|
|
||||||
|
TIMEVAL tv;
|
||||||
|
tv.tv_sec= 0;
|
||||||
|
tv.tv_usec= 1;
|
||||||
|
|
||||||
|
fd_set set;
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(sock, &set);
|
||||||
|
|
||||||
|
int i= select(sock+1, &set, NULL, NULL, &tv);
|
||||||
|
if(i==SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] error while selecting socket data, err = %d, errno = %d\n",__FILE__,__FUNCTION__,i,WSAGetLastError());
|
||||||
|
printf("%s",szBuf);
|
||||||
|
}
|
||||||
|
//return (i == 1 && FD_ISSET(sock, &set));
|
||||||
|
return (i == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::isWritable(bool waitOnDelayedResponse)
|
||||||
|
{
|
||||||
|
if(sock <= 0) return false;
|
||||||
|
|
||||||
|
TIMEVAL tv;
|
||||||
|
tv.tv_sec= 0;
|
||||||
|
tv.tv_usec= 1;
|
||||||
|
|
||||||
|
fd_set set;
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(sock, &set);
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int i= select(sock+1, NULL, &set, NULL, &tv);
|
||||||
|
if(i==SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] error while selecting socket data, err = %d, errno = %d\n",__FILE__,__FUNCTION__,i,WSAGetLastError());
|
||||||
|
printf("%s",szBuf);
|
||||||
|
waitOnDelayedResponse = false;
|
||||||
|
}
|
||||||
|
else if(i == 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] TIMEOUT while selecting socket data, err = %d, errno = %d\n",__FILE__,__FUNCTION__,i,WSAGetLastError());
|
||||||
|
printf("%s",szBuf);
|
||||||
|
|
||||||
|
if(waitOnDelayedResponse == false)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
} while(waitOnDelayedResponse == true && result == false);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::isConnected(){
|
||||||
|
|
||||||
|
//if the socket is not writable then it is not conencted
|
||||||
|
if(isWritable(false) == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the socket is readable it is connected if we can read a byte from it
|
||||||
|
if(isReadable())
|
||||||
|
{
|
||||||
|
char tmp;
|
||||||
|
int err = peek(&tmp, sizeof(tmp));
|
||||||
|
return (err > 0);
|
||||||
|
/*
|
||||||
|
int err = recv(sock, &tmp, sizeof(tmp), MSG_PEEK);
|
||||||
|
|
||||||
|
if(err <= 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
int iErr = WSAGetLastError();
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"[%s::%s] DISCONNECTED SOCKET error while peeking isconnected socket data, err = %d, WSAGetLastError() = %d\n",__FILE__,__FUNCTION__,err,iErr);
|
||||||
|
printf("%s",szBuf);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise the socket is connected
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Socket::getHostName() const{
|
||||||
|
const int strSize= 256;
|
||||||
|
char hostname[strSize];
|
||||||
|
gethostname(hostname, strSize);
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Socket::getIp() const{
|
||||||
|
hostent* info= gethostbyname(getHostName().c_str());
|
||||||
|
unsigned char* address;
|
||||||
|
|
||||||
|
if(info==NULL)
|
||||||
|
{
|
||||||
|
throwException("Error getting host by name");
|
||||||
|
}
|
||||||
|
|
||||||
|
address= reinterpret_cast<unsigned char*>(info->h_addr_list[0]);
|
||||||
|
|
||||||
|
if(address==NULL)
|
||||||
|
{
|
||||||
|
throwException("Error getting host ip");
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
intToStr(address[0]) + "." +
|
||||||
|
intToStr(address[1]) + "." +
|
||||||
|
intToStr(address[2]) + "." +
|
||||||
|
intToStr(address[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::throwException(const string &str){
|
||||||
|
throw runtime_error("Network error: " + str+" (Code: " + intToStr(WSAGetLastError())+")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ClientSocket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
void ClientSocket::connect(const Ip &ip, int port)
|
||||||
|
{
|
||||||
|
sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
|
||||||
|
addr.sin_family= AF_INET;
|
||||||
|
addr.sin_addr.s_addr= inet_addr(ip.getString().c_str());
|
||||||
|
addr.sin_port= htons(port);
|
||||||
|
|
||||||
|
fprintf(stderr, "Connecting to host [%s] on port = %d\n", ip.getString().c_str(),port);
|
||||||
|
|
||||||
|
int err= ::connect(sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr));
|
||||||
|
if(err < 0)
|
||||||
|
{
|
||||||
|
char szBuf[1024]="";
|
||||||
|
sprintf(szBuf,"#2 Error connecting socket for IP: %s for Port: %d err = %d WSAGetLastError() = %d",ip.getString().c_str(),port,err,WSAGetLastError());
|
||||||
|
fprintf(stderr, "%s\n", WSAGetLastErrorMessage(szBuf));
|
||||||
|
//fprintf(stderr, "%s", szBuf);
|
||||||
|
|
||||||
|
if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
fd_set myset;
|
||||||
|
struct timeval tv;
|
||||||
|
int valopt;
|
||||||
|
socklen_t lon;
|
||||||
|
|
||||||
|
fprintf(stderr, "WSAEINPROGRESS or WSAEWOULDBLOCK in connect() - selecting\n");
|
||||||
|
do {
|
||||||
|
tv.tv_sec = 10;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
FD_ZERO(&myset);
|
||||||
|
FD_SET(sock, &myset);
|
||||||
|
|
||||||
|
err = select(0, NULL, &myset, NULL, &tv);
|
||||||
|
|
||||||
|
if (err < 0 && WSAGetLastError() != WSAEWOULDBLOCK && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "Error connecting %d\n", WSAGetLastError());
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (err > 0) {
|
||||||
|
// Socket selected for write
|
||||||
|
lon = sizeof(int);
|
||||||
|
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)(&valopt), &lon) < 0)
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "Error in getsockopt() %d\n", WSAGetLastError());
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Check the value returned...
|
||||||
|
if (valopt)
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "Error in delayed connection() %d\n", valopt);
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Apparent recovery for connection sock = %d, err = %d, WSAGetLastError() = %d\n",sock,err,WSAGetLastError());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(szBuf, "Timeout in select() - Cancelling!\n");
|
||||||
|
//throwException(szBuf);
|
||||||
|
fprintf(stderr, "%s", szBuf);
|
||||||
|
|
||||||
|
disconnectSocket();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "In [%s::%s] Before END sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,WSAGetLastError());
|
||||||
|
//throwException(szBuf);
|
||||||
|
disconnectSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Valid recovery for connection sock = %d, err = %d, WSAGetLastError() = %d\n",sock,err,WSAGetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Connected to host [%s] on port = %d sock = %d err = %d", ip.getString().c_str(),port,err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class ServerSocket
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
void ServerSocket::bind(int port){
|
||||||
|
//sockaddr structure
|
||||||
|
sockaddr_in addr;
|
||||||
|
addr.sin_family= AF_INET;
|
||||||
|
addr.sin_addr.s_addr= INADDR_ANY;
|
||||||
|
addr.sin_port= htons(port);
|
||||||
|
|
||||||
|
int err= ::bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
|
||||||
|
if(err==SOCKET_ERROR){
|
||||||
|
throwException("Error binding socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerSocket::listen(int connectionQueueSize){
|
||||||
|
int err= ::listen(sock, connectionQueueSize);
|
||||||
|
if(err==SOCKET_ERROR){
|
||||||
|
throwException("Error listening socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket *ServerSocket::accept(){
|
||||||
|
SOCKET newSock= ::accept(sock, NULL, NULL);
|
||||||
|
if(newSock==INVALID_SOCKET){
|
||||||
|
if(WSAGetLastError()==WSAEWOULDBLOCK){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
throwException("Error accepting socket connection");
|
||||||
|
}
|
||||||
|
return new Socket(newSock);
|
||||||
|
}
|
||||||
|
|
||||||
|
}}//end namespace
|
Loading…
Reference in New Issue
Block a user