mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-30 08:34:16 +01:00
Merge remote-tracking branch 'origin/android_branch' into android_branch
This commit is contained in:
commit
54ad381749
20 changed files with 700 additions and 500 deletions
|
@ -1380,16 +1380,17 @@ gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
|
|||
allocAndSet( map, &dctx->white, 0xFFFF, 0xFFFF, 0xFFFF );
|
||||
|
||||
{
|
||||
GdkWindow *window = NULL;
|
||||
if ( GTK_WIDGET_FLAGS(GTK_WIDGET(drawing_area)) & GTK_NO_WINDOW ) {
|
||||
/* XXX I'm not sure about this function because I never used it.
|
||||
* (the name seems to indicate what you want though).
|
||||
*/
|
||||
window = gtk_widget_get_parent_window( GTK_WIDGET(drawing_area) );
|
||||
} else {
|
||||
window = GTK_WIDGET(drawing_area)->window;
|
||||
}
|
||||
window = GTK_WIDGET(drawing_area)->window;
|
||||
// GdkWindow *window = NULL;
|
||||
/* if ( GTK_WIDGET_FLAGS(GTK_WIDGET(drawing_area)) & GTK_NO_WINDOW ) { */
|
||||
/* /\* XXX I'm not sure about this function because I never used it. */
|
||||
/* * (the name seems to indicate what you want though). */
|
||||
/* *\/ */
|
||||
/* window = gtk_widget_get_parent_window( GTK_WIDGET(drawing_area) ); */
|
||||
/* } else { */
|
||||
/* window = GTK_WIDGET(drawing_area)->window; */
|
||||
/* } */
|
||||
GdkWindow* window = GTK_WIDGET(drawing_area)->window;
|
||||
XP_ASSERT( !!window );
|
||||
#ifdef USE_CAIRO
|
||||
dctx->cr = gdk_cairo_create( window );
|
||||
XP_LOGF( "dctx->cr=%p", dctx->cr );
|
||||
|
|
|
@ -30,6 +30,7 @@ SRC = \
|
|||
timermgr.cpp \
|
||||
tpool.cpp \
|
||||
cidlock.cpp \
|
||||
addrinfo.cpp \
|
||||
xwrelay.cpp \
|
||||
|
||||
# STATIC ?= -static
|
||||
|
|
40
xwords4/relay/addrinfo.cpp
Normal file
40
xwords4/relay/addrinfo.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2005-2011 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "addrinfo.h"
|
||||
|
||||
bool
|
||||
AddrInfo::equals( const AddrInfo& other ) const
|
||||
{
|
||||
bool equal = other.isTCP() == isTCP();
|
||||
if ( equal ) {
|
||||
if ( isTCP() ) {
|
||||
equal = m_socket == other.m_socket;
|
||||
} else {
|
||||
assert(0); /* later.... */
|
||||
}
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
63
xwords4/relay/addrinfo.h
Normal file
63
xwords4/relay/addrinfo.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2005 - 2013 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ADDRINFO_H_
|
||||
#define _ADDRINFO_H_
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
class AddrInfo {
|
||||
public:
|
||||
typedef union _AddrUnion {
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in addr_in;
|
||||
} AddrUnion;
|
||||
|
||||
AddrInfo() {
|
||||
memset( this, 0, sizeof(*this) );
|
||||
m_socket = -1;
|
||||
m_isValid = false;
|
||||
}
|
||||
|
||||
AddrInfo( bool isTCP, int socket, const AddrUnion* saddr ) {
|
||||
m_isValid = true;
|
||||
m_isTCP = isTCP;
|
||||
m_socket = socket;
|
||||
memcpy( &m_saddr, saddr, sizeof(m_saddr) );
|
||||
}
|
||||
|
||||
void setIsTCP( bool val ) { m_isTCP = val; }
|
||||
bool isTCP() const { return m_isTCP; } /* later UDP will be here too */
|
||||
int socket() const { assert(m_isValid); return m_socket; }
|
||||
struct in_addr sin_addr() const { return m_saddr.addr_in.sin_addr; }
|
||||
|
||||
bool equals( const AddrInfo& other ) const;
|
||||
|
||||
private:
|
||||
// AddrInfo& operator=(const AddrInfo&); // Prevent assignment
|
||||
int m_socket;
|
||||
bool m_isTCP;
|
||||
bool m_isValid;
|
||||
AddrUnion m_saddr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -27,11 +27,11 @@
|
|||
|
||||
// #define CIDLOCK_DEBUG
|
||||
|
||||
const set<int>
|
||||
CidInfo::GetSockets( void )
|
||||
const vector<AddrInfo>
|
||||
CidInfo::GetAddrs( void )
|
||||
{
|
||||
return 0 == m_owner || NULL == m_cref ?
|
||||
m_sockets : m_cref->GetSockets();
|
||||
m_addrs : m_cref->GetAddrs();
|
||||
}
|
||||
|
||||
CidLock* CidLock::s_instance = NULL;
|
||||
|
@ -117,7 +117,7 @@ CidLock::Claim( CookieID cid )
|
|||
} /* CidLock::Claim */
|
||||
|
||||
CidInfo*
|
||||
CidLock::ClaimSocket( int sock )
|
||||
CidLock::ClaimSocket( const AddrInfo* addr )
|
||||
{
|
||||
CidInfo* info = NULL;
|
||||
#ifdef CIDLOCK_DEBUG
|
||||
|
@ -126,16 +126,19 @@ CidLock::ClaimSocket( int sock )
|
|||
for ( ; ; ) {
|
||||
MutexLock ml( &m_infos_mutex );
|
||||
|
||||
map< CookieID, CidInfo*>::iterator iter;
|
||||
for ( iter = m_infos.begin(); iter != m_infos.end(); ++iter ) {
|
||||
const set<int>& sockets = iter->second->GetSockets();
|
||||
if ( sockets.end() != sockets.find( sock ) ) {
|
||||
if ( 0 == iter->second->GetOwner() ) {
|
||||
info = iter->second;
|
||||
info->SetOwner( pthread_self() );
|
||||
PRINT_CLAIMED();
|
||||
map<CookieID, CidInfo*>::iterator iter;
|
||||
for ( iter = m_infos.begin(); NULL == info && iter != m_infos.end(); ++iter ) {
|
||||
const vector<AddrInfo>& addrs = iter->second->GetAddrs();
|
||||
vector<AddrInfo>::const_iterator iter2;
|
||||
for ( iter2 = addrs.begin(); iter2 != addrs.end(); ++iter2 ) {
|
||||
if ( iter2->equals(*addr) ) {
|
||||
if ( 0 == iter->second->GetOwner() ) {
|
||||
info = iter->second;
|
||||
info->SetOwner( pthread_self() );
|
||||
PRINT_CLAIMED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +180,7 @@ CidLock::Relinquish( CidInfo* claim, bool drop )
|
|||
} else {
|
||||
CookieRef* ref = claim->GetRef();
|
||||
if ( NULL != ref ) {
|
||||
claim->SetSockets( ref->GetSockets() ); /* cache these */
|
||||
claim->SetAddrs( ref->GetAddrs() ); /* cache these */
|
||||
}
|
||||
claim->SetOwner( 0 );
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ class CidInfo {
|
|||
CookieID GetCid( void ) { return m_cid; }
|
||||
CookieRef* GetRef( void ) { return m_cref; }
|
||||
pthread_t GetOwner( void ) { return m_owner; }
|
||||
const set<int> GetSockets( void );
|
||||
void SetSockets( set<int> sockets ) { m_sockets = sockets; };
|
||||
const vector<AddrInfo> GetAddrs( void );
|
||||
void SetAddrs( vector<AddrInfo> addrs ) { m_addrs = addrs; };
|
||||
|
||||
void SetRef( CookieRef* cref ) { m_cref = cref; }
|
||||
void SetOwner( pthread_t owner ) { m_owner = owner; }
|
||||
|
@ -49,7 +49,7 @@ class CidInfo {
|
|||
CookieID m_cid;
|
||||
CookieRef* m_cref;
|
||||
pthread_t m_owner;
|
||||
set<int> m_sockets;
|
||||
vector<AddrInfo> m_addrs;
|
||||
};
|
||||
|
||||
class CidLock {
|
||||
|
@ -65,7 +65,7 @@ class CidLock {
|
|||
|
||||
CidInfo* Claim( void ) { return Claim(0); }
|
||||
CidInfo* Claim( CookieID cid );
|
||||
CidInfo* ClaimSocket( int sock );
|
||||
CidInfo* ClaimSocket( const AddrInfo* addr );
|
||||
void Relinquish( CidInfo* claim, bool drop );
|
||||
|
||||
private:
|
||||
|
|
|
@ -128,12 +128,14 @@ CookieRef::~CookieRef()
|
|||
XWThreadPool* tPool = XWThreadPool::GetTPool();
|
||||
|
||||
ASSERT_LOCKED();
|
||||
map<int,HostRec>::iterator iter;
|
||||
vector<HostRec>::iterator iter;
|
||||
{
|
||||
RWWriteLock rwl( &m_socketsRWLock );
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
int socket = iter->first;
|
||||
tPool->CloseSocket( socket );
|
||||
AddrInfo addr = iter->m_addr;
|
||||
if ( addr.isTCP() ) {
|
||||
tPool->CloseSocket( &addr );
|
||||
}
|
||||
m_sockets.erase( iter );
|
||||
}
|
||||
}
|
||||
|
@ -180,13 +182,13 @@ CookieRef::Unlock() {
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::_Connect( int socket, int clientVersion, DevID* devID,
|
||||
CookieRef::_Connect( int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS, int seed,
|
||||
bool seenSeed, in_addr& addr )
|
||||
bool seenSeed, const AddrInfo* addr )
|
||||
{
|
||||
bool connected = false;
|
||||
HostID prevHostID = HOST_ID_NONE;
|
||||
bool alreadyHere = AlreadyHere( seed, socket, &prevHostID );
|
||||
bool alreadyHere = AlreadyHere( seed, addr, &prevHostID );
|
||||
|
||||
if ( alreadyHere ) {
|
||||
if ( seenSeed ) { /* we need to get rid of the current entry, then
|
||||
|
@ -199,12 +201,23 @@ CookieRef::_Connect( int socket, int clientVersion, DevID* devID,
|
|||
}
|
||||
|
||||
if ( !connected ) {
|
||||
set<int> sockets = GetSockets();
|
||||
if ( sockets.end() == sockets.find( socket ) ) {
|
||||
pushConnectEvent( socket, clientVersion, devID, nPlayersH,
|
||||
nPlayersS, seed, addr );
|
||||
bool socketOK = !addr->isTCP();
|
||||
if ( !socketOK ) {
|
||||
socketOK = true;
|
||||
vector<AddrInfo> addrs = GetAddrs();
|
||||
vector<AddrInfo>::const_iterator iter;
|
||||
for ( iter = addrs.begin(); iter != addrs.end(); ++iter ) {
|
||||
if ( iter->equals( *addr ) ) {
|
||||
socketOK = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( socketOK ) {
|
||||
pushConnectEvent( clientVersion, devID, nPlayersH, nPlayersS,
|
||||
seed, addr );
|
||||
handleEvents();
|
||||
connected = HasSocket_locked( socket );
|
||||
connected = HasSocket_locked( addr );
|
||||
} else {
|
||||
logf( XW_LOGINFO, "dropping connect event; already connected" );
|
||||
}
|
||||
|
@ -213,12 +226,12 @@ CookieRef::_Connect( int socket, int clientVersion, DevID* devID,
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::_Reconnect( int socket, int clientVersion, DevID* devID,
|
||||
HostID hid, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr, bool gameDead )
|
||||
CookieRef::_Reconnect( int clientVersion, DevID* devID, HostID hid,
|
||||
int nPlayersH, int nPlayersS, int seed,
|
||||
const AddrInfo* addr, bool gameDead )
|
||||
{
|
||||
bool spotTaken = false;
|
||||
bool alreadyHere = AlreadyHere( hid, seed, socket, &spotTaken );
|
||||
bool alreadyHere = AlreadyHere( hid, seed, addr, &spotTaken );
|
||||
if ( spotTaken ) {
|
||||
logf( XW_LOGINFO, "%s: failing because spot taken", __func__ );
|
||||
} else {
|
||||
|
@ -226,11 +239,11 @@ CookieRef::_Reconnect( int socket, int clientVersion, DevID* devID,
|
|||
logf( XW_LOGINFO, "%s: dropping because already here",
|
||||
__func__ );
|
||||
} else {
|
||||
pushReconnectEvent( socket, clientVersion, devID, hid, nPlayersH,
|
||||
pushReconnectEvent( clientVersion, devID, hid, nPlayersH,
|
||||
nPlayersS, seed, addr );
|
||||
}
|
||||
if ( gameDead ) {
|
||||
pushGameDead( socket );
|
||||
pushGameDead( addr );
|
||||
}
|
||||
handleEvents();
|
||||
}
|
||||
|
@ -247,27 +260,25 @@ CookieRef::_HandleAck( HostID hostID )
|
|||
}
|
||||
|
||||
void
|
||||
CookieRef::_PutMsg( HostID srcID, in_addr& addr, HostID destID,
|
||||
CookieRef::_PutMsg( HostID srcID, const AddrInfo* addr, HostID destID,
|
||||
unsigned char* buf, int buflen )
|
||||
{
|
||||
CRefEvent evt( XWE_PROXYMSG );
|
||||
CRefEvent evt( XWE_PROXYMSG, addr );
|
||||
evt.u.fwd.src = srcID;
|
||||
evt.u.fwd.dest = destID;
|
||||
evt.u.fwd.buf = buf;
|
||||
evt.u.fwd.buflen = buflen;
|
||||
evt.u.fwd.addr = addr;
|
||||
|
||||
m_eventQueue.push_back( evt );
|
||||
handleEvents();
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::_Disconnect( int socket, HostID hostID )
|
||||
CookieRef::_Disconnect( const AddrInfo* addr, HostID hostID )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(socket=%d, hostID=%d)", __func__, socket, hostID );
|
||||
|
||||
CRefEvent evt( XWE_DISCONN );
|
||||
evt.u.discon.socket = socket;
|
||||
CRefEvent evt( XWE_DISCONN, addr );
|
||||
evt.u.discon.srcID = hostID;
|
||||
m_eventQueue.push_back( evt );
|
||||
|
||||
|
@ -295,54 +306,58 @@ CookieRef::_Shutdown()
|
|||
} /* _Shutdown */
|
||||
|
||||
HostID
|
||||
CookieRef::HostForSocket( int sock )
|
||||
CookieRef::HostForSocket( const AddrInfo* addr )
|
||||
{
|
||||
HostID hid = -1;
|
||||
ASSERT_LOCKED();
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int, HostRec>::const_iterator iter = m_sockets.find( sock );
|
||||
if ( iter != m_sockets.end() ) {
|
||||
hid = iter->second.m_hostID;
|
||||
logf( XW_LOGINFO, "%s: assigning hid of %d", __func__, hid );
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->m_addr.equals( *addr ) ) {
|
||||
hid = iter->m_hostID;
|
||||
logf( XW_LOGINFO, "%s: assigning hid of %d", __func__, hid );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hid;
|
||||
}
|
||||
|
||||
int
|
||||
const AddrInfo*
|
||||
CookieRef::SocketForHost( HostID dest )
|
||||
{
|
||||
int socket = -1;
|
||||
const AddrInfo* result = NULL;
|
||||
ASSERT_LOCKED();
|
||||
assert( dest != 0 ); /* don't use as lookup before assigned */
|
||||
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->second.m_hostID == dest ) {
|
||||
socket = iter->first;
|
||||
if ( iter->m_hostID == dest ) {
|
||||
result = &iter->m_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logf( XW_LOGVERBOSE0, "returning socket=%d for hostid=%x", socket, dest );
|
||||
return socket;
|
||||
// logf( XW_LOGVERBOSE0, "returning socket=%d for hostid=%x", socket, dest );
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
CookieRef::AlreadyHere( unsigned short seed, int socket, HostID* prevHostID )
|
||||
CookieRef::AlreadyHere( unsigned short seed, const AddrInfo* addr,
|
||||
HostID* prevHostID )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(seed=%x(%d),socket=%d)", __func__, seed, seed, socket );
|
||||
bool here = false;
|
||||
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
here = iter->second.m_seed == seed; /* client already registered */
|
||||
here = iter->m_seed == seed; /* client already registered */
|
||||
if ( here ) {
|
||||
if ( iter->first != socket ) { /* not just a dupe packet */
|
||||
logf( XW_LOGINFO, "%s: seeds match; socket %d assumed closed",
|
||||
__func__, iter->first );
|
||||
*prevHostID = iter->second.m_hostID;
|
||||
if ( !addr->equals(iter->m_addr) ) { /* not just a dupe packet */
|
||||
logf( XW_LOGINFO, "%s: seeds match; socket assumed closed",
|
||||
__func__ );
|
||||
*prevHostID = iter->m_hostID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -353,7 +368,7 @@ CookieRef::AlreadyHere( unsigned short seed, int socket, HostID* prevHostID )
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::AlreadyHere( HostID hid, unsigned short seed, int socket,
|
||||
CookieRef::AlreadyHere( HostID hid, unsigned short seed, const AddrInfo* addr,
|
||||
bool* spotTaken )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(hid=%d,seed=%x(%d),socket=%d)", __func__,
|
||||
|
@ -361,17 +376,16 @@ CookieRef::AlreadyHere( HostID hid, unsigned short seed, int socket,
|
|||
bool here = false;
|
||||
|
||||
RWWriteLock rwl( &m_socketsRWLock );
|
||||
map<int,HostRec>::iterator iter;
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->second.m_hostID == hid ) {
|
||||
if ( seed != iter->second.m_seed ) {
|
||||
if ( iter->m_hostID == hid ) {
|
||||
if ( seed != iter->m_seed ) {
|
||||
*spotTaken = true;
|
||||
} else if ( socket == iter->first ) {
|
||||
} else if ( addr->equals( iter->m_addr ) ) {
|
||||
here = true; /* dup packet */
|
||||
} else {
|
||||
logf( XW_LOGINFO, "%s: hids match; nuking existing record "
|
||||
"for socket %d b/c assumed closed", __func__,
|
||||
iter->first );
|
||||
"for socket b/c assumed closed", __func__ );
|
||||
m_sockets.erase( iter );
|
||||
}
|
||||
break;
|
||||
|
@ -385,41 +399,42 @@ CookieRef::AlreadyHere( HostID hid, unsigned short seed, int socket,
|
|||
void
|
||||
CookieRef::notifyDisconn( const CRefEvent* evt )
|
||||
{
|
||||
int socket = evt->u.disnote.socket;
|
||||
unsigned char buf[] = {
|
||||
XWRELAY_DISCONNECT_YOU,
|
||||
evt->u.disnote.why
|
||||
};
|
||||
|
||||
send_with_length( socket, buf, sizeof(buf), true );
|
||||
send_with_length( &evt->addr, buf, sizeof(buf), true );
|
||||
} /* notifyDisconn */
|
||||
|
||||
void
|
||||
CookieRef::removeSocket( int socket )
|
||||
CookieRef::removeSocket( const AddrInfo* addr )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(socket=%d)", __func__, socket );
|
||||
logf( XW_LOGINFO, "%s(socket=%d)", __func__, addr->socket() );
|
||||
bool found = false;
|
||||
ASSERT_LOCKED();
|
||||
|
||||
{
|
||||
RWWriteLock rwl( &m_socketsRWLock );
|
||||
map<int,HostRec>::iterator iter = m_sockets.find(socket);
|
||||
if ( iter != m_sockets.end() ) {
|
||||
if ( iter->second.m_ackPending ) {
|
||||
logf( XW_LOGINFO,
|
||||
"Never got ack; removing hid %d from DB",
|
||||
iter->second.m_hostID );
|
||||
DBMgr::Get()->RmDeviceByHid( ConnName(),
|
||||
iter->second.m_hostID );
|
||||
m_nPlayersHere -= iter->second.m_nPlayersH;
|
||||
cancelAckTimer( iter->second.m_hostID );
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); !found && iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->m_addr.equals( *addr ) ) {
|
||||
if ( iter->m_ackPending ) {
|
||||
logf( XW_LOGINFO,
|
||||
"Never got ack; removing hid %d from DB",
|
||||
iter->m_hostID );
|
||||
DBMgr::Get()->RmDeviceByHid( ConnName(),
|
||||
iter->m_hostID );
|
||||
m_nPlayersHere -= iter->m_nPlayersH;
|
||||
cancelAckTimer( iter->m_hostID );
|
||||
}
|
||||
m_sockets.erase(iter);
|
||||
found = true;
|
||||
}
|
||||
m_sockets.erase(iter);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if ( !found ) {
|
||||
logf( XW_LOGINFO, "%s: socket %d not found", __func__, socket );
|
||||
logf( XW_LOGINFO, "%s: socket not found", __func__ );
|
||||
}
|
||||
|
||||
printSeeds(__func__);
|
||||
|
@ -441,35 +456,38 @@ CookieRef::HaveRoom( int nPlayers )
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::HasSocket( int socket )
|
||||
CookieRef::HasSocket( const AddrInfo* addr )
|
||||
{
|
||||
bool result = Lock();
|
||||
if ( result ) {
|
||||
result = HasSocket_locked( socket );
|
||||
result = HasSocket_locked( addr );
|
||||
Unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
set<int>
|
||||
CookieRef::GetSockets()
|
||||
vector<AddrInfo>
|
||||
CookieRef::GetAddrs()
|
||||
{
|
||||
set<int> result;
|
||||
vector<AddrInfo> result;
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
result.insert( iter->first );
|
||||
result.push_back( iter->m_addr );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
CookieRef::HasSocket_locked( int socket )
|
||||
CookieRef::HasSocket_locked( const AddrInfo* addr )
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter = m_sockets.find( socket );
|
||||
bool found = iter != m_sockets.end();
|
||||
vector<HostRec>::const_iterator iter;
|
||||
bool found = false;
|
||||
for ( iter = m_sockets.begin(); !found && iter != m_sockets.end(); ++iter ) {
|
||||
found = iter->m_addr.equals( *addr );
|
||||
}
|
||||
|
||||
logf( XW_LOGINFO, "%s=>%d", __func__, found );
|
||||
return found;
|
||||
|
@ -503,52 +521,47 @@ CookieRef::_CheckHeartbeats( time_t now )
|
|||
#endif
|
||||
|
||||
void
|
||||
CookieRef::_Forward( HostID src, in_addr& addr, HostID dest, unsigned char* buf,
|
||||
int buflen )
|
||||
CookieRef::_Forward( HostID src, const AddrInfo* addr,
|
||||
HostID dest, unsigned char* buf, int buflen )
|
||||
{
|
||||
pushForwardEvent( src, addr, dest, buf, buflen );
|
||||
handleEvents();
|
||||
} /* Forward */
|
||||
|
||||
void
|
||||
CookieRef::_Remove( int socket )
|
||||
CookieRef::_Remove( const AddrInfo* addr )
|
||||
{
|
||||
pushRemoveSocketEvent( socket );
|
||||
pushRemoveSocketEvent( addr );
|
||||
handleEvents();
|
||||
} /* Forward */
|
||||
|
||||
void
|
||||
CookieRef::pushConnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
CookieRef::pushConnectEvent( int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr )
|
||||
int seed, const AddrInfo* addr )
|
||||
{
|
||||
CRefEvent evt;
|
||||
evt.type = XWE_DEVCONNECT;
|
||||
evt.u.con.socket = socket;
|
||||
CRefEvent evt( XWE_DEVCONNECT, addr );
|
||||
evt.u.con.clientVersion = clientVersion;
|
||||
evt.u.con.devID = devID;
|
||||
evt.u.con.srcID = HOST_ID_NONE;
|
||||
evt.u.con.nPlayersH = nPlayersH;
|
||||
evt.u.con.nPlayersS = nPlayersS;
|
||||
evt.u.con.seed = seed;
|
||||
evt.u.con.addr = addr;
|
||||
m_eventQueue.push_back( evt );
|
||||
} /* pushConnectEvent */
|
||||
|
||||
void
|
||||
CookieRef::pushReconnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
CookieRef::pushReconnectEvent( int clientVersion, DevID* devID,
|
||||
HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr )
|
||||
int seed, const AddrInfo* addr )
|
||||
{
|
||||
CRefEvent evt( XWE_RECONNECT );
|
||||
evt.u.con.socket = socket;
|
||||
CRefEvent evt( XWE_RECONNECT, addr );
|
||||
evt.u.con.clientVersion = clientVersion;
|
||||
evt.u.con.devID = devID;
|
||||
evt.u.con.srcID = srcID;
|
||||
evt.u.con.nPlayersH = nPlayersH;
|
||||
evt.u.con.nPlayersS = nPlayersS;
|
||||
evt.u.con.seed = seed;
|
||||
evt.u.con.addr = addr;
|
||||
m_eventQueue.push_back( evt );
|
||||
} /* pushReconnectEvent */
|
||||
|
||||
|
@ -573,32 +586,29 @@ CookieRef::pushHeartFailedEvent( int socket )
|
|||
#endif
|
||||
|
||||
void
|
||||
CookieRef::pushForwardEvent( HostID src, in_addr& addr, HostID dest,
|
||||
CookieRef::pushForwardEvent( HostID src, const AddrInfo* addr, HostID dest,
|
||||
unsigned char* buf, int buflen )
|
||||
{
|
||||
logf( XW_LOGVERBOSE1, "pushForwardEvent: %d -> %d", src, dest );
|
||||
CRefEvent evt( XWE_FORWARDMSG );
|
||||
CRefEvent evt( XWE_FORWARDMSG, addr );
|
||||
evt.u.fwd.src = src;
|
||||
evt.u.fwd.dest = dest;
|
||||
evt.u.fwd.buf = buf;
|
||||
evt.u.fwd.buflen = buflen;
|
||||
evt.u.fwd.addr = addr;
|
||||
m_eventQueue.push_back( evt );
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::pushRemoveSocketEvent( int socket )
|
||||
CookieRef::pushRemoveSocketEvent( const AddrInfo* addr )
|
||||
{
|
||||
CRefEvent evt( XWE_REMOVESOCKET );
|
||||
evt.u.rmsock.socket = socket;
|
||||
CRefEvent evt( XWE_REMOVESOCKET, addr );
|
||||
m_eventQueue.push_back( evt );
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::pushNotifyDisconEvent( int socket, XWREASON why )
|
||||
CookieRef::pushNotifyDisconEvent( const AddrInfo* addr, XWREASON why )
|
||||
{
|
||||
CRefEvent evt( XWE_NOTIFYDISCON );
|
||||
evt.u.disnote.socket = socket;
|
||||
CRefEvent evt( XWE_NOTIFYDISCON, addr );
|
||||
evt.u.disnote.why = why;
|
||||
m_eventQueue.push_back( evt );
|
||||
}
|
||||
|
@ -611,10 +621,9 @@ CookieRef::pushLastSocketGoneEvent()
|
|||
}
|
||||
|
||||
void
|
||||
CookieRef::pushGameDead( int socket )
|
||||
CookieRef::pushGameDead( const AddrInfo* addr )
|
||||
{
|
||||
CRefEvent evt( XWE_GAMEDEAD );
|
||||
evt.u.discon.socket = socket;
|
||||
CRefEvent evt( XWE_GAMEDEAD, addr );
|
||||
m_eventQueue.push_back( evt );
|
||||
}
|
||||
|
||||
|
@ -679,11 +688,11 @@ CookieRef::handleEvents()
|
|||
break;
|
||||
case XWA_SEND_DUP_ROOM:
|
||||
send_denied( &evt, XWRELAY_ERROR_DUP_ROOM );
|
||||
removeSocket( evt.u.rmsock.socket );
|
||||
removeSocket( &evt.addr );
|
||||
break;
|
||||
case XWA_SEND_TOO_MANY:
|
||||
send_denied( &evt, XWRELAY_ERROR_TOO_MANY );
|
||||
removeSocket( evt.u.rmsock.socket );
|
||||
removeSocket( &evt.addr );
|
||||
break;
|
||||
|
||||
case XWA_FWD:
|
||||
|
@ -703,20 +712,19 @@ CookieRef::handleEvents()
|
|||
break;
|
||||
|
||||
case XWA_HEARTDISCONN:
|
||||
notifyOthers( evt.u.heart.socket, XWRELAY_DISCONNECT_OTHER,
|
||||
notifyOthers( &evt.addr, XWRELAY_DISCONNECT_OTHER,
|
||||
XWRELAY_ERROR_HEART_OTHER );
|
||||
setAllConnectedTimer();
|
||||
// reducePlayerCounts( evt.u.discon.socket );
|
||||
disconnectSocket( evt.u.heart.socket,
|
||||
XWRELAY_ERROR_HEART_YOU );
|
||||
disconnectSocket( &evt.addr, XWRELAY_ERROR_HEART_YOU );
|
||||
break;
|
||||
|
||||
case XWA_DISCONNECT:
|
||||
setAllConnectedTimer();
|
||||
// reducePlayerCounts( evt.u.discon.socket );
|
||||
notifyOthers( evt.u.discon.socket, XWRELAY_DISCONNECT_OTHER,
|
||||
notifyOthers( &evt.addr, XWRELAY_DISCONNECT_OTHER,
|
||||
XWRELAY_ERROR_OTHER_DISCON );
|
||||
removeSocket( evt.u.discon.socket );
|
||||
removeSocket( &evt.addr );
|
||||
/* Don't notify. This is a normal part of a game ending. */
|
||||
break;
|
||||
|
||||
|
@ -725,7 +733,7 @@ CookieRef::handleEvents()
|
|||
break;
|
||||
|
||||
case XWA_TELLGAMEDEAD:
|
||||
notifyGameDead( evt.u.discon.socket );
|
||||
notifyGameDead( &evt.addr );
|
||||
break;
|
||||
|
||||
case XWA_NOTEHEART:
|
||||
|
@ -742,10 +750,10 @@ CookieRef::handleEvents()
|
|||
case XWA_REMOVESOCK_1:
|
||||
// reducePlayerCounts( evt.u.rmsock.socket );
|
||||
if ( XWA_REMOVESOCK_2 == takeAction ) {
|
||||
notifyOthers( evt.u.rmsock.socket, XWRELAY_DISCONNECT_OTHER,
|
||||
notifyOthers( &evt.addr, XWRELAY_DISCONNECT_OTHER,
|
||||
XWRELAY_ERROR_LOST_OTHER );
|
||||
}
|
||||
removeSocket( evt.u.rmsock.socket );
|
||||
removeSocket( &evt.addr );
|
||||
break;
|
||||
|
||||
case XWA_SENDALLHERE:
|
||||
|
@ -799,19 +807,19 @@ CookieRef::handleEvents()
|
|||
} /* handleEvents */
|
||||
|
||||
bool
|
||||
CookieRef::send_with_length( int socket, unsigned char* buf, int bufLen,
|
||||
bool cascade )
|
||||
CookieRef::send_with_length( const AddrInfo* addr,
|
||||
unsigned char* buf, int bufLen, bool cascade )
|
||||
{
|
||||
bool failed = false;
|
||||
if ( send_with_length_unsafe( socket, buf, bufLen ) ) {
|
||||
DBMgr::Get()->RecordSent( ConnName(), HostForSocket(socket), bufLen );
|
||||
if ( send_with_length_unsafe( addr, buf, bufLen ) ) {
|
||||
DBMgr::Get()->RecordSent( ConnName(), HostForSocket(addr), bufLen );
|
||||
} else {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if ( failed && cascade ) {
|
||||
pushRemoveSocketEvent( socket );
|
||||
XWThreadPool::GetTPool()->CloseSocket( socket );
|
||||
pushRemoveSocketEvent( addr );
|
||||
XWThreadPool::GetTPool()->CloseSocket( addr );
|
||||
}
|
||||
return !failed;
|
||||
} /* send_with_length */
|
||||
|
@ -834,12 +842,13 @@ CookieRef::store_message( HostID dest, const unsigned char* buf,
|
|||
}
|
||||
|
||||
void
|
||||
CookieRef::send_stored_messages( HostID dest, int socket )
|
||||
CookieRef::send_stored_messages( HostID dest, const AddrInfo* addr )
|
||||
{
|
||||
logf( XW_LOGVERBOSE0, "%s(dest=%d)", __func__, dest );
|
||||
|
||||
assert( dest > 0 && dest <= 4 );
|
||||
assert( -1 != socket );
|
||||
assert( -1 != addr->socket() );
|
||||
assert( addr->isTCP() );
|
||||
|
||||
for ( ; ; ) {
|
||||
unsigned char buf[MAX_MSG_LEN];
|
||||
|
@ -849,7 +858,7 @@ CookieRef::send_stored_messages( HostID dest, int socket )
|
|||
buf, &buflen, &msgID ) ) {
|
||||
break;
|
||||
}
|
||||
if ( ! send_with_length( socket, buf, buflen, true ) ) {
|
||||
if ( ! send_with_length( addr, buf, buflen, true ) ) {
|
||||
break;
|
||||
}
|
||||
DBMgr::Get()->RemoveStoredMessages( &msgID, 1 );
|
||||
|
@ -862,7 +871,6 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
|||
{
|
||||
DBMgr::DevIDRelay devID = DBMgr::DEVID_NONE;
|
||||
int nPlayersH = evt->u.con.nPlayersH;
|
||||
int socket = evt->u.con.socket;
|
||||
int seed = evt->u.con.seed;
|
||||
|
||||
assert( m_nPlayersSought > 0 );
|
||||
|
@ -899,7 +907,7 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
|||
evt->u.con.srcID =
|
||||
DBMgr::Get()->AddDevice( ConnName(), evt->u.con.srcID,
|
||||
evt->u.con.clientVersion, nPlayersH, seed,
|
||||
evt->u.con.addr, devID, reconn );
|
||||
&evt->addr, devID, reconn );
|
||||
|
||||
HostID hostid = evt->u.con.srcID;
|
||||
if ( NULL != hidp ) {
|
||||
|
@ -915,8 +923,8 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
|||
|
||||
{
|
||||
RWWriteLock rwl( &m_socketsRWLock );
|
||||
HostRec hr( hostid, nPlayersH, seed, !reconn );
|
||||
m_sockets.insert( pair<int,HostRec>(socket, hr) );
|
||||
HostRec hr( hostid, &evt->addr, nPlayersH, seed, !reconn );
|
||||
m_sockets.push_back( hr );
|
||||
}
|
||||
|
||||
printSeeds(__func__);
|
||||
|
@ -932,28 +940,28 @@ CookieRef::updateAck( HostID hostID, bool keep )
|
|||
{
|
||||
assert( hostID >= HOST_ID_SERVER );
|
||||
assert( hostID <= 4 );
|
||||
int socket = 0;
|
||||
const AddrInfo* nonKeeper = NULL;
|
||||
|
||||
cancelAckTimer( hostID );
|
||||
|
||||
{
|
||||
RWWriteLock rwl( &m_socketsRWLock );
|
||||
map<int, HostRec>::iterator iter;
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->second.m_ackPending && iter->second.m_hostID == hostID ) {
|
||||
if ( iter->m_ackPending && iter->m_hostID == hostID ) {
|
||||
if ( keep ) {
|
||||
iter->second.m_ackPending = false;
|
||||
iter->m_ackPending = false;
|
||||
DBMgr::Get()->NoteAckd( ConnName(), hostID );
|
||||
} else {
|
||||
socket = iter->first;
|
||||
nonKeeper = &iter->m_addr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 != socket ) {
|
||||
removeSocket( socket );
|
||||
if ( NULL != nonKeeper ) {
|
||||
removeSocket( nonKeeper );
|
||||
}
|
||||
|
||||
printSeeds(__func__);
|
||||
|
@ -1032,8 +1040,6 @@ void
|
|||
CookieRef::sendResponse( const CRefEvent* evt, bool initial,
|
||||
const DBMgr::DevIDRelay* devID )
|
||||
{
|
||||
int socket = evt->u.con.socket;
|
||||
|
||||
/* Now send the response */
|
||||
unsigned char buf[1 /* cmd */
|
||||
+ sizeof(unsigned char) /* hostID */
|
||||
|
@ -1099,7 +1105,7 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial,
|
|||
}
|
||||
}
|
||||
|
||||
send_with_length( socket, buf, bufp - buf, true );
|
||||
send_with_length( &evt->addr, buf, bufp - buf, true );
|
||||
logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) );
|
||||
} /* sendResponse */
|
||||
|
||||
|
@ -1108,7 +1114,7 @@ CookieRef::sendAnyStored( const CRefEvent* evt )
|
|||
{
|
||||
HostID dest = evt->u.con.srcID;
|
||||
if ( HOST_ID_NONE != dest ) {
|
||||
send_stored_messages( dest, evt->u.con.socket );
|
||||
send_stored_messages( dest, &evt->addr );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1130,20 +1136,20 @@ CookieRef::forward_or_store( const CRefEvent* evt )
|
|||
|
||||
int buflen = evt->u.fwd.buflen;
|
||||
HostID dest = evt->u.fwd.dest;
|
||||
int destSocket = SocketForHost( dest );
|
||||
const AddrInfo* destAddr = SocketForHost( dest );
|
||||
|
||||
if ( 0 < m_delayMicros && destSocket != -1 ) {
|
||||
if ( 0 < m_delayMicros && NULL != destAddr ) {
|
||||
usleep( m_delayMicros );
|
||||
}
|
||||
|
||||
if ( (destSocket == -1)
|
||||
|| !send_with_length( destSocket, buf, buflen, true ) ) {
|
||||
if ( (NULL == destAddr)
|
||||
|| !send_with_length( destAddr, buf, buflen, true ) ) {
|
||||
store_message( dest, buf, buflen );
|
||||
}
|
||||
|
||||
/* also note that we've heard from src recently */
|
||||
HostID src = evt->u.fwd.src;
|
||||
DBMgr::Get()->RecordAddress( ConnName(), src, evt->u.fwd.addr );
|
||||
DBMgr::Get()->RecordAddress( ConnName(), src, &evt->addr );
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
pushHeartbeatEvent( src, SocketForHost(src) );
|
||||
#endif
|
||||
|
@ -1153,12 +1159,12 @@ CookieRef::forward_or_store( const CRefEvent* evt )
|
|||
void
|
||||
CookieRef::send_denied( const CRefEvent* evt, XWREASON why )
|
||||
{
|
||||
denyConnection( evt->u.con.socket, why );
|
||||
denyConnection( &evt->addr, why );
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::send_msg( int socket, HostID id, XWRelayMsg msg, XWREASON why,
|
||||
bool cascade )
|
||||
CookieRef::send_msg( const AddrInfo* addr, HostID id,
|
||||
XWRelayMsg msg, XWREASON why, bool cascade )
|
||||
{
|
||||
unsigned char buf[10];
|
||||
short tmp;
|
||||
|
@ -1178,34 +1184,35 @@ CookieRef::send_msg( int socket, HostID id, XWRelayMsg msg, XWREASON why,
|
|||
}
|
||||
|
||||
assert( len <= sizeof(buf) );
|
||||
send_with_length( socket, buf, len, cascade );
|
||||
send_with_length( addr, buf, len, cascade );
|
||||
} /* send_msg */
|
||||
|
||||
void
|
||||
CookieRef::notifyOthers( int socket, XWRelayMsg msg, XWREASON why )
|
||||
CookieRef::notifyOthers( const AddrInfo* addr, XWRelayMsg msg, XWREASON why )
|
||||
{
|
||||
assert( socket != 0 );
|
||||
assert( addr->socket() != 0 );
|
||||
assert( addr->isTCP() );
|
||||
|
||||
ASSERT_LOCKED();
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
int other = iter->first;
|
||||
if ( other != socket ) {
|
||||
send_msg( other, iter->second.m_hostID, msg, why, false );
|
||||
const AddrInfo* other = &iter->m_addr;
|
||||
if ( !other->equals( *addr ) ) {
|
||||
send_msg( other, iter->m_hostID, msg, why, false );
|
||||
}
|
||||
}
|
||||
} /* notifyOthers */
|
||||
|
||||
void
|
||||
CookieRef::notifyGameDead( int socket )
|
||||
CookieRef::notifyGameDead( const AddrInfo* addr )
|
||||
{
|
||||
unsigned char buf[] = {
|
||||
XWRELAY_MSG_STATUS
|
||||
,XWRELAY_ERROR_DELETED
|
||||
};
|
||||
|
||||
send_with_length( socket, buf, sizeof(buf), true );
|
||||
send_with_length( addr, buf, sizeof(buf), true );
|
||||
}
|
||||
|
||||
/* void */
|
||||
|
@ -1255,11 +1262,10 @@ CookieRef::sendAllHere( bool initial )
|
|||
|
||||
{
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->second.m_hostID == dest ) {
|
||||
sent = send_with_length( iter->first, buf, bufp-buf,
|
||||
true );
|
||||
if ( iter->m_hostID == dest ) {
|
||||
sent = send_with_length( &iter->m_addr, buf, bufp-buf, true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1289,21 +1295,23 @@ CookieRef::disconnectSockets( XWREASON why )
|
|||
{
|
||||
ASSERT_LOCKED();
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
assert( iter->first != 0 );
|
||||
if ( iter->first != 0 ) {
|
||||
disconnectSocket( iter->first, why );
|
||||
const AddrInfo* addr = &iter->m_addr;
|
||||
if ( addr->socket() != 0 ) {
|
||||
disconnectSocket( addr, why );
|
||||
} else {
|
||||
assert( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::disconnectSocket( int socket, XWREASON why )
|
||||
CookieRef::disconnectSocket( const AddrInfo* addr, XWREASON why )
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
pushNotifyDisconEvent( socket, why );
|
||||
pushRemoveSocketEvent( socket );
|
||||
pushNotifyDisconEvent( addr, why );
|
||||
pushRemoveSocketEvent( addr );
|
||||
} /* disconnectSocket */
|
||||
|
||||
void
|
||||
|
@ -1315,9 +1323,9 @@ CookieRef::removeDevice( const CRefEvent* const evt )
|
|||
dbmgr->KillGame( ConnName(), evt->u.devgone.hid );
|
||||
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
notifyGameDead( iter->first );
|
||||
notifyGameDead( &iter->m_addr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1325,25 +1333,24 @@ CookieRef::removeDevice( const CRefEvent* const evt )
|
|||
void
|
||||
CookieRef::noteHeartbeat( const CRefEvent* evt )
|
||||
{
|
||||
int socket = evt->u.heart.socket;
|
||||
const AddrInfo& addr = evt->addr;
|
||||
HostID id = evt->u.heart.id;
|
||||
|
||||
ASSERT_LOCKED();
|
||||
RWWriteLock rwl( &m_socketsRWLock );
|
||||
map<int,HostRec>::iterator iter;
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->second.m_hostID == id ) {
|
||||
int second_socket = iter->first;
|
||||
if ( second_socket == socket ) {
|
||||
if ( iter->m_hostID == id ) {
|
||||
if ( iter->m_addr.equals(addr) ) {
|
||||
logf( XW_LOGVERBOSE1, "upping m_lastHeartbeat from %d to %d",
|
||||
iter->second.m_lastHeartbeat, uptime() );
|
||||
iter->second.m_lastHeartbeat = uptime();
|
||||
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 );
|
||||
"wanted %d, found %d", id, addr.socket(), iter->m_addr.socket() );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1403,12 +1410,12 @@ CookieRef::printSeeds( const char* caller )
|
|||
char buf[64] = {0};
|
||||
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
len += snprintf( &buf[len], sizeof(buf)-len, "[%d]%.4x(%d)/%d/%c ",
|
||||
iter->second.m_hostID, iter->second.m_seed,
|
||||
iter->second.m_seed, iter->first,
|
||||
iter->second.m_ackPending?'a':'A' );
|
||||
iter->m_hostID, iter->m_seed,
|
||||
iter->m_seed, iter->m_addr.socket(),
|
||||
iter->m_ackPending?'a':'A' );
|
||||
}
|
||||
logf( XW_LOGINFO, "seeds/sockets/ack'd after %s(): %s", caller, buf );
|
||||
}
|
||||
|
@ -1464,11 +1471,11 @@ CookieRef::_PrintCookieInfo( string& out )
|
|||
out += buf;
|
||||
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
snprintf( buf, sizeof(buf), " HostID=%d; socket=%d;last hbeat=%ld\n",
|
||||
iter->second.m_hostID, iter->first,
|
||||
iter->second.m_lastHeartbeat );
|
||||
iter->m_hostID, iter->m_addr.socket(),
|
||||
iter->m_lastHeartbeat );
|
||||
out += buf;
|
||||
}
|
||||
|
||||
|
@ -1479,26 +1486,26 @@ CookieRef::_FormatHostInfo( string* hostIds, string* seeds, string* addrs )
|
|||
{
|
||||
ASSERT_LOCKED();
|
||||
RWReadLock rrl( &m_socketsRWLock );
|
||||
map<int,HostRec>::const_iterator iter;
|
||||
vector<HostRec>::const_iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
|
||||
if ( !!hostIds ) {
|
||||
char buf[8];
|
||||
snprintf( buf, sizeof(buf), "%d ", iter->second.m_hostID );
|
||||
snprintf( buf, sizeof(buf), "%d ", iter->m_hostID );
|
||||
*hostIds += buf;
|
||||
}
|
||||
|
||||
if ( !!seeds ) {
|
||||
char buf[6];
|
||||
snprintf( buf, sizeof(buf), "%.4X ", iter->second.m_seed );
|
||||
snprintf( buf, sizeof(buf), "%.4X ", iter->m_seed );
|
||||
*seeds += buf;
|
||||
}
|
||||
|
||||
if ( !!addrs ) {
|
||||
int s = iter->first;
|
||||
struct sockaddr_in name;
|
||||
int socket = iter->m_addr.socket();
|
||||
sockaddr_in name;
|
||||
socklen_t siz = sizeof(name);
|
||||
if ( 0 == getpeername( s, (struct sockaddr*)&name, &siz) ) {
|
||||
if ( 0 == getpeername( socket, (struct sockaddr*)&name, &siz) ) {
|
||||
char buf[32] = {0};
|
||||
snprintf( buf, sizeof(buf), "%s ", inet_ntoa(name.sin_addr) );
|
||||
*addrs += buf;
|
||||
|
|
|
@ -43,8 +43,9 @@ class CookieMapIterator; /* forward */
|
|||
|
||||
struct HostRec {
|
||||
public:
|
||||
HostRec(HostID hostID, int nPlayersH, int seed, bool ackPending )
|
||||
HostRec(HostID hostID, const AddrInfo* addr, int nPlayersH, int seed, bool ackPending )
|
||||
: m_hostID(hostID)
|
||||
, m_addr(*addr)
|
||||
, m_nPlayersH(nPlayersH)
|
||||
, m_seed(seed)
|
||||
, m_lastHeartbeat(uptime())
|
||||
|
@ -53,6 +54,7 @@ HostRec(HostID hostID, int nPlayersH, int seed, bool ackPending )
|
|||
::logf( XW_LOGINFO, "created HostRec with id %d", m_hostID);
|
||||
}
|
||||
HostID m_hostID;
|
||||
AddrInfo m_addr;
|
||||
int m_nPlayersH;
|
||||
int m_seed;
|
||||
time_t m_lastHeartbeat;
|
||||
|
@ -67,7 +69,7 @@ public:
|
|||
|
||||
class CookieRef {
|
||||
public:
|
||||
set<int> GetSockets();
|
||||
vector<AddrInfo> GetAddrs( void );
|
||||
|
||||
private:
|
||||
/* These classes have access to CookieRef. All others should go through
|
||||
|
@ -96,19 +98,19 @@ class CookieRef {
|
|||
bool HaveRoom( int nPlayers );
|
||||
|
||||
int CountSockets() { return m_sockets.size(); }
|
||||
bool HasSocket( int socket );
|
||||
bool HasSocket_locked( int socket );
|
||||
bool HasSocket( const AddrInfo* addr );
|
||||
bool HasSocket_locked( const AddrInfo* addr );
|
||||
const char* Cookie() const { return m_cookie.c_str(); }
|
||||
const char* ConnName() { return m_connName.c_str(); }
|
||||
|
||||
int GetHeartbeat() { return m_heatbeat; }
|
||||
int SocketForHost( HostID dest );
|
||||
HostID HostForSocket( int sock );
|
||||
const AddrInfo* SocketForHost( HostID dest );
|
||||
HostID HostForSocket( const AddrInfo* addr );
|
||||
|
||||
/* connect case */
|
||||
bool AlreadyHere( unsigned short seed, int socket, HostID* prevHostID );
|
||||
bool AlreadyHere( unsigned short seed, const AddrInfo* addr, HostID* prevHostID );
|
||||
/* reconnect case */
|
||||
bool AlreadyHere( HostID hid, unsigned short seed, int socket, bool* spotTaken );
|
||||
bool AlreadyHere( HostID hid, unsigned short seed, const AddrInfo* addr, bool* spotTaken );
|
||||
|
||||
/* for console */
|
||||
void _PrintCookieInfo( string& out );
|
||||
|
@ -121,21 +123,23 @@ class CookieRef {
|
|||
static void Delete( CookieID cid );
|
||||
static void Delete( const char* name );
|
||||
|
||||
bool _Connect( int socket, int clientVersion, DevID* devID,
|
||||
bool _Connect( int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS, int seed, bool seenSeed,
|
||||
in_addr& addr );
|
||||
bool _Reconnect( int socket, int clientVersion, DevID* devID,
|
||||
const AddrInfo* addr );
|
||||
bool _Reconnect( int clientVersion, DevID* devID,
|
||||
HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr, bool gameDead );
|
||||
int seed, const AddrInfo* addr, bool gameDead );
|
||||
void _HandleAck( HostID hostID );
|
||||
void _PutMsg( HostID srcID, in_addr& addr, HostID destID, unsigned char* buf, int buflen );
|
||||
void _Disconnect(int socket, HostID hostID );
|
||||
void _PutMsg( HostID srcID, const AddrInfo* addr, HostID destID,
|
||||
unsigned char* buf, int buflen );
|
||||
void _Disconnect( const AddrInfo* addr, HostID hostID );
|
||||
void _DeviceGone( HostID hostID, int seed );
|
||||
void _Shutdown();
|
||||
void _HandleHeartbeat( HostID id, int socket );
|
||||
void _HandleHeartbeat( HostID id, const AddrInfo* addr );
|
||||
void _CheckHeartbeats( time_t now );
|
||||
void _Forward( HostID src, in_addr& addr, HostID dest, unsigned char* buf, int buflen );
|
||||
void _Remove( int socket );
|
||||
void _Forward( HostID src, const AddrInfo* addr, HostID dest,
|
||||
unsigned char* buf, int buflen );
|
||||
void _Remove( const AddrInfo* addr );
|
||||
void _CheckAllConnected();
|
||||
void _CheckNotAcked( HostID hid );
|
||||
|
||||
|
@ -148,30 +152,28 @@ class CookieRef {
|
|||
public:
|
||||
CRefEvent() { type = XWE_NONE; }
|
||||
CRefEvent( XW_RELAY_EVENT typ ) { type = typ; }
|
||||
CRefEvent( XW_RELAY_EVENT typ, const AddrInfo* addrp ) { type = typ; addr = *addrp; }
|
||||
XW_RELAY_EVENT type;
|
||||
AddrInfo addr; /* sender's address */
|
||||
union {
|
||||
struct {
|
||||
HostID src;
|
||||
HostID dest;
|
||||
unsigned char* buf;
|
||||
int buflen;
|
||||
in_addr addr;
|
||||
} fwd;
|
||||
struct {
|
||||
int socket;
|
||||
int clientVersion;
|
||||
DevID* devID;
|
||||
int nPlayersH;
|
||||
int nPlayersS;
|
||||
int seed;
|
||||
HostID srcID;
|
||||
in_addr addr;
|
||||
} con;
|
||||
struct {
|
||||
HostID srcID;
|
||||
} ack;
|
||||
struct {
|
||||
int socket;
|
||||
HostID srcID;
|
||||
} discon;
|
||||
struct {
|
||||
|
@ -180,42 +182,39 @@ class CookieRef {
|
|||
} devgone;
|
||||
struct {
|
||||
HostID id;
|
||||
int socket;
|
||||
} heart;
|
||||
struct {
|
||||
time_t now;
|
||||
} htime;
|
||||
struct {
|
||||
int socket;
|
||||
} rmsock;
|
||||
struct {
|
||||
int socket;
|
||||
XWREASON why;
|
||||
} disnote;
|
||||
} u;
|
||||
};
|
||||
|
||||
bool send_with_length( int socket, unsigned char* buf, int bufLen,
|
||||
bool cascade );
|
||||
void send_msg( int socket, HostID id, XWRelayMsg msg, XWREASON why,
|
||||
bool cascade );
|
||||
void pushConnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
bool send_with_length( const AddrInfo* addr,
|
||||
unsigned char* buf, int bufLen, bool cascade );
|
||||
void send_msg( const AddrInfo* addr, HostID id,
|
||||
XWRelayMsg msg, XWREASON why, bool cascade );
|
||||
void pushConnectEvent( int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr );
|
||||
void pushReconnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
int seed, const AddrInfo* addr );
|
||||
void pushReconnectEvent( int clientVersion, DevID* devID,
|
||||
HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr );
|
||||
void pushHeartbeatEvent( HostID id, int socket );
|
||||
void pushHeartFailedEvent( int socket );
|
||||
int seed, const AddrInfo* addr );
|
||||
void pushHeartbeatEvent( HostID id, const AddrInfo* addr );
|
||||
void pushHeartFailedEvent( const AddrInfo* addr );
|
||||
|
||||
void pushForwardEvent( HostID src, in_addr& addr, HostID dest, unsigned char* buf,
|
||||
int buflen );
|
||||
void pushForwardEvent( HostID src, const AddrInfo* addr,
|
||||
HostID dest, unsigned char* buf, int buflen );
|
||||
void pushDestBadEvent();
|
||||
void pushLastSocketGoneEvent();
|
||||
void pushGameDead( int socket );
|
||||
void pushGameDead( const AddrInfo* addr );
|
||||
void checkHaveRoom( const CRefEvent* evt );
|
||||
void pushRemoveSocketEvent( int socket );
|
||||
void pushNotifyDisconEvent( int socket, XWREASON why );
|
||||
void pushRemoveSocketEvent( const AddrInfo* addr );
|
||||
void pushNotifyDisconEvent( const AddrInfo* addr, XWREASON why );
|
||||
|
||||
void handleEvents();
|
||||
|
||||
|
@ -231,8 +230,6 @@ class CookieRef {
|
|||
void postCheckAllHere();
|
||||
void postDropDevice( HostID hostID );
|
||||
|
||||
void reducePlayerCounts( int socket );
|
||||
|
||||
void setAllConnectedTimer();
|
||||
void cancelAllConnectedTimer();
|
||||
void setAckTimer( HostID hid );
|
||||
|
@ -242,15 +239,15 @@ class CookieRef {
|
|||
void send_denied( const CRefEvent* evt, XWREASON why );
|
||||
|
||||
void checkFromServer( const CRefEvent* evt );
|
||||
void notifyOthers( int socket, XWRelayMsg msg, XWREASON why );
|
||||
void notifyGameDead( int socket );
|
||||
void notifyOthers( const AddrInfo* addr, XWRelayMsg msg, XWREASON why );
|
||||
void notifyGameDead( const AddrInfo* addr );
|
||||
|
||||
void disconnectSockets( XWREASON why );
|
||||
void disconnectSocket( int socket, XWREASON why );
|
||||
void disconnectSocket( const AddrInfo* addr, XWREASON why );
|
||||
void removeDevice( const CRefEvent* const evt );
|
||||
void noteHeartbeat(const CRefEvent* evt);
|
||||
void notifyDisconn(const CRefEvent* evt);
|
||||
void removeSocket( int socket );
|
||||
void removeSocket( const AddrInfo* addr );
|
||||
void sendAllHere( bool initial );
|
||||
|
||||
void assignConnName( void );
|
||||
|
@ -262,19 +259,18 @@ class CookieRef {
|
|||
|
||||
void store_message( HostID dest, const unsigned char* buf,
|
||||
unsigned int len );
|
||||
void send_stored_messages( HostID dest, int socket );
|
||||
void send_stored_messages( HostID dest, const AddrInfo* addr );
|
||||
|
||||
void printSeeds( const char* caller );
|
||||
|
||||
void AddSocket( int socket );
|
||||
void RmSocket( int socket );
|
||||
|
||||
/* timer callback */
|
||||
static void s_checkAllConnected( void* closure );
|
||||
static void s_checkAck( void* closure );
|
||||
|
||||
/* Track sockets (= current connections with games on devices) in this
|
||||
game. There will never be more than four of these */
|
||||
pthread_rwlock_t m_socketsRWLock;
|
||||
map<int, HostRec> m_sockets;
|
||||
vector<HostRec> m_sockets;
|
||||
|
||||
int m_heatbeat; /* might change per carrier or something. */
|
||||
string m_cookie; /* cookie used for initial connections */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "crefmgr.h"
|
||||
#include "cref.h"
|
||||
|
@ -215,7 +216,7 @@ CRefMgr::getFromFreeList( void )
|
|||
|
||||
/* connect case */
|
||||
CidInfo*
|
||||
CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
|
||||
CRefMgr::getMakeCookieRef( const char* cookie, HostID hid,
|
||||
int nPlayersH, int nPlayersT, int langCode,
|
||||
int seed, bool wantsPublic,
|
||||
bool makePublic, bool* seenSeed )
|
||||
|
@ -286,9 +287,8 @@ CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
|
|||
/* reconnect case */
|
||||
CidInfo*
|
||||
CRefMgr::getMakeCookieRef( const char* connName, const char* cookie,
|
||||
HostID hid, int socket, int nPlayersH,
|
||||
int nPlayersS, int seed, int langCode,
|
||||
bool isPublic, bool* isDead )
|
||||
HostID hid, int nPlayersH, int nPlayersS, int seed,
|
||||
int langCode, bool isPublic, bool* isDead )
|
||||
{
|
||||
CookieRef* cref = NULL;
|
||||
CidInfo* cinfo;
|
||||
|
@ -377,11 +377,11 @@ CRefMgr::getMakeCookieRef( const char* const connName, bool* isDead )
|
|||
}
|
||||
|
||||
void
|
||||
CRefMgr::RemoveSocketRefs( int socket )
|
||||
CRefMgr::RemoveSocketRefs( const AddrInfo* addr )
|
||||
{
|
||||
{
|
||||
SafeCref scr( socket );
|
||||
scr.Remove( socket );
|
||||
SafeCref scr( addr );
|
||||
scr.Remove( addr );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,14 +413,16 @@ CRefMgr::getCookieRef( CookieID cid, bool failOk )
|
|||
break;
|
||||
}
|
||||
m_cidlock->Relinquish( cinfo, true );
|
||||
logf( XW_LOGINFO, "%s: sleeping after failing to get cinfo", __func__ );
|
||||
usleep(200000); /* 2/10 second */
|
||||
}
|
||||
return cinfo;
|
||||
} /* getCookieRef */
|
||||
|
||||
CidInfo*
|
||||
CRefMgr::getCookieRef( int socket )
|
||||
CRefMgr::getCookieRef( const AddrInfo* addr )
|
||||
{
|
||||
CidInfo* cinfo = m_cidlock->ClaimSocket( socket );
|
||||
CidInfo* cinfo = m_cidlock->ClaimSocket( addr );
|
||||
|
||||
assert( NULL == cinfo || NULL != cinfo->GetRef() );
|
||||
return cinfo;
|
||||
|
@ -589,21 +591,21 @@ CookieMapIterator::Next()
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* connect case */
|
||||
SafeCref::SafeCref( const char* cookie, int socket, int clientVersion,
|
||||
SafeCref::SafeCref( const char* cookie, const AddrInfo* addr, int clientVers,
|
||||
DevID* devID, int nPlayersH, int nPlayersS,
|
||||
unsigned short gameSeed, int langCode, bool wantsPublic,
|
||||
bool makePublic )
|
||||
: m_cinfo( NULL )
|
||||
, m_mgr( CRefMgr::Get() )
|
||||
, m_clientVersion( clientVersion )
|
||||
, m_addr( *addr )
|
||||
, m_clientVersion( clientVers )
|
||||
, m_devID( devID )
|
||||
, m_isValid( false )
|
||||
, m_seenSeed( false )
|
||||
{
|
||||
CidInfo* cinfo;
|
||||
|
||||
cinfo = m_mgr->getMakeCookieRef( cookie, 0, socket,
|
||||
nPlayersH, nPlayersS, langCode,
|
||||
cinfo = m_mgr->getMakeCookieRef( cookie, 0, nPlayersH, nPlayersS, langCode,
|
||||
gameSeed, wantsPublic, makePublic,
|
||||
&m_seenSeed );
|
||||
if ( cinfo != NULL ) {
|
||||
|
@ -616,12 +618,13 @@ SafeCref::SafeCref( const char* cookie, int socket, int clientVersion,
|
|||
|
||||
/* REconnect case */
|
||||
SafeCref::SafeCref( const char* connName, const char* cookie, HostID hid,
|
||||
int socket, int clientVersion, DevID* devID, int nPlayersH,
|
||||
const AddrInfo* addr, int clientVers, DevID* devID, int nPlayersH,
|
||||
int nPlayersS, unsigned short gameSeed, int langCode,
|
||||
bool wantsPublic, bool makePublic )
|
||||
: m_cinfo( NULL )
|
||||
, m_mgr( CRefMgr::Get() )
|
||||
, m_clientVersion( clientVersion )
|
||||
, m_addr( *addr )
|
||||
, m_clientVersion( clientVers )
|
||||
, m_devID( devID )
|
||||
, m_isValid( false )
|
||||
{
|
||||
|
@ -629,7 +632,7 @@ SafeCref::SafeCref( const char* connName, const char* cookie, HostID hid,
|
|||
assert( hid <= 4 ); /* no more than 4 hosts */
|
||||
|
||||
bool isDead = false;
|
||||
cinfo = m_mgr->getMakeCookieRef( connName, cookie, hid, socket, nPlayersH,
|
||||
cinfo = m_mgr->getMakeCookieRef( connName, cookie, hid, nPlayersH,
|
||||
nPlayersS, gameSeed, langCode,
|
||||
wantsPublic || makePublic, &isDead );
|
||||
if ( cinfo != NULL ) {
|
||||
|
@ -676,17 +679,18 @@ SafeCref::SafeCref( CookieID cid, bool failOk )
|
|||
}
|
||||
}
|
||||
|
||||
SafeCref::SafeCref( int socket )
|
||||
SafeCref::SafeCref( const AddrInfo* addr )
|
||||
: m_cinfo( NULL )
|
||||
, m_mgr( CRefMgr::Get() )
|
||||
, m_addr( *addr )
|
||||
, m_isValid( false )
|
||||
{
|
||||
CidInfo* cinfo = m_mgr->getCookieRef( socket );
|
||||
CidInfo* cinfo = m_mgr->getCookieRef( addr );
|
||||
if ( cinfo != NULL ) { /* known socket? */
|
||||
CookieRef* cref = cinfo->GetRef();
|
||||
assert( cinfo->GetCid() == cref->GetCid() );
|
||||
m_locked = cref->Lock();
|
||||
m_isValid = m_locked && cref->HasSocket_locked( socket );
|
||||
m_isValid = m_locked && cref->HasSocket_locked( addr );
|
||||
m_cinfo = cinfo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ class CRefMgr {
|
|||
|
||||
void MoveSockets( vector<int> sockets, CookieRef* cref );
|
||||
pthread_mutex_t* GetWriteMutexForSocket( int socket );
|
||||
void RemoveSocketRefs( int socket );
|
||||
void RemoveSocketRefs( const AddrInfo* addr );
|
||||
void PrintSocketInfo( int socket, string& out );
|
||||
|
||||
void IncrementFullCount( void );
|
||||
|
@ -117,22 +117,21 @@ class CRefMgr {
|
|||
CookieRef* getFromFreeList( void );
|
||||
|
||||
/* connect case */
|
||||
CidInfo* getMakeCookieRef( const char* cookie,
|
||||
HostID hid, int socket, int nPlayersH,
|
||||
CidInfo* getMakeCookieRef( const char* cookie, HostID hid, int nPlayersH,
|
||||
int nPlayersS, int langCode, int seed,
|
||||
bool wantsPublic, bool makePublic,
|
||||
bool* seenSeed );
|
||||
|
||||
/* reconnect case; just the stuff we don't have in db */
|
||||
CidInfo* getMakeCookieRef( const char* connName, const char* cookie,
|
||||
HostID hid, int socket, int nPlayersH,
|
||||
HostID hid, int nPlayersH,
|
||||
int nPlayersS, int seed, int langCode,
|
||||
bool isPublic, bool* isDead );
|
||||
|
||||
CidInfo* getMakeCookieRef( const char* const connName, bool* isDead );
|
||||
|
||||
CidInfo* getCookieRef( CookieID cid, bool failOk = false );
|
||||
CidInfo* getCookieRef( int socket );
|
||||
CidInfo* getCookieRef( const AddrInfo* addr );
|
||||
bool checkCookieRef_locked( CookieRef* cref );
|
||||
CidInfo* getCookieRef_impl( CookieID cid );
|
||||
CookieRef* AddNew( const char* cookie, const char* connName, CookieID cid,
|
||||
|
@ -171,23 +170,23 @@ class SafeCref {
|
|||
|
||||
public:
|
||||
/* for connect */
|
||||
SafeCref( const char* cookie, int socket, int clientVersion,
|
||||
SafeCref( const char* cookie, const AddrInfo* addr, int clientVers,
|
||||
DevID* devID, int nPlayersH, int nPlayersS,
|
||||
unsigned short gameSeed, int langCode, bool wantsPublic,
|
||||
bool makePublic );
|
||||
/* for reconnect */
|
||||
SafeCref( const char* connName, const char* cookie, HostID hid,
|
||||
int socket, int clientVersion, DevID* devID, int nPlayersH,
|
||||
int nPlayersS, unsigned short gameSeed, int langCode,
|
||||
bool wantsPublic, bool makePublic );
|
||||
const AddrInfo* addr, int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS, unsigned short gameSeed,
|
||||
int langCode, bool wantsPublic, bool makePublic );
|
||||
SafeCref( const char* const connName );
|
||||
SafeCref( CookieID cid, bool failOk = false );
|
||||
SafeCref( int socket );
|
||||
SafeCref( const AddrInfo* addr );
|
||||
/* SafeCref( CookieRef* cref ); */
|
||||
~SafeCref();
|
||||
|
||||
bool Forward( HostID src, in_addr& addr, HostID dest, unsigned char* buf,
|
||||
int buflen ) {
|
||||
bool Forward( HostID src, const AddrInfo* addr, HostID dest,
|
||||
unsigned char* buf, int buflen ) {
|
||||
if ( IsValid() ) {
|
||||
CookieRef* cref = m_cinfo->GetRef();
|
||||
assert( 0 != cref->GetCid() );
|
||||
|
@ -198,8 +197,8 @@ class SafeCref {
|
|||
}
|
||||
}
|
||||
|
||||
void PutMsg( HostID srcID, in_addr& addr, HostID destID, unsigned char* buf,
|
||||
int buflen ) {
|
||||
void PutMsg( HostID srcID, const AddrInfo* addr, HostID destID,
|
||||
unsigned char* buf, int buflen ) {
|
||||
if ( IsValid() ) {
|
||||
CookieRef* cref = m_cinfo->GetRef();
|
||||
assert( 0 != cref->GetCid() );
|
||||
|
@ -207,20 +206,19 @@ class SafeCref {
|
|||
}
|
||||
}
|
||||
|
||||
bool Connect( int socket, int nPlayersH, int nPlayersS, int seed,
|
||||
in_addr& addr ) {
|
||||
bool Connect( int nPlayersH, int nPlayersS, int seed ) {
|
||||
if ( IsValid() ) {
|
||||
CookieRef* cref = m_cinfo->GetRef();
|
||||
assert( 0 != cref->GetCid() );
|
||||
return cref->_Connect( socket, m_clientVersion, m_devID,
|
||||
return cref->_Connect( m_clientVersion, m_devID,
|
||||
nPlayersH, nPlayersS, seed,
|
||||
m_seenSeed, addr );
|
||||
m_seenSeed, &m_addr );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr, XWREASON* errp ) {
|
||||
bool Reconnect( HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, XWREASON* errp ) {
|
||||
bool success = false;
|
||||
*errp = XWRELAY_ERROR_NONE;
|
||||
if ( IsValid() ) {
|
||||
|
@ -229,18 +227,18 @@ class SafeCref {
|
|||
if ( m_dead ) {
|
||||
*errp = XWRELAY_ERROR_DEADGAME;
|
||||
} else {
|
||||
success = cref->_Reconnect( socket, m_clientVersion, m_devID,
|
||||
success = cref->_Reconnect( m_clientVersion, m_devID,
|
||||
srcID, nPlayersH, nPlayersS, seed,
|
||||
addr, m_dead );
|
||||
&m_addr, m_dead );
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void Disconnect(int socket, HostID hostID ) {
|
||||
void Disconnect( const AddrInfo* addr, HostID hostID ) {
|
||||
if ( IsValid() ) {
|
||||
CookieRef* cref = m_cinfo->GetRef();
|
||||
assert( 0 != cref->GetCid() );
|
||||
cref->_Disconnect( socket, hostID );
|
||||
cref->_Disconnect( addr, hostID );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,11 +268,11 @@ class SafeCref {
|
|||
cref->_Shutdown();
|
||||
}
|
||||
}
|
||||
void Remove( int socket ) {
|
||||
void Remove( const AddrInfo* addr ) {
|
||||
if ( IsValid() ) {
|
||||
CookieRef* cref = m_cinfo->GetRef();
|
||||
assert( 0 != cref->GetCid() );
|
||||
cref->_Remove( socket );
|
||||
cref->_Remove( addr );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,6 +388,7 @@ class SafeCref {
|
|||
private:
|
||||
CidInfo* m_cinfo;
|
||||
CRefMgr* m_mgr;
|
||||
AddrInfo m_addr;
|
||||
int m_clientVersion;
|
||||
DevID* m_devID;
|
||||
bool m_isValid;
|
||||
|
|
|
@ -47,7 +47,6 @@ static void formatParams( char* paramValues[], int nParams, const char* fmt,
|
|||
static int here_less_seed( const char* seeds, int perDeviceSum,
|
||||
unsigned short seed );
|
||||
static void destr_function( void* conn );
|
||||
static void string_printf( string& str, const char* fmt, ... );
|
||||
|
||||
/* static */ DBMgr*
|
||||
DBMgr::Get()
|
||||
|
@ -302,7 +301,7 @@ DBMgr::RegisterDevice( const DevID* host )
|
|||
|
||||
HostID
|
||||
DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion,
|
||||
int nToAdd, unsigned short seed, const in_addr& addr,
|
||||
int nToAdd, unsigned short seed, const AddrInfo* addr,
|
||||
DevIDRelay devID, bool ackd )
|
||||
{
|
||||
HostID newID = curID;
|
||||
|
@ -331,9 +330,10 @@ DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion,
|
|||
" mtimes[%d]='now', ack[%d]=\'%c\'"
|
||||
" WHERE connName = '%s'";
|
||||
string query;
|
||||
char* ntoa = inet_ntoa( addr->sin_addr() );
|
||||
string_printf( query, fmt, newID, nToAdd, newID, clientVersion,
|
||||
newID, seed, newID, inet_ntoa(addr), devIDBuf.c_str(),
|
||||
newID, newID, ackd?'A':'a', connName );
|
||||
newID, seed, newID, ntoa, devIDBuf.c_str(), newID,
|
||||
newID, ackd?'A':'a', connName );
|
||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query.c_str() );
|
||||
|
||||
execSql( query );
|
||||
|
@ -500,14 +500,15 @@ DBMgr::RecordSent( const int* msgIDs, int nMsgIDs )
|
|||
|
||||
void
|
||||
DBMgr::RecordAddress( const char* const connName, HostID hid,
|
||||
const in_addr& addr )
|
||||
const AddrInfo* addr )
|
||||
{
|
||||
assert( hid >= 0 && hid <= 4 );
|
||||
const char* fmt = "UPDATE " GAMES_TABLE " SET addrs[%d] = \'%s\'"
|
||||
" WHERE connName = '%s'";
|
||||
string query;
|
||||
string_printf( query, fmt, hid, inet_ntoa(addr), connName );
|
||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query.c_str() );
|
||||
char* ntoa = inet_ntoa( addr->sin_addr() );
|
||||
string_printf( query, fmt, hid, ntoa, connName );
|
||||
logf( XW_LOGVERBOSE0, "%s: query: %s", __func__, query.c_str() );
|
||||
|
||||
execSql( query );
|
||||
}
|
||||
|
@ -587,7 +588,7 @@ DBMgr::PendingMsgCount( const char* connName, int hid )
|
|||
;
|
||||
string query;
|
||||
string_printf( query, fmt, connName, hid );
|
||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query.c_str() );
|
||||
logf( XW_LOGVERBOSE0, "%s: query: %s", __func__, query.c_str() );
|
||||
|
||||
PGresult* result = PQexec( getThreadConn(), query.c_str() );
|
||||
if ( 1 == PQntuples( result ) ) {
|
||||
|
@ -742,9 +743,8 @@ DBMgr::StoreMessage( const char* const connName, int hid,
|
|||
}
|
||||
|
||||
bool
|
||||
DBMgr::GetNthStoredMessage( const char* const connName, int hid,
|
||||
int nn, unsigned char* buf, size_t* buflen,
|
||||
int* msgID )
|
||||
DBMgr::GetNthStoredMessage( const char* const connName, int hid, int nn,
|
||||
unsigned char* buf, size_t* buflen, int* msgID )
|
||||
{
|
||||
const char* fmt = "SELECT id, msg, msglen FROM " MSGS_TABLE
|
||||
" WHERE connName = '%s' AND hid = %d "
|
||||
|
@ -878,29 +878,3 @@ DBMgr::getThreadConn( void )
|
|||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/* From stack overflow, toward a snprintf with an expanding buffer.
|
||||
*/
|
||||
static void
|
||||
string_printf( string& str, const char* fmt, ... )
|
||||
{
|
||||
const int origsiz = str.size();
|
||||
int newsiz = 100;
|
||||
va_list ap;
|
||||
for ( ; ; ) {
|
||||
str.resize( origsiz + newsiz );
|
||||
|
||||
va_start( ap, fmt );
|
||||
int len = vsnprintf( (char *)str.c_str() + origsiz, newsiz, fmt, ap );
|
||||
va_end( ap );
|
||||
|
||||
if ( len > newsiz ) { // needs more space
|
||||
newsiz = len + 1;
|
||||
} else if ( -1 == len ) {
|
||||
assert(0); // should be impossible
|
||||
} else {
|
||||
str.resize( origsiz + len );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class DBMgr {
|
|||
DevIDRelay RegisterDevice( const DevID* hosts );
|
||||
|
||||
HostID AddDevice( const char* const connName, HostID curID, int clientVersion,
|
||||
int nToAdd, unsigned short seed, const in_addr& addr,
|
||||
int nToAdd, unsigned short seed, const AddrInfo* addr,
|
||||
DevIDRelay devID, bool unAckd );
|
||||
void NoteAckd( const char* const connName, HostID id );
|
||||
HostID HIDForSeed( const char* const connName, unsigned short seed );
|
||||
|
@ -77,7 +77,7 @@ class DBMgr {
|
|||
void RecordSent( const char* const connName, HostID hid, int nBytes );
|
||||
void RecordSent( const int* msgID, int nMsgIDs );
|
||||
void RecordAddress( const char* const connName, HostID hid,
|
||||
const in_addr& addr );
|
||||
const AddrInfo* addr );
|
||||
void GetPlayerCounts( const char* const connName, int* nTotal,
|
||||
int* nHere );
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ http_thread_main( void* arg )
|
|||
struct sockaddr_in name;
|
||||
socklen_t namelen = sizeof(name);
|
||||
|
||||
bool isLocal = 0 == getpeername( sock, (struct sockaddr*)&name,
|
||||
bool isLocal = 0 == getpeername( sock, (AddrInfo*)&name,
|
||||
&namelen );
|
||||
if ( isLocal ) {
|
||||
in_addr_t s_addr = name.sin_addr.s_addr;
|
||||
|
|
1
xwords4/relay/scripts/.gitignore
vendored
1
xwords4/relay/scripts/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
gcm.py
|
||||
gcm.pyc
|
||||
mykey.py*
|
||||
gcm_loop.pyc
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import sys, gcm, psycopg2, json
|
||||
import sys, psycopg2, json, urllib, urllib2
|
||||
|
||||
# I'm not checking my key in...
|
||||
import mykey
|
||||
|
||||
GCM_URL = 'https://android.googleapis.com/gcm/send'
|
||||
|
||||
def usage():
|
||||
print 'usage:', sys.argv[0], '[--to <name>] msg'
|
||||
sys.exit()
|
||||
|
||||
def msgViaGCM( devid, msg ):
|
||||
instance = gcm.GCM( mykey.myKey )
|
||||
data = { 'title' : 'Msg from Darth',
|
||||
'msg' : msg,
|
||||
}
|
||||
def sendMsg( devid, msg ):
|
||||
values = {
|
||||
'registration_ids': [ devid ],
|
||||
'data' : { 'title' : 'Msg from Darth2',
|
||||
'msg' : msg,
|
||||
}
|
||||
}
|
||||
params = json.dumps( values )
|
||||
req = urllib2.Request("https://android.googleapis.com/gcm/send", params )
|
||||
req.add_header( 'Content-Type' , 'application/x-www-form-urlencoded;charset=UTF-8' )
|
||||
req.add_header( 'Authorization' , 'key=' + mykey.myKey )
|
||||
req.add_header('Content-Type', 'application/json' )
|
||||
response = urllib2.urlopen( req )
|
||||
|
||||
response = instance.json_request( registration_ids = [devid],
|
||||
data = data )
|
||||
if 'errors' in response:
|
||||
response = response['errors']
|
||||
if 'NotRegistered' in response:
|
||||
ids = response['NotRegistered']
|
||||
for id in ids:
|
||||
print 'need to remove "', id, '" from db'
|
||||
else:
|
||||
print 'no errors'
|
||||
response = response.read()
|
||||
print response
|
||||
|
||||
def main():
|
||||
to = None
|
||||
|
@ -40,7 +42,7 @@ def main():
|
|||
if not to: usage()
|
||||
devid = mykey.devids[to]
|
||||
print 'sending: "%s" to' % msg, to
|
||||
msgViaGCM( devid, msg )
|
||||
sendMsg( devid, msg )
|
||||
|
||||
##############################################################################
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -81,18 +81,19 @@ void
|
|||
XWThreadPool::Setup( int nThreads, packet_func pFunc, kill_func kFunc )
|
||||
{
|
||||
m_nThreads = nThreads;
|
||||
m_threadInfos = (ThreadInfo*)malloc( nThreads * sizeof(*m_threadInfos) );
|
||||
m_pFunc = pFunc;
|
||||
m_kFunc = kFunc;
|
||||
|
||||
pthread_t thread;
|
||||
|
||||
int ii;
|
||||
for ( ii = 0; ii < nThreads; ++ii ) {
|
||||
int result = pthread_create( &thread, NULL, tpool_main, this );
|
||||
for ( int ii = 0; ii < nThreads; ++ii ) {
|
||||
ThreadInfo* tip = &m_threadInfos[ii];
|
||||
tip->me = this;
|
||||
int result = pthread_create( &tip->thread, NULL, tpool_main, tip );
|
||||
assert( result == 0 );
|
||||
pthread_detach( thread );
|
||||
pthread_detach( tip->thread );
|
||||
}
|
||||
|
||||
pthread_t thread;
|
||||
int result = pthread_create( &thread, NULL, listener_main, this );
|
||||
assert( result == 0 );
|
||||
result = pthread_detach( thread );
|
||||
|
@ -106,55 +107,65 @@ XWThreadPool::Stop()
|
|||
|
||||
int ii;
|
||||
for ( ii = 0; ii < m_nThreads; ++ii ) {
|
||||
SockInfo si = { STYPE_UNKNOWN, {0} };
|
||||
enqueue( 0, si );
|
||||
SockInfo si;
|
||||
si.m_type = STYPE_UNKNOWN;
|
||||
enqueue( si );
|
||||
}
|
||||
|
||||
interrupt_poll();
|
||||
}
|
||||
|
||||
void
|
||||
XWThreadPool::AddSocket( int socket, SockType stype, in_addr& from )
|
||||
XWThreadPool::AddSocket( SockType stype, const AddrInfo* from )
|
||||
{
|
||||
{
|
||||
RWWriteLock ml( &m_activeSocketsRWLock );
|
||||
SockInfo si;
|
||||
si.m_type = stype;
|
||||
si.m_addr = from;
|
||||
m_activeSockets.push_back( pair<int,SockInfo>(socket, si) );
|
||||
si.m_addr = *from;
|
||||
m_activeSockets.push_back( si );
|
||||
logf( XW_LOGINFO, "%s: %d sockets active", __func__,
|
||||
m_activeSockets.size() );
|
||||
}
|
||||
interrupt_poll();
|
||||
}
|
||||
|
||||
bool
|
||||
XWThreadPool::RemoveSocket( int socket )
|
||||
XWThreadPool::RemoveSocket( const AddrInfo* addr )
|
||||
{
|
||||
assert( addr->isTCP() );
|
||||
bool found = false;
|
||||
{
|
||||
RWWriteLock ml( &m_activeSocketsRWLock );
|
||||
|
||||
vector< pair<int,SockInfo> >::iterator iter = m_activeSockets.begin();
|
||||
while ( iter != m_activeSockets.end() ) {
|
||||
if ( iter->first == socket ) {
|
||||
logf( XW_LOGINFO, "%s: START: %d sockets active", __func__,
|
||||
m_activeSockets.size() );
|
||||
|
||||
vector<SockInfo>::iterator iter;
|
||||
for ( iter = m_activeSockets.begin();
|
||||
iter != m_activeSockets.end(); ++iter ) {
|
||||
if ( iter->m_addr.equals( *addr ) ) {
|
||||
m_activeSockets.erase( iter );
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
logf( XW_LOGINFO, "%s: AFTER: %d sockets active", __func__,
|
||||
m_activeSockets.size() );
|
||||
}
|
||||
return found;
|
||||
} /* RemoveSocket */
|
||||
|
||||
void
|
||||
XWThreadPool::CloseSocket( int socket )
|
||||
XWThreadPool::CloseSocket( const AddrInfo* addr )
|
||||
{
|
||||
/* bool do_interrupt = false; */
|
||||
if ( !RemoveSocket( socket ) ) {
|
||||
assert( addr->isTCP() );
|
||||
if ( !RemoveSocket( addr ) ) {
|
||||
MutexLock ml( &m_queueMutex );
|
||||
deque<QueuePr>::iterator iter = m_queue.begin();
|
||||
while ( iter != m_queue.end() ) {
|
||||
if ( iter->m_socket == socket ) {
|
||||
if ( iter->m_info.m_addr.equals( *addr ) ) {
|
||||
m_queue.erase( iter );
|
||||
/* do_interrupt = true; */
|
||||
break;
|
||||
|
@ -163,7 +174,7 @@ XWThreadPool::CloseSocket( int socket )
|
|||
}
|
||||
}
|
||||
logf( XW_LOGINFO, "CLOSING socket %d", socket );
|
||||
close( socket );
|
||||
close( addr->socket() );
|
||||
/* if ( do_interrupt ) { */
|
||||
/* We always need to interrupt the poll because the socket we're closing
|
||||
will be in the list being listened to. That or we need to drop sockets
|
||||
|
@ -174,51 +185,57 @@ XWThreadPool::CloseSocket( int socket )
|
|||
}
|
||||
|
||||
void
|
||||
XWThreadPool::EnqueueKill( int socket, const char* const why )
|
||||
XWThreadPool::EnqueueKill( const AddrInfo* addr, const char* const why )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(%d) reason: %s", __func__, socket, why );
|
||||
SockInfo si = { STYPE_UNKNOWN, {0} };
|
||||
enqueue( socket, si, Q_KILL );
|
||||
if ( addr->isTCP() ) {
|
||||
SockInfo si;
|
||||
si.m_type = STYPE_UNKNOWN;
|
||||
si.m_addr = *addr;
|
||||
enqueue( si, Q_KILL );
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
XWThreadPool::get_process_packet( int socket, SockType stype, in_addr& addr )
|
||||
XWThreadPool::get_process_packet( SockType stype, const AddrInfo* addr )
|
||||
{
|
||||
bool success = false;
|
||||
short packetSize;
|
||||
assert( sizeof(packetSize) == 2 );
|
||||
|
||||
unsigned char buf[MAX_MSG_LEN+1];
|
||||
int nRead = read_packet( socket, buf, sizeof(buf) );
|
||||
int nRead = read_packet( addr->socket(), buf, sizeof(buf) );
|
||||
if ( nRead < 0 ) {
|
||||
EnqueueKill( socket, "bad packet" );
|
||||
EnqueueKill( addr, "bad packet" );
|
||||
} else if ( STYPE_GAME == stype ) {
|
||||
logf( XW_LOGINFO, "calling m_pFunc" );
|
||||
success = (*m_pFunc)( buf, nRead, socket, addr );
|
||||
success = (*m_pFunc)( buf, nRead, addr );
|
||||
} else {
|
||||
buf[nRead] = '\0';
|
||||
handle_proxy_packet( buf, nRead, socket, addr );
|
||||
CloseSocket( socket );
|
||||
handle_proxy_packet( buf, nRead, addr );
|
||||
CloseSocket( addr );
|
||||
}
|
||||
return success;
|
||||
} /* get_process_packet */
|
||||
|
||||
/* static */ void*
|
||||
void*
|
||||
XWThreadPool::tpool_main( void* closure )
|
||||
{
|
||||
blockSignals();
|
||||
|
||||
XWThreadPool* me = (XWThreadPool*)closure;
|
||||
return me->real_tpool_main();
|
||||
ThreadInfo* tip = (ThreadInfo*)closure;
|
||||
return tip->me->real_tpool_main( tip );
|
||||
}
|
||||
|
||||
void*
|
||||
XWThreadPool::real_tpool_main()
|
||||
XWThreadPool::real_tpool_main( ThreadInfo* tip )
|
||||
{
|
||||
logf( XW_LOGINFO, "tpool worker thread starting" );
|
||||
int socket = -1;
|
||||
for ( ; ; ) {
|
||||
pthread_mutex_lock( &m_queueMutex );
|
||||
tip->recentTime = 0;
|
||||
|
||||
release_socket_locked( socket );
|
||||
|
||||
while ( !m_timeToDie && m_queue.size() == 0 ) {
|
||||
|
@ -232,26 +249,29 @@ XWThreadPool::real_tpool_main()
|
|||
}
|
||||
|
||||
QueuePr pr;
|
||||
grab_elem_locked( &pr );
|
||||
bool gotOne = grab_elem_locked( &pr );
|
||||
|
||||
tip->recentTime = time( NULL );
|
||||
pthread_mutex_unlock( &m_queueMutex );
|
||||
|
||||
if ( pr.m_socket >= 0 ) {
|
||||
logf( XW_LOGINFO, "worker thread got socket %d from queue",
|
||||
pr.m_socket );
|
||||
if ( gotOne ) {
|
||||
socket = pr.m_info.m_addr.socket();
|
||||
logf( XW_LOGINFO, "worker thread got socket %d from queue", socket );
|
||||
switch ( pr.m_act ) {
|
||||
case Q_READ:
|
||||
if ( get_process_packet( pr.m_socket, pr.m_info.m_type, pr.m_info.m_addr ) ) {
|
||||
AddSocket( pr.m_socket, pr.m_info.m_type, pr.m_info.m_addr );
|
||||
assert( socket >= 0 );
|
||||
if ( get_process_packet( pr.m_info.m_type, &pr.m_info.m_addr ) ) {
|
||||
AddSocket( pr.m_info.m_type, &pr.m_info.m_addr );
|
||||
}
|
||||
break;
|
||||
case Q_KILL:
|
||||
(*m_kFunc)( pr.m_socket );
|
||||
CloseSocket( pr.m_socket );
|
||||
(*m_kFunc)( &pr.m_info.m_addr );
|
||||
CloseSocket( &pr.m_info.m_addr );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
socket = -1;
|
||||
}
|
||||
socket = pr.m_socket;
|
||||
}
|
||||
logf( XW_LOGINFO, "tpool worker thread exiting" );
|
||||
return NULL;
|
||||
|
@ -310,11 +330,11 @@ XWThreadPool::real_listener()
|
|||
#endif
|
||||
++curfd;
|
||||
|
||||
vector< pair<int,SockInfo> >::iterator iter;
|
||||
vector<SockInfo>::iterator iter;
|
||||
for ( iter = m_activeSockets.begin(); iter != m_activeSockets.end();
|
||||
++iter ) {
|
||||
fds[curfd].fd = iter->first;
|
||||
sinfos[curfd] = iter->second;
|
||||
fds[curfd].fd = iter->m_addr.socket();
|
||||
sinfos[curfd] = *iter;
|
||||
fds[curfd].events = flags;
|
||||
#ifdef LOG_POLL
|
||||
if ( logCapacity > logLen ) {
|
||||
|
@ -366,7 +386,9 @@ XWThreadPool::real_listener()
|
|||
|
||||
if ( fds[curfd].revents != 0 ) {
|
||||
int socket = fds[curfd].fd;
|
||||
if ( !RemoveSocket( socket ) ) {
|
||||
const AddrInfo* addr = &sinfos[curfd].m_addr;
|
||||
assert( socket == addr->socket() );
|
||||
if ( !RemoveSocket( addr ) ) {
|
||||
/* no further processing if it's been removed while
|
||||
we've been sleeping in poll */
|
||||
--nEvents;
|
||||
|
@ -374,11 +396,11 @@ XWThreadPool::real_listener()
|
|||
}
|
||||
|
||||
if ( 0 != (fds[curfd].revents & (POLLIN | POLLPRI)) ) {
|
||||
enqueue( socket, sinfos[curfd] );
|
||||
enqueue( sinfos[curfd] );
|
||||
} else {
|
||||
logf( XW_LOGERROR, "odd revents: %x",
|
||||
fds[curfd].revents );
|
||||
EnqueueKill( socket, "error/hup in poll()" );
|
||||
EnqueueKill( addr, "error/hup in poll()" );
|
||||
}
|
||||
--nEvents;
|
||||
}
|
||||
|
@ -408,23 +430,23 @@ XWThreadPool::listener_main( void* closure )
|
|||
}
|
||||
|
||||
void
|
||||
XWThreadPool::enqueue( int socket, SockInfo si, QAction act )
|
||||
XWThreadPool::enqueue( SockInfo si, QAction act )
|
||||
{
|
||||
QueuePr pr = { act, socket, si };
|
||||
QueuePr pr = { act, si };
|
||||
MutexLock ml( &m_queueMutex );
|
||||
m_queue.push_back( pr );
|
||||
|
||||
pthread_cond_signal( &m_queueCondVar );
|
||||
log_hung_threads();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
XWThreadPool::grab_elem_locked( QueuePr* prp )
|
||||
{
|
||||
bool found = false;
|
||||
prp->m_socket = -1;
|
||||
deque<QueuePr>::iterator iter;
|
||||
for ( iter = m_queue.begin(); !found && iter != m_queue.end(); ++iter ) {
|
||||
int socket = iter->m_socket;
|
||||
int socket = iter->m_info.m_addr.socket();
|
||||
/* If NOT found */
|
||||
if ( m_sockets_in_use.end() == m_sockets_in_use.find( socket ) ) {
|
||||
*prp = *iter;
|
||||
|
@ -435,6 +457,7 @@ XWThreadPool::grab_elem_locked( QueuePr* prp )
|
|||
}
|
||||
|
||||
print_in_use();
|
||||
return found;
|
||||
} /* grab_elem_locked */
|
||||
|
||||
void
|
||||
|
@ -451,12 +474,36 @@ XWThreadPool::release_socket_locked( int socket )
|
|||
void
|
||||
XWThreadPool::print_in_use( void )
|
||||
{
|
||||
char buf[32] = {0};
|
||||
int len = 0;
|
||||
string str;
|
||||
set<int>::iterator iter;
|
||||
|
||||
for ( iter = m_sockets_in_use.begin();
|
||||
iter != m_sockets_in_use.end(); ++iter ) {
|
||||
len += snprintf( &buf[len], sizeof(buf)-len, "%d ", *iter );
|
||||
string_printf( str, "%d ", *iter );
|
||||
}
|
||||
if ( 0 < str.size() ) {
|
||||
logf( XW_LOGINFO, "Sockets in use: %s", str.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
// We have the mutex when this is called
|
||||
void
|
||||
XWThreadPool::log_hung_threads( void )
|
||||
{
|
||||
const time_t HUNG_THREASHHOLD = 300; // seconds
|
||||
int ii;
|
||||
time_t now = time( NULL );
|
||||
for ( ii = 0; ii < m_nThreads; ++ii ) {
|
||||
ThreadInfo* tip = &m_threadInfos[ii];
|
||||
time_t recentTime = tip->recentTime;
|
||||
if ( 0 != recentTime ) {
|
||||
time_t howLong = now - recentTime;
|
||||
if ( HUNG_THREASHHOLD < howLong ) {
|
||||
logf( XW_LOGERROR, "thread %d (%p) stopped for %d seconds!",
|
||||
ii, tip->thread, howLong );
|
||||
tip->recentTime = 0; // only log once
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <deque>
|
||||
#include <set>
|
||||
|
||||
#include "addrinfo.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class XWThreadPool {
|
||||
|
@ -39,13 +41,19 @@ class XWThreadPool {
|
|||
typedef enum { STYPE_UNKNOWN, STYPE_GAME, STYPE_PROXY } SockType;
|
||||
typedef struct _SockInfo {
|
||||
SockType m_type;
|
||||
in_addr m_addr;
|
||||
AddrInfo m_addr;
|
||||
} SockInfo;
|
||||
|
||||
typedef struct _ThreadInfo {
|
||||
XWThreadPool* me;
|
||||
pthread_t thread;
|
||||
time_t recentTime;
|
||||
} ThreadInfo;
|
||||
|
||||
static XWThreadPool* GetTPool();
|
||||
typedef bool (*packet_func)( unsigned char* buf, int bufLen, int socket,
|
||||
in_addr& addr );
|
||||
typedef void (*kill_func)( int socket );
|
||||
typedef bool (*packet_func)( unsigned char* buf, int bufLen,
|
||||
const AddrInfo* from );
|
||||
typedef void (*kill_func)( const AddrInfo* addr );
|
||||
|
||||
XWThreadPool();
|
||||
~XWThreadPool();
|
||||
|
@ -54,36 +62,37 @@ class XWThreadPool {
|
|||
void Stop();
|
||||
|
||||
/* Add to set being listened on */
|
||||
void AddSocket( int socket, SockType stype, in_addr& fromAddr );
|
||||
void AddSocket( SockType stype, const AddrInfo* from );
|
||||
/* remove from tpool altogether, and close */
|
||||
void CloseSocket( int socket );
|
||||
void CloseSocket( const AddrInfo* addr );
|
||||
|
||||
void EnqueueKill( int socket, const char* const why );
|
||||
void EnqueueKill( const AddrInfo* addr, const char* const why );
|
||||
|
||||
private:
|
||||
typedef enum { Q_READ, Q_KILL } QAction;
|
||||
typedef struct { QAction m_act; int m_socket; SockInfo m_info; } QueuePr;
|
||||
typedef struct { QAction m_act; SockInfo m_info; } QueuePr;
|
||||
|
||||
/* Remove from set being listened on */
|
||||
bool RemoveSocket( int socket );
|
||||
bool RemoveSocket( const AddrInfo* addr );
|
||||
|
||||
void enqueue( int socket, QAction act = Q_READ );
|
||||
void enqueue( int socket, SockInfo si, QAction act = Q_READ );
|
||||
void enqueue( QAction act = Q_READ );
|
||||
void enqueue( SockInfo si, QAction act = Q_READ );
|
||||
void release_socket_locked( int socket );
|
||||
void grab_elem_locked( QueuePr* qpp );
|
||||
bool grab_elem_locked( QueuePr* qpp );
|
||||
void print_in_use( void );
|
||||
void log_hung_threads( void );
|
||||
|
||||
bool get_process_packet( int socket, SockType stype, in_addr& addr );
|
||||
bool get_process_packet( SockType stype, const AddrInfo* from );
|
||||
void interrupt_poll();
|
||||
|
||||
void* real_tpool_main();
|
||||
void* real_tpool_main( ThreadInfo* tsp );
|
||||
static void* tpool_main( void* closure );
|
||||
|
||||
void* real_listener();
|
||||
static void* listener_main( void* closure );
|
||||
|
||||
/* Sockets main thread listens on */
|
||||
vector< pair<int,SockInfo> >m_activeSockets;
|
||||
vector<SockInfo>m_activeSockets;
|
||||
pthread_rwlock_t m_activeSocketsRWLock;
|
||||
|
||||
/* Sockets waiting for a thread to read 'em */
|
||||
|
@ -100,6 +109,7 @@ class XWThreadPool {
|
|||
int m_nThreads;
|
||||
packet_func m_pFunc;
|
||||
kill_func m_kFunc;
|
||||
ThreadInfo* m_threadInfos;
|
||||
|
||||
static XWThreadPool* g_instance;
|
||||
};
|
||||
|
|
|
@ -75,8 +75,10 @@
|
|||
#include "permid.h"
|
||||
#include "lstnrmgr.h"
|
||||
#include "dbmgr.h"
|
||||
#include "addrinfo.h"
|
||||
|
||||
static int s_nSpawns = 0;
|
||||
static int g_maxsocks = -1;
|
||||
|
||||
void
|
||||
logf( XW_LogLevel level, const char* format, ... )
|
||||
|
@ -322,27 +324,31 @@ flagsOK( unsigned char** bufp, unsigned char const* end,
|
|||
} /* flagsOK */
|
||||
|
||||
void
|
||||
denyConnection( int socket, XWREASON err )
|
||||
denyConnection( const AddrInfo* addr, XWREASON err )
|
||||
{
|
||||
unsigned char buf[2];
|
||||
|
||||
buf[0] = XWRELAY_CONNECTDENIED;
|
||||
buf[1] = err;
|
||||
|
||||
send_with_length_unsafe( socket, buf, sizeof(buf) );
|
||||
send_with_length_unsafe( addr, buf, sizeof(buf) );
|
||||
}
|
||||
|
||||
/* No mutex here. Caller better be ensuring no other thread can access this
|
||||
* socket. */
|
||||
bool
|
||||
send_with_length_unsafe( int socket, unsigned char* buf, int bufLen )
|
||||
send_with_length_unsafe( const AddrInfo* addr, unsigned char* buf,
|
||||
size_t bufLen )
|
||||
{
|
||||
assert( !!addr );
|
||||
bool ok = false;
|
||||
int socket = addr->socket();
|
||||
assert ( addr->isTCP() );
|
||||
unsigned short len = htons( bufLen );
|
||||
ssize_t nSent = send( socket, &len, 2, 0 );
|
||||
if ( nSent == 2 ) {
|
||||
nSent = send( socket, buf, bufLen, 0 );
|
||||
if ( nSent == bufLen ) {
|
||||
if ( nSent == ssize_t(bufLen) ) {
|
||||
logf( XW_LOGINFO, "sent %d bytes on socket %d", nSent, socket );
|
||||
ok = true;
|
||||
}
|
||||
|
@ -368,7 +374,7 @@ send_with_length_unsafe( int socket, unsigned char* buf, int bufLen )
|
|||
* game?
|
||||
*/
|
||||
static bool
|
||||
processConnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
||||
processConnect( unsigned char* bufp, int bufLen, const AddrInfo* addr )
|
||||
{
|
||||
char cookie[MAX_INVITE_LEN+1];
|
||||
unsigned char* end = bufp + bufLen;
|
||||
|
@ -407,25 +413,25 @@ processConnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
MutexLock ml( &s_newCookieLock );
|
||||
|
||||
SafeCref scr( cookie, socket, clientVersion, &devID,
|
||||
SafeCref scr( cookie, addr, clientVersion, &devID,
|
||||
nPlayersH, nPlayersT, seed, langCode,
|
||||
wantsPublic, makePublic );
|
||||
/* nPlayersT etc could be slots in SafeCref to avoid passing
|
||||
here */
|
||||
success = scr.Connect( socket, nPlayersH, nPlayersT, seed, addr );
|
||||
success = scr.Connect( nPlayersH, nPlayersT, seed );
|
||||
} else {
|
||||
err = XWRELAY_ERROR_BADPROTO;
|
||||
}
|
||||
}
|
||||
|
||||
if ( err != XWRELAY_ERROR_NONE ) {
|
||||
denyConnection( socket, err );
|
||||
denyConnection( addr, err );
|
||||
}
|
||||
return success;
|
||||
} /* processConnect */
|
||||
|
||||
static bool
|
||||
processReconnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
||||
processReconnect( unsigned char* bufp, int bufLen, const AddrInfo* addr )
|
||||
{
|
||||
unsigned char* end = bufp + bufLen;
|
||||
bool success = false;
|
||||
|
@ -459,11 +465,11 @@ processReconnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
getDevID( &bufp, end, flags, &devID );
|
||||
|
||||
SafeCref scr( connName[0]? connName : NULL,
|
||||
cookie, srcID, socket, clientVersion, &devID,
|
||||
cookie, srcID, addr, clientVersion, &devID,
|
||||
nPlayersH, nPlayersT, gameSeed, langCode,
|
||||
wantsPublic, makePublic );
|
||||
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT,
|
||||
gameSeed, addr, &err );
|
||||
success = scr.Reconnect( srcID, nPlayersH, nPlayersT, gameSeed,
|
||||
&err );
|
||||
if ( !success ) {
|
||||
assert( err != XWRELAY_ERROR_NONE );
|
||||
}
|
||||
|
@ -473,27 +479,27 @@ processReconnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
}
|
||||
|
||||
if ( err != XWRELAY_ERROR_NONE ) {
|
||||
denyConnection( socket, err );
|
||||
denyConnection( addr, err );
|
||||
}
|
||||
|
||||
return success;
|
||||
} /* processReconnect */
|
||||
|
||||
static bool
|
||||
processAck( unsigned char* bufp, int bufLen, int socket )
|
||||
processAck( unsigned char* bufp, int bufLen, const AddrInfo* addr )
|
||||
{
|
||||
bool success = false;
|
||||
unsigned char* end = bufp + bufLen;
|
||||
HostID srcID;
|
||||
if ( getNetByte( &bufp, end, &srcID ) ) {
|
||||
SafeCref scr( socket );
|
||||
SafeCref scr( addr );
|
||||
success = scr.HandleAck( srcID );
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool
|
||||
processDisconnect( unsigned char* bufp, int bufLen, int socket )
|
||||
processDisconnect( unsigned char* bufp, int bufLen, const AddrInfo* addr )
|
||||
{
|
||||
unsigned char* end = bufp + bufLen;
|
||||
CookieID cookieID;
|
||||
|
@ -503,8 +509,8 @@ processDisconnect( unsigned char* bufp, int bufLen, int socket )
|
|||
if ( getNetShort( &bufp, end, &cookieID )
|
||||
&& getNetByte( &bufp, end, &hostID ) ) {
|
||||
|
||||
SafeCref scr( socket );
|
||||
scr.Disconnect( socket, hostID );
|
||||
SafeCref scr( addr );
|
||||
scr.Disconnect( addr, hostID );
|
||||
success = true;
|
||||
} else {
|
||||
logf( XW_LOGERROR, "dropping XWRELAY_GAME_DISCONNECT; wrong length" );
|
||||
|
@ -513,10 +519,10 @@ processDisconnect( unsigned char* bufp, int bufLen, int socket )
|
|||
} /* processDisconnect */
|
||||
|
||||
static void
|
||||
killSocket( int socket )
|
||||
killSocket( const AddrInfo* addr )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(%d)", __func__, socket );
|
||||
CRefMgr::Get()->RemoveSocketRefs( socket );
|
||||
logf( XW_LOGINFO, "%s(addr.socket=%d)", __func__, addr->socket() );
|
||||
CRefMgr::Get()->RemoveSocketRefs( addr );
|
||||
}
|
||||
|
||||
time_t
|
||||
|
@ -546,7 +552,7 @@ GetNSpawns(void)
|
|||
/* forward the message. Need only change the command after looking up the
|
||||
* socket and it's ready to go. */
|
||||
static bool
|
||||
forwardMessage( unsigned char* buf, int buflen, int srcSocket, in_addr& addr )
|
||||
forwardMessage( unsigned char* buf, int buflen, const AddrInfo* addr )
|
||||
{
|
||||
bool success = false;
|
||||
unsigned char* bufp = buf + 1; /* skip cmd */
|
||||
|
@ -561,7 +567,7 @@ forwardMessage( unsigned char* buf, int buflen, int srcSocket, in_addr& addr )
|
|||
logf( XW_LOGINFO, "cookieID = %d", cookieID );
|
||||
|
||||
if ( COOKIE_ID_NONE == cookieID ) {
|
||||
SafeCref scr( srcSocket );
|
||||
SafeCref scr( addr );
|
||||
success = scr.Forward( src, addr, dest, buf, buflen );
|
||||
} else {
|
||||
SafeCref scr( cookieID ); /* won't work if not allcon; will be 0 */
|
||||
|
@ -572,7 +578,7 @@ forwardMessage( unsigned char* buf, int buflen, int srcSocket, in_addr& addr )
|
|||
} /* forwardMessage */
|
||||
|
||||
static bool
|
||||
processMessage( unsigned char* buf, int bufLen, int socket, in_addr& addr )
|
||||
processMessage( unsigned char* buf, int bufLen, const AddrInfo* addr )
|
||||
{
|
||||
bool success = false; /* default is failure */
|
||||
XWRELAY_Cmd cmd = *buf;
|
||||
|
@ -581,16 +587,16 @@ processMessage( unsigned char* buf, int bufLen, int socket, in_addr& addr )
|
|||
|
||||
switch( cmd ) {
|
||||
case XWRELAY_GAME_CONNECT:
|
||||
success = processConnect( buf+1, bufLen-1, socket, addr );
|
||||
success = processConnect( buf+1, bufLen-1, addr );
|
||||
break;
|
||||
case XWRELAY_GAME_RECONNECT:
|
||||
success = processReconnect( buf+1, bufLen-1, socket, addr );
|
||||
success = processReconnect( buf+1, bufLen-1, addr );
|
||||
break;
|
||||
case XWRELAY_ACK:
|
||||
success = processAck( buf+1, bufLen-1, socket );
|
||||
success = processAck( buf+1, bufLen-1, addr );
|
||||
break;
|
||||
case XWRELAY_GAME_DISCONNECT:
|
||||
success = processDisconnect( buf+1, bufLen-1, socket );
|
||||
success = processDisconnect( buf+1, bufLen-1, addr );
|
||||
break;
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
case XWRELAY_HEARTBEAT:
|
||||
|
@ -598,7 +604,7 @@ processMessage( unsigned char* buf, int bufLen, int socket, in_addr& addr )
|
|||
break;
|
||||
#endif
|
||||
case XWRELAY_MSG_TORELAY:
|
||||
success = forwardMessage( buf, bufLen, socket, addr );
|
||||
success = forwardMessage( buf, bufLen, addr );
|
||||
break;
|
||||
default:
|
||||
logf( XW_LOGERROR, "%s bad: %d", __func__, cmd );
|
||||
|
@ -607,7 +613,7 @@ processMessage( unsigned char* buf, int bufLen, int socket, in_addr& addr )
|
|||
}
|
||||
|
||||
if ( !success ) {
|
||||
XWThreadPool::GetTPool()->EnqueueKill( socket, "failure" );
|
||||
XWThreadPool::GetTPool()->EnqueueKill( addr, "failure" );
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -628,7 +634,7 @@ make_socket( unsigned long addr, unsigned short port )
|
|||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in sockAddr;
|
||||
sockaddr_in sockAddr;
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_addr.s_addr = htonl(addr);
|
||||
sockAddr.sin_port = htons(port);
|
||||
|
@ -667,6 +673,7 @@ usage( char* arg0 )
|
|||
"\t-h (print this help)\\\n"
|
||||
"\t-i <idfile> (file where next global id stored)\\\n"
|
||||
"\t-l <logfile> (write logs here, not stderr)\\\n"
|
||||
"\t-m <num_sockets> (max number of simultaneous sockets to have open)\\\n"
|
||||
"\t-n <serverName> (used in permID generation)\\\n"
|
||||
"\t-p <port> (port to listen on)\\\n"
|
||||
#ifdef DO_HTTP
|
||||
|
@ -806,7 +813,7 @@ pushMsgs( vector<unsigned char>& out, DBMgr* dbmgr, const char* connName,
|
|||
}
|
||||
|
||||
static void
|
||||
handleMsgsMsg( int sock, in_addr& addr, bool sendFull,
|
||||
handleMsgsMsg( const AddrInfo* addr, bool sendFull,
|
||||
unsigned char* bufp, const unsigned char* end )
|
||||
{
|
||||
unsigned short nameCount;
|
||||
|
@ -850,8 +857,8 @@ handleMsgsMsg( int sock, in_addr& addr, bool sendFull,
|
|||
memcpy( &out[0], &tmp, sizeof(tmp) );
|
||||
tmp = htons( nameCount );
|
||||
memcpy( &out[2], &tmp, sizeof(tmp) );
|
||||
ssize_t nwritten = write( sock, &out[0], out.size() );
|
||||
logf( XW_LOGINFO, "%s: wrote %d bytes", __func__, nwritten );
|
||||
ssize_t nwritten = write( addr->socket(), &out[0], out.size() );
|
||||
logf( XW_LOGVERBOSE0, "%s: wrote %d bytes", __func__, nwritten );
|
||||
if ( sendFull && nwritten >= 0 && (size_t)nwritten == out.size() ) {
|
||||
dbmgr->RecordSent( &msgIDs[0], msgIDs.size() );
|
||||
dbmgr->RemoveStoredMessages( &msgIDs[0], msgIDs.size() );
|
||||
|
@ -907,7 +914,8 @@ log_hex( const unsigned char* memp, int len, const char* tag )
|
|||
} // log_hex
|
||||
|
||||
static void
|
||||
handleProxyMsgs( int sock, in_addr& addr, unsigned char* bufp, unsigned char* end )
|
||||
handleProxyMsgs( int sock, const AddrInfo* addr, unsigned char* bufp,
|
||||
unsigned char* end )
|
||||
{
|
||||
// log_hex( bufp, end-bufp, __func__ );
|
||||
unsigned short nameCount;
|
||||
|
@ -962,10 +970,12 @@ handleProxyMsgs( int sock, in_addr& addr, unsigned char* bufp, unsigned char* en
|
|||
} // handleProxyMsgs
|
||||
|
||||
void
|
||||
handle_proxy_packet( unsigned char* buf, int len, int sock, in_addr& addr )
|
||||
handle_proxy_packet( unsigned char* buf, int len, const AddrInfo* addr )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s()", __func__ );
|
||||
logf( XW_LOGVERBOSE0, "%s()", __func__ );
|
||||
if ( len > 0 ) {
|
||||
assert( addr->isTCP() );
|
||||
int socket = addr->socket();
|
||||
unsigned char* bufp = buf;
|
||||
unsigned char* end = bufp + len;
|
||||
if ( (0 == *bufp++) ) { /* protocol */
|
||||
|
@ -985,21 +995,21 @@ handle_proxy_packet( unsigned char* buf, int len, int sock, in_addr& addr )
|
|||
DBMgr::Get()->PublicRooms( lang, nPlayers, &nNames, names );
|
||||
unsigned short netshort = htons( names.size()
|
||||
+ sizeof(unsigned short) );
|
||||
write( sock, &netshort, sizeof(netshort) );
|
||||
write( socket, &netshort, sizeof(netshort) );
|
||||
netshort = htons( (unsigned short)nNames );
|
||||
write( sock, &netshort, sizeof(netshort) );
|
||||
write( sock, names.c_str(), names.size() );
|
||||
write( socket, &netshort, sizeof(netshort) );
|
||||
write( socket, names.c_str(), names.size() );
|
||||
}
|
||||
break;
|
||||
case PRX_HAS_MSGS:
|
||||
case PRX_GET_MSGS:
|
||||
if ( len >= 2 ) {
|
||||
handleMsgsMsg( sock, addr, PRX_GET_MSGS == cmd, bufp, end );
|
||||
handleMsgsMsg( addr, PRX_GET_MSGS == cmd, bufp, end );
|
||||
}
|
||||
break; /* PRX_HAS_MSGS */
|
||||
|
||||
case PRX_PUT_MSGS:
|
||||
handleProxyMsgs( sock, addr, bufp, end );
|
||||
handleProxyMsgs( socket, addr, bufp, end );
|
||||
break;
|
||||
|
||||
case PRX_DEVICE_GONE:
|
||||
|
@ -1026,7 +1036,7 @@ handle_proxy_packet( unsigned char* buf, int len, int sock, in_addr& addr )
|
|||
}
|
||||
}
|
||||
len = 0; /* return a 0-length message */
|
||||
write( sock, &len, sizeof(len) );
|
||||
write( socket, &len, sizeof(len) );
|
||||
break; /* PRX_DEVICE_GONE */
|
||||
default:
|
||||
logf( XW_LOGERROR, "unexpected command %d", __func__, cmd );
|
||||
|
@ -1036,6 +1046,32 @@ handle_proxy_packet( unsigned char* buf, int len, int sock, in_addr& addr )
|
|||
}
|
||||
} /* handle_proxy_packet */
|
||||
|
||||
/* From stack overflow, toward a snprintf with an expanding buffer.
|
||||
*/
|
||||
void
|
||||
string_printf( string& str, const char* fmt, ... )
|
||||
{
|
||||
const int origsiz = str.size();
|
||||
int newsiz = 100;
|
||||
va_list ap;
|
||||
for ( ; ; ) {
|
||||
str.resize( origsiz + newsiz );
|
||||
|
||||
va_start( ap, fmt );
|
||||
int len = vsnprintf( (char *)str.c_str() + origsiz, newsiz, fmt, ap );
|
||||
va_end( ap );
|
||||
|
||||
if ( len > newsiz ) { // needs more space
|
||||
newsiz = len + 1;
|
||||
} else if ( -1 == len ) {
|
||||
assert(0); // should be impossible
|
||||
} else {
|
||||
str.resize( origsiz + len );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_timeouts( int sock )
|
||||
{
|
||||
|
@ -1120,7 +1156,7 @@ main( int argc, char** argv )
|
|||
first. */
|
||||
|
||||
for ( ; ; ) {
|
||||
int opt = getopt(argc, argv, "h?c:p:n:f:l:t:s:w:"
|
||||
int opt = getopt(argc, argv, "h?c:p:m:n:f:l:t:s:w:"
|
||||
"DF" );
|
||||
|
||||
if ( opt == -1 ) {
|
||||
|
@ -1162,6 +1198,9 @@ main( int argc, char** argv )
|
|||
case 'l':
|
||||
logFile = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
g_maxsocks = atoi( optarg );
|
||||
break;
|
||||
case 'n':
|
||||
serverName = optarg;
|
||||
break;
|
||||
|
@ -1201,6 +1240,11 @@ main( int argc, char** argv )
|
|||
if ( nWorkerThreads == 0 ) {
|
||||
(void)cfg->GetValueFor( "NTHREADS", &nWorkerThreads );
|
||||
}
|
||||
if ( g_maxsocks == -1 ) {
|
||||
(void)cfg->GetValueFor( "MAXSOCKS", &g_maxsocks );
|
||||
} else {
|
||||
g_maxsocks = 100;
|
||||
}
|
||||
char serverNameBuf[128];
|
||||
if ( serverName == NULL ) {
|
||||
if ( cfg->GetValueFor( "SERVERNAME", serverNameBuf,
|
||||
|
@ -1391,15 +1435,19 @@ main( int argc, char** argv )
|
|||
}
|
||||
|
||||
if ( FD_ISSET( listener, &rfds ) ) {
|
||||
struct sockaddr_in newaddr;
|
||||
socklen_t siz = sizeof(newaddr);
|
||||
int newSock = accept( listener, (sockaddr*)&newaddr,
|
||||
&siz );
|
||||
AddrInfo::AddrUnion saddr;
|
||||
socklen_t siz = sizeof(saddr.addr_in);
|
||||
int newSock = accept( listener, &saddr.addr, &siz );
|
||||
if ( newSock < 0 ) {
|
||||
logf( XW_LOGERROR, "accept failed: errno(%d)=%s",
|
||||
errno, strerror(errno) );
|
||||
assert( 0 ); // we're leaking files or load has grown
|
||||
} else {
|
||||
// I've seen a bug where we accept but never service
|
||||
// connections. Sockets are not closed, and so the
|
||||
// number goes up. Probably need a watchdog instead,
|
||||
// but this will work around it.
|
||||
assert( g_maxsocks > newSock );
|
||||
|
||||
/* Set timeout so send and recv won't block forever */
|
||||
set_timeouts( newSock );
|
||||
|
@ -1408,12 +1456,12 @@ main( int argc, char** argv )
|
|||
|
||||
logf( XW_LOGINFO,
|
||||
"%s: accepting connection from %s on socket %d",
|
||||
__func__, inet_ntoa(newaddr.sin_addr), newSock );
|
||||
__func__, inet_ntoa(saddr.addr_in.sin_addr), newSock );
|
||||
|
||||
tPool->AddSocket( newSock,
|
||||
perGame ? XWThreadPool::STYPE_GAME
|
||||
AddrInfo addr( true, newSock, &saddr );
|
||||
tPool->AddSocket( perGame ? XWThreadPool::STYPE_GAME
|
||||
: XWThreadPool::STYPE_PROXY,
|
||||
newaddr.sin_addr );
|
||||
&addr );
|
||||
}
|
||||
--retval;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ XWRELAY=${DIR}/xwrelay
|
|||
PIDFILE=${DIR}/xwrelay.pid
|
||||
CONFFILE=${DIR}/xwrelay.conf
|
||||
IDFILE=${DIR}/nextid.txt
|
||||
CSSFILE=${DIR}/xwrelay.css
|
||||
|
||||
LOGFILE=/tmp/xwrelay_log_$$.txt
|
||||
#LOGFILE=/dev/null
|
||||
|
@ -98,8 +97,8 @@ do_start() {
|
|||
exit 1
|
||||
fi
|
||||
echo "starting..." | tee -a $LOGFILE
|
||||
echo "running $XWRELAY $@ -f $CONFFILE -s $CSSFILE" | tee -a $LOGFILE
|
||||
$XWRELAY $@ -f $CONFFILE -s $CSSFILE &
|
||||
echo "running $XWRELAY $@ -f $CONFFILE" | tee -a $LOGFILE
|
||||
$XWRELAY $@ -f $CONFFILE &
|
||||
NEWPID=$!
|
||||
echo -n $NEWPID > $PIDFILE
|
||||
sleep 1
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
#ifndef _XWRELAY_PRIV_H_
|
||||
#define _XWRELAY_PRIV_H_
|
||||
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
#include "lstnrmgr.h"
|
||||
#include "xwrelay.h"
|
||||
#include "addrinfo.h"
|
||||
|
||||
typedef unsigned char HostID; /* see HOST_ID_SERVER */
|
||||
|
||||
|
@ -38,8 +40,9 @@ typedef enum {
|
|||
|
||||
void logf( XW_LogLevel level, const char* format, ... );
|
||||
|
||||
void denyConnection( int socket, XWREASON err );
|
||||
bool send_with_length_unsafe( int socket, unsigned char* buf, int bufLen );
|
||||
void denyConnection( const AddrInfo* addr, XWREASON err );
|
||||
bool send_with_length_unsafe( const AddrInfo* addr,
|
||||
unsigned char* buf, size_t bufLen );
|
||||
|
||||
time_t uptime(void);
|
||||
|
||||
|
@ -49,9 +52,11 @@ int GetNSpawns(void);
|
|||
|
||||
int make_socket( unsigned long addr, unsigned short port );
|
||||
|
||||
void string_printf( std::string& str, const char* fmt, ... );
|
||||
|
||||
int read_packet( int sock, unsigned char* buf, int buflen );
|
||||
void handle_proxy_packet( unsigned char* buf, int bufLen, int socket,
|
||||
in_addr& addr );
|
||||
void handle_proxy_packet( unsigned char* buf, int bufLen,
|
||||
const AddrInfo* addr );
|
||||
|
||||
const char* cmdToStr( XWRELAY_Cmd cmd );
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue