2005-03-19 23:14:27 +01:00
|
|
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
2005-09-02 08:56:34 +02:00
|
|
|
/*
|
2009-02-28 20:35:32 +01:00
|
|
|
* Copyright 2005-2009 by Eric House (xwords@eehouse.org). All rights
|
|
|
|
* reserved.
|
2005-09-02 08:56:34 +02:00
|
|
|
*
|
|
|
|
* 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; either version 2
|
|
|
|
* of the License, or (at your option.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
#ifndef _CREF_H_
|
|
|
|
#define _CREF_H_
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
2005-03-25 03:59:44 +01:00
|
|
|
#include <string>
|
2005-07-06 00:05:37 +02:00
|
|
|
#include <deque>
|
2005-03-25 03:59:44 +01:00
|
|
|
#include <pthread.h>
|
2005-03-19 23:14:27 +01:00
|
|
|
#include "xwrelay_priv.h"
|
2005-09-03 08:55:08 +02:00
|
|
|
#include "xwrelay.h"
|
2005-07-06 00:05:37 +02:00
|
|
|
#include "states.h"
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2009-11-08 22:35:39 +01:00
|
|
|
typedef vector<unsigned char> MsgBuffer;
|
|
|
|
typedef deque<MsgBuffer*> MsgBufQueue;
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
class CookieMapIterator; /* forward */
|
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
struct HostRec {
|
2005-06-23 06:26:44 +02:00
|
|
|
public:
|
2009-11-01 02:38:03 +01:00
|
|
|
HostRec(HostID hostID, int socket, int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed )
|
2009-08-21 14:00:09 +02:00
|
|
|
: m_hostID(hostID)
|
|
|
|
, m_socket(socket)
|
2005-10-02 17:39:38 +02:00
|
|
|
, m_nPlayersH(nPlayersH)
|
2009-11-01 02:38:03 +01:00
|
|
|
, m_nPlayersS(nPlayersS)
|
2009-09-26 16:37:49 +02:00
|
|
|
, m_seed(seed)
|
2009-03-10 13:52:17 +01:00
|
|
|
, m_lastHeartbeat(uptime())
|
2005-10-02 17:39:38 +02:00
|
|
|
{}
|
2009-08-21 14:00:09 +02:00
|
|
|
HostID m_hostID;
|
2005-06-23 06:26:44 +02:00
|
|
|
int m_socket;
|
2005-10-02 17:39:38 +02:00
|
|
|
int m_nPlayersH;
|
2009-11-01 02:38:03 +01:00
|
|
|
int m_nPlayersS;
|
2009-09-26 16:37:49 +02:00
|
|
|
int m_seed;
|
2005-06-23 06:26:44 +02:00
|
|
|
time_t m_lastHeartbeat;
|
|
|
|
};
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
class CookieRef {
|
|
|
|
|
2005-09-03 17:59:48 +02:00
|
|
|
private:
|
|
|
|
/* These classes have access to CookieRef. All others should go through
|
|
|
|
SafeCref instances. */
|
|
|
|
friend class CRefMgr;
|
|
|
|
friend class SafeCref;
|
|
|
|
friend class CookieMapIterator;
|
2005-03-25 03:59:44 +01:00
|
|
|
|
2005-10-01 18:33:45 +02:00
|
|
|
CookieRef( const char* cookie, const char* connName, CookieID id );
|
2009-07-28 07:15:26 +02:00
|
|
|
void ReInit( const char* cookie, const char* connName, CookieID id );
|
2005-03-19 23:14:27 +01:00
|
|
|
~CookieRef();
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
void Clear(void); /* make clear it's unused */
|
|
|
|
|
|
|
|
bool Lock( void );
|
|
|
|
void Unlock( void );
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
/* Within this cookie, remember that this hostID and socket go together.
|
|
|
|
If the hostID is HOST_ID_SERVER, it's the server. */
|
2005-10-01 18:33:45 +02:00
|
|
|
CookieID GetCookieID() { return m_cookieID; }
|
2009-02-28 17:15:59 +01:00
|
|
|
int GetTotalSent() { return m_totalSent; }
|
2009-08-13 14:59:55 +02:00
|
|
|
int GetPlayersSought() { return m_nPlayersSought; }
|
2009-02-28 17:15:59 +01:00
|
|
|
int GetPlayersHere() { return m_nPlayersHere; }
|
|
|
|
|
2005-09-05 17:50:49 +02:00
|
|
|
int CountSockets() { return m_sockets.size(); }
|
2008-12-30 06:13:30 +01:00
|
|
|
bool HasSocket( int socket );
|
2009-07-28 07:15:26 +02:00
|
|
|
bool HasSocket_locked( int socket );
|
2009-11-02 02:01:47 +01:00
|
|
|
const char* Cookie() const { return m_cookie.c_str(); }
|
2005-10-01 18:33:45 +02:00
|
|
|
const char* ConnName() { return m_connName.c_str(); }
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2009-03-02 02:50:14 +01:00
|
|
|
int GetHeartbeat() { return m_heatbeat; }
|
2005-09-03 17:59:48 +02:00
|
|
|
int SocketForHost( HostID dest );
|
|
|
|
|
2008-12-30 06:13:30 +01:00
|
|
|
bool NeverFullyConnected();
|
2009-12-04 09:03:27 +01:00
|
|
|
bool GameOpen( const char* cookie, bool isNew, bool* alreadyHere );
|
2005-04-20 14:10:05 +02:00
|
|
|
|
|
|
|
/* for console */
|
2005-09-02 08:56:34 +02:00
|
|
|
void _PrintCookieInfo( string& out );
|
2005-04-20 14:10:05 +02:00
|
|
|
void PrintSocketInfo( string& out, int socket );
|
2009-09-26 16:37:49 +02:00
|
|
|
void _FormatHostInfo( string* hostIds, string* seeds, string* addrs );
|
2005-04-20 14:10:05 +02:00
|
|
|
|
|
|
|
static CookieMapIterator GetCookieIterator();
|
2005-09-05 17:50:49 +02:00
|
|
|
|
2005-04-20 14:10:05 +02:00
|
|
|
/* Nuke an existing */
|
|
|
|
static void Delete( CookieID id );
|
|
|
|
static void Delete( const char* name );
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2009-12-04 09:03:27 +01:00
|
|
|
bool _Connect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed );
|
2009-11-01 02:38:03 +01:00
|
|
|
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed );
|
2005-09-05 17:50:49 +02:00
|
|
|
void _Disconnect(int socket, HostID hostID );
|
2005-10-30 06:20:31 +01:00
|
|
|
void _Shutdown();
|
2005-09-02 08:56:34 +02:00
|
|
|
void _HandleHeartbeat( HostID id, int socket );
|
2005-09-03 08:55:08 +02:00
|
|
|
void _CheckHeartbeats( time_t now );
|
2005-09-02 08:56:34 +02:00
|
|
|
void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen );
|
|
|
|
void _Remove( int socket );
|
|
|
|
void _CheckAllConnected();
|
|
|
|
|
2008-12-30 06:13:30 +01:00
|
|
|
bool ShouldDie() { return m_curState == XWS_DEAD; }
|
2009-02-28 17:15:59 +01:00
|
|
|
XW_RELAY_STATE CurState() { return m_curState; }
|
2005-09-02 08:56:34 +02:00
|
|
|
|
2005-10-30 06:20:31 +01:00
|
|
|
void logf( XW_LogLevel level, const char* format, ... );
|
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
typedef struct CRefEvent {
|
|
|
|
XW_RELAY_EVENT type;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
HostID src;
|
|
|
|
HostID dest;
|
|
|
|
unsigned char* buf;
|
|
|
|
int buflen;
|
|
|
|
} fwd;
|
|
|
|
struct {
|
|
|
|
int socket;
|
2005-10-02 17:39:38 +02:00
|
|
|
int nPlayersH;
|
2009-11-01 02:38:03 +01:00
|
|
|
int nPlayersS;
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed;
|
2005-07-06 00:05:37 +02:00
|
|
|
HostID srcID;
|
|
|
|
} con;
|
2005-09-05 17:50:49 +02:00
|
|
|
struct {
|
|
|
|
int socket;
|
|
|
|
HostID srcID;
|
|
|
|
} discon;
|
2005-07-06 00:05:37 +02:00
|
|
|
struct {
|
|
|
|
HostID id;
|
|
|
|
int socket;
|
|
|
|
} heart;
|
|
|
|
struct {
|
|
|
|
time_t now;
|
|
|
|
} htime;
|
2005-09-02 08:56:34 +02:00
|
|
|
struct {
|
|
|
|
int socket;
|
|
|
|
} rmsock;
|
2005-09-03 08:55:08 +02:00
|
|
|
struct {
|
|
|
|
int socket;
|
|
|
|
XWREASON why;
|
|
|
|
} disnote;
|
2005-07-06 00:05:37 +02:00
|
|
|
} u;
|
|
|
|
} CRefEvent;
|
|
|
|
|
2009-11-08 22:35:39 +01:00
|
|
|
bool send_with_length( int socket, unsigned char* buf, int bufLen,
|
2009-07-06 03:50:51 +02:00
|
|
|
bool cascade );
|
|
|
|
void send_msg( int socket, HostID id, XWRelayMsg msg, XWREASON why,
|
|
|
|
bool cascade );
|
2005-09-03 20:35:34 +02:00
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
void RecordSent( int nBytes, int socket ) {
|
|
|
|
m_totalSent += nBytes;
|
|
|
|
}
|
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
void pushConnectEvent( int socket, HostID srcID,
|
2009-11-01 02:38:03 +01:00
|
|
|
int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed );
|
2009-08-21 14:00:09 +02:00
|
|
|
void pushReconnectEvent( int socket, HostID srcID,
|
2009-11-01 02:38:03 +01:00
|
|
|
int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed );
|
2005-07-06 00:05:37 +02:00
|
|
|
void pushHeartbeatEvent( HostID id, int socket );
|
2005-09-03 08:55:08 +02:00
|
|
|
void pushHeartFailedEvent( int socket );
|
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
void pushForwardEvent( HostID src, HostID dest, unsigned char* buf,
|
|
|
|
int buflen );
|
2005-08-02 06:57:13 +02:00
|
|
|
void pushDestBadEvent();
|
2005-09-02 08:56:34 +02:00
|
|
|
void pushLastSocketGoneEvent();
|
2009-12-14 05:10:23 +01:00
|
|
|
void checkHaveRoom( const CRefEvent* evt );
|
2005-09-02 08:56:34 +02:00
|
|
|
void pushRemoveSocketEvent( int socket );
|
2005-09-03 08:55:08 +02:00
|
|
|
void pushNotifyDisconEvent( int socket, XWREASON why );
|
2005-09-02 08:56:34 +02:00
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
void handleEvents();
|
|
|
|
|
2008-12-30 06:13:30 +01:00
|
|
|
void sendResponse( const CRefEvent* evt, bool initial );
|
2009-11-08 22:35:39 +01:00
|
|
|
void sendAnyStored( const CRefEvent* evt );
|
2009-12-04 09:03:27 +01:00
|
|
|
bool increasePlayerCounts( const CRefEvent* evt, bool reconn );
|
2005-10-02 17:39:38 +02:00
|
|
|
void reducePlayerCounts( int socket );
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void setAllConnectedTimer();
|
|
|
|
void cancelAllConnectedTimer();
|
|
|
|
|
2009-11-08 22:35:39 +01:00
|
|
|
void forward_or_store( const CRefEvent* evt );
|
2009-12-04 09:03:27 +01:00
|
|
|
void send_denied( const CRefEvent* evt, XWREASON why );
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void checkFromServer( const CRefEvent* evt );
|
2005-09-03 20:35:34 +02:00
|
|
|
void notifyOthers( int socket, XWRelayMsg msg, XWREASON why );
|
2005-08-02 06:57:13 +02:00
|
|
|
|
2005-09-03 08:55:08 +02:00
|
|
|
void disconnectSockets( int socket, XWREASON why );
|
2005-07-06 00:05:37 +02:00
|
|
|
void noteHeartbeat(const CRefEvent* evt);
|
2005-09-03 08:55:08 +02:00
|
|
|
void notifyDisconn(const CRefEvent* evt);
|
2005-09-05 17:50:49 +02:00
|
|
|
void removeSocket( int socket );
|
2009-12-14 05:10:23 +01:00
|
|
|
void sendAllHere( bool initial );
|
2009-11-02 02:01:47 +01:00
|
|
|
void moveSockets( void );
|
2009-09-26 16:37:49 +02:00
|
|
|
bool SeedBelongs( int gameSeed );
|
|
|
|
bool SeedsBelong( const char* connName );
|
2009-08-21 14:00:09 +02:00
|
|
|
void assignConnName( void );
|
|
|
|
void assignHostIds( void );
|
2005-09-03 08:55:08 +02:00
|
|
|
|
2005-10-01 18:33:45 +02:00
|
|
|
HostID nextHostID() { return ++m_nextHostID; }
|
2009-07-28 07:15:26 +02:00
|
|
|
|
2009-07-28 07:41:15 +02:00
|
|
|
time_t GetStarttime( void ) { return m_starttime; }
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
bool notInUse(void) { return m_cookieID == 0; }
|
|
|
|
|
2009-11-08 22:35:39 +01:00
|
|
|
void store_message( HostID dest, const unsigned char* buf,
|
|
|
|
unsigned int len );
|
|
|
|
void send_stored_messages( HostID dest, int socket );
|
|
|
|
unsigned int count_msgs_stored( void ) { return m_nHostMsgs; }
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
/* timer callback */
|
|
|
|
static void s_checkAllConnected( void* closure );
|
2005-04-08 16:13:25 +02:00
|
|
|
|
2009-11-08 22:35:39 +01:00
|
|
|
unsigned int m_nHostMsgs;
|
|
|
|
MsgBufQueue m_hostMsgQueues[4];
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec> m_sockets;
|
2009-09-14 03:55:03 +02:00
|
|
|
bool m_gameFull; /* once we've filled up, no more *new*
|
|
|
|
connections ever */
|
2009-03-02 02:50:14 +01:00
|
|
|
int m_heatbeat; /* might change per carrier or something. */
|
2005-10-16 03:19:25 +02:00
|
|
|
string m_cookie; /* cookie used for initial connections */
|
2005-10-01 18:33:45 +02:00
|
|
|
string m_connName; /* globally unique name */
|
|
|
|
CookieID m_cookieID; /* Unique among current games on this server */
|
2005-04-20 14:10:05 +02:00
|
|
|
int m_totalSent;
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
/* Guard the event queue. Only one thread at a time can post to the
|
|
|
|
queue, but once in a thread can post new events while processing
|
|
|
|
current ones. */
|
2005-09-14 07:15:27 +02:00
|
|
|
/* pthread_mutex_t m_EventsMutex; */
|
2005-07-06 00:05:37 +02:00
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
XW_RELAY_STATE m_curState;
|
|
|
|
deque<CRefEvent> m_eventQueue;
|
|
|
|
|
2005-10-01 18:33:45 +02:00
|
|
|
HostID m_nextHostID;
|
2009-08-13 14:59:55 +02:00
|
|
|
int m_nPlayersSought;
|
2005-10-02 17:39:38 +02:00
|
|
|
int m_nPlayersHere;
|
2009-07-28 07:15:26 +02:00
|
|
|
|
2009-07-28 07:41:15 +02:00
|
|
|
time_t m_starttime;
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
pthread_mutex_t m_mutex;
|
|
|
|
|
|
|
|
pthread_t m_locking_thread; /* for debugging only */
|
2009-11-09 06:30:42 +01:00
|
|
|
bool m_in_handleEvents; /* for debugging only */
|
2005-07-06 00:05:37 +02:00
|
|
|
}; /* CookieRef */
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
#endif
|