2005-03-19 23:14:27 +01:00
|
|
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
|
|
|
|
2005-03-25 03:59:44 +01:00
|
|
|
/*
|
2009-07-30 14:54:17 +02:00
|
|
|
* Copyright 2005-2009 by Eric House (xwords@eehouse.org). All rights
|
|
|
|
* reserved.
|
2005-03-25 03:59:44 +01: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) any later version.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
#include <assert.h>
|
2005-03-25 03:59:44 +01:00
|
|
|
#include <pthread.h>
|
2005-07-06 00:05:37 +02:00
|
|
|
#include <netinet/in.h>
|
2005-10-30 06:20:31 +01:00
|
|
|
#include <stdarg.h>
|
2006-03-21 05:05:33 +01:00
|
|
|
#include <stdio.h>
|
2008-12-30 06:13:30 +01:00
|
|
|
#include <string.h>
|
2009-07-28 07:15:26 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
#include "cref.h"
|
|
|
|
#include "xwrelay.h"
|
2005-03-25 03:59:44 +01:00
|
|
|
#include "mlock.h"
|
2005-04-20 14:13:20 +02:00
|
|
|
#include "tpool.h"
|
2005-07-06 00:05:37 +02:00
|
|
|
#include "states.h"
|
2005-09-02 08:56:34 +02:00
|
|
|
#include "timermgr.h"
|
|
|
|
#include "configs.h"
|
|
|
|
#include "crefmgr.h"
|
2009-08-21 14:00:09 +02:00
|
|
|
#include "permid.h"
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* SocketsIterator class
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
SocketsIterator::SocketsIterator( SocketMap::iterator iter,
|
|
|
|
SocketMap::iterator end,
|
2009-07-31 14:43:04 +02:00
|
|
|
pthread_mutex_t* mutex )
|
2005-04-20 14:13:20 +02:00
|
|
|
: m_iter( iter )
|
2005-09-02 08:56:34 +02:00
|
|
|
, m_end( end )
|
2009-07-31 14:43:04 +02:00
|
|
|
, m_mutex( mutex )
|
2005-09-02 08:56:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SocketsIterator::~SocketsIterator()
|
2005-04-20 14:13:20 +02:00
|
|
|
{
|
2005-09-02 08:56:34 +02:00
|
|
|
pthread_mutex_unlock( m_mutex );
|
2005-04-20 14:13:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SocketsIterator::Next()
|
|
|
|
{
|
2005-09-02 08:56:34 +02:00
|
|
|
int socket = 0;
|
|
|
|
if ( m_iter != m_end ) {
|
|
|
|
socket = m_iter->first;
|
|
|
|
++m_iter;
|
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
return socket;
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* CookieRef class
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
#define ASSERT_LOCKED() \
|
|
|
|
assert( m_locking_thread == pthread_self() )
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::ReInit( const char* cookie, const char* connName, CookieID id )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2009-07-28 07:15:26 +02:00
|
|
|
m_cookie = cookie==NULL?"":cookie;
|
2009-08-21 14:00:09 +02:00
|
|
|
m_connName = connName==NULL?"":connName;
|
2009-07-28 07:15:26 +02:00
|
|
|
m_cookieID = id;
|
|
|
|
m_totalSent = 0;
|
|
|
|
m_curState = XWS_INITED;
|
|
|
|
m_nextState = XWS_INITED;
|
|
|
|
m_nextHostID = HOST_ID_SERVER;
|
2009-08-13 14:59:55 +02:00
|
|
|
m_nPlayersSought = 0;
|
2009-07-28 07:15:26 +02:00
|
|
|
m_nPlayersHere = 0;
|
2009-07-31 14:43:04 +02:00
|
|
|
m_locking_thread = 0;
|
2009-07-28 07:41:15 +02:00
|
|
|
m_starttime = uptime();
|
2009-07-28 07:15:26 +02:00
|
|
|
|
2009-03-02 02:50:14 +01:00
|
|
|
RelayConfigs::GetConfigs()->GetValueFor( "HEARTBEAT", &m_heatbeat );
|
2009-07-28 07:15:26 +02:00
|
|
|
logf( XW_LOGINFO, "initing cref for cookie %s, connName %s",
|
2005-10-30 06:20:31 +01:00
|
|
|
m_cookie.c_str(), m_connName.c_str() );
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
|
|
|
|
CookieRef::CookieRef( const char* cookie, const char* connName, CookieID id )
|
|
|
|
{
|
|
|
|
pthread_mutex_init( &m_mutex, NULL );
|
|
|
|
ReInit( cookie, connName, id );
|
|
|
|
}
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
CookieRef::~CookieRef()
|
|
|
|
{
|
2005-09-02 08:56:34 +02:00
|
|
|
cancelAllConnectedTimer();
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/* get rid of any sockets still contained */
|
|
|
|
XWThreadPool* tPool = XWThreadPool::GetTPool();
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
int socket = iter->m_socket;
|
2005-04-20 14:13:20 +02:00
|
|
|
tPool->CloseSocket( socket );
|
2005-09-05 17:50:49 +02:00
|
|
|
m_sockets.erase( iter );
|
2005-04-20 14:13:20 +02:00
|
|
|
}
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
logf( XW_LOGINFO,
|
|
|
|
"CookieRef for %d being deleted; sent %d bytes over lifetime",
|
2005-10-01 18:33:45 +02:00
|
|
|
m_cookieID, m_totalSent );
|
2005-09-02 08:56:34 +02:00
|
|
|
} /* ~CookieRef */
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
void
|
|
|
|
CookieRef::Clear(void)
|
|
|
|
{
|
|
|
|
m_cookie = "";
|
|
|
|
m_connName = "";
|
|
|
|
m_cookieID = 0;
|
|
|
|
m_eventQueue.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CookieRef::Lock( void )
|
|
|
|
{
|
|
|
|
bool success = true;
|
|
|
|
|
|
|
|
pthread_mutex_lock( &m_mutex );
|
|
|
|
|
|
|
|
/* We get here possibly after having been blocked on the mutex for a
|
|
|
|
while. This cref may no longer be live. If it's not, unlock and
|
|
|
|
return. */
|
|
|
|
|
|
|
|
assert( m_locking_thread == 0 );
|
|
|
|
m_locking_thread = pthread_self();
|
|
|
|
|
|
|
|
if ( notInUse() ) {
|
2009-07-31 14:43:04 +02:00
|
|
|
logf( XW_LOGINFO, "%s: not locking %p because not in use", __func__,
|
|
|
|
this );
|
2009-07-28 07:15:26 +02:00
|
|
|
success = false;
|
2009-07-31 14:43:04 +02:00
|
|
|
m_locking_thread = 0;
|
2009-07-28 07:15:26 +02:00
|
|
|
pthread_mutex_unlock( &m_mutex );
|
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
} /* CookieRef::Lock */
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::Unlock() {
|
|
|
|
assert( m_locking_thread == pthread_self() );
|
2009-07-31 14:43:04 +02:00
|
|
|
m_locking_thread = 0;
|
2009-07-28 07:15:26 +02:00
|
|
|
pthread_mutex_unlock( &m_mutex );
|
|
|
|
}
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
void
|
2005-10-02 17:39:38 +02:00
|
|
|
CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2009-02-01 17:00:20 +01:00
|
|
|
if ( CRefMgr::Get()->Associate( socket, this ) ) {
|
|
|
|
pushConnectEvent( socket, hid, nPlayersH, nPlayersT );
|
|
|
|
handleEvents();
|
|
|
|
} else {
|
|
|
|
logf( XW_LOGINFO, "dropping connect event; already connected" );
|
2005-10-01 18:33:45 +02:00
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void
|
2005-10-02 17:39:38 +02:00
|
|
|
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
2005-09-02 08:56:34 +02:00
|
|
|
{
|
2009-02-01 17:00:20 +01:00
|
|
|
(void)CRefMgr::Get()->Associate( socket, this );
|
2005-10-02 17:39:38 +02:00
|
|
|
pushReconnectEvent( socket, hid, nPlayersH, nPlayersT );
|
2005-09-02 08:56:34 +02:00
|
|
|
handleEvents();
|
|
|
|
}
|
|
|
|
|
2005-09-05 17:50:49 +02:00
|
|
|
void
|
|
|
|
CookieRef::_Disconnect( int socket, HostID hostID )
|
|
|
|
{
|
2009-02-01 17:00:20 +01:00
|
|
|
logf( XW_LOGINFO, "%s(socket=%d, hostID=%d)", __func__, socket, hostID );
|
2005-09-05 17:50:49 +02:00
|
|
|
CRefMgr::Get()->Disassociate( socket, this );
|
|
|
|
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_DISCONNMSG;
|
2005-09-05 17:50:49 +02:00
|
|
|
evt.u.discon.socket = socket;
|
|
|
|
evt.u.discon.srcID = hostID;
|
|
|
|
m_eventQueue.push_back( evt );
|
|
|
|
|
|
|
|
handleEvents();
|
|
|
|
}
|
|
|
|
|
2005-10-30 06:20:31 +01:00
|
|
|
void
|
|
|
|
CookieRef::_Shutdown()
|
|
|
|
{
|
|
|
|
CRefEvent evt;
|
|
|
|
evt.type = XWE_SHUTDOWN;
|
|
|
|
m_eventQueue.push_back( evt );
|
|
|
|
|
|
|
|
handleEvents();
|
|
|
|
} /* _Shutdown */
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
int
|
|
|
|
CookieRef::SocketForHost( HostID dest )
|
|
|
|
{
|
2009-08-21 14:00:09 +02:00
|
|
|
int socket = -1;
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::const_iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_hostID == dest ) {
|
|
|
|
socket = iter->m_socket;
|
|
|
|
break;
|
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
2009-08-21 14:00:09 +02:00
|
|
|
|
2005-10-30 06:20:31 +01:00
|
|
|
logf( XW_LOGVERBOSE0, "returning socket=%d for hostid=%x", socket, dest );
|
2005-03-19 23:14:27 +01:00
|
|
|
return socket;
|
|
|
|
}
|
|
|
|
|
2005-09-05 17:50:49 +02:00
|
|
|
/* The idea here is: have we never seen the XW_ST_ALLCONNECTED state. This
|
|
|
|
needs to include any states reachable from XW_ST_ALLCONNECTED from which
|
|
|
|
recovery back to XW_ST_ALLCONNECTED is possible. This is used to decide
|
|
|
|
whether to admit a connection based on its cookie -- whether that cookie
|
|
|
|
should join an existing cref or get a new one? */
|
2008-12-30 06:13:30 +01:00
|
|
|
bool
|
2005-09-05 17:50:49 +02:00
|
|
|
CookieRef::NeverFullyConnected()
|
|
|
|
{
|
2009-07-29 06:25:21 +02:00
|
|
|
return m_curState != XWS_ALLCONND
|
2005-10-02 18:08:42 +02:00
|
|
|
&& m_curState != XWS_MISSING;
|
2005-09-05 17:50:49 +02:00
|
|
|
}
|
|
|
|
|
2008-12-30 06:13:30 +01:00
|
|
|
bool
|
2009-08-21 14:00:09 +02:00
|
|
|
CookieRef::AcceptingReconnections( HostID hid, const char* cookie,
|
|
|
|
int nPlayersH )
|
2005-10-02 17:39:38 +02:00
|
|
|
{
|
2008-12-30 06:13:30 +01:00
|
|
|
bool accept = false;
|
2005-10-02 17:39:38 +02:00
|
|
|
/* First, do we have room. Second, are we missing this guy? */
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
if ( m_curState != XWS_INITED
|
|
|
|
&& m_curState != XWS_CONNECTING
|
|
|
|
&& m_curState != XWS_MISSING ) {
|
2005-10-02 17:39:38 +02:00
|
|
|
/* do nothing; reject */
|
2005-10-02 18:08:42 +02:00
|
|
|
logf( XW_LOGINFO, "reject: bad state %s", stateString(m_curState) );
|
2005-10-02 17:39:38 +02:00
|
|
|
} else if ( HostKnown( hid ) ) {
|
2005-10-02 18:08:42 +02:00
|
|
|
logf( XW_LOGINFO, "reject: known hid" );
|
2005-10-02 17:39:38 +02:00
|
|
|
/* do nothing: reject */
|
|
|
|
} else {
|
2009-08-13 14:59:55 +02:00
|
|
|
if ( m_nPlayersSought == 0 ) {
|
2008-12-30 06:13:30 +01:00
|
|
|
accept = true;
|
2009-08-13 14:59:55 +02:00
|
|
|
} else if ( nPlayersH + m_nPlayersHere <= m_nPlayersSought ) {
|
2008-12-30 06:13:30 +01:00
|
|
|
accept = true;
|
2005-10-02 17:39:38 +02:00
|
|
|
} else {
|
2009-08-13 14:59:55 +02:00
|
|
|
logf( XW_LOGINFO, "reject: m_nPlayersSought=%d, m_nPlayersHere=%d",
|
|
|
|
m_nPlayersSought, m_nPlayersHere );
|
2005-10-02 17:39:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
/* Error to connect if cookie doesn't match. */
|
|
|
|
if ( accept && !!cookie && 0 != strcmp( cookie, Cookie() ) ) {
|
|
|
|
logf( XW_LOGERROR, "%s: not accepting b/c cookie mismatch: %s vs %s",
|
|
|
|
__func__, cookie, Cookie() );
|
|
|
|
accept = false;
|
|
|
|
}
|
|
|
|
|
2005-10-02 17:39:38 +02:00
|
|
|
return accept;
|
|
|
|
} /* AcceptingReconnections */
|
2005-10-01 18:33:45 +02:00
|
|
|
|
2005-09-03 08:55:08 +02:00
|
|
|
void
|
|
|
|
CookieRef::notifyDisconn( const CRefEvent* evt )
|
|
|
|
{
|
|
|
|
int socket = evt->u.disnote.socket;
|
2005-09-03 17:41:17 +02:00
|
|
|
unsigned char buf[] = {
|
|
|
|
XWRELAY_DISCONNECT_YOU,
|
|
|
|
evt->u.disnote.why
|
|
|
|
};
|
2005-09-03 08:55:08 +02:00
|
|
|
|
2009-07-06 03:50:51 +02:00
|
|
|
send_with_length( socket, buf, sizeof(buf), true );
|
2005-09-03 08:55:08 +02:00
|
|
|
} /* notifyDisconn */
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
void
|
2005-09-05 17:50:49 +02:00
|
|
|
CookieRef::removeSocket( int socket )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2009-07-06 03:50:51 +02:00
|
|
|
logf( XW_LOGINFO, "%s(socket=%d)", __func__, socket );
|
2005-04-20 14:13:20 +02:00
|
|
|
int count;
|
|
|
|
{
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2005-04-20 14:13:20 +02:00
|
|
|
|
2005-09-05 17:50:49 +02:00
|
|
|
count = m_sockets.size();
|
2005-04-20 14:13:20 +02:00
|
|
|
assert( count > 0 );
|
2009-08-21 14:00:09 +02:00
|
|
|
|
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_socket == socket ) {
|
2005-09-05 17:50:49 +02:00
|
|
|
m_sockets.erase(iter);
|
2005-04-20 14:13:20 +02:00
|
|
|
--count;
|
|
|
|
break;
|
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
}
|
2005-03-25 03:59:44 +01:00
|
|
|
|
|
|
|
if ( count == 0 ) {
|
2005-09-02 08:56:34 +02:00
|
|
|
pushLastSocketGoneEvent();
|
2005-03-25 03:59:44 +01:00
|
|
|
}
|
2005-10-30 06:20:31 +01:00
|
|
|
} /* removeSocket */
|
2005-09-02 08:56:34 +02:00
|
|
|
|
2008-12-30 06:13:30 +01:00
|
|
|
bool
|
2005-09-02 08:56:34 +02:00
|
|
|
CookieRef::HasSocket( int socket )
|
2009-07-28 07:15:26 +02:00
|
|
|
{
|
|
|
|
bool result = Lock();
|
|
|
|
if ( result ) {
|
|
|
|
result = HasSocket_locked( socket );
|
|
|
|
Unlock();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CookieRef::HasSocket_locked( int socket )
|
2005-09-02 08:56:34 +02:00
|
|
|
{
|
2008-12-30 06:13:30 +01:00
|
|
|
bool found = false;
|
2005-09-02 08:56:34 +02:00
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_socket == socket ) {
|
2008-12-30 06:13:30 +01:00
|
|
|
found = true;
|
2005-09-02 08:56:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-07-28 07:15:26 +02:00
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
return found;
|
2009-07-28 07:15:26 +02:00
|
|
|
} /* HasSocket_locked */
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2007-11-19 00:38:56 +01:00
|
|
|
#ifdef RELAY_HEARTBEAT
|
2005-06-23 06:26:44 +02:00
|
|
|
void
|
2005-09-02 08:56:34 +02:00
|
|
|
CookieRef::_HandleHeartbeat( HostID id, int socket )
|
2005-06-23 06:26:44 +02:00
|
|
|
{
|
2005-07-06 00:05:37 +02:00
|
|
|
pushHeartbeatEvent( id, socket );
|
|
|
|
handleEvents();
|
|
|
|
} /* HandleHeartbeat */
|
|
|
|
|
|
|
|
void
|
2005-09-03 08:55:08 +02:00
|
|
|
CookieRef::_CheckHeartbeats( time_t now )
|
2005-07-06 00:05:37 +02:00
|
|
|
{
|
2009-08-21 14:00:09 +02:00
|
|
|
logf( XW_LOGINFO, "%s", __func__ );
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
time_t last = iter->m_lastHeartbeat;
|
2005-10-30 06:20:31 +01:00
|
|
|
if ( (now - last) > GetHeartbeat() ) {
|
2009-08-21 14:00:09 +02:00
|
|
|
pushHeartFailedEvent( iter->m_socket );
|
2005-09-03 08:55:08 +02:00
|
|
|
}
|
|
|
|
}
|
2005-10-30 06:20:31 +01:00
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
handleEvents();
|
|
|
|
} /* CheckHeartbeats */
|
2007-11-19 00:38:56 +01:00
|
|
|
#endif
|
2005-07-06 00:05:37 +02:00
|
|
|
|
|
|
|
void
|
2005-09-02 08:56:34 +02:00
|
|
|
CookieRef::_Forward( HostID src, HostID dest, unsigned char* buf, int buflen )
|
2005-07-06 00:05:37 +02:00
|
|
|
{
|
|
|
|
pushForwardEvent( src, dest, buf, buflen );
|
|
|
|
handleEvents();
|
|
|
|
} /* Forward */
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void
|
|
|
|
CookieRef::_Remove( int socket )
|
|
|
|
{
|
|
|
|
pushRemoveSocketEvent( socket );
|
|
|
|
handleEvents();
|
|
|
|
} /* Forward */
|
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
void
|
2009-08-21 14:00:09 +02:00
|
|
|
CookieRef::pushConnectEvent( int socket, HostID srcID,
|
2005-10-02 17:39:38 +02:00
|
|
|
int nPlayersH, int nPlayersT )
|
2005-07-06 00:05:37 +02:00
|
|
|
{
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_CONNECTMSG;
|
2005-07-06 00:05:37 +02:00
|
|
|
evt.u.con.socket = socket;
|
|
|
|
evt.u.con.srcID = srcID;
|
2005-10-02 17:39:38 +02:00
|
|
|
evt.u.con.nPlayersH = nPlayersH;
|
|
|
|
evt.u.con.nPlayersT = nPlayersT;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( evt );
|
2005-07-06 00:05:37 +02:00
|
|
|
} /* pushConnectEvent */
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void
|
2009-08-21 14:00:09 +02:00
|
|
|
CookieRef::pushReconnectEvent( int socket, HostID srcID,
|
2005-10-02 17:39:38 +02:00
|
|
|
int nPlayersH, int nPlayersT )
|
2005-09-02 08:56:34 +02:00
|
|
|
{
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_RECONNECTMSG;
|
2005-09-03 20:35:34 +02:00
|
|
|
evt.u.con.socket = socket;
|
|
|
|
evt.u.con.srcID = srcID;
|
2005-10-02 17:39:38 +02:00
|
|
|
evt.u.con.nPlayersH = nPlayersH;
|
|
|
|
evt.u.con.nPlayersT = nPlayersT;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( evt );
|
2005-09-03 20:35:34 +02:00
|
|
|
} /* pushReconnectEvent */
|
2005-09-02 08:56:34 +02:00
|
|
|
|
2007-11-19 00:38:56 +01:00
|
|
|
#ifdef RELAY_HEARTBEAT
|
2005-07-06 00:05:37 +02:00
|
|
|
void
|
|
|
|
CookieRef::pushHeartbeatEvent( HostID id, int socket )
|
|
|
|
{
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_HEARTRCVD;
|
2005-07-06 00:05:37 +02:00
|
|
|
evt.u.heart.id = id;
|
|
|
|
evt.u.heart.socket = socket;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( evt );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::pushHeartFailedEvent( int socket )
|
|
|
|
{
|
2009-08-21 14:00:09 +02:00
|
|
|
logf( XW_LOGINFO, "%s", __func__ );
|
2005-09-03 08:55:08 +02:00
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_HEARTFAILED;
|
2005-09-03 08:55:08 +02:00
|
|
|
evt.u.heart.socket = socket;
|
|
|
|
m_eventQueue.push_back( evt );
|
2005-07-06 00:05:37 +02:00
|
|
|
}
|
2007-11-19 00:38:56 +01:00
|
|
|
#endif
|
2005-07-06 00:05:37 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::pushForwardEvent( HostID src, HostID dest,
|
|
|
|
unsigned char* buf, int buflen )
|
|
|
|
{
|
2005-10-30 06:20:31 +01:00
|
|
|
logf( XW_LOGVERBOSE1, "pushForwardEvent: %d -> %d", src, dest );
|
2005-07-06 00:05:37 +02:00
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_FORWARDMSG;
|
2005-07-06 00:05:37 +02:00
|
|
|
evt.u.fwd.src = src;
|
|
|
|
evt.u.fwd.dest = dest;
|
|
|
|
evt.u.fwd.buf = buf;
|
|
|
|
evt.u.fwd.buflen = buflen;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( evt );
|
2005-07-06 00:05:37 +02:00
|
|
|
}
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void
|
|
|
|
CookieRef::pushRemoveSocketEvent( int socket )
|
|
|
|
{
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_REMOVESOCKET;
|
2005-09-02 08:56:34 +02:00
|
|
|
evt.u.rmsock.socket = socket;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( evt );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::pushNotifyDisconEvent( int socket, XWREASON why )
|
|
|
|
{
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_NOTIFYDISCON;
|
2005-09-03 08:55:08 +02:00
|
|
|
evt.u.disnote.socket = socket;
|
|
|
|
evt.u.disnote.why = why;
|
|
|
|
m_eventQueue.push_back( evt );
|
2005-09-02 08:56:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::pushLastSocketGoneEvent()
|
|
|
|
{
|
|
|
|
CRefEvent evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
evt.type = XWE_NOMORESOCKETS;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( evt );
|
2005-09-02 08:56:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::handleEvents()
|
|
|
|
{
|
|
|
|
/* Assumption: has mutex!!!! */
|
|
|
|
while ( m_eventQueue.size () > 0 ) {
|
2005-07-06 00:05:37 +02:00
|
|
|
CRefEvent evt = m_eventQueue.front();
|
|
|
|
m_eventQueue.pop_front();
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
XW_RELAY_ACTION takeAction;
|
2005-07-06 00:05:37 +02:00
|
|
|
if ( getFromTable( m_curState, evt.type, &takeAction, &m_nextState ) ) {
|
|
|
|
|
2007-02-06 06:52:22 +01:00
|
|
|
logf( XW_LOGINFO, "%s: %s -> %s on evt %s, act=%s", __func__,
|
2005-10-30 06:20:31 +01:00
|
|
|
stateString(m_curState), stateString(m_nextState),
|
|
|
|
eventString(evt.type), actString(takeAction) );
|
2005-07-06 00:05:37 +02:00
|
|
|
|
|
|
|
switch( takeAction ) {
|
2005-10-02 17:39:38 +02:00
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_CHKCOUNTS:
|
2005-10-02 17:39:38 +02:00
|
|
|
checkCounts( &evt );
|
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_SEND_1ST_RSP:
|
|
|
|
case XWA_SEND_1ST_RERSP:
|
2005-09-02 08:56:34 +02:00
|
|
|
setAllConnectedTimer();
|
2005-10-02 17:39:38 +02:00
|
|
|
increasePlayerCounts( &evt );
|
2005-10-02 18:08:42 +02:00
|
|
|
sendResponse( &evt, takeAction == XWA_SEND_1ST_RSP );
|
2005-09-03 20:35:34 +02:00
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_SEND_RSP:
|
|
|
|
case XWA_SEND_RERSP:
|
2005-10-02 17:39:38 +02:00
|
|
|
increasePlayerCounts( &evt );
|
2005-10-02 18:08:42 +02:00
|
|
|
sendResponse( &evt, takeAction == XWA_SEND_RSP );
|
2005-07-06 00:05:37 +02:00
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_FWD:
|
2005-07-06 00:05:37 +02:00
|
|
|
forward( &evt );
|
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_TIMERDISCONN:
|
2005-09-03 08:55:08 +02:00
|
|
|
disconnectSockets( 0, XWRELAY_ERROR_TIMEOUT );
|
|
|
|
break;
|
2005-10-19 05:44:55 +02:00
|
|
|
|
2005-10-30 06:20:31 +01:00
|
|
|
case XWA_SHUTDOWN:
|
|
|
|
disconnectSockets( 0, XWRELAY_ERROR_SHUTDOWN );
|
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_HEARTDISCONN:
|
2005-09-03 20:35:34 +02:00
|
|
|
notifyOthers( evt.u.heart.socket, XWRELAY_DISCONNECT_OTHER,
|
|
|
|
XWRELAY_ERROR_HEART_OTHER );
|
2005-10-19 05:44:55 +02:00
|
|
|
setAllConnectedTimer();
|
|
|
|
reducePlayerCounts( evt.u.discon.socket );
|
2005-09-03 17:41:17 +02:00
|
|
|
disconnectSockets( evt.u.heart.socket,
|
|
|
|
XWRELAY_ERROR_HEART_YOU );
|
2005-07-06 00:05:37 +02:00
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_DISCONNECT:
|
2005-10-19 05:44:55 +02:00
|
|
|
setAllConnectedTimer();
|
2005-10-02 17:39:38 +02:00
|
|
|
reducePlayerCounts( evt.u.discon.socket );
|
2005-09-05 17:50:49 +02:00
|
|
|
removeSocket( evt.u.discon.socket );
|
|
|
|
/* Don't notify. This is a normal part of a game ending. */
|
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_NOTEHEART:
|
2005-07-06 00:05:37 +02:00
|
|
|
noteHeartbeat( &evt );
|
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_NOTIFYDISCON:
|
2005-09-03 08:55:08 +02:00
|
|
|
notifyDisconn( &evt );
|
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_REMOVESOCKET:
|
2005-10-19 05:44:55 +02:00
|
|
|
setAllConnectedTimer();
|
2005-10-02 17:39:38 +02:00
|
|
|
reducePlayerCounts( evt.u.rmsock.socket );
|
2005-09-04 22:37:42 +02:00
|
|
|
notifyOthers( evt.u.rmsock.socket, XWRELAY_DISCONNECT_OTHER,
|
|
|
|
XWRELAY_ERROR_LOST_OTHER );
|
2005-09-05 17:50:49 +02:00
|
|
|
removeSocket( evt.u.rmsock.socket );
|
2005-09-02 08:56:34 +02:00
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_SENDALLHERE:
|
|
|
|
case XWA_SNDALLHERE_2:
|
2005-10-15 18:35:18 +02:00
|
|
|
cancelAllConnectedTimer();
|
2009-08-21 14:00:09 +02:00
|
|
|
assignConnName();
|
|
|
|
assignHostIds();
|
2005-10-15 18:35:18 +02:00
|
|
|
sendAllHere( takeAction == XWA_SENDALLHERE );
|
2005-10-02 17:39:38 +02:00
|
|
|
break;
|
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_REJECT:
|
2005-10-02 17:39:38 +02:00
|
|
|
|
2005-10-02 18:08:42 +02:00
|
|
|
case XWA_NONE:
|
2005-08-02 06:57:13 +02:00
|
|
|
/* nothing to do for these */
|
2005-07-06 00:05:37 +02:00
|
|
|
break;
|
|
|
|
|
2005-10-02 17:39:38 +02:00
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_curState = m_nextState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* handleEvents */
|
|
|
|
|
2005-09-02 09:18:39 +02:00
|
|
|
void
|
2009-07-06 03:50:51 +02:00
|
|
|
CookieRef::send_with_length( int socket, unsigned char* buf, int bufLen,
|
|
|
|
bool cascade )
|
2005-07-06 00:05:37 +02:00
|
|
|
{
|
2009-07-06 03:50:51 +02:00
|
|
|
bool failed = false;
|
2009-07-28 07:15:26 +02:00
|
|
|
if ( send_with_length_unsafe( socket, buf, bufLen ) ) {
|
|
|
|
RecordSent( bufLen, socket );
|
|
|
|
} else {
|
|
|
|
failed = true;
|
2005-07-06 00:05:37 +02:00
|
|
|
}
|
2009-07-28 07:15:26 +02:00
|
|
|
|
2009-07-06 03:50:51 +02:00
|
|
|
if ( failed && cascade ) {
|
|
|
|
_Remove( socket );
|
|
|
|
XWThreadPool::GetTPool()->CloseSocket( socket );
|
|
|
|
}
|
2009-07-28 07:15:26 +02:00
|
|
|
} /* send_with_length */
|
2005-07-06 00:05:37 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
putNetShort( unsigned char** bufpp, unsigned short s )
|
|
|
|
{
|
|
|
|
s = htons( s );
|
|
|
|
memcpy( *bufpp, &s, sizeof(s) );
|
|
|
|
*bufpp += sizeof(s);
|
|
|
|
}
|
|
|
|
|
2005-10-02 17:39:38 +02:00
|
|
|
void
|
|
|
|
CookieRef::increasePlayerCounts( const CRefEvent* evt )
|
|
|
|
{
|
|
|
|
int nPlayersH = evt->u.con.nPlayersH;
|
|
|
|
int nPlayersT = evt->u.con.nPlayersT;
|
|
|
|
HostID hid = evt->u.con.srcID;
|
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
logf( XW_LOGINFO, "increasePlayerCounts: hid=%d, nPlayersH=%d, "
|
2009-02-28 20:35:32 +01:00
|
|
|
"nPlayersT=%d", hid, nPlayersH, nPlayersT );
|
2005-10-02 17:39:38 +02:00
|
|
|
|
|
|
|
if ( hid == HOST_ID_SERVER ) {
|
2009-08-13 14:59:55 +02:00
|
|
|
assert( m_nPlayersSought == 0 );
|
|
|
|
m_nPlayersSought = nPlayersT;
|
2005-10-02 17:39:38 +02:00
|
|
|
} else {
|
|
|
|
assert( nPlayersT == 0 ); /* should catch this earlier!!! */
|
2009-08-13 14:59:55 +02:00
|
|
|
assert( m_nPlayersSought == 0 || m_nPlayersHere <= m_nPlayersSought );
|
2005-10-02 17:39:38 +02:00
|
|
|
}
|
|
|
|
m_nPlayersHere += nPlayersH;
|
|
|
|
|
2005-10-30 06:20:31 +01:00
|
|
|
logf( XW_LOGVERBOSE1, "increasePlayerCounts: here=%d; total=%d",
|
2009-08-13 14:59:55 +02:00
|
|
|
m_nPlayersHere, m_nPlayersSought );
|
2005-10-02 17:39:38 +02:00
|
|
|
|
|
|
|
CRefEvent newevt;
|
2009-08-13 14:59:55 +02:00
|
|
|
newevt.type = (m_nPlayersHere == m_nPlayersSought) ?
|
2005-10-02 18:08:42 +02:00
|
|
|
XWE_ALLHERE : XWE_SOMEMISSING;
|
2005-10-02 17:39:38 +02:00
|
|
|
m_eventQueue.push_back( newevt );
|
|
|
|
} /* increasePlayerCounts */
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::reducePlayerCounts( int socket )
|
|
|
|
{
|
2005-10-30 06:20:31 +01:00
|
|
|
logf( XW_LOGVERBOSE1, "reducePlayerCounts on socket %d", socket );
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_socket == socket ) {
|
|
|
|
if ( iter->m_hostID == HOST_ID_SERVER ) {
|
2009-08-13 14:59:55 +02:00
|
|
|
m_nPlayersSought = 0;
|
2005-10-02 17:39:38 +02:00
|
|
|
} else {
|
2009-08-21 14:00:09 +02:00
|
|
|
assert( iter->m_nPlayersT == 0 );
|
2005-10-02 17:39:38 +02:00
|
|
|
}
|
2009-08-21 14:00:09 +02:00
|
|
|
m_nPlayersHere -= iter->m_nPlayersH;
|
2005-10-02 17:39:38 +02:00
|
|
|
|
2009-08-13 14:59:55 +02:00
|
|
|
logf( XW_LOGVERBOSE1, "reducePlayerCounts: m_nPlayersHere=%d; m_nPlayersSought=%d",
|
|
|
|
m_nPlayersHere, m_nPlayersSought );
|
2005-10-02 17:39:38 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* reducePlayerCounts */
|
|
|
|
|
|
|
|
/* Determine if adding this device to the game would give us too many
|
|
|
|
players. */
|
|
|
|
void
|
|
|
|
CookieRef::checkCounts( const CRefEvent* evt )
|
|
|
|
{
|
|
|
|
int nPlayersH = evt->u.con.nPlayersH;
|
|
|
|
/* int nPlayersT = evt->u.con.nPlayersT; */
|
|
|
|
HostID hid = evt->u.con.srcID;
|
2008-12-30 06:13:30 +01:00
|
|
|
bool success;
|
2005-10-02 17:39:38 +02:00
|
|
|
|
2009-08-13 14:59:55 +02:00
|
|
|
logf( XW_LOGVERBOSE1, "checkCounts: hid=%d, nPlayers=%d, m_nPlayersSought = %d, "
|
2005-10-02 17:39:38 +02:00
|
|
|
"m_nPlayersHere = %d",
|
2009-08-13 14:59:55 +02:00
|
|
|
hid, nPlayersH, m_nPlayersSought, m_nPlayersHere );
|
2005-10-02 17:39:38 +02:00
|
|
|
|
|
|
|
if ( hid == HOST_ID_SERVER ) {
|
2009-08-13 14:59:55 +02:00
|
|
|
success = m_nPlayersSought == 0;
|
2005-10-02 17:39:38 +02:00
|
|
|
} else {
|
2009-08-13 14:59:55 +02:00
|
|
|
success = (m_nPlayersSought == 0) /* if no server present yet */
|
|
|
|
|| (m_nPlayersSought >= m_nPlayersHere + nPlayersH);
|
2005-10-02 17:39:38 +02:00
|
|
|
}
|
2005-10-30 06:20:31 +01:00
|
|
|
logf( XW_LOGVERBOSE1, "success = %d", success );
|
2005-10-02 17:39:38 +02:00
|
|
|
|
|
|
|
CRefEvent newevt;
|
|
|
|
if ( success ) {
|
|
|
|
newevt = *evt;
|
2005-10-02 18:08:42 +02:00
|
|
|
newevt.type = XWE_OKTOSEND;
|
2005-10-02 17:39:38 +02:00
|
|
|
} else {
|
2005-10-02 18:08:42 +02:00
|
|
|
newevt.type = XWE_COUNTSBAD;
|
2005-10-02 17:39:38 +02:00
|
|
|
}
|
|
|
|
m_eventQueue.push_back( newevt );
|
|
|
|
} /* checkCounts */
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void
|
|
|
|
CookieRef::setAllConnectedTimer()
|
|
|
|
{
|
|
|
|
time_t inHowLong;
|
2009-03-02 02:50:14 +01:00
|
|
|
RelayConfigs::GetConfigs()->GetValueFor( "ALLCONN", &inHowLong );
|
2005-10-15 17:49:22 +02:00
|
|
|
TimerMgr::GetTimerMgr()->SetTimer( inHowLong,
|
2005-09-02 08:56:34 +02:00
|
|
|
s_checkAllConnected, this, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::cancelAllConnectedTimer()
|
|
|
|
{
|
2005-10-15 17:49:22 +02:00
|
|
|
TimerMgr::GetTimerMgr()->ClearTimer( s_checkAllConnected, this );
|
2005-09-02 08:56:34 +02:00
|
|
|
}
|
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
void
|
2008-12-30 06:13:30 +01:00
|
|
|
CookieRef::sendResponse( const CRefEvent* evt, bool initial )
|
2005-07-06 00:05:37 +02:00
|
|
|
{
|
|
|
|
int socket = evt->u.con.socket;
|
|
|
|
HostID id = evt->u.con.srcID;
|
2005-10-02 17:39:38 +02:00
|
|
|
int nPlayersH = evt->u.con.nPlayersH;
|
|
|
|
int nPlayersT = evt->u.con.nPlayersT;
|
2005-07-06 00:05:37 +02:00
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
|
|
|
|
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, socket=%d (size=%d)",
|
|
|
|
__func__, id, socket, m_sockets.size());
|
|
|
|
HostRec hr(id, socket, nPlayersH, nPlayersT);
|
|
|
|
m_sockets.push_back( hr );
|
2005-07-06 00:05:37 +02:00
|
|
|
|
|
|
|
/* Now send the response */
|
2005-10-01 18:33:45 +02:00
|
|
|
unsigned char buf[1 + /* cmd */
|
|
|
|
sizeof(short) + /* heartbeat */
|
2005-10-02 17:39:38 +02:00
|
|
|
sizeof(CookieID) +
|
|
|
|
1 /* hostID */
|
|
|
|
];
|
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
unsigned char* bufp = buf;
|
|
|
|
|
2005-10-01 18:33:45 +02:00
|
|
|
*bufp++ = initial ? XWRELAY_CONNECT_RESP : XWRELAY_RECONNECT_RESP;
|
2005-07-06 00:05:37 +02:00
|
|
|
putNetShort( &bufp, GetHeartbeat() );
|
2005-10-01 18:33:45 +02:00
|
|
|
putNetShort( &bufp, GetCookieID() );
|
2005-07-06 00:05:37 +02:00
|
|
|
|
2009-07-06 03:50:51 +02:00
|
|
|
send_with_length( socket, buf, bufp - buf, true );
|
2009-08-21 14:00:09 +02:00
|
|
|
logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) );
|
2005-07-06 00:05:37 +02:00
|
|
|
} /* sendResponse */
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::forward( const CRefEvent* evt )
|
|
|
|
{
|
|
|
|
unsigned char* buf = evt->u.fwd.buf;
|
|
|
|
int buflen = evt->u.fwd.buflen;
|
|
|
|
HostID dest = evt->u.fwd.dest;
|
|
|
|
|
|
|
|
int destSocket = SocketForHost( dest );
|
|
|
|
|
2005-08-02 06:57:13 +02:00
|
|
|
if ( destSocket != -1 ) {
|
|
|
|
/* This is an ugly hack!!!! */
|
|
|
|
*buf = XWRELAY_MSG_FROMRELAY;
|
2009-07-06 03:50:51 +02:00
|
|
|
send_with_length( destSocket, buf, buflen, true );
|
2005-07-06 00:05:37 +02:00
|
|
|
|
2005-08-02 06:57:13 +02:00
|
|
|
/* also note that we've heard from src recently */
|
2007-11-19 00:38:56 +01:00
|
|
|
#ifdef RELAY_HEARTBEAT
|
|
|
|
HostID src = evt->u.fwd.src;
|
2005-08-02 06:57:13 +02:00
|
|
|
pushHeartbeatEvent( src, SocketForHost(src) );
|
2007-11-19 00:38:56 +01:00
|
|
|
#endif
|
2005-08-02 06:57:13 +02:00
|
|
|
} else {
|
|
|
|
/* We're not really connected yet! */
|
|
|
|
}
|
2005-07-06 00:05:37 +02:00
|
|
|
} /* forward */
|
|
|
|
|
2005-09-03 17:41:17 +02:00
|
|
|
void
|
2009-07-06 03:50:51 +02:00
|
|
|
CookieRef::send_msg( int socket, HostID id, XWRelayMsg msg, XWREASON why,
|
|
|
|
bool cascade )
|
2005-09-03 20:35:34 +02:00
|
|
|
{
|
|
|
|
unsigned char buf[10];
|
|
|
|
short tmp;
|
2009-07-06 03:50:51 +02:00
|
|
|
unsigned int len = 0;
|
2005-09-03 20:35:34 +02:00
|
|
|
buf[len++] = msg;
|
|
|
|
|
|
|
|
switch ( msg ) {
|
|
|
|
case XWRELAY_DISCONNECT_OTHER:
|
|
|
|
buf[len++] = why;
|
|
|
|
tmp = htons( id );
|
|
|
|
memcpy( &buf[len], &tmp, 2 );
|
|
|
|
len += 2;
|
|
|
|
break;
|
|
|
|
default:
|
2005-10-02 18:08:42 +02:00
|
|
|
logf( XW_LOGINFO, "not handling message %d", msg );
|
2005-09-03 20:35:34 +02:00
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
2009-04-05 20:47:45 +02:00
|
|
|
assert( len <= sizeof(buf) );
|
2009-07-06 03:50:51 +02:00
|
|
|
send_with_length( socket, buf, len, cascade );
|
2005-09-03 20:35:34 +02:00
|
|
|
} /* send_msg */
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::notifyOthers( int socket, XWRelayMsg msg, XWREASON why )
|
2005-09-03 17:41:17 +02:00
|
|
|
{
|
|
|
|
assert( socket != 0 );
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
int other = iter->m_socket;
|
2005-09-03 17:41:17 +02:00
|
|
|
if ( other != socket ) {
|
2009-08-21 14:00:09 +02:00
|
|
|
send_msg( other, iter->m_hostID, msg, why, false );
|
2005-09-03 17:41:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* notifyOthers */
|
|
|
|
|
2005-10-02 17:39:38 +02:00
|
|
|
void
|
2008-12-30 06:13:30 +01:00
|
|
|
CookieRef::sendAllHere( bool includeName )
|
2005-10-02 17:39:38 +02:00
|
|
|
{
|
|
|
|
unsigned char buf[1 + 1 + MAX_CONNNAME_LEN];
|
|
|
|
unsigned char* bufp = buf;
|
2009-08-21 14:00:09 +02:00
|
|
|
unsigned char* idLoc;
|
2005-10-02 17:39:38 +02:00
|
|
|
|
|
|
|
*bufp++ = XWRELAY_ALLHERE;
|
2009-08-21 14:00:09 +02:00
|
|
|
idLoc = bufp++; /* space for hostId, remembering address */
|
2005-10-02 17:39:38 +02:00
|
|
|
*bufp++ = includeName? 1 : 0;
|
|
|
|
|
|
|
|
if ( includeName ) {
|
|
|
|
const char* connName = ConnName();
|
2009-08-21 14:00:09 +02:00
|
|
|
assert( !!connName && connName[0] );
|
2005-10-02 17:39:38 +02:00
|
|
|
int len = strlen( connName );
|
|
|
|
assert( len < MAX_CONNNAME_LEN );
|
|
|
|
*bufp++ = (char)len;
|
|
|
|
memcpy( bufp, connName, len );
|
|
|
|
bufp += len;
|
|
|
|
}
|
2009-08-21 14:00:09 +02:00
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter = m_sockets.begin();
|
2005-10-02 17:39:38 +02:00
|
|
|
while ( iter != m_sockets.end() ) {
|
2009-08-21 14:00:09 +02:00
|
|
|
logf( XW_LOGINFO, "%s: sending to hostid %d", __func__,
|
|
|
|
iter->m_hostID );
|
|
|
|
*idLoc = iter->m_hostID; /* write in this target's hostId */
|
|
|
|
send_with_length( iter->m_socket, buf, bufp-buf,
|
2009-07-06 03:50:51 +02:00
|
|
|
true );
|
2005-10-02 17:39:38 +02:00
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
} /* sendAllHere */
|
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
void
|
|
|
|
CookieRef::assignConnName( void )
|
|
|
|
{
|
|
|
|
if ( !ConnName()[0] ) {
|
|
|
|
m_connName = PermID::GetNextUniqueID();
|
|
|
|
logf( XW_LOGINFO, "%s: assigning name: %s", __func__, ConnName() );
|
|
|
|
assert( GetCookieID() != 0 );
|
|
|
|
} else {
|
|
|
|
logf( XW_LOGINFO, "%s: has name: %s", __func__, ConnName() );
|
|
|
|
}
|
|
|
|
} /* assignConnName */
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::assignHostIds( void )
|
|
|
|
{
|
|
|
|
ASSERT_LOCKED();
|
|
|
|
HostID nextId = HOST_ID_SERVER;
|
|
|
|
|
|
|
|
unsigned int bits = 0;
|
|
|
|
|
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_hostID != HOST_ID_NONE ) {
|
|
|
|
bits |= 1 << iter->m_hostID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( (bits & (1 << HOST_ID_SERVER)) != 0 );
|
|
|
|
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_hostID == HOST_ID_NONE ) {
|
|
|
|
while ( ((1 << nextId) & bits) != 0 ) {
|
|
|
|
++nextId;
|
|
|
|
}
|
|
|
|
iter->m_hostID = nextId++; /* ++: don't reuse */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-06 00:05:37 +02:00
|
|
|
void
|
2005-09-03 08:55:08 +02:00
|
|
|
CookieRef::disconnectSockets( int socket, XWREASON why )
|
2005-07-06 00:05:37 +02:00
|
|
|
{
|
2005-09-03 08:55:08 +02:00
|
|
|
if ( socket == 0 ) {
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
assert( iter->m_socket != 0 );
|
|
|
|
disconnectSockets( iter->m_socket, why );
|
2005-09-03 08:55:08 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pushNotifyDisconEvent( socket, why );
|
|
|
|
pushRemoveSocketEvent( socket );
|
2005-09-02 08:56:34 +02:00
|
|
|
}
|
2005-09-03 08:55:08 +02:00
|
|
|
} /* disconnectSockets */
|
2005-07-06 00:05:37 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::noteHeartbeat( const CRefEvent* evt )
|
|
|
|
{
|
|
|
|
int socket = evt->u.heart.socket;
|
|
|
|
HostID id = evt->u.heart.id;
|
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
if ( iter->m_hostID == id ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-05 17:50:49 +02:00
|
|
|
if ( iter == m_sockets.end() ) {
|
2005-10-02 18:08:42 +02:00
|
|
|
logf( XW_LOGERROR, "no socket for HostID %x", id );
|
2005-09-02 08:56:34 +02:00
|
|
|
} else {
|
2005-06-23 06:26:44 +02:00
|
|
|
|
2009-08-21 14:00:09 +02:00
|
|
|
int second_socket = iter->m_socket;
|
|
|
|
if ( second_socket == socket ) {
|
|
|
|
logf( XW_LOGVERBOSE1, "upping m_lastHeartbeat from %d to %d",
|
|
|
|
iter->m_lastHeartbeat, uptime() );
|
|
|
|
iter->m_lastHeartbeat = uptime();
|
|
|
|
} else {
|
|
|
|
/* PENDING If the message came on an unexpected socket, kill the
|
|
|
|
connection. An attack is the most likely explanation. But:
|
|
|
|
now it's happening after a crash and clients reconnect. */
|
|
|
|
logf( XW_LOGERROR, "wrong socket record for HostID %x; wanted %d, found %d",
|
|
|
|
id, socket, second_socket );
|
|
|
|
}
|
2005-09-02 08:56:34 +02:00
|
|
|
}
|
2005-07-06 00:05:37 +02:00
|
|
|
} /* noteHeartbeat */
|
2005-06-23 06:26:44 +02:00
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
/* timer callback */
|
|
|
|
/* static */ void
|
|
|
|
CookieRef::s_checkAllConnected( void* closure )
|
|
|
|
{
|
|
|
|
/* Need to ensure */
|
|
|
|
CookieRef* self = (CookieRef*)closure;
|
|
|
|
SafeCref scr(self);
|
2005-10-01 18:33:45 +02:00
|
|
|
scr.CheckAllConnected();
|
2005-09-02 08:56:34 +02:00
|
|
|
}
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
void
|
2005-09-02 08:56:34 +02:00
|
|
|
CookieRef::_CheckAllConnected()
|
|
|
|
{
|
2009-08-21 14:00:09 +02:00
|
|
|
logf( XW_LOGVERBOSE0, "%s", __func__ );
|
2005-09-14 07:15:27 +02:00
|
|
|
/* MutexLock ml( &m_EventsMutex ); */
|
2005-09-02 08:56:34 +02:00
|
|
|
CRefEvent newEvt;
|
2005-10-02 18:08:42 +02:00
|
|
|
newEvt.type = XWE_CONNTIMER;
|
2005-09-03 08:55:08 +02:00
|
|
|
m_eventQueue.push_back( newEvt );
|
2005-09-02 08:56:34 +02:00
|
|
|
handleEvents();
|
|
|
|
}
|
|
|
|
|
2005-10-30 06:20:31 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::logf( XW_LogLevel level, const char* format, ... )
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
int len;
|
|
|
|
|
2009-02-28 20:35:32 +01:00
|
|
|
len = snprintf( buf, sizeof(buf), "cid:%d ", m_cookieID );
|
2005-10-30 06:20:31 +01:00
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start( ap, format );
|
|
|
|
vsnprintf( buf + len, sizeof(buf) - len, format, ap );
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
::logf( level, buf );
|
|
|
|
}
|
|
|
|
|
2005-09-02 08:56:34 +02:00
|
|
|
void
|
|
|
|
CookieRef::_PrintCookieInfo( string& out )
|
2005-04-20 14:13:20 +02:00
|
|
|
{
|
2005-10-16 03:19:25 +02:00
|
|
|
out += "Cookie=";
|
|
|
|
out += Cookie();
|
2005-04-20 14:13:20 +02:00
|
|
|
out += "\n";
|
2005-10-16 03:19:25 +02:00
|
|
|
out += "connName=";
|
2005-10-01 18:33:45 +02:00
|
|
|
char buf[MAX_CONNNAME_LEN+MAX_COOKIE_LEN];
|
|
|
|
|
2005-10-16 03:19:25 +02:00
|
|
|
snprintf( buf, sizeof(buf), "%s\n", ConnName() );
|
2005-10-01 18:33:45 +02:00
|
|
|
out += buf;
|
2005-09-04 22:37:42 +02:00
|
|
|
|
2005-10-16 03:19:25 +02:00
|
|
|
snprintf( buf, sizeof(buf), "id=%d\n", GetCookieID() );
|
2005-04-20 14:13:20 +02:00
|
|
|
out += buf;
|
|
|
|
|
2005-10-16 03:19:25 +02:00
|
|
|
snprintf( buf, sizeof(buf), "Bytes sent=%d\n", m_totalSent );
|
|
|
|
out += buf;
|
|
|
|
|
2009-08-13 14:59:55 +02:00
|
|
|
snprintf( buf, sizeof(buf), "Total players=%d\n", m_nPlayersSought );
|
2005-10-16 03:19:25 +02:00
|
|
|
out += buf;
|
|
|
|
snprintf( buf, sizeof(buf), "Players here=%d\n", m_nPlayersHere );
|
2005-04-20 14:13:20 +02:00
|
|
|
out += buf;
|
|
|
|
|
2005-10-19 05:44:55 +02:00
|
|
|
snprintf( buf, sizeof(buf), "State=%s\n", stateString( m_curState ) );
|
|
|
|
out += buf;
|
|
|
|
|
|
|
|
/* Timer state: how long since last heartbeat; how long til disconn timer
|
|
|
|
fires. */
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/* n messages */
|
|
|
|
/* open since when */
|
2005-10-19 05:44:55 +02:00
|
|
|
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2005-10-19 05:44:55 +02:00
|
|
|
snprintf( buf, sizeof(buf), "Hosts connected=%d; cur time = %ld\n",
|
2009-03-10 13:52:17 +01:00
|
|
|
m_sockets.size(), uptime() );
|
2005-10-19 05:44:55 +02:00
|
|
|
out += buf;
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
2005-10-19 05:44:55 +02:00
|
|
|
snprintf( buf, sizeof(buf), " HostID=%d; socket=%d;last hbeat=%ld\n",
|
2009-08-21 14:00:09 +02:00
|
|
|
iter->m_hostID, iter->m_socket,
|
|
|
|
iter->m_lastHeartbeat );
|
2005-10-19 05:44:55 +02:00
|
|
|
out += buf;
|
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
|
|
|
|
} /* PrintCookieInfo */
|
2009-02-28 20:35:32 +01:00
|
|
|
|
|
|
|
void
|
2009-07-28 07:15:26 +02:00
|
|
|
CookieRef::_FormatHostInfo( string* hostIds, string* addrs )
|
2009-02-28 20:35:32 +01:00
|
|
|
{
|
2009-07-28 07:15:26 +02:00
|
|
|
ASSERT_LOCKED();
|
2009-08-21 14:00:09 +02:00
|
|
|
vector<HostRec>::iterator iter;
|
2009-07-28 07:15:26 +02:00
|
|
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
|
|
|
|
|
|
|
if ( !!hostIds ) {
|
|
|
|
char buf[8];
|
2009-08-21 14:00:09 +02:00
|
|
|
snprintf( buf, sizeof(buf), "%d ", iter->m_hostID );
|
2009-07-28 07:15:26 +02:00
|
|
|
*hostIds += buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !!addrs ) {
|
2009-08-21 14:00:09 +02:00
|
|
|
int s = iter->m_socket;
|
2009-07-28 07:15:26 +02:00
|
|
|
struct sockaddr_in name;
|
|
|
|
socklen_t siz = sizeof(name);
|
|
|
|
if ( 0 == getpeername( s, (struct sockaddr*)&name, &siz) ) {
|
|
|
|
char buf[32] = {0};
|
|
|
|
snprintf( buf, sizeof(buf), "%s ", inet_ntoa(name.sin_addr) );
|
|
|
|
*addrs += buf;
|
|
|
|
}
|
|
|
|
}
|
2009-02-28 20:35:32 +01:00
|
|
|
}
|
|
|
|
}
|