2005-03-19 23:14:27 +01:00
|
|
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
|
|
|
|
2005-03-25 03:59:44 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
#include <assert.h>
|
2005-03-25 03:59:44 +01:00
|
|
|
#include <pthread.h>
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
#include "cref.h"
|
|
|
|
#include "xwrelay.h"
|
2005-03-25 03:59:44 +01:00
|
|
|
#include "mlock.h"
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
static CookieMap gCookieMap;
|
2005-04-08 16:15:23 +02:00
|
|
|
pthread_rwlock_t gCookieMapRWLock = PTHREAD_RWLOCK_INITIALIZER;
|
2005-03-25 03:59:44 +01:00
|
|
|
|
|
|
|
CookieID CookieRef::ms_nextConnectionID = 1000;
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-04-08 16:15:23 +02:00
|
|
|
/* 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;
|
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
CookieRef*
|
2005-04-08 16:15:23 +02:00
|
|
|
get_make_cookieRef( char* cookie, CookieID connID ) /* connID ignored for now */
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-04-08 16:15:23 +02:00
|
|
|
CookieRef* ref = NULL;
|
2005-03-19 23:14:27 +01:00
|
|
|
string s(cookie);
|
2005-04-08 16:15:23 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-08 16:15:23 +02:00
|
|
|
if ( !ref ) {
|
|
|
|
ref = CookieRef::AddNew(s);
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
CookieRef*
|
2005-03-25 03:59:44 +01:00
|
|
|
get_cookieRef( CookieID cookieID )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-03-25 03:59:44 +01:00
|
|
|
CookieRef* ref = NULL;
|
2005-04-08 16:15:23 +02:00
|
|
|
RWReadLock rwl( &gCookieMapRWLock );
|
2005-03-25 03:59:44 +01:00
|
|
|
|
|
|
|
CookieMap::iterator iter = gCookieMap.find( cookieID);
|
2005-03-19 23:14:27 +01:00
|
|
|
while ( iter != gCookieMap.end() ) {
|
2005-03-25 03:59:44 +01:00
|
|
|
CookieRef* sec = iter->second;
|
|
|
|
if ( sec->GetConnID() == cookieID ) {
|
|
|
|
ref = sec;
|
|
|
|
break;
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
++iter;
|
|
|
|
}
|
2005-03-25 03:59:44 +01:00
|
|
|
return ref;
|
2005-03-19 23:14:27 +01:00
|
|
|
} /* get_cookieRef */
|
|
|
|
|
|
|
|
static void
|
|
|
|
ForgetCref( CookieRef* cref )
|
|
|
|
{
|
2005-04-08 16:15:23 +02:00
|
|
|
RWWriteLock ml( &gCookieMapRWLock );
|
2005-03-25 03:59:44 +01:00
|
|
|
|
2005-03-19 23:14:27 +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;
|
2005-03-19 23:14:27 +01:00
|
|
|
static SocketMap gSocketStuff;
|
2005-03-25 03:59:44 +01:00
|
|
|
static pthread_mutex_t gSocketStuffMutex = PTHREAD_MUTEX_INITIALIZER;
|
2005-03-19 23:14:27 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
Associate( int socket, CookieRef* cref )
|
|
|
|
{
|
2005-03-25 03:59:44 +01:00
|
|
|
pthread_mutex_lock( &gSocketStuffMutex );
|
2005-03-19 23:14:27 +01:00
|
|
|
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 );
|
2005-03-19 23:14:27 +01:00
|
|
|
} /* Associate */
|
|
|
|
|
|
|
|
static CookieRef*
|
|
|
|
getCookieRefForSocket( int socket )
|
|
|
|
{
|
2005-03-25 03:59:44 +01:00
|
|
|
MutexLock ml( &gSocketStuffMutex );
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
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-19 23:14:27 +01:00
|
|
|
}
|
2005-03-25 03:59:44 +01:00
|
|
|
assert( 0 );
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RemoveSocketRefs( int socket )
|
|
|
|
{
|
|
|
|
CookieRef* cref = getCookieRefForSocket( socket );
|
2005-03-21 06:30:12 +01:00
|
|
|
if ( cref != NULL ) {
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-03-25 03:59:44 +01:00
|
|
|
MutexLock ml( &gSocketStuffMutex );
|
2005-03-21 06:30:12 +01:00
|
|
|
SocketMap::iterator iter = gSocketStuff.find( socket );
|
|
|
|
assert( iter != gSocketStuff.end() );
|
2005-03-25 03:59:44 +01:00
|
|
|
delete iter->second;
|
2005-03-21 06:30:12 +01:00
|
|
|
gSocketStuff.erase( iter );
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-03-25 03:59:44 +01:00
|
|
|
cref->Remove( socket );
|
2005-03-21 06:30:12 +01:00
|
|
|
} else {
|
|
|
|
logf( "socket already dead" );
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* CookieRef class
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-03-25 03:59:44 +01:00
|
|
|
CookieRef::CookieRef(string s)
|
|
|
|
: m_name(s)
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-03-25 03:59:44 +01:00
|
|
|
pthread_mutex_init( &m_mutex, NULL );
|
2005-03-19 23:14:27 +01:00
|
|
|
m_connectionID = ms_nextConnectionID++; /* needs a mutex!!! */
|
|
|
|
}
|
|
|
|
|
|
|
|
CookieRef::~CookieRef()
|
|
|
|
{
|
2005-03-25 03:59:44 +01:00
|
|
|
pthread_mutex_destroy( &m_mutex );
|
2005-03-19 23:14:27 +01:00
|
|
|
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();
|
2005-03-19 23:14:27 +01:00
|
|
|
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;
|
2005-03-19 23:14:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
++iter;
|
|
|
|
}
|
2005-03-25 03:59:44 +01:00
|
|
|
|
|
|
|
if ( count == 0 ) {
|
|
|
|
ForgetCref( this );
|
|
|
|
delete this;
|
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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();
|
2005-03-19 23:14:27 +01:00
|
|
|
++_iter;
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|