lots more changes -- another snapshot, this, rather than stuff

carefully polished and reviewed.  Shows progress, though, in getting
through tests.
This commit is contained in:
Andy2 2011-06-23 07:12:50 -07:00
parent b4381e8403
commit e886a1aefe
13 changed files with 340 additions and 266 deletions

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */ /* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
/* /*
* Copyright 2001-2009 by Eric House (xwords@eehouse.org). All rights * Copyright 2001-2011 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -236,6 +236,7 @@ XWREASON2Str( XWREASON reason )
CASE_STR(XWRELAY_ERROR_DUP_ROOM); CASE_STR(XWRELAY_ERROR_DUP_ROOM);
CASE_STR(XWRELAY_ERROR_TOO_MANY); CASE_STR(XWRELAY_ERROR_TOO_MANY);
CASE_STR(XWRELAY_ERROR_DELETED); CASE_STR(XWRELAY_ERROR_DELETED);
CASE_STR(XWRELAY_ERROR_NORECONN);
CASE_STR(XWRELAY_ERROR_LASTERR); CASE_STR(XWRELAY_ERROR_LASTERR);
default: default:
XP_ASSERT(0); XP_ASSERT(0);
@ -360,7 +361,7 @@ reset_internal( CommsCtxt* comms, XP_Bool isServer,
} }
#endif #endif
LOG_RETURN_VOID(); LOG_RETURN_VOID();
} /* comms_reset */ } /* reset_internal */
void void
comms_reset( CommsCtxt* comms, XP_Bool isServer, comms_reset( CommsCtxt* comms, XP_Bool isServer,
@ -1247,7 +1248,7 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
XP_Bool consumed = XP_TRUE; XP_Bool consumed = XP_TRUE;
XWHostID destID, srcID; XWHostID destID, srcID;
CookieID cookieID; CookieID cookieID;
XP_U8 relayErr; XWREASON relayErr;
/* nothing for us to do here if not using relay */ /* nothing for us to do here if not using relay */
XWRELAY_Cmd cmd = stream_getU8( stream ); XWRELAY_Cmd cmd = stream_getU8( stream );
@ -1355,10 +1356,16 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
case XWRELAY_CONNECTDENIED: /* socket will get closed by relay */ case XWRELAY_CONNECTDENIED: /* socket will get closed by relay */
relayErr = stream_getU8( stream ); relayErr = stream_getU8( stream );
XP_LOGF( "%s: got reason: %s", __func__, XWREASON2Str( relayErr ) );
set_relay_state( comms, COMMS_RELAYSTATE_DENIED ); set_relay_state( comms, COMMS_RELAYSTATE_DENIED );
util_userError( comms->util, ERR_RELAY_BASE + relayErr );
/* requires action, not just notification */ if ( XWRELAY_ERROR_NORECONN == relayErr ) {
(*comms->procs.rerror)( comms->procs.closure, relayErr ); init_relay( comms, comms->r.nPlayersHere, comms->r.nPlayersTotal );
} else {
util_userError( comms->util, ERR_RELAY_BASE + relayErr );
/* requires action, not just notification */
(*comms->procs.rerror)( comms->procs.closure, relayErr );
}
break; break;
/* fallthru */ /* fallthru */

View file

@ -22,7 +22,6 @@ SRC = \
configs.cpp \ configs.cpp \
cref.cpp \ cref.cpp \
crefmgr.cpp \ crefmgr.cpp \
ctrl.cpp \
dbmgr.cpp \ dbmgr.cpp \
http.cpp \ http.cpp \
lstnrmgr.cpp \ lstnrmgr.cpp \

View file

@ -112,10 +112,9 @@ CidLock::ClaimSocket( int sock )
return info; return info;
} }
void bool
CidLock::Associate( const CookieRef* cref, int socket ) CidLock::Associate_locked( const CookieRef* cref, int socket )
{ {
MutexLock ml( &m_infos_mutex );
map< CookieID, CidInfo*>::iterator iter = m_infos.begin(); map< CookieID, CidInfo*>::iterator iter = m_infos.begin();
while ( iter != m_infos.end() ) { while ( iter != m_infos.end() ) {
if ( cref == iter->second->GetRef() ) { if ( cref == iter->second->GetRef() ) {
@ -124,16 +123,30 @@ CidLock::Associate( const CookieRef* cref, int socket )
} }
++iter; ++iter;
} }
bool isNew = m_sockets.find( socket ) == m_sockets.end();
if ( isNew ) {
m_sockets.insert( socket );
}
return isNew;
}
bool
CidLock::Associate( const CookieRef* cref, int socket )
{
MutexLock ml( &m_infos_mutex );
return Associate_locked( cref, socket );
} }
void void
CidLock::DisAssociate( const CookieRef* cref, int socket ) CidLock::DisAssociate( const CookieRef* cref, int socket )
{ {
Associate( cref, 0 ); MutexLock ml( &m_infos_mutex );
Associate_locked( cref, 0 );
m_sockets.erase( socket );
} }
void void
CidLock::Relinquish( CidInfo* claim ) CidLock::Relinquish( CidInfo* claim, bool drop )
{ {
CookieID cid = claim->GetCid(); CookieID cid = claim->GetCid();
logf( XW_LOGINFO, "%s(%d)", __func__, cid ); logf( XW_LOGINFO, "%s(%d)", __func__, cid );
@ -141,7 +154,12 @@ CidLock::Relinquish( CidInfo* claim )
MutexLock ml( &m_infos_mutex ); MutexLock ml( &m_infos_mutex );
map< CookieID, CidInfo*>::iterator iter = m_infos.find( cid ); map< CookieID, CidInfo*>::iterator iter = m_infos.find( cid );
assert( iter != m_infos.end() ); assert( iter != m_infos.end() );
iter->second->SetOwner( 0 ); if ( drop ) {
delete iter->second;
m_infos.erase( iter );
} else {
iter->second->SetOwner( 0 );
}
print_claimed(); print_claimed();
pthread_cond_signal( &m_infos_condvar ); pthread_cond_signal( &m_infos_condvar );
logf( XW_LOGINFO, "%s(%d): DONE", __func__, cid ); logf( XW_LOGINFO, "%s(%d): DONE", __func__, cid );

View file

@ -23,6 +23,7 @@
#define _CIDLOCK_H_ #define _CIDLOCK_H_
#include <map> #include <map>
#include <set>
#include "xwrelay.h" #include "xwrelay.h"
#include "cref.h" #include "cref.h"
@ -61,22 +62,24 @@ class CidLock {
} }
return s_instance; return s_instance;
} }
~CidLock();
CidInfo* Claim( void ) { return Claim(0); } CidInfo* Claim( void ) { return Claim(0); }
CidInfo* Claim( CookieID cid ); CidInfo* Claim( CookieID cid );
CidInfo* ClaimSocket( int sock ); CidInfo* ClaimSocket( int sock );
void Relinquish( CidInfo* claim ); void Relinquish( CidInfo* claim, bool drop );
void Associate( const CookieRef* cref, int socket ); bool Associate( const CookieRef* cref, int socket ); /* return true if new association */
void DisAssociate( const CookieRef* cref, int socket ); void DisAssociate( const CookieRef* cref, int socket );
private: private:
CidLock(); CidLock();
~CidLock();
void print_claimed(); void print_claimed();
bool Associate_locked( const CookieRef* cref, int socket );
static CidLock* s_instance; static CidLock* s_instance;
map< CookieID, CidInfo*> m_infos; set<int> m_sockets;
map< CookieID, CidInfo* > m_infos;
pthread_mutex_t m_infos_mutex; pthread_mutex_t m_infos_mutex;
pthread_cond_t m_infos_condvar; pthread_cond_t m_infos_condvar;
int m_nextCID; int m_nextCID;

