2005-09-02 08:35:25 +02:00
|
|
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
|
|
|
|
|
|
|
/*
|
2009-07-30 14:54:17 +02:00
|
|
|
* Copyright 2005-2009 by Eric House (xwords@eehouse.org). All rights
|
|
|
|
* reserved.
|
2005-09-02 08:35:25 +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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _CREFMGR_H_
|
|
|
|
#define _CREFMGR_H_
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
#include <list>
|
|
|
|
|
2005-09-02 08:35:25 +02:00
|
|
|
#include "cref.h"
|
2009-07-28 07:15:26 +02:00
|
|
|
#include "mlock.h"
|
2005-09-02 08:35:25 +02:00
|
|
|
|
|
|
|
typedef map<CookieID,CookieRef*> CookieMap;
|
|
|
|
class CookieMapIterator;
|
|
|
|
class SocketStuff;
|
|
|
|
typedef map< int, SocketStuff* > SocketMap;
|
|
|
|
|
|
|
|
class SocketsIterator {
|
|
|
|
public:
|
|
|
|
SocketsIterator( SocketMap::iterator iter, SocketMap::iterator end,
|
|
|
|
pthread_mutex_t* mutex );
|
|
|
|
~SocketsIterator();
|
|
|
|
int Next();
|
|
|
|
private:
|
|
|
|
SocketMap::iterator m_iter;
|
|
|
|
SocketMap::iterator m_end;
|
|
|
|
pthread_mutex_t* m_mutex; /* locked */
|
|
|
|
};
|
|
|
|
|
2009-08-21 14:32:57 +02:00
|
|
|
class CrefInfo {
|
|
|
|
public:
|
|
|
|
string m_cookie;
|
|
|
|
string m_connName;
|
|
|
|
CookieID m_cookieID;
|
|
|
|
int m_totalSent;
|
|
|
|
int m_nPlayersSought;
|
|
|
|
int m_nPlayersHere;
|
|
|
|
XW_RELAY_STATE m_curState;
|
|
|
|
time_t m_startTime;
|
|
|
|
int m_nHosts;
|
|
|
|
string m_hostsIds;
|
2009-09-26 16:37:49 +02:00
|
|
|
string m_hostSeeds;
|
2009-08-21 14:32:57 +02:00
|
|
|
string m_hostIps;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CrefMgrInfo {
|
|
|
|
public:
|
2009-12-16 03:43:52 +01:00
|
|
|
const char* m_ports;
|
2009-08-21 14:32:57 +02:00
|
|
|
int m_nCrefsAll;
|
|
|
|
int m_nCrefsCurrent;
|
|
|
|
time_t m_startTimeSpawn;
|
|
|
|
vector<CrefInfo> m_crefInfo;
|
|
|
|
};
|
2005-09-02 08:35:25 +02:00
|
|
|
|
|
|
|
class CRefMgr {
|
|
|
|
/* Maintain access to CookieRef instances, ultimately to ensure that no
|
|
|
|
single instance is being acted on by more than one thread at a time,
|
|
|
|
and that once one is destroyed no additional threads attempt to access
|
|
|
|
it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
static CRefMgr* Get();
|
|
|
|
|
|
|
|
CRefMgr();
|
|
|
|
~CRefMgr();
|
|
|
|
|
2005-10-23 17:49:48 +02:00
|
|
|
void CloseAll();
|
|
|
|
|
2005-09-02 08:35:25 +02:00
|
|
|
CookieMapIterator GetCookieIterator();
|
|
|
|
|
|
|
|
/* PENDING. These need to go through SafeCref */
|
2009-07-28 07:15:26 +02:00
|
|
|
void Recycle( CookieID id );
|
2009-07-31 14:56:04 +02:00
|
|
|
void Recycle_locked( CookieRef* cref );
|
2009-07-28 07:15:26 +02:00
|
|
|
void Recycle( const char* connName );
|
2005-09-02 08:35:25 +02:00
|
|
|
CookieID CookieIdForName( const char* name );
|
|
|
|
|
|
|
|
/* For use from ctrl only!!!! */
|
|
|
|
void LockAll() { pthread_rwlock_wrlock( &m_cookieMapRWLock ); }
|
|
|
|
void UnlockAll() { pthread_rwlock_unlock( &m_cookieMapRWLock ); }
|
|
|
|
|
|
|
|
/* Track sockets independent of cookie refs */
|
2009-02-01 17:00:20 +01:00
|
|
|
bool Associate( int socket, CookieRef* cref );
|
2009-11-02 02:01:47 +01:00
|
|
|
bool Associate_locked( int socket, CookieRef* cref );
|
2005-09-05 17:50:49 +02:00
|
|
|
void Disassociate( int socket, CookieRef* cref );
|
2009-11-02 02:01:47 +01:00
|
|
|
void Disassociate_locked( int socket, CookieRef* cref );
|
|
|
|
void MoveSockets( vector<int> sockets, CookieRef* cref );
|
|
|
|
CookieRef* Clone( const CookieRef* parent );
|
2005-09-02 08:35:25 +02:00
|
|
|
pthread_mutex_t* GetWriteMutexForSocket( int socket );
|
|
|
|
void RemoveSocketRefs( int socket );
|
|
|
|
void PrintSocketInfo( int socket, string& out );
|
|
|
|
SocketsIterator MakeSocketsIterator();
|
|
|
|
|
2009-07-06 03:50:51 +02:00
|
|
|
int GetNumGamesSeen( void );
|
2009-07-13 05:01:22 +02:00
|
|
|
int GetSize( void );
|
2009-07-06 03:50:51 +02:00
|
|
|
|
2009-07-31 14:56:04 +02:00
|
|
|
time_t uptime();
|
|
|
|
|
2009-08-21 14:32:57 +02:00
|
|
|
void GetStats( CrefMgrInfo& info );
|
|
|
|
|
2005-09-02 08:35:25 +02:00
|
|
|
private:
|
|
|
|
friend class SafeCref;
|
2009-07-28 07:15:26 +02:00
|
|
|
|
|
|
|
/* We'll recycle cref instances rather than free and new them. This
|
|
|
|
solves, inelegantly, a problem where I want to free an instance (while
|
|
|
|
holding its mutex) but can't know if other threads are trying to obtain
|
|
|
|
that mutex. It's illegal to destroy a mutex somebody's trying to lock.
|
|
|
|
So we recycle, let the other thread succeed in locking but then quickly
|
|
|
|
discover that the cref it got isn't what it wants. See the SafeCref
|
|
|
|
class. */
|
|
|
|
list<CookieRef*> m_freeList;
|
|
|
|
pthread_mutex_t m_freeList_mutex;
|
|
|
|
void addToFreeList( CookieRef* cref );
|
|
|
|
CookieRef* getFromFreeList( void );
|
|
|
|
|
2009-11-01 02:38:03 +01:00
|
|
|
CookieRef* getMakeCookieRef_locked( const char* cookie,
|
|
|
|
const char* connName,
|
|
|
|
HostID hid, int socket, int nPlayersH,
|
|
|
|
int nPlayersS, int seed );
|
2009-07-28 07:15:26 +02:00
|
|
|
CookieRef* getCookieRef( CookieID cookieID );
|
|
|
|
CookieRef* getCookieRef( int socket );
|
2008-12-30 06:13:30 +01:00
|
|
|
bool checkCookieRef_locked( CookieRef* cref );
|
2005-09-02 08:35:25 +02:00
|
|
|
CookieRef* getCookieRef_impl( CookieID cookieID );
|
2009-11-02 02:01:47 +01:00
|
|
|
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id );
|
2009-08-21 14:00:09 +02:00
|
|
|
CookieRef* FindOpenGameFor( const char* cookie, const char* connName,
|
|
|
|
HostID hid, int socket, int nPlayersH,
|
2009-11-01 02:38:03 +01:00
|
|
|
int nPlayersS, int gameSeed,
|
2009-09-26 16:37:49 +02:00
|
|
|
bool* alreadyHere );
|
2005-10-01 18:33:45 +02:00
|
|
|
|
|
|
|
CookieID cookieIDForConnName( const char* connName );
|
|
|
|
CookieID nextCID( const char* connName );
|
|
|
|
|
2005-10-15 18:30:10 +02:00
|
|
|
static void heartbeatProc( void* closure );
|
|
|
|
void checkHeartbeats( time_t now );
|
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
pthread_mutex_t m_nextCIDMutex;
|
2005-10-01 18:33:45 +02:00
|
|
|
CookieID m_nextCID;
|
2005-09-02 08:35:25 +02:00
|
|
|
|
|
|
|
pthread_rwlock_t m_cookieMapRWLock;
|
|
|
|
CookieMap m_cookieMap;
|
|
|
|
|
|
|
|
pthread_mutex_t m_SocketStuffMutex;
|
|
|
|
SocketMap m_SocketStuff;
|
|
|
|
|
2009-07-31 14:56:04 +02:00
|
|
|
time_t m_startTime;
|
2009-12-16 03:43:52 +01:00
|
|
|
string m_ports;
|
2009-07-31 14:56:04 +02:00
|
|
|
|
2005-09-02 08:35:25 +02:00
|
|
|
friend class CookieMapIterator;
|
|
|
|
}; /* CRefMgr */
|
|
|
|
|
|
|
|
|
|
|
|
class SafeCref {
|
|
|
|
|
|
|
|
/* Stack-based class that keeps more than one thread from accessing a
|
|
|
|
CookieRef instance at a time. */
|
|
|
|
|
|
|
|
public:
|
2009-08-21 14:00:09 +02:00
|
|
|
SafeCref( const char* cookie, const char* connName, HostID hid,
|
2009-11-01 02:38:03 +01:00
|
|
|
int socket, int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
unsigned short gameSeed );
|
2009-07-28 07:15:26 +02:00
|
|
|
SafeCref( CookieID cid, bool failOk = false );
|
2005-09-02 08:35:25 +02:00
|
|
|
SafeCref( int socket );
|
|
|
|
SafeCref( CookieRef* cref );
|
|
|
|
~SafeCref();
|
|
|
|
|
2008-12-30 06:13:30 +01:00
|
|
|
bool Forward( HostID src, HostID dest, unsigned char* buf, int buflen ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_Forward( src, dest, buf, buflen );
|
2008-12-30 06:13:30 +01:00
|
|
|
return true;
|
2005-10-01 18:33:45 +02:00
|
|
|
} else {
|
2008-12-30 06:13:30 +01:00
|
|
|
return false;
|
2005-10-01 18:33:45 +02:00
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
2009-11-01 02:38:03 +01:00
|
|
|
bool Connect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
2009-12-04 08:59:07 +01:00
|
|
|
return m_cref->_Connect( socket, srcID, nPlayersH, nPlayersS, seed );
|
2005-10-01 18:33:45 +02:00
|
|
|
} else {
|
2008-12-30 06:13:30 +01:00
|
|
|
return false;
|
2005-10-01 18:33:45 +02:00
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
2009-11-01 02:38:03 +01:00
|
|
|
bool Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
|
2009-09-26 16:37:49 +02:00
|
|
|
int seed ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
2009-11-01 02:38:03 +01:00
|
|
|
m_cref->_Reconnect( socket, srcID, nPlayersH, nPlayersS, seed );
|
2008-12-30 06:13:30 +01:00
|
|
|
return true;
|
2005-10-01 18:33:45 +02:00
|
|
|
} else {
|
2008-12-30 06:13:30 +01:00
|
|
|
return false;
|
2005-10-01 18:33:45 +02:00
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
2005-09-05 17:50:49 +02:00
|
|
|
void Disconnect(int socket, HostID hostID ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_Disconnect( socket, hostID );
|
|
|
|
}
|
2005-09-05 17:50:49 +02:00
|
|
|
}
|
2005-10-30 06:16:35 +01:00
|
|
|
void Shutdown() {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_Shutdown();
|
|
|
|
}
|
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
void Remove( int socket ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_Remove( socket );
|
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
2007-11-19 00:38:56 +01:00
|
|
|
|
|
|
|
#ifdef RELAY_HEARTBEAT
|
2008-12-30 06:13:30 +01:00
|
|
|
bool HandleHeartbeat( HostID id, int socket ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_HandleHeartbeat( id, socket );
|
2009-02-01 17:00:20 +01:00
|
|
|
return true;
|
2005-10-01 18:33:45 +02:00
|
|
|
} else {
|
2008-12-30 06:13:30 +01:00
|
|
|
return false;
|
2005-10-01 18:33:45 +02:00
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
2005-09-03 08:55:08 +02:00
|
|
|
void CheckHeartbeats( time_t now ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_CheckHeartbeats( now );
|
|
|
|
}
|
2005-09-03 08:55:08 +02:00
|
|
|
}
|
2007-11-19 00:38:56 +01:00
|
|
|
#endif
|
|
|
|
|
2005-09-02 08:35:25 +02:00
|
|
|
void PrintCookieInfo( string& out ) {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_PrintCookieInfo( out );
|
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
|
|
|
void CheckAllConnected() {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
|
|
|
m_cref->_CheckAllConnected();
|
|
|
|
}
|
|
|
|
}
|
2005-10-16 03:19:25 +02:00
|
|
|
const char* Cookie() {
|
2005-10-01 18:33:45 +02:00
|
|
|
if ( IsValid() ) {
|
2005-10-16 03:19:25 +02:00
|
|
|
return m_cref->Cookie();
|
|
|
|
} else {
|
|
|
|
return ""; /* so don't crash.... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const char* ConnName() {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
return m_cref->ConnName();
|
2005-10-01 18:33:45 +02:00
|
|
|
} else {
|
|
|
|
return ""; /* so don't crash.... */
|
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
}
|
|
|
|
|
2009-02-28 17:15:59 +01:00
|
|
|
CookieID GetCookieID() {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
return m_cref->GetCookieID();
|
|
|
|
} else {
|
|
|
|
return 0; /* so don't crash.... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetTotalSent() {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
return m_cref->GetTotalSent();
|
|
|
|
} else {
|
|
|
|
return -1; /* so don't crash.... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetPlayersTotal() {
|
|
|
|
if ( IsValid() ) {
|
2009-08-13 14:59:55 +02:00
|
|
|
return m_cref->GetPlayersSought();
|
2009-02-28 17:15:59 +01:00
|
|
|
} else {
|
|
|
|
return -1; /* so don't crash.... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int GetPlayersHere() {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
return m_cref->GetPlayersHere();
|
|
|
|
} else {
|
|
|
|
return -1; /* so don't crash.... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* StateString() {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
return stateString( m_cref->CurState() );
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-26 16:37:49 +02:00
|
|
|
void GetHostsConnected( string* hosts, string* seeds, string* addrs ) {
|
2009-02-28 17:15:59 +01:00
|
|
|
if ( IsValid() ) {
|
2009-09-26 16:37:49 +02:00
|
|
|
m_cref->_FormatHostInfo( hosts, seeds, addrs );
|
2009-02-28 17:15:59 +01:00
|
|
|
}
|
|
|
|
}
|
2005-09-02 08:35:25 +02:00
|
|
|
|
2009-07-28 07:41:15 +02:00
|
|
|
time_t GetStartTime(void) {
|
|
|
|
if ( IsValid() ) {
|
|
|
|
return m_cref->GetStarttime();
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
bool IsValid() { return m_isValid; }
|
2005-10-01 18:33:45 +02:00
|
|
|
|
2009-09-26 16:37:49 +02:00
|
|
|
private:
|
2005-09-02 08:35:25 +02:00
|
|
|
CookieRef* m_cref;
|
|
|
|
CRefMgr* m_mgr;
|
2009-07-28 07:15:26 +02:00
|
|
|
bool m_isValid;
|
|
|
|
bool m_locked;
|
2009-09-26 16:37:49 +02:00
|
|
|
}; /* SafeCref class */
|
2005-09-02 08:35:25 +02:00
|
|
|
|
|
|
|
|
|
|
|
class CookieMapIterator {
|
|
|
|
public:
|
2009-07-28 07:15:26 +02:00
|
|
|
CookieMapIterator(pthread_rwlock_t* rwlock);
|
2005-09-02 08:35:25 +02:00
|
|
|
~CookieMapIterator() {}
|
|
|
|
CookieID Next();
|
|
|
|
private:
|
2009-07-28 07:15:26 +02:00
|
|
|
RWReadLock m_rwl;
|
2005-09-02 08:35:25 +02:00
|
|
|
CookieMap::const_iterator _iter;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|