xwords/xwords4/relay/cref.cpp

273 lines
6.8 KiB
C++
Raw Normal View History

/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
2005-03-25 03:59:44 +01:00
/*
* Copyright 2005 by Eric House (fixin@peak.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 <string>
#include <map>
#include <assert.h>
2005-03-25 03:59:44 +01:00
#include <pthread.h>
#include "cref.h"
#include "xwrelay.h"
2005-03-25 03:59:44 +01:00
#include "mlock.h"
using namespace std;
static CookieMap gCookieMap;
pthread_rwlock_t gCookieMapRWLock = PTHREAD_RWLOCK_INITIALIZER;
2005-03-25 03:59:44 +01:00
CookieID CookieRef::ms_nextConnectionID = 1000;
/* static */ CookieRef*
CookieRef::AddNew( string s )
{
RWWriteLock rwl( &gCookieMapRWLock );
CookieRef* ref = new CookieRef( s );
gCookieMap.insert( pair<CookieID, CookieRef*>(ref->GetConnID(), ref ) );
logf( "paired cookie %s with id %d", s.c_str(), ref->GetConnID() );
return ref;
}
CookieRef*
get_make_cookieRef( char* cookie, CookieID connID ) /* connID ignored for now */
{
CookieRef* ref = NULL;
string s(cookie);
{
RWReadLock rwl( &gCookieMapRWLock );
CookieMap::iterator iter = gCookieMap.begin();
while ( iter != gCookieMap.end() ) {
ref = iter->second;
if ( ref->Name() == s ) {
ref = iter->second;
break;
}
++iter;
2005-03-25 03:59:44 +01:00
}
}
if ( !ref ) {
ref = CookieRef::AddNew(s);
}
return ref;
}
CookieRef*
2005-03-25 03:59:44 +01:00
get_cookieRef( CookieID cookieID )
{
2005-03-25 03:59:44 +01:00
CookieRef* ref = NULL;
RWReadLock rwl( &gCookieMapRWLock );
2005-03-25 03:59:44 +01:00
CookieMap::iterator iter = gCookieMap.find( cookieID);
while ( iter != gCookieMap.end() ) {
2005-03-25 03:59:44 +01:00
CookieRef* sec = iter->second;
if ( sec->GetConnID() == cookieID ) {
ref = sec;
break;
}
++iter;
}
2005-03-25 03:59:44 +01:00
return ref;
} /* get_cookieRef */
static void
ForgetCref( CookieRef* cref )
{
RWWriteLock ml( &gCookieMapRWLock );
2005-03-25 03:59:44 +01:00
CookieMap::iterator iter = gCookieMap.begin();
while ( iter != gCookieMap.end() ) {
CookieRef* ref = iter->second;
if ( ref == cref ) {
logf( "erasing cref" );
gCookieMap.erase( iter );
break;
}
++iter;
}
assert( iter != gCookieMap.end() ); /* didn't find it */
}
2005-03-25 03:59:44 +01:00
class SocketStuff {
public:
SocketStuff( pthread_t id, CookieRef* cref )
: m_threadID(id),
m_cref(cref)
{
pthread_mutex_init( &m_writeMutex, NULL );
}
~SocketStuff() { pthread_mutex_destroy( &m_writeMutex ); }
pthread_t m_threadID;
CookieRef* m_cref;
pthread_mutex_t m_writeMutex; /* so only one thread writes at a time */
};
typedef map< int, SocketStuff* > SocketMap;
static SocketMap gSocketStuff;
2005-03-25 03:59:44 +01:00
static pthread_mutex_t gSocketStuffMutex = PTHREAD_MUTEX_INITIALIZER;
void
Associate( int socket, CookieRef* cref )
{
2005-03-25 03:59:44 +01:00
pthread_mutex_lock( &gSocketStuffMutex );
SocketMap::iterator iter = gSocketStuff.find( socket );
if ( iter == gSocketStuff.end() ) {
logf( "replacing existing cref/threadID pair for socket %d", socket );
}
pthread_t self = pthread_self();
2005-03-25 03:59:44 +01:00
SocketStuff* stuff = new SocketStuff( self, cref );
gSocketStuff.insert( pair< int, SocketStuff* >( socket, stuff ) );
pthread_mutex_unlock( &gSocketStuffMutex );
} /* Associate */
static CookieRef*
getCookieRefForSocket( int socket )
{
2005-03-25 03:59:44 +01:00
MutexLock ml( &gSocketStuffMutex );
SocketMap::iterator iter = gSocketStuff.find( socket );
if ( iter != gSocketStuff.end() ) {
2005-03-25 03:59:44 +01:00
SocketStuff* stuff = iter->second;
return stuff->m_cref;
}
return NULL;
}
pthread_mutex_t*
GetWriteMutexForSocket( int socket )
{
MutexLock ml( &gSocketStuffMutex );
SocketMap::iterator iter = gSocketStuff.find( socket );
if ( iter != gSocketStuff.end() ) {
SocketStuff* stuff = iter->second;
return &stuff->m_writeMutex;
}
2005-03-25 03:59:44 +01:00
assert( 0 );
}
void
RemoveSocketRefs( int socket )
{
CookieRef* cref = getCookieRefForSocket( socket );
if ( cref != NULL ) {
2005-03-25 03:59:44 +01:00
MutexLock ml( &gSocketStuffMutex );
SocketMap::iterator iter = gSocketStuff.find( socket );
assert( iter != gSocketStuff.end() );
2005-03-25 03:59:44 +01:00
delete iter->second;
gSocketStuff.erase( iter );
2005-03-25 03:59:44 +01:00
cref->Remove( socket );
} else {
logf( "socket already dead" );
}
}
/*****************************************************************************
* CookieRef class
*****************************************************************************/
2005-03-25 03:59:44 +01:00
CookieRef::CookieRef(string s)
: m_name(s)
{
2005-03-25 03:59:44 +01:00
pthread_mutex_init( &m_mutex, NULL );
m_connectionID = ms_nextConnectionID++; /* needs a mutex!!! */
}
CookieRef::~CookieRef()
{
2005-03-25 03:59:44 +01:00
pthread_mutex_destroy( &m_mutex );
logf( "CookieRef for %d being deleted", m_connectionID );
}
void
CookieRef::Associate( int socket, HostID srcID )
{
assert( srcID != HOST_ID_NONE );
logf( "remembering pair: hostid=%x, socket=%d", srcID, socket );
m_hostSockets.insert( pair<HostID,int>(srcID,socket) );
}
int
CookieRef::SocketForHost( HostID dest )
{
int socket;
map<HostID,int>::iterator iter = m_hostSockets.find( dest );
if ( iter == m_hostSockets.end() ) {
socket = -1;
} else {
socket = iter->second;
logf( "socketForHost(%x) => %d", dest, socket );
}
logf( "returning socket=%d for hostid=%x", socket, dest );
return socket;
}
void
CookieRef::Remove( int socket )
{
2005-03-25 03:59:44 +01:00
pthread_mutex_t mutexCopy = m_mutex; /* in case we call delete */
MutexLock ml( &mutexCopy );
int count = CountSockets();
map<HostID,int>::iterator iter = m_hostSockets.begin();
while ( iter != m_hostSockets.end() ) {
if ( iter->second == socket ) {
m_hostSockets.erase(iter);
2005-03-25 03:59:44 +01:00
--count;
break;
}
++iter;
}
2005-03-25 03:59:44 +01:00
if ( count == 0 ) {
ForgetCref( this );
delete this;
}
}
/* static */ CookieMapIterator
CookieRef::GetCookieNameIterator()
{
CookieMapIterator iter;
return iter;
}
CookieMapIterator:: CookieMapIterator()
: _iter( gCookieMap.begin() )
{
}
const char*
CookieMapIterator::Next()
{
const char* str = NULL;
if ( _iter != gCookieMap.end() ) {
2005-03-25 03:59:44 +01:00
CookieRef* cref = _iter->second;
str = cref->Name().c_str();
++_iter;
}
return str;
}