Merge remote-tracking branch 'origin/android_branch' into android_branch

This commit is contained in:
Eric House 2013-01-19 15:54:40 -08:00
commit 54ad381749
20 changed files with 700 additions and 500 deletions

View file

@ -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 );

View file

@ -30,6 +30,7 @@ SRC = \
timermgr.cpp \
tpool.cpp \
cidlock.cpp \
addrinfo.cpp \
xwrelay.cpp \
# STATIC ?= -static

View 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
View 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

View file

@ -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 );
}

View file

@ -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:

View file

@ -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;

View file

@ -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 */

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;
}
}
}

View file

@ -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 );

View file

@ -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;

View file

@ -1,3 +1,4 @@
gcm.py
gcm.pyc
mykey.py*
gcm_loop.pyc

View file

@ -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__':

View file

@ -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);
}
}
}
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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

View file

@ -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 );