View file

@ -47,30 +47,30 @@ using namespace std;
* SocketsIterator class * SocketsIterator class
*****************************************************************************/ *****************************************************************************/
SocketsIterator::SocketsIterator( SocketMap::iterator iter, /* SocketsIterator::SocketsIterator( SocketMap::iterator iter, */
SocketMap::iterator end, /* SocketMap::iterator end, */
pthread_mutex_t* mutex ) /* pthread_mutex_t* mutex ) */
: m_iter( iter ) /* : m_iter( iter ) */
, m_end( end ) /* , m_end( end ) */
, m_mutex( mutex ) /* , m_mutex( mutex ) */
{ /* { */
} /* } */
SocketsIterator::~SocketsIterator() /* SocketsIterator::~SocketsIterator() */
{ /* { */
pthread_mutex_unlock( m_mutex ); /* pthread_mutex_unlock( m_mutex ); */
} /* } */
int /* int */
SocketsIterator::Next() /* SocketsIterator::Next() */
{ /* { */
int socket = 0; /* int socket = 0; */
if ( m_iter != m_end ) { /* if ( m_iter != m_end ) { */
socket = m_iter->first; /* socket = m_iter->first; */
++m_iter; /* ++m_iter; */
} /* } */
return socket; /* return socket; */
} /* } */
/***************************************************************************** /*****************************************************************************
* CookieRef class * CookieRef class
@ -209,20 +209,28 @@ CookieRef::_Connect( int socket, int nPlayersH, int nPlayersS, int seed,
return connected; return connected;
} }
void bool
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersS, CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersS,
int seed, bool gameDead ) int seed, bool gameDead )
{ {
if ( AlreadyHere( hid, seed, socket ) ) { bool spotTaken = false;
logf( XW_LOGINFO, "dropping reconnection because already here" ); bool alreadyHere = AlreadyHere( hid, seed, socket, &spotTaken );
if ( spotTaken ) {
logf( XW_LOGINFO, "%s: failing because spot taken", __func__ );
} else { } else {
(void)CRefMgr::Get()->Associate( socket, this ); if ( alreadyHere ) {
pushReconnectEvent( socket, hid, nPlayersH, nPlayersS, seed ); logf( XW_LOGINFO, "%s: dropping because already here",
__func__ );
} else {
(void)CRefMgr::Get()->Associate( socket, this );
pushReconnectEvent( socket, hid, nPlayersH, nPlayersS, seed );
}
if ( gameDead ) {
pushGameDead( socket );
}
handleEvents();
} }
if ( gameDead ) { return !spotTaken;
pushGameDead( socket );
}
handleEvents();
} }
void void
@ -326,7 +334,8 @@ CookieRef::AlreadyHere( unsigned short seed, int socket, HostID* prevHostID )
} }
bool bool
CookieRef::AlreadyHere( HostID hid, unsigned short seed, int socket ) CookieRef::AlreadyHere( HostID hid, unsigned short seed, int socket,
bool* spotTaken )
{ {
logf( XW_LOGINFO, "%s(hid=%d,seed=%x,socket=%d)", __func__, logf( XW_LOGINFO, "%s(hid=%d,seed=%x,socket=%d)", __func__,
hid, seed, socket ); hid, seed, socket );
@ -335,8 +344,9 @@ CookieRef::AlreadyHere( HostID hid, unsigned short seed, int socket )
vector<HostRec>::iterator iter; vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_hostID == hid ) { if ( iter->m_hostID == hid ) {
assert( seed == iter->m_seed ); if ( seed != iter->m_seed ) {
if ( socket == iter->m_socket ) { *spotTaken = true;
} else if ( socket == iter->m_socket ) {
here = true; /* dup packet */ here = true; /* dup packet */
} else { } else {
logf( XW_LOGINFO, "%s: hids match; nuking existing record" logf( XW_LOGINFO, "%s: hids match; nuking existing record"
@ -386,6 +396,7 @@ CookieRef::removeSocket( int socket )
iter->m_hostID ); iter->m_hostID );
DBMgr::Get()->RmDeviceByHid( ConnName(), iter->m_hostID ); DBMgr::Get()->RmDeviceByHid( ConnName(), iter->m_hostID );
m_nPlayersHere -= iter->m_nPlayersH; m_nPlayersHere -= iter->m_nPlayersH;
cancelAckTimer( iter->m_hostID );
} }
m_sockets.erase(iter); m_sockets.erase(iter);
--count; --count;
@ -918,7 +929,7 @@ void
CookieRef::setAckTimer( HostID hid ) CookieRef::setAckTimer( HostID hid )
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
logf( XW_LOGINFO, "%s(%d)", __func__, hid ); logf( XW_LOGINFO, "%s(hid=%d)", __func__, hid );
assert( hid >= HOST_ID_SERVER ); assert( hid >= HOST_ID_SERVER );
assert( hid <= 4 ); assert( hid <= 4 );
@ -940,12 +951,11 @@ void
CookieRef::cancelAckTimer( HostID hid ) CookieRef::cancelAckTimer( HostID hid )
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
logf( XW_LOGINFO, "%s(%d)", __func__, hid ); logf( XW_LOGINFO, "%s(hid=%d)", __func__, hid );
assert( hid >= HOST_ID_SERVER ); assert( hid >= HOST_ID_SERVER );
assert( hid <= 4 ); assert( hid <= 4 );
--hid; m_timers[hid-1].m_this = NULL;
m_timers[hid].m_this = NULL;
// TimerMgr::GetTimerMgr()->ClearTimer( s_checkAck, this ); // TimerMgr::GetTimerMgr()->ClearTimer( s_checkAck, this );
} }
@ -1088,19 +1098,19 @@ CookieRef::notifyGameDead( int socket )
send_with_length( socket, buf, sizeof(buf), true ); send_with_length( socket, buf, sizeof(buf), true );
} }
void /* void */
CookieRef::moveSockets( void ) /* CookieRef::moveSockets( void ) */
{ /* { */
ASSERT_LOCKED(); /* ASSERT_LOCKED(); */
vector<int> sockets; /* vector<int> sockets; */
vector<HostRec>::iterator iter; /* vector<HostRec>::iterator iter; */
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { /* for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { */
sockets.push_back( iter->m_socket ); /* sockets.push_back( iter->m_socket ); */
} /* } */
CRefMgr::Get()->MoveSockets( sockets, this ); /* CRefMgr::Get()->MoveSockets( sockets, this ); */
} /* } */
void void
CookieRef::sendAllHere( bool initial ) CookieRef::sendAllHere( bool initial )
@ -1326,9 +1336,9 @@ CookieRef::printSeeds( const char* caller )
char buf[64] = {0}; char buf[64] = {0};
vector<HostRec>::iterator iter; vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
len += snprintf( &buf[len], sizeof(buf)-len, "%.4x/%d/%c ", len += snprintf( &buf[len], sizeof(buf)-len, "[%d]%.4x(%d)/%d/%c ",
iter->m_seed, iter->m_socket, iter->m_hostID, iter->m_seed, iter->m_seed,
iter->m_ackPending?'a':'A' ); iter->m_socket, iter->m_ackPending?'a':'A' );
} }
logf( XW_LOGINFO, "seeds/sockets/ack'd after %s(): %s", caller, buf ); logf( XW_LOGINFO, "seeds/sockets/ack'd after %s(): %s", caller, buf );
} }

