Add classes CHost and CUDPSocket.

This commit is contained in:
joris 2013-04-04 23:59:29 +02:00
parent 3c8cbe8e84
commit af53391cee
13 changed files with 487 additions and 166 deletions

View file

@ -229,6 +229,7 @@ set(network_SRCS
src/network/master.cpp
src/network/netconnect.cpp
src/network/network.cpp
src/network/udpsocket.cpp
)
source_group(network FILES ${network_SRCS})
@ -534,6 +535,7 @@ set(stratagus_generic_HDRS
src/include/net_message.h
src/include/netconnect.h
src/include/network.h
src/include/network/udpsocket.h
src/include/parameters.h
src/include/particle.h
src/include/pathfinder.h

View file

@ -114,8 +114,8 @@ extern unsigned long NetResolveHost(const std::string &host);
/// Get local IP from network file descriptor
extern int NetSocketAddr(const Socket sock, unsigned long *ips, int maxAddr);
/// Open a UDP Socket port.
extern Socket NetOpenUDP(const char *addr, int port);
/// Open a UDP Socket port. (param in network format)
extern Socket NetOpenUDP(unsigned long ip, int port);
/// Close a UDP socket port.
extern void NetCloseUDP(Socket sockfd);
/// Send through a UPD socket to a host:port.

View file

@ -33,6 +33,8 @@
#include "net_message.h"
class CHost;
/*----------------------------------------------------------------------------
-- Defines
----------------------------------------------------------------------------*/
@ -101,7 +103,7 @@ extern CServerSetup LocalSetupState; /// Network menu: Multiplayer Client
-- Functions
----------------------------------------------------------------------------*/
extern int FindHostIndexBy(unsigned long ip, int port);
extern int FindHostIndexBy(const CHost &host);
extern void NetworkServerStartGame(); /// Server user has finally hit the start game button
extern void NetworkGamePrepareGameSettings();
@ -109,7 +111,7 @@ extern int GetNetworkState();
extern void NetworkInitClientConnect(); /// Setup network connect state machine for clients
extern void NetworkInitServerConnect(int openslots); /// Setup network connect state machine for the server
extern int NetworkParseSetupEvent(const unsigned char *buf, int size, unsigned long host, int port); /// Parse a network connect event
extern int NetworkParseSetupEvent(const unsigned char *buf, int size, const CHost &host); /// Parse a network connect event
extern int NetworkSetupServerAddress(const std::string &serveraddr, int port); /// Menu: Setup the server IP
extern void NetworkProcessClientRequest(); /// Menu Loop: Send out client request messages
extern void NetworkProcessServerRequest(); /// Menu Loop: Send out server request messages

View file

@ -35,15 +35,12 @@
-- Includes
----------------------------------------------------------------------------*/
#include <stdint.h>
#include "net_lowlevel.h"
#include "network/udpsocket.h"
/*----------------------------------------------------------------------------
-- Defines
----------------------------------------------------------------------------*/
#define IsNetworkGame() (NetworkFildes != (Socket)-1)
#define NetworkDefaultPort 6660 /// Default communication port
/*----------------------------------------------------------------------------
@ -59,7 +56,7 @@ class CUnitType;
extern char *NetworkAddr; /// Local network address to use
extern int NetworkPort; /// Local network port to use
extern Socket NetworkFildes; /// Network file descriptor
extern CUDPSocket NetworkFildes; /// Network file descriptor
extern int NetworkInSync; /// Network is in sync
extern int NetworkUpdates; /// Network update each # game cycles
extern int NetworkLag; /// Network lag (# game cycles)
@ -68,6 +65,7 @@ extern int NetworkLag; /// Network lag (# game cycles)
-- Functions
----------------------------------------------------------------------------*/
extern inline bool IsNetworkGame() { return NetworkFildes.IsValid(); }
extern void InitNetwork1(); /// Initialise network part 1 (ports)
extern void InitNetwork2(); /// Initialise network part 2
extern void ExitNetwork1(); /// Cleanup network part 1 (ports)

View file

@ -0,0 +1,75 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name udpsocket.h - The udp socket header file. */
//
// (c) Copyright 2013 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#ifndef UDPSOCKET_H
#define UDPSOCKET_H
#include <string>
//@{
class CHost
{
public:
CHost() : ip(0), port(0) {}
CHost(const char *name, int port);
CHost(unsigned long ip, int port) : ip(ip), port(port) {}
unsigned long getIp() const { return ip; }
int getPort() const { return port; }
std::string toString() const;
bool isValid() const;
bool operator == (const CHost &rhs) const { return ip == rhs.ip && port == rhs.port; }
bool operator != (const CHost &rhs) const { return !(*this == rhs); }
private:
unsigned long ip;
int port;
};
class CUDPSocket_Impl;
class CUDPSocket
{
public:
CUDPSocket();
~CUDPSocket();
bool Open(const CHost &host);
void Close();
void Send(const CHost &host, const void *buf, unsigned int len);
int Recv(void *buf, int len, CHost *hostFrom);
void SetNonBlocking();
//
int HasDataToRead(int timeout);
bool IsValid() const;
private:
CUDPSocket_Impl *m_impl;
};
//@}
#endif // !UDPSOCKET_H

View file

@ -351,11 +351,12 @@ int NetSocketAddr(const Socket sock, unsigned long *ips, int maxAddr)
/**
** Open an UDP Socket port.
**
** @param ip !=0 Ip to bind in host notation.
** @param port !=0 Port to bind in host notation.
**
** @return If success the socket fildes, -1 otherwise.
*/
Socket NetOpenUDP(const char *addr, int port)
Socket NetOpenUDP(unsigned long ip, int port)
{
// open the socket
Socket sockfd = socket(AF_INET, SOCK_DGRAM, 0);
@ -369,12 +370,8 @@ Socket NetOpenUDP(const char *addr, int port)
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
if (addr) {
sock_addr.sin_addr.s_addr = inet_addr(addr);
} else {
sock_addr.sin_addr.s_addr = INADDR_ANY;
}
sock_addr.sin_port = htons(port);
sock_addr.sin_addr.s_addr = ip;
sock_addr.sin_port = port;
// Bind the socket for listening
if (bind(sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) {
fprintf(stderr, "Couldn't bind to local port\n");

View file

@ -40,7 +40,6 @@
#include "interface.h"
#include "map.h"
#include "master.h"
#include "net_lowlevel.h"
#include "network.h"
#include "parameters.h"
#include "player.h"
@ -97,12 +96,12 @@ public:
void Init(const std::string &name, CServerSetup *serverSetup);
void Update(unsigned long frameCounter);
void Parse(unsigned long frameCounter, const unsigned char *buf, unsigned long host, int port);
void Parse(unsigned long frameCounter, const unsigned char *buf, const CHost &host);
void MarkClientsAsResync();
void KickClient(int c);
private:
int Parse_Hello(int h, const CInitMessage_Hello &msg, unsigned long host, int port);
int Parse_Hello(int h, const CInitMessage_Hello &msg, const CHost &host);
void Parse_Resync(const int h);
void Parse_Waiting(const int h);
void Parse_Map(const int h);
@ -111,7 +110,7 @@ private:
void Parse_SeeYou(const int h);
void Send_AreYouThere(const CNetworkHost &host);
void Send_GameFull(unsigned long host, int port);
void Send_GameFull(const CHost &host);
void Send_Welcome(const CNetworkHost &host, int hostIndex);
void Send_Resync(const CNetworkHost &host, int hostIndex);
void Send_Map(const CNetworkHost &host);
@ -127,18 +126,15 @@ class CClient
{
public:
void Init(const std::string &name, CServerSetup *serverSetup, CServerSetup *localSetup, unsigned long tick);
bool SetupServerAddress(const std::string &serveraddr, int port);
void SetServerHost(const CHost &host) { serverHost = host; }
bool Parse(const unsigned char *buf, unsigned long host, int port);
bool Parse(const unsigned char *buf, const CHost &host);
bool Update(unsigned long tick);
void DetachFromServer();
int GetNetworkState() const { return networkState.State; }
unsigned long GetServerIP() const { return ntohl(serverIP); }
int GetServerPort() const { return ntohs(serverPort); }
private:
bool Update_disconnected();
bool Update_detaching(unsigned long tick);
@ -179,8 +175,7 @@ private:
private:
std::string name;
unsigned long serverIP; /// IP of server to join
int serverPort; /// Server network port to use
CHost serverHost; /// IP:port of server to join
NetworkState networkState;
unsigned char lastMsgTypeSent; /// Subtype of last InitConfig message sent
CServerSetup *serverSetup;
@ -202,18 +197,18 @@ static CClient Client;
** @param msg The message to send
*/
template <typename T>
static void NetworkSendICMessage(unsigned long host, int port, const T &msg)
static void NetworkSendICMessage(const CHost &host, const T &msg)
{
const unsigned char *buf = msg.Serialize();
NetSendUDP(NetworkFildes, host, port, buf, msg.Size());
NetworkFildes.Send(host, buf, msg.Size());
delete[] buf;
}
void NetworkSendICMessage(unsigned long host, int port, const CInitMessage_Header &msg)
void NetworkSendICMessage(const CHost &host, const CInitMessage_Header &msg)
{
unsigned char *buf = new unsigned char [msg.Size()];
msg.Serialize(buf);
NetSendUDP(NetworkFildes, host, port, buf, msg.Size());
NetworkFildes.Send(host, buf, msg.Size());
delete[] buf;
}
@ -267,22 +262,26 @@ static const char *icmsgsubtypenames[] = {
#endif
template <typename T>
static void NetworkSendICMessage_Log(unsigned long ip, int port, const T &msg)
static void NetworkSendICMessage_Log(const CHost &host, const T &msg)
{
NetworkSendICMessage(ip, port, msg);
NetworkSendICMessage(host, msg);
DebugPrint("Sending to %d.%d.%d.%d:%d -> %s\n"
_C_ NIPQUAD(ntohl(ip)) _C_ ntohs(port)
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("Sending to %s -> %s\n" _C_ hostStr.c_str()
_C_ icmsgsubtypenames[msg.GetHeader().GetSubType()]);
#endif
}
static void NetworkSendICMessage_Log(unsigned long ip, int port, const CInitMessage_Header &msg)
static void NetworkSendICMessage_Log(const CHost &host, const CInitMessage_Header &msg)
{
NetworkSendICMessage(ip, port, msg);
NetworkSendICMessage(host, msg);
DebugPrint("Sending to %d.%d.%d.%d:%d -> %s\n"
_C_ NIPQUAD(ntohl(ip)) _C_ ntohs(port)
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("Sending to %s -> %s\n" _C_ hostStr.c_str()
_C_ icmsgsubtypenames[msg.GetSubType()]);
#endif
}
/**
@ -307,7 +306,7 @@ void CClient::SendRateLimited(const T &msg, unsigned long tick, unsigned long ms
networkState.MsgCnt = 0;
lastMsgTypeSent = subtype;
}
NetworkSendICMessage(serverIP, serverPort, msg);
NetworkSendICMessage(serverHost, msg);
DebugPrint("[%s] Sending (%s:#%d)\n" _C_
ncconstatenames[networkState.State] _C_
icmsgsubtypenames[subtype] _C_ networkState.MsgCnt);
@ -328,24 +327,12 @@ void CClient::SendRateLimited<CInitMessage_Header>(const CInitMessage_Header &ms
networkState.MsgCnt = 0;
lastMsgTypeSent = subtype;
}
NetworkSendICMessage(serverIP, serverPort, msg);
NetworkSendICMessage(serverHost, msg);
DebugPrint("[%s] Sending (%s:#%d)\n" _C_
ncconstatenames[networkState.State] _C_
icmsgsubtypenames[subtype] _C_ networkState.MsgCnt);
}
bool CClient::SetupServerAddress(const std::string &serveraddr, int port)
{
unsigned long addr = NetResolveHost(serveraddr);
if (addr == INADDR_NONE) {
return false;
}
serverIP = addr;
serverPort = htons(port);
return true;
}
void CClient::Init(const std::string &name, CServerSetup *serverSetup, CServerSetup *localSetup, unsigned long tick)
{
networkState.LastFrame = tick;
@ -370,7 +357,7 @@ bool CClient::Update_disconnected()
// Spew out 5 and trust in God that they arrive
for (int i = 0; i < 5; ++i) {
NetworkSendICMessage(serverIP, serverPort, message);
NetworkSendICMessage(serverHost, message);
}
networkState.State = ccs_usercanceled;
return false;
@ -612,11 +599,13 @@ void CClient::SetConfig(const CInitMessage_Config &msg)
if (i != msg.clientIndex) {
Hosts[HostsCount] = msg.hosts[i];
HostsCount++;
DebugPrint("Client %d = %d.%d.%d.%d:%d [%.*s]\n" _C_
msg.hosts[i].PlyNr _C_ NIPQUAD(ntohl(msg.hosts[i].Host)) _C_
ntohs(msg.hosts[i].Port) _C_
#ifdef DEBUG
const std::string hostStr = CHost(msg.hosts[i].Host, msg.hosts[i].Port).toString();
DebugPrint("Client %d = %s [%.*s]\n" _C_
msg.hosts[i].PlyNr _C_ hostStr.c_str() _C_
static_cast<int>(sizeof(msg.hosts[i].PlyName)) _C_
msg.hosts[i].PlyName);
#endif
} else { // Own client
NetLocalPlayerNumber = msg.hosts[i].PlyNr;
DebugPrint("SELF %d [%.*s]\n" _C_ msg.hosts[i].PlyNr _C_
@ -625,20 +614,23 @@ void CClient::SetConfig(const CInitMessage_Config &msg)
}
}
// server is last:
Hosts[HostsCount].Host = serverIP;
Hosts[HostsCount].Port = serverPort;
Hosts[HostsCount].Host = serverHost.getIp();
Hosts[HostsCount].Port = serverHost.getPort();
Hosts[HostsCount].PlyNr = msg.hosts[msg.hostsCount - 1].PlyNr;
Hosts[HostsCount].SetName(msg.hosts[msg.hostsCount - 1].PlyName);
++HostsCount;
NetPlayers = HostsCount + 1;
DebugPrint("Server %d = %d.%d.%d.%d:%d [%.*s]\n" _C_
#ifdef DEBUG
const std::string serverHostStr = serverHost.toString();
DebugPrint("Server %d = %s [%.*s]\n" _C_
msg.hosts[msg.hostsCount - 1].PlyNr _C_
NIPQUAD(GetServerIP()) _C_ GetServerPort() _C_
serverHostStr.c_str() _C_
static_cast<int>(sizeof(msg.hosts[msg.hostsCount - 1].PlyName)) _C_
msg.hosts[msg.hostsCount - 1].PlyName);
#endif
}
bool CClient::Parse(const unsigned char *buf, unsigned long host, int port)
bool CClient::Parse(const unsigned char *buf, const CHost &host)
{
CInitMessage_Header header;
header.Deserialize(buf);
@ -646,8 +638,7 @@ bool CClient::Parse(const unsigned char *buf, unsigned long host, int port)
if (header.GetType() != MessageInit_FromServer) {
return true;
}
// Assert(host == this->serverIP);
// Assert(port == this->serverPort);
// Assert(host == this->serverHost);
const unsigned char msgsubtype = header.GetSubType();
DebugPrint("Received %s in state %s\n" _C_ icmsgsubtypenames[msgsubtype]
@ -788,8 +779,8 @@ void CClient::Parse_Welcome(const unsigned char *buf)
NetworkLag = msg.Lag;
NetworkUpdates = msg.Updates;
Hosts[0].Host = serverIP;
Hosts[0].Port = serverPort;
Hosts[0].Host = serverHost.getIp();
Hosts[0].Port = serverHost.getPort();
for (int i = 1; i < PlayerMax; ++i) {
if (i != NetLocalHostsSlot) {
Hosts[i] = msg.hosts[i];
@ -861,8 +852,8 @@ void CClient::Parse_GameFull()
if (networkState.State != ccs_connecting) {
return;
}
fprintf(stderr, "Server at %d.%d.%d.%d:%d is full!\n",
NIPQUAD(GetServerIP()), GetServerPort());
const std::string serverHostStr = serverHost.toString();
fprintf(stderr, "Server at %s is full!\n", serverHostStr.c_str());
networkState.State = ccs_nofreeslots;
}
@ -874,11 +865,12 @@ void CClient::Parse_ProtocolMismatch(const unsigned char *buf)
CInitMessage_ProtocolMismatch msg;
msg.Deserialize(buf);
const std::string serverHostStr = serverHost.toString();
fprintf(stderr, "Incompatible network protocol version "
NetworkProtocolFormatString " <-> " NetworkProtocolFormatString "\n"
"from %d.%d.%d.%d:%d\n",
"from %s\n",
NetworkProtocolFormatArgs(NetworkProtocolVersion), NetworkProtocolFormatArgs(msg.Version),
NIPQUAD(GetServerIP()), GetServerPort());
serverHostStr.c_str());
networkState.State = ccs_incompatiblenetwork;
}
@ -890,10 +882,9 @@ void CClient::Parse_EngineMismatch(const unsigned char *buf)
CInitMessage_EngineMismatch msg;
msg.Deserialize(buf);
fprintf(stderr, "Incompatible Stratagus version %d <-> %d\n"
"from %d.%d.%d.%d:%d\n",
StratagusVersion, msg.Stratagus,
NIPQUAD(GetServerIP()), GetServerPort());
const std::string serverHostStr = serverHost.toString();
fprintf(stderr, "Incompatible Stratagus version %d <-> %d\nfrom %s\n",
StratagusVersion, msg.Stratagus, serverHostStr.c_str());
networkState.State = ccs_incompatibleengine;
}
@ -906,7 +897,7 @@ void CClient::Parse_AreYouThere()
{
const CInitMessage_Header message(MessageInit_FromClient, ICMIAH); // IAmHere
NetworkSendICMessage(serverIP, serverPort, message);
NetworkSendICMessage(serverHost, message);
}
//
@ -942,14 +933,14 @@ void CServer::Send_AreYouThere(const CNetworkHost &host)
{
const CInitMessage_Header message(MessageInit_FromServer, ICMAYT); // AreYouThere
NetworkSendICMessage(host.Host, host.Port, message);
NetworkSendICMessage(CHost(host.Host, host.Port), message);
}
void CServer::Send_GameFull(unsigned long host, int port)
void CServer::Send_GameFull(const CHost &host)
{
const CInitMessage_Header message(MessageInit_FromServer, ICMGameFull);
NetworkSendICMessage_Log(host, port, message);
NetworkSendICMessage_Log(host, message);
}
void CServer::Send_Welcome(const CNetworkHost &host, int index)
@ -963,7 +954,7 @@ void CServer::Send_Welcome(const CNetworkHost &host, int index)
message.hosts[i] = Hosts[i];
}
}
NetworkSendICMessage_Log(host.Host, host.Port, message);
NetworkSendICMessage_Log(CHost(host.Host, host.Port), message);
}
void CServer::Send_Resync(const CNetworkHost &host, int hostIndex)
@ -975,28 +966,28 @@ void CServer::Send_Resync(const CNetworkHost &host, int hostIndex)
message.hosts[i] = Hosts[i];
}
}
NetworkSendICMessage_Log(host.Host, host.Port, message);
NetworkSendICMessage_Log(CHost(host.Host, host.Port), message);
}
void CServer::Send_Map(const CNetworkHost &host)
{
const CInitMessage_Map message(NetworkMapName.c_str(), Map.Info.MapUID);
NetworkSendICMessage_Log(host.Host, host.Port, message);
NetworkSendICMessage_Log(CHost(host.Host, host.Port), message);
}
void CServer::Send_State(const CNetworkHost &host)
{
const CInitMessage_State message(MessageInit_FromServer, *serverSetup);
NetworkSendICMessage_Log(host.Host, host.Port, message);
NetworkSendICMessage_Log(CHost(host.Host, host.Port), message);
}
void CServer::Send_GoodBye(const CNetworkHost &host)
{
const CInitMessage_Header message(MessageInit_FromServer, ICMGoodBye);
NetworkSendICMessage_Log(host.Host, host.Port, message);
NetworkSendICMessage_Log(CHost(host.Host, host.Port), message);
}
void CServer::Update(unsigned long frameCounter)
@ -1031,11 +1022,10 @@ void CServer::MarkClientsAsResync()
** @param h slot number of host msg originates from
** @param msg message received
** @param host host which send the message
** @param port port from where the messahe nas been sent
**
** @return host index
*/
int CServer::Parse_Hello(int h, const CInitMessage_Hello &msg, unsigned long host, int port)
int CServer::Parse_Hello(int h, const CInitMessage_Hello &msg, const CHost &host)
{
if (h == -1) { // it is a new client
for (int i = 1; i < PlayerMax - 1; ++i) {
@ -1048,17 +1038,19 @@ int CServer::Parse_Hello(int h, const CInitMessage_Hello &msg, unsigned long hos
}
}
if (h != -1) {
Hosts[h].Host = host;
Hosts[h].Port = port;
Hosts[h].Host = host.getIp();
Hosts[h].Port = host.getPort();
Hosts[h].PlyNr = h;
Hosts[h].SetName(msg.PlyName);
DebugPrint("New client %d.%d.%d.%d:%d [%s]\n" _C_
NIPQUAD(ntohl(host)) _C_ ntohs(port) _C_ Hosts[h].PlyName);
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("New client %s [%s]\n" _C_ hostStr.c_str() _C_ Hosts[h].PlyName);
#endif
networkStates[h].State = ccs_connecting;
networkStates[h].MsgCnt = 0;
} else {
// Game is full - reject connnection
Send_GameFull(host, port);
Send_GameFull(host);
return -1;
}
}
@ -1291,55 +1283,53 @@ void CServer::Parse_SeeYou(const int h)
**
** @param msg message received
** @param host host which send the message
** @param port port from where the message nas been sent
**
** @return 0 if the versions match, -1 otherwise
*/
static int CheckVersions(const CInitMessage_Hello &msg, unsigned long host, int port)
static int CheckVersions(const CInitMessage_Hello &msg, const CHost &host)
{
if (msg.Stratagus != StratagusVersion) {
fprintf(stderr, "Incompatible Stratagus version "
"%d <-> %d\n"
"from %d.%d.%d.%d:%d\n",
StratagusVersion, msg.Stratagus,
NIPQUAD(ntohl(host)), ntohs(port));
const std::string hostStr = host.toString();
fprintf(stderr, "Incompatible Stratagus version %d <-> %d from %s\n",
StratagusVersion, msg.Stratagus, hostStr.c_str());
const CInitMessage_EngineMismatch message;
NetworkSendICMessage_Log(host, port, message);
NetworkSendICMessage_Log(host, message);
return -1;
}
if (msg.Version != NetworkProtocolVersion) {
const std::string hostStr = host.toString();
fprintf(stderr, "Incompatible network protocol version "
NetworkProtocolFormatString " <-> "
NetworkProtocolFormatString "\n"
"from %d.%d.%d.%d:%d\n",
"from %s\n",
NetworkProtocolFormatArgs(NetworkProtocolVersion),
NetworkProtocolFormatArgs(msg.Version),
NIPQUAD(ntohl(host)), ntohs(port));
hostStr.c_str());
const CInitMessage_ProtocolMismatch message;
NetworkSendICMessage_Log(host, port, message);
NetworkSendICMessage_Log(host, message);
return -1;
}
return 0;
}
void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, unsigned long host, int port)
void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, const CHost &host)
{
const unsigned char msgsubtype = buf[1];
int index = FindHostIndexBy(host, port);
int index = FindHostIndexBy(host);
if (index == -1) {
if (msgsubtype == ICMHello) {
CInitMessage_Hello msg;
msg.Deserialize(buf);
if (CheckVersions(msg, host, port)) {
if (CheckVersions(msg, host)) {
return;
}
// Special case: a new client has arrived
index = Parse_Hello(-1, msg, host, port);
index = Parse_Hello(-1, msg, host);
networkStates[index].LastFrame = frameCounter;
}
return;
@ -1350,7 +1340,7 @@ void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, unsign
CInitMessage_Hello msg;
msg.Deserialize(buf);
Parse_Hello(index, msg, host, port);
Parse_Hello(index, msg, host);
break;
}
case ICMResync: Parse_Resync(index); break;
@ -1385,11 +1375,10 @@ void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, unsign
** @param buf Packet received
** @param size size of the received packet.
** @param host host which send the message
** @param port port from where the message nas been sent
**
** @return 1 if packet is an InitConfig message, 0 otherwise
*/
int NetworkParseSetupEvent(const unsigned char *buf, int size, unsigned long host, int port)
int NetworkParseSetupEvent(const unsigned char *buf, int size, const CHost &host)
{
Assert(NetConnectRunning != 0);
@ -1408,16 +1397,18 @@ int NetworkParseSetupEvent(const unsigned char *buf, int size, unsigned long hos
}
const unsigned char msgsubtype = header.GetSubType();
DebugPrint("Received %s (%d) from %d.%d.%d.%d:%d\n" _C_
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("Received %s (%d) from %s\n" _C_
icmsgsubtypenames[int(msgsubtype)] _C_ msgsubtype _C_
NIPQUAD(ntohl(host)) _C_ ntohs(port));
hostStr.c_str());
#endif
if (NetConnectRunning == 2) { // client
if (Client.Parse(buf, host, port) == false) {
if (Client.Parse(buf, host) == false) {
NetConnectRunning = 0;
}
} else if (NetConnectRunning == 1) { // server
Server.Parse(FrameCounter, buf, host, port);
Server.Parse(FrameCounter, buf, host);
}
return 1;
}
@ -1437,10 +1428,10 @@ int GetNetworkState()
return Client.GetNetworkState();
}
int FindHostIndexBy(unsigned long ip, int port)
int FindHostIndexBy(const CHost &host)
{
for (int i = 0; i != PlayerMax; ++i) {
if (Hosts[i].Host == ip && Hosts[i].Port == port) {
if (Hosts[i].Host == host.getIp() && Hosts[i].Port == host.getPort()) {
return i;
}
}
@ -1517,7 +1508,8 @@ void NetworkServerStartGame()
for (int i = 0; i < PlayerMax - 1; ++i) {
printf("%02d: CO: %d Race: %d Host: ", i, ServerSetupState.CompOpt[i], ServerSetupState.Race[i]);
if (ServerSetupState.CompOpt[i] == 0) {
printf(" %d.%d.%d.%d:%d %s", NIPQUAD(ntohl(Hosts[i].Host)), ntohs(Hosts[i].Port), Hosts[i].PlyName);
const std::string hostStr = CHost(Hosts[i].Host, Hosts[i].Port).toString();
printf(" %s %s", hostStr.c_str(), Hosts[i].PlyName);
}
printf("\n");
}
@ -1640,26 +1632,26 @@ void NetworkServerStartGame()
breakout:
// Send to all clients.
for (int i = 0; i < HostsCount; ++i) {
const unsigned long host = message.hosts[i].Host;
const int port = message.hosts[i].Port;
const CHost host(message.hosts[i].Host, message.hosts[i].Port);
if (num[Hosts[i].PlyNr] == 1) { // not acknowledged yet
message.clientIndex = i;
NetworkSendICMessage_Log(host, port, message);
NetworkSendICMessage_Log(host, message);
} else if (num[Hosts[i].PlyNr] == 2) {
NetworkSendICMessage_Log(host, port, statemsg);
NetworkSendICMessage_Log(host, statemsg);
}
}
// Wait for acknowledge
unsigned char buf[1024];
while (j && NetSocketReady(NetworkFildes, 1000)) {
unsigned long host;
int port;
const int len = NetRecvUDP(NetworkFildes, buf, sizeof(buf), &host, &port);
while (j && NetworkFildes.HasDataToRead(1000)) {
CHost host;
const int len = NetworkFildes.Recv(buf, sizeof(buf), &host);
if (len < 0) {
DebugPrint("*Receive ack failed: (%d) from %d.%d.%d.%d:%d\n" _C_
len _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("*Receive ack failed: (%d) from %s\n" _C_ len _C_ hostStr.c_str());
#endif
continue;
}
CInitMessage_Header header;
@ -1670,10 +1662,11 @@ breakout:
if (type == MessageInit_FromClient) {
switch (subtype) {
case ICMConfig: {
DebugPrint("Got ack for InitConfig from %d.%d.%d.%d:%d\n"
_C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
const int index = FindHostIndexBy(host, port);
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("Got ack for InitConfig from %s\n" _C_ hostStr.c_str());
#endif
const int index = FindHostIndexBy(host);
if (index != -1) {
if (num[Hosts[index].PlyNr] == 1) {
num[Hosts[index].PlyNr]++;
@ -1683,10 +1676,11 @@ breakout:
break;
}
case ICMGo: {
DebugPrint("Got ack for InitState from %d.%d.%d.%d:%d\n"
_C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
const int index = FindHostIndexBy(host, port);
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("Got ack for InitState from %s\n" _C_ hostStr.c_str());
#endif
const int index = FindHostIndexBy(host);
if (index != -1) {
if (num[Hosts[index].PlyNr] == 2) {
num[Hosts[index].PlyNr] = 0;
@ -1710,9 +1704,8 @@ breakout:
// Give clients a quick-start kick..
const CInitMessage_Header message_go(MessageInit_FromServer, ICMGo);
for (int i = 0; i < HostsCount; ++i) {
const unsigned long host = Hosts[i].Host;
const int port = Hosts[i].Port;
NetworkSendICMessage_Log(host, port, message_go);
const CHost host(Hosts[i].Host, Hosts[i].Port);
NetworkSendICMessage_Log(host, message_go);
}
}
@ -1728,10 +1721,15 @@ int NetworkSetupServerAddress(const std::string &serveraddr, int port)
if (port == 0) {
port = NetworkDefaultPort;
}
if (Client.SetupServerAddress(serveraddr, port) == false) {
CHost host(serveraddr.c_str(), port);
if (host.isValid() == false) {
return 1;
}
DebugPrint("SELECTED SERVER: %s:%d (%d.%d.%d.%d)\n" _C_ serveraddr.c_str() _C_ Client.GetServerPort() _C_ NIPQUAD(Client.GetServerIP()));
Client.SetServerHost(host);
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("SELECTED SERVER: %s [%s]\n" _C_ hostStr.c_str() _C_ serveraddr.c_str());
#endif
return 0;
}

View file

@ -270,7 +270,7 @@ struct NetworkSelectionHeader {
char *NetworkAddr = NULL; /// Local network address to use
int NetworkPort = NetworkDefaultPort; /// Local network port to use
Socket NetworkFildes = static_cast<Socket>(-1); /// Network file descriptor
CUDPSocket NetworkFildes; /// Network file descriptor
int NetworkInSync = 1; /// Network is in sync
int NetworkUpdates = 5; /// Network update each # game cycles
int NetworkLag = 10; /// Network lag in # game cycles
@ -321,7 +321,8 @@ static void NetworkBroadcast(const CNetworkPacket &packet, int numcommands)
// Send to all clients.
for (int i = 0; i < HostsCount; ++i) {
NetSendUDP(NetworkFildes, Hosts[i].Host, Hosts[i].Port, buf, CNetworkPacket::Size(numcommands));
const CHost host(Hosts[i].Host, Hosts[i].Port);
NetworkFildes.Send(host, buf, CNetworkPacket::Size(numcommands));
}
delete[] buf;
}
@ -367,7 +368,7 @@ static void NetworkSendPacket(const CNetworkCommandQueue ncq[])
*/
void InitNetwork1()
{
NetworkFildes = static_cast<Socket>(-1);
NetworkFildes.Close();
NetworkInSync = 1;
NetInit(); // machine dependent setup
@ -384,16 +385,15 @@ void InitNetwork1()
// Our communication port
int port = NetworkPort;
int i;
for (i = 0; i < 10; ++i) {
NetworkFildes = NetOpenUDP(NetworkAddr, port + i);
if (NetworkFildes != static_cast<Socket>(-1)) {
for (int i = 0; i < 10; ++i) {
NetworkFildes.Open(CHost(NetworkAddr, port + i));
if (NetworkFildes.IsValid()) {
port = port + i;
break;
}
}
if (i == 10) {
fprintf(stderr, "NETWORK: No free ports %d-%d available, aborting\n", port, port + i);
if (NetworkFildes.IsValid() == false) {
fprintf(stderr, "NETWORK: No free ports %d-%d available, aborting\n", port, port + 10);
NetExit(); // machine dependent network exit
return;
}
@ -419,10 +419,8 @@ void InitNetwork1()
gethostname(buf, sizeof(buf));
DebugPrint("%s\n" _C_ buf);
const unsigned long myHost = NetResolveHost(buf);
const int myPort = port;
DebugPrint("My host:port %d.%d.%d.%d:%d\n" _C_
NIPQUAD(ntohl(myHost)) _C_ myPort);
const std::string hostStr = CHost(buf, port).toString();
DebugPrint("My host:port %s\n" _C_ hostStr.c_str());
}
#endif
@ -449,10 +447,9 @@ void ExitNetwork1()
NetworkSendPackets _C_ NetworkSendResend);
#endif
NetCloseUDP(NetworkFildes);
NetworkFildes.Close();
NetExit(); // machine dependent setup
NetworkFildes = static_cast<Socket>(-1);
NetworkInSync = 1;
NetPlayers = 0;
HostsCount = 0;
@ -672,9 +669,8 @@ void NetworkSendSelection(CUnit **units, int count)
const int len = CNetworkPacketHeader::Size() + CNetworkSelection::Size() * numcommands;
for (int i = 0; i < numteammates; ++i) {
const unsigned long ip = Hosts[teammates[i]].Host;
const int port = Hosts[teammates[i]].Port;
NetSendUDP(NetworkFildes, ip, port, buf, len);
const CHost host(Hosts[teammates[i]].Host, Hosts[teammates[i]].Port);
NetworkFildes.Send(host, buf, len);
}
delete [] buf;
}
@ -743,9 +739,8 @@ void NetworkEvent()
}
// Read the packet.
unsigned char buf[1024];
unsigned long host;
int port;
int len = NetRecvUDP(NetworkFildes, &buf, sizeof(buf), &host, &port);
CHost host;
int len = NetworkFildes.Recv(&buf, sizeof(buf), &host);
if (len < 0) {
DebugPrint("Server/Client gone?\n");
// just hope for an automatic recover right now..
@ -759,7 +754,7 @@ void NetworkEvent()
// Setup messages
if (NetConnectRunning) {
if (NetworkParseSetupEvent(buf, len, host, port)) {
if (NetworkParseSetupEvent(buf, len, host)) {
return;
}
}
@ -771,10 +766,12 @@ void NetworkEvent()
return;
}
const int index = FindHostIndexBy(host, port);
const int index = FindHostIndexBy(host);
if (index == -1 || PlayerQuit[Hosts[index].PlyNr]) {
DebugPrint("Not a host in play: %d.%d.%d.%d:%d\n" _C_
NIPQUAD(ntohl(host)) _C_ ntohs(port));
#ifdef DEBUG
const std::string hostStr = host.toString();
DebugPrint("Not a host in play: %s\n" _C_ hostStr.c_str());
#endif
return;
}
const int player = Hosts[index].PlyNr;

141
src/network/udpsocket.cpp Normal file
View file

@ -0,0 +1,141 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name udpsocket.cpp - The udpsocket class. */
//
// (c) Copyright 2013 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
//----------------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------------
#include "stratagus.h"
#include "network/udpsocket.h"
#include "net_lowlevel.h"
#include <stdio.h>
//
// CHost
//
CHost::CHost(const char *name, int port)
{
this->ip = NetResolveHost(name ? name : "127.0.0.1");
this->port = htons(port);
}
std::string CHost::toString() const
{
char buf[24]; // 127.255.255.255:65555
sprintf(buf, "%d.%d.%d.%d:%d", NIPQUAD(ntohl(ip)), ntohs(port));
return buf;
}
bool CHost::isValid() const
{
return ip != 0 && port != 0;
}
//
// CUDPSocket_Impl
//
class CUDPSocket_Impl
{
public:
CUDPSocket_Impl() : socket((Socket)-1) {}
~CUDPSocket_Impl() { if (IsValid()) { Close(); } }
bool Open(const CHost &host) { socket = NetOpenUDP(host.getIp(), host.getPort()); return socket != INVALID_SOCKET; }
void Close() { NetCloseUDP(socket); socket = ((Socket)-1); }
void Send(const CHost &host, const void *buf, unsigned int len) { NetSendUDP(socket, host.getIp(), host.getPort(), buf, len); }
int Recv(void *buf, int len, CHost *hostFrom)
{
unsigned long ip;
int port;
int res = NetRecvUDP(socket, buf, len, &ip, &port);
*hostFrom = CHost(ip, port);
return res;
}
void SetNonBlocking() { NetSetNonBlocking(socket); }
int HasDataToRead(int timeout) { return NetSocketReady(socket, timeout); }
bool IsValid() const { return socket != (Socket)-1; }
private:
Socket socket;
};
//
// CUDPSocket
//
CUDPSocket::CUDPSocket()
{
m_impl = new CUDPSocket_Impl();
}
CUDPSocket::~CUDPSocket()
{
delete m_impl;
}
bool CUDPSocket::Open(const CHost &host)
{
return m_impl->Open(host);
}
void CUDPSocket::Close()
{
m_impl->Close();
}
void CUDPSocket::Send(const CHost &host, const void *buf, unsigned int len)
{
return m_impl->Send(host, buf, len);
}
int CUDPSocket::Recv(void *buf, int len, CHost *hostFrom)
{
return m_impl->Recv(buf, len, hostFrom);
}
void CUDPSocket::SetNonBlocking()
{
m_impl->SetNonBlocking();
}
int CUDPSocket::HasDataToRead(int timeout)
{
return m_impl->HasDataToRead(timeout);
}
bool CUDPSocket::IsValid() const
{
return m_impl->IsValid();
}
//@}

View file

@ -213,6 +213,7 @@ extern void beos_init(int argc, char **argv);
#if defined(USE_WIN32) && ! defined(NO_STDIO_REDIRECT)
#include "windows.h"
#define REDIRECT_OUTPUT
#endif

View file

@ -943,7 +943,7 @@ void WaitEventsOneFrame()
// Network
int s = 0;
if (IsNetworkGame()) {
s = NetSocketReady(NetworkFildes, 0);
s = NetworkFildes.HasDataToRead(0);
if (s > 0) {
GetCallbacks()->NetworkEvent();
}

View file

@ -249,7 +249,7 @@ void UDPRead(Socket socket, T *obj, unsigned long *hostFrom, int *portFrom)
class ClientUDP
{
public:
explicit ClientUDP(int port) { socket = NetOpenUDP(NULL, port); }
explicit ClientUDP(int port) { socket = NetOpenUDP(htonl(0x7F000001), htons(port)); }
~ClientUDP() { NetCloseUDP(socket); }
template <typename T>

View file

@ -0,0 +1,110 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name test_udpsocket.cpp - The test file for net_lowlevel.cpp. */
//
// (c) Copyright 2013 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
#include <UnitTest++.h>
#include "stratagus.h"
#include "network/udpsocket.h"
#include "net_lowlevel.h"
class AutoNetwork
{
public:
AutoNetwork() { NetInit(); }
~AutoNetwork() { NetExit(); }
};
TEST_FIXTURE(AutoNetwork, CHost)
{
const CHost host1("127.0.0.1", 6502);
const CHost host2(htonl(0x7F000001), htons(6502));
CHECK(host1 == host2);
CHECK_EQUAL(std::string("127.0.0.1:6502"), host2.toString());
}
class Foo
{
public:
Foo() { memset(&data, 0, sizeof(data)); }
void Fill()
{
for (int i = 0; i != 42; ++i) {
data[i] = i;
}
}
bool Check() const
{
for (int i = 0; i != 42; ++i) {
if (data[i] != i) {
return false;
}
}
return true;
}
public:
char data[42];
};
TEST_FIXTURE(AutoNetwork, CUDPSocket)
{
const CHost host1("127.0.0.1", 6501);
const CHost host2("localhost", 6502);
CUDPSocket socket1;
CUDPSocket socket2;
socket1.Open(host1);
socket2.Open(host2);
CHECK(socket1.IsValid());
CHECK(socket2.IsValid());
Foo foo2;
foo2.Fill();
socket1.Send(host2, &foo2, sizeof(foo2));
Foo foo1;
CHECK(foo1.Check() == false);
CHost from;
CHECK(socket2.HasDataToRead(1000));
CHECK_EQUAL(int(sizeof(foo1)), socket2.Recv(&foo1, sizeof(foo1) + 4, &from));
CHECK(host1 == from);
CHECK(foo1.Check() == true);
socket2.Close();
CHECK(socket2.IsValid() == false);
}