View file

@ -103,7 +103,7 @@ class CookieRef {
/* connect case */ /* connect case */
bool AlreadyHere( unsigned short seed, int socket, HostID* prevHostID ); bool AlreadyHere( unsigned short seed, int socket, HostID* prevHostID );
/* reconnect case */ /* reconnect case */
bool AlreadyHere( HostID hid, unsigned short seed, int socket ); bool AlreadyHere( HostID hid, unsigned short seed, int socket, bool* spotTaken );
/* for console */ /* for console */
void _PrintCookieInfo( string& out ); void _PrintCookieInfo( string& out );
@ -118,7 +118,7 @@ class CookieRef {
bool _Connect( int socket, int nPlayersH, int nPlayersS, int seed, bool _Connect( int socket, int nPlayersH, int nPlayersS, int seed,
bool seenSeed ); bool seenSeed );
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS, bool _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed, bool gameDead ); int seed, bool gameDead );
void _HandleAck( HostID hostID ); void _HandleAck( HostID hostID );
void _Disconnect(int socket, HostID hostID ); void _Disconnect(int socket, HostID hostID );

View file

@ -59,7 +59,7 @@ CRefMgr::CRefMgr()
, m_startTime(time(NULL)) , m_startTime(time(NULL))
{ {
/* should be using pthread_once() here */ /* should be using pthread_once() here */
pthread_mutex_init( &m_SocketStuffMutex, NULL ); /* pthread_mutex_init( &m_SocketStuffMutex, NULL ); */
pthread_mutex_init( &m_roomsFilledMutex, NULL ); pthread_mutex_init( &m_roomsFilledMutex, NULL );
pthread_mutex_init( &m_freeList_mutex, NULL ); pthread_mutex_init( &m_freeList_mutex, NULL );
pthread_rwlock_init( &m_cookieMapRWLock, NULL ); pthread_rwlock_init( &m_cookieMapRWLock, NULL );
@ -72,15 +72,16 @@ CRefMgr::~CRefMgr()
assert( this == s_instance ); assert( this == s_instance );
delete m_db; delete m_db;
delete m_cidlock;
pthread_mutex_destroy( &m_freeList_mutex ); pthread_mutex_destroy( &m_freeList_mutex );
pthread_rwlock_destroy( &m_cookieMapRWLock ); pthread_rwlock_destroy( &m_cookieMapRWLock );
SocketMap::iterator iter; /* SocketMap::iterator iter; */
for ( iter = m_SocketStuff.begin(); iter != m_SocketStuff.end(); ++iter ) { /* for ( iter = m_SocketStuff.begin(); iter != m_SocketStuff.end(); ++iter ) { */
SocketStuff* stuff = iter->second; /* SocketStuff* stuff = iter->second; */
delete stuff; /* delete stuff; */
} /* } */
s_instance = NULL; s_instance = NULL;
} }
@ -235,9 +236,6 @@ CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
bool makePublic, bool* seenSeed ) bool makePublic, bool* seenSeed )
{ {
CidInfo* cinfo; CidInfo* cinfo;
CookieID cid;
char connNameBuf[MAX_CONNNAME_LEN+1] = {0};
int alreadyHere = 0;
/* We have a cookie from a new connection or from a reconnect. This may /* We have a cookie from a new connection or from a reconnect. This may
be the first time it's been seen, or there may be a game currently in be the first time it's been seen, or there may be a game currently in
@ -246,32 +244,54 @@ CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
a new one. Pass the connName which will be used if set, but if not set a new one. Pass the connName which will be used if set, but if not set
we'll be generating another later when the game is complete. we'll be generating another later when the game is complete.
*/ */
for ( ; ; ) {
/* What's this for loop thing. It's to fix a race condition. One
thread has "claim" on cid <N>, which is in the DB. Another comes
into this function and looks it up in the DB, retrieving <N>, but
progress is blocked inside getCookieRef_impl which calls Claim().
The first thread winds up removing <N> from the DB and deleting its
cref before calling Relinquish so that when Claim() returns there's
no cref. So we test for that case and retry. */
*seenSeed = m_db->SeenSeed( cookie, seed, langCode, nPlayersT,
wantsPublic, connNameBuf,
sizeof(connNameBuf), &alreadyHere, &cid );
if ( !*seenSeed ) {
cid = m_db->FindOpen( cookie, langCode, nPlayersT, nPlayersH,
wantsPublic, connNameBuf, sizeof(connNameBuf),
&alreadyHere );
}
if ( cid > 0 ) { CookieID cid;
cinfo = getCookieRef_impl( cid ); char connNameBuf[MAX_CONNNAME_LEN+1] = {0};
} else { int alreadyHere = 0;
cinfo = m_cidlock->Claim();
cid = cinfo->GetCid(); *seenSeed = m_db->SeenSeed( cookie, seed, langCode, nPlayersT,
CookieRef* cref = AddNew( cookie, connNameBuf, cid, langCode, wantsPublic, connNameBuf,
nPlayersT, alreadyHere ); sizeof(connNameBuf), &alreadyHere, &cid );
cinfo->SetRef( cref ); if ( !*seenSeed ) {
if ( !connNameBuf[0] ) { /* didn't exist in DB */ cid = m_db->FindOpen( cookie, langCode, nPlayersT, nPlayersH,
m_db->AddNew( cookie, cref->ConnName(), cid, langCode, nPlayersT, wantsPublic, connNameBuf, sizeof(connNameBuf),
wantsPublic || makePublic ); &alreadyHere );
} else {
m_db->AddCID( connNameBuf, cid );
} }
}
if ( cid > 0 ) {
cinfo = m_cidlock->Claim( cid );
if ( NULL == cinfo->GetRef() ) {
m_cidlock->Relinquish( cinfo, true );
continue;
}
} else {
cinfo = m_cidlock->Claim();
cid = cinfo->GetCid();
CookieRef* cref = AddNew( cookie, connNameBuf, cid, langCode,
nPlayersT, alreadyHere );
cinfo->SetRef( cref );
if ( !connNameBuf[0] ) { /* didn't exist in DB */
m_db->AddNew( cookie, cref->ConnName(), cid, langCode, nPlayersT,
wantsPublic || makePublic );
} else {
if ( !m_db->AddCID( connNameBuf, cid ) ) {
m_cidlock->Relinquish( cinfo, true );
continue;
}
}
}
break;
}
assert( cinfo->GetRef() );
return cinfo; return cinfo;
} /* getMakeCookieRef */ } /* getMakeCookieRef */
@ -285,37 +305,48 @@ CRefMgr::getMakeCookieRef( const char* connName, const char* cookie,
CookieRef* cref = NULL; CookieRef* cref = NULL;
CidInfo* cinfo; CidInfo* cinfo;
/* fetch these from DB */ for ( ; ; ) { /* for: see comment above */
char curCookie[MAX_INVITE_LEN+1]; /* fetch these from DB */
int curLangCode; char curCookie[MAX_INVITE_LEN+1];
int nPlayersT = 0; int curLangCode;
int nAlreadyHere = 0; int nPlayersT = 0;
int nAlreadyHere = 0;
CookieID cid = m_db->FindGame( connName, curCookie, sizeof(curCookie), CookieID cid = m_db->FindGame( connName, curCookie, sizeof(curCookie),
&curLangCode, &nPlayersT, &nAlreadyHere, &curLangCode, &nPlayersT, &nAlreadyHere,
isDead ); isDead );
if ( 0 != cid ) { /* already open */ if ( 0 != cid ) { /* already open */
cinfo = getCookieRef_impl( cid ); cinfo = m_cidlock->Claim( cid );
} else { if ( NULL == cinfo->GetRef() ) {
CookieID cid; m_cidlock->Relinquish( cinfo, true );
/* The entry may not even be in the DB, e.g. if it got deleted. continue;
Deal with that possibility by taking the caller's word for it. */ }
cinfo = m_cidlock->Claim();
cid = cinfo->GetCid();
if ( nPlayersT == 0 ) { /* wasn't in the DB */
m_db->AddNew( cookie, connName, cid, langCode, nPlayersS, isPublic );
curLangCode = langCode;
nPlayersT = nPlayersS;
} else { } else {
cookie = curCookie; CookieID cid;
} /* The entry may not even be in the DB, e.g. if it got deleted.
Deal with that possibility by taking the caller's word for it. */
cinfo = m_cidlock->Claim();
cid = cinfo->GetCid();
cref = AddNew( cookie, connName, cid, curLangCode, nPlayersT, if ( nPlayersT == 0 ) { /* wasn't in the DB */
nAlreadyHere ); m_db->AddNew( cookie, connName, cid, langCode, nPlayersS, isPublic );
cinfo->SetRef( cref ); curLangCode = langCode;
m_db->AddCID( connName, cid ); nPlayersT = nPlayersS;
} } else {
if ( !m_db->AddCID( connName, cid ) ) {
m_cidlock->Relinquish( cinfo, true );
continue;
}
cookie = curCookie;
}
cref = AddNew( cookie, connName, cid, curLangCode, nPlayersT,
nAlreadyHere );
cinfo->SetRef( cref );
}
break;
} /* for */
assert( cinfo->GetRef() );
return cinfo; return cinfo;
} /* getMakeCookieRef */ } /* getMakeCookieRef */
@ -329,86 +360,97 @@ CRefMgr::getMakeCookieRef( const char* const connName, bool* isDead )
int nPlayersT = 0; int nPlayersT = 0;
int nAlreadyHere = 0; int nAlreadyHere = 0;
CookieID cid = m_db->FindGame( connName, curCookie, sizeof(curCookie), for ( ; ; ) { /* for: see comment above */
&curLangCode, &nPlayersT, &nAlreadyHere, CookieID cid = m_db->FindGame( connName, curCookie, sizeof(curCookie),
isDead ); &curLangCode, &nPlayersT, &nAlreadyHere,
if ( 0 != cid ) { /* already open */ isDead );
cinfo = getCookieRef_impl( cid ); if ( 0 != cid ) { /* already open */
} else { cinfo = m_cidlock->Claim( cid );
if ( nPlayersT == 0 ) { /* wasn't in the DB */ if ( NULL == cinfo->GetRef() ) {
/* do nothing; insufficient info to fake it */ m_cidlock->Relinquish( cinfo, true );
continue;
}
} else { } else {
cinfo = m_cidlock->Claim(); if ( nPlayersT == 0 ) { /* wasn't in the DB */
cref = AddNew( curCookie, connName, cinfo->GetCid(), curLangCode, /* do nothing; insufficient info to fake it */
nPlayersT, nAlreadyHere ); } else {
cinfo->SetRef( cref ); cinfo = m_cidlock->Claim();
m_db->AddCID( connName, cinfo->GetCid() ); if ( !m_db->AddCID( connName, cinfo->GetCid() ) ) {
m_cidlock->Relinquish( cinfo, true );
continue;
}
cref = AddNew( curCookie, connName, cinfo->GetCid(), curLangCode,
nPlayersT, nAlreadyHere );
cinfo->SetRef( cref );
}
} }
break;
} }
assert( cinfo->GetRef() );
return cinfo; return cinfo;
} }
bool bool
CRefMgr::Associate( int socket, CookieRef* cref ) CRefMgr::Associate( int socket, CookieRef* cref )
{ {
m_cidlock->Associate( cref, socket ); return m_cidlock->Associate( cref, socket );
MutexLock ml( &m_SocketStuffMutex ); /* MutexLock ml( &m_SocketStuffMutex ); */
return Associate_locked( socket, cref ); /* return Associate_locked( socket, cref ); */
} }
bool /* bool */
CRefMgr::Associate_locked( int socket, CookieRef* cref ) /* CRefMgr::Associate_locked( int socket, CookieRef* cref ) */
{ /* { */
bool isNew = false; /* bool isNew = false; */
SocketMap::iterator iter = m_SocketStuff.find( socket ); /* SocketMap::iterator iter = m_SocketStuff.find( socket ); */
/* This isn't enough. Must provide a way to reuse sockets should a /* /\* This isn't enough. Must provide a way to reuse sockets should a */
genuinely different connection appear. Now maybe we already remove /* genuinely different connection appear. Now maybe we already remove */
this reference when a socket is closed. Test this! Or assert /* this reference when a socket is closed. Test this! Or assert */
something here. Bottom line: need to swallow repeated/duplicate /* something here. Bottom line: need to swallow repeated/duplicate */
connect messages from same host. */ /* connect messages from same host. *\/ */
if ( iter == m_SocketStuff.end() ) { /* if ( iter == m_SocketStuff.end() ) { */
SocketStuff* stuff = new SocketStuff( cref ); /* SocketStuff* stuff = new SocketStuff( cref ); */
m_SocketStuff.insert( pair< int, SocketStuff* >( socket, stuff ) ); /* m_SocketStuff.insert( pair< int, SocketStuff* >( socket, stuff ) ); */
isNew = true; /* isNew = true; */
} else { /* } else { */
logf( XW_LOGERROR, "Already have cref/threadID pair for socket %d; " /* logf( XW_LOGERROR, "Already have cref/threadID pair for socket %d; " */
"error???", socket ); /* "error???", socket ); */
} /* } */
return isNew; /* return isNew; */
} /* } */
void /* void */
CRefMgr::Disassociate_locked( int socket, CookieRef* cref ) /* CRefMgr::Disassociate_locked( int socket, CookieRef* cref ) */
{ /* { */
m_cidlock->DisAssociate( cref, socket ); /* SocketMap::iterator iter = m_SocketStuff.find( socket ); */
SocketMap::iterator iter = m_SocketStuff.find( socket ); /* if ( iter == m_SocketStuff.end() ) { */
if ( iter == m_SocketStuff.end() ) { /* logf( XW_LOGERROR, "can't find SocketStuff for socket %d", socket ); */
logf( XW_LOGERROR, "can't find SocketStuff for socket %d", socket ); /* } else { */
} else { /* SocketStuff* stuff = iter->second; */
SocketStuff* stuff = iter->second; /* assert( cref == NULL || stuff->m_cref == cref ); */
assert( cref == NULL || stuff->m_cref == cref ); /* delete stuff; */
delete stuff; /* m_SocketStuff.erase( iter ); */
m_SocketStuff.erase( iter ); /* } */
} /* } */
}
void void
CRefMgr::Disassociate( int socket, CookieRef* cref ) CRefMgr::Disassociate( int socket, CookieRef* cref )
{ {
MutexLock ml( &m_SocketStuffMutex ); m_cidlock->DisAssociate( cref, socket );
Disassociate_locked( socket, cref ); /* MutexLock ml( &m_SocketStuffMutex ); */
/* Disassociate_locked( socket, cref ); */
} }
void /* void */
CRefMgr::MoveSockets( vector<int> sockets, CookieRef* cref ) /* CRefMgr::MoveSockets( vector<int> sockets, CookieRef* cref ) */
{ /* { */
MutexLock ml( &m_SocketStuffMutex ); /* MutexLock ml( &m_SocketStuffMutex ); */
vector<int>::iterator iter; /* vector<int>::iterator iter; */
for ( iter = sockets.begin(); iter != sockets.end(); ++iter ) { /* for ( iter = sockets.begin(); iter != sockets.end(); ++iter ) { */
Disassociate_locked( *iter, NULL ); /* Disassociate_locked( *iter, NULL ); */
Associate_locked( *iter, cref ); /* Associate_locked( *iter, cref ); */
} /* } */
} /* } */
#if 0 #if 0
pthread_mutex_t* pthread_mutex_t*
@ -457,19 +499,20 @@ CRefMgr::PrintSocketInfo( int socket, string& out )
} }
} }
/* static */ SocketsIterator /* /\* static *\/ SocketsIterator */
CRefMgr::MakeSocketsIterator() /* CRefMgr::MakeSocketsIterator() */
{ /* { */
pthread_mutex_lock( &m_SocketStuffMutex ); /* assert( 0 ); /\* called? *\/ */
SocketsIterator iter( m_SocketStuff.begin(), m_SocketStuff.end(), /* pthread_mutex_lock( &m_SocketStuffMutex ); */
&m_SocketStuffMutex ); /* SocketsIterator iter( m_SocketStuff.begin(), m_SocketStuff.end(), */
return iter; /* &m_SocketStuffMutex ); */
} /* return iter; */
/* } */
CidInfo* CidInfo*
CRefMgr::getCookieRef( CookieID cookieID ) CRefMgr::getCookieRef( CookieID cid )
{ {
return getCookieRef_impl( cookieID ); return m_cidlock->Claim( cid );
} /* getCookieRef */ } /* getCookieRef */
CidInfo* CidInfo*
@ -485,6 +528,7 @@ CRefMgr::getCookieRef( int socket )
/* } */ /* } */
/* } */ /* } */
assert( NULL == cinfo || NULL != cinfo->GetRef() );
return cinfo; return cinfo;
} /* getCookieRef */ } /* getCookieRef */
@ -498,7 +542,7 @@ CRefMgr::heartbeatProc( void* closure )
#endif #endif
CookieRef* CookieRef*
CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id, CRefMgr::AddNew( const char* cookie, const char* connName, CookieID cid,
int langCode, int nPlayers, int nAlreadyHere ) int langCode, int nPlayers, int nAlreadyHere )
{ {
if ( 0 == connName[0] ) { if ( 0 == connName[0] ) {
@ -506,17 +550,17 @@ CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id,
} }
/* PENDING: should this return a locked cref? */ /* PENDING: should this return a locked cref? */
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, cid=%d)", __func__, logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, cid=%d)", __func__,
cookie, connName, id ); cookie, connName, cid );
CookieRef* ref = getFromFreeList(); CookieRef* ref = getFromFreeList();
RWWriteLock rwl( &m_cookieMapRWLock ); RWWriteLock rwl( &m_cookieMapRWLock );
logf( XW_LOGINFO, "making new cref: %d", id ); logf( XW_LOGINFO, "making new cref: %d", cid );
if ( !!ref ) { if ( !!ref ) {
ref->ReInit( cookie, connName, id, langCode, nPlayers, nAlreadyHere ); ref->ReInit( cookie, connName, cid, langCode, nPlayers, nAlreadyHere );
} else { } else {
ref = new CookieRef( cookie, connName, id, langCode, nPlayers, ref = new CookieRef( cookie, connName, cid, langCode, nPlayers,
nAlreadyHere ); nAlreadyHere );
} }
@ -551,6 +595,8 @@ CRefMgr::Recycle_locked( CookieRef* cref )
cref->Unlock(); cref->Unlock();
sleep(2);
/* don't grab this lock until after releasing cref's lock; otherwise /* don't grab this lock until after releasing cref's lock; otherwise
deadlock happens. */ deadlock happens. */
RWWriteLock rwl( &m_cookieMapRWLock ); RWWriteLock rwl( &m_cookieMapRWLock );
@ -592,25 +638,25 @@ CRefMgr::Recycle( const char* connName )
Recycle( id ); Recycle( id );
} /* Delete */ } /* Delete */
CidInfo* /* CidInfo* */
CRefMgr::getCookieRef_impl( CookieID cid ) /* CRefMgr::getCookieRef_impl( CookieID cid ) */
{ /* { */
CidInfo* info = m_cidlock->Claim( cid ); /* CidInfo* info = m_cidlock->Claim( cid ); */
/* CookieRef* ref = NULL; */ /* /\* CookieRef* ref = NULL; *\/ */
/* RWReadLock rwl( &m_cookieMapRWLock ); */ /* /\* RWReadLock rwl( &m_cookieMapRWLock ); *\/ */
/* CookieMap::iterator iter = m_cookieMap.find( cid ); */ /* /\* CookieMap::iterator iter = m_cookieMap.find( cid ); *\/ */
/* while ( iter != m_cookieMap.end() ) { */ /* /\* while ( iter != m_cookieMap.end() ) { *\/ */
/* CookieRef* second = iter->second; */ /* /\* CookieRef* second = iter->second; *\/ */
/* if ( second->GetCookieID() == cid ) { */ /* /\* if ( second->GetCookieID() == cid ) { *\/ */
/* ref = second; */ /* /\* ref = second; *\/ */
/* break; */ /* /\* break; *\/ */
/* } */ /* /\* } *\/ */
/* ++iter; */ /* /\* ++iter; *\/ */
/* } */ /* /\* } *\/ */
/* info->SetRef( ref ); */ /* /\* info->SetRef( ref ); *\/ */
return info; /* return info; */
} /* } */
#ifdef RELAY_HEARTBEAT #ifdef RELAY_HEARTBEAT
void void
@ -776,14 +822,16 @@ SafeCref::SafeCref( int socket )
SafeCref::~SafeCref() SafeCref::~SafeCref()
{ {
if ( m_cinfo != NULL ) { if ( m_cinfo != NULL ) {
bool recycle = false;
if ( m_locked ) { if ( m_locked ) {
CookieRef* cref = m_cinfo->GetRef(); CookieRef* cref = m_cinfo->GetRef();
if ( cref->ShouldDie() ) { recycle = cref->ShouldDie();
if ( recycle ) {
m_mgr->Recycle_locked( cref ); m_mgr->Recycle_locked( cref );
} else { } else {
cref->Unlock(); cref->Unlock();
} }
} }
m_mgr->m_cidlock->Relinquish( m_cinfo ); m_mgr->m_cidlock->Relinquish( m_cinfo, recycle );
} }
} }

View file

@ -31,20 +31,6 @@
typedef map<CookieID,CookieRef*> CookieMap; typedef map<CookieID,CookieRef*> CookieMap;
class CookieMapIterator; class CookieMapIterator;
class SocketStuff;
typedef map< int, SocketStuff* > SocketMap;
class SocketsIterator {
public:
SocketsIterator( SocketMap::iterator iter, SocketMap::iterator end,
pthread_mutex_t* mutex );
~SocketsIterator();
int Next();
private:
SocketMap::iterator m_iter;
SocketMap::iterator m_end;
pthread_mutex_t* m_mutex; /* locked */
};
class CrefInfo { class CrefInfo {
public: public:
@ -97,8 +83,8 @@ class CRefMgr {
CookieID CookieIdForName( const char* name ); CookieID CookieIdForName( const char* name );
/* For use from ctrl only!!!! */ /* For use from ctrl only!!!! */
void LockAll() { pthread_rwlock_wrlock( &m_cookieMapRWLock ); } /* void LockAll() { pthread_rwlock_wrlock( &m_cookieMapRWLock ); } */
void UnlockAll() { pthread_rwlock_unlock( &m_cookieMapRWLock ); } /* void UnlockAll() { pthread_rwlock_unlock( &m_cookieMapRWLock ); } */
/* Track sockets independent of cookie refs */ /* Track sockets independent of cookie refs */
bool Associate( int socket, CookieRef* cref ); bool Associate( int socket, CookieRef* cref );
@ -109,7 +95,7 @@ class CRefMgr {
pthread_mutex_t* GetWriteMutexForSocket( int socket ); pthread_mutex_t* GetWriteMutexForSocket( int socket );
void RemoveSocketRefs( int socket ); void RemoveSocketRefs( int socket );
void PrintSocketInfo( int socket, string& out ); void PrintSocketInfo( int socket, string& out );
SocketsIterator MakeSocketsIterator(); /* SocketsIterator MakeSocketsIterator(); */
void IncrementFullCount( void ); void IncrementFullCount( void );
int GetNumRoomsFilled( void ); int GetNumRoomsFilled( void );
@ -176,9 +162,6 @@ class CRefMgr {
pthread_rwlock_t m_cookieMapRWLock; pthread_rwlock_t m_cookieMapRWLock;
CookieMap m_cookieMap; CookieMap m_cookieMap;
pthread_mutex_t m_SocketStuffMutex;
SocketMap m_SocketStuff;
time_t m_startTime; time_t m_startTime;
string m_ports; string m_ports;
@ -235,9 +218,8 @@ class SafeCref {
if ( IsValid() ) { if ( IsValid() ) {
CookieRef* cref = m_cinfo->GetRef(); CookieRef* cref = m_cinfo->GetRef();
assert( 0 != cref->GetCookieID() ); assert( 0 != cref->GetCookieID() );
cref->_Reconnect( socket, srcID, nPlayersH, nPlayersS, return cref->_Reconnect( socket, srcID, nPlayersH, nPlayersS,
seed, m_dead ); seed, m_dead );
return true;
} else { } else {
return false; return false;
} }

View file

@ -341,16 +341,18 @@ DBMgr::HaveDevice( const char* connName, HostID hid, int seed )
return found; return found;
} }
void bool
DBMgr::AddCID( const char* const connName, CookieID cid ) DBMgr::AddCID( const char* const connName, CookieID cid )
{ {
const char* fmt = "UPDATE " GAMES_TABLE " SET cid = %d " const char* fmt = "UPDATE " GAMES_TABLE " SET cid = %d "
" WHERE connName = '%s'"; " WHERE connName = '%s' AND cid IS NULL";
char query[256]; char query[256];
snprintf( query, sizeof(query), fmt, cid, connName ); snprintf( query, sizeof(query), fmt, cid, connName );
logf( XW_LOGINFO, "%s: query: %s", __func__, query ); logf( XW_LOGINFO, "%s: query: %s", __func__, query );
execSql( query ); bool result = execSql( query );
logf( XW_LOGINFO, "%s(cid=%d)=>%d", __func__, cid, result );
return result;
} }
void void

View file

@ -60,7 +60,7 @@ class DBMgr {
bool RmDeviceByHid( const char* const connName, HostID id ); bool RmDeviceByHid( const char* const connName, HostID id );
void RmDeviceBySeed( const char* const connName, unsigned short seed ); void RmDeviceBySeed( const char* const connName, unsigned short seed );
bool HaveDevice( const char* const connName, HostID id, int seed ); bool HaveDevice( const char* const connName, HostID id, int seed );
void AddCID( const char* const connName, CookieID cid ); bool AddCID( const char* const connName, CookieID cid );
void ClearCID( const char* connName ); void ClearCID( const char* connName );
void RecordSent( const char* const connName, HostID hid, int nBytes ); void RecordSent( const char* const connName, HostID hid, int nBytes );
void GetPlayerCounts( const char* const connName, int* nTotal, void GetPlayerCounts( const char* const connName, int* nTotal,

View file

@ -95,9 +95,8 @@ static StateTable g_stateTable[] = {
/* { XWS_CHK_ALLHERE, XWE_SOMEMISSING, XWA_NONE, XWS_WAITMORE }, */ /* { XWS_CHK_ALLHERE, XWE_SOMEMISSING, XWA_NONE, XWS_WAITMORE }, */
/* { XWS_ALLCONND, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING }, */ { XWS_ALLCONND, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITMORE },
/* { XWS_WAITMORE, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITMORE }, */ { XWS_WAITMORE, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITMORE },
/* { XWS_MISSING, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING }, */
/* EMPTY means have messages to send but no connections. Time out and free /* EMPTY means have messages to send but no connections. Time out and free
memory after a while. BUT: don't I really want to keep these forever and memory after a while. BUT: don't I really want to keep these forever and

View file

@ -368,9 +368,7 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
unsigned char flags = *bufp++; unsigned char flags = *bufp++;
XWREASON err = flagsOK( flags ); XWREASON err = flagsOK( flags );
if ( err != XWRELAY_ERROR_NONE ) { if ( err == XWRELAY_ERROR_NONE ) {
denyConnection( socket, err );
} else {
char cookie[MAX_INVITE_LEN+1]; char cookie[MAX_INVITE_LEN+1];
char connName[MAX_CONNNAME_LEN+1] = {0}; char connName[MAX_CONNNAME_LEN+1] = {0};
HostID srcID; HostID srcID;
@ -396,12 +394,18 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
wantsPublic, makePublic ); wantsPublic, makePublic );
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT, success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT,
gameSeed ); gameSeed );
} if ( !success ) {
err = XWRELAY_ERROR_NORECONN;
if ( !success ) { }
denyConnection( socket, XWRELAY_ERROR_BADPROTO ); } else {
err = XWRELAY_ERROR_BADPROTO;
} }
} }
if ( err != XWRELAY_ERROR_NONE ) {
denyConnection( socket, err );
}
return success; return success;
} /* processReconnect */ } /* processReconnect */
@ -626,7 +630,7 @@ shutdown()
delete tPool; delete tPool;
stop_ctrl_threads(); //stop_ctrl_threads();
g_listeners.RemoveAll(); g_listeners.RemoveAll();
close( g_control ); close( g_control );
@ -1180,7 +1184,8 @@ main( int argc, char** argv )
} }
} }
if ( FD_ISSET( g_control, &rfds ) ) { if ( FD_ISSET( g_control, &rfds ) ) {
run_ctrl_thread( g_control ); assert(0); // not working; don't use until fixed
// run_ctrl_thread( g_control );
--retval; --retval;
} }
#ifdef DO_HTTP #ifdef DO_HTTP

View file

@ -140,6 +140,7 @@ enum {
,XWRELAY_ERROR_DUP_ROOM ,XWRELAY_ERROR_DUP_ROOM
,XWRELAY_ERROR_TOO_MANY ,XWRELAY_ERROR_TOO_MANY
,XWRELAY_ERROR_DELETED ,XWRELAY_ERROR_DELETED
,XWRELAY_ERROR_NORECONN /* you can't reconnect; reset and try CONNECTING again */
,XWRELAY_ERROR_LASTERR ,XWRELAY_ERROR_LASTERR
} }
#ifndef CANT_DO_TYPEDEF #ifndef CANT_DO_TYPEDEF