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-04-20 14:13:20 +02:00
|
|
|
#include "tpool.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
|
|
|
|
2005-06-23 06:26:44 +02:00
|
|
|
|
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 );
|
2005-04-20 14:13:20 +02:00
|
|
|
gCookieMap.insert( pair<CookieID, CookieRef*>(ref->GetCookieID(), ref ) );
|
|
|
|
logf( "paired cookie %s with id %d", s.c_str(), ref->GetCookieID() );
|
2005-04-08 16:15:23 +02:00
|
|
|
return ref;
|
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/* static */ void
|
|
|
|
CookieRef::Delete( CookieID id )
|
|
|
|
{
|
|
|
|
CookieRef* cref = get_cookieRef( id );
|
|
|
|
if ( cref != NULL ) {
|
|
|
|
delete cref;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
CookieRef::Delete( const char* name )
|
|
|
|
{
|
|
|
|
CookieID id = CookieIdForName( name );
|
|
|
|
Delete( id );
|
|
|
|
} /* Delete */
|
|
|
|
|
|
|
|
CookieID
|
|
|
|
CookieIdForName( const char* name )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-04-08 16:15:23 +02:00
|
|
|
CookieRef* ref = NULL;
|
2005-04-20 14:13:20 +02:00
|
|
|
string s(name);
|
2005-04-08 16:15:23 +02:00
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
RWReadLock rwl( &gCookieMapRWLock );
|
2005-04-08 16:15:23 +02:00
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
CookieMap::iterator iter = gCookieMap.begin();
|
|
|
|
while ( iter != gCookieMap.end() ) {
|
|
|
|
ref = iter->second;
|
|
|
|
if ( ref->Name() == s ) {
|
2005-04-08 16:15:23 +02:00
|
|
|
ref = iter->second;
|
2005-04-20 14:13:20 +02:00
|
|
|
return ref->GetCookieID();
|
2005-03-25 03:59:44 +01:00
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
++iter;
|
2005-03-25 03:59:44 +01:00
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
return 0;
|
|
|
|
} /* CookieIdForName */
|
2005-03-25 03:59:44 +01:00
|
|
|
|
2005-06-23 06:26:44 +02:00
|
|
|
void
|
|
|
|
CheckHeartbeats( time_t now, vector<int>* sockets )
|
|
|
|
{
|
|
|
|
logf( "CheckHeartbeats" );
|
|
|
|
RWReadLock rwl( &gCookieMapRWLock );
|
|
|
|
CookieMap::iterator iter = gCookieMap.begin();
|
|
|
|
while ( iter != gCookieMap.end() ) {
|
|
|
|
CookieRef* ref = iter->second;
|
|
|
|
ref->CheckHeartbeats( now, sockets );
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
logf( "CheckHeartbeats done" );
|
|
|
|
} /* CheckHeartbeats */
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
CookieRef*
|
|
|
|
get_make_cookieRef( const char* cookie,
|
|
|
|
CookieID connID ) /* connID ignored for now */
|
|
|
|
{
|
|
|
|
CookieID id = CookieIdForName( cookie );
|
|
|
|
CookieRef* cref;
|
|
|
|
|
|
|
|
if ( id == 0 ) {
|
|
|
|
cref = CookieRef::AddNew( string(cookie) );
|
|
|
|
} else {
|
|
|
|
cref = get_cookieRef( id );
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
|
|
|
|
return cref;
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2005-04-20 14:13:20 +02:00
|
|
|
if ( sec->GetCookieID() == cookieID ) {
|
2005-03-25 03:59:44 +01:00
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
SocketMap SocketMgr::ms_SocketStuff;
|
|
|
|
pthread_mutex_t SocketMgr::ms_SocketStuffMutex = PTHREAD_MUTEX_INITIALIZER;
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/* static */ void
|
|
|
|
SocketMgr::Associate( int socket, CookieRef* cref )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
logf( "ms_SocketStuffMutex=%x", &ms_SocketStuffMutex );
|
|
|
|
MutexLock ml( &ms_SocketStuffMutex );
|
|
|
|
SocketMap::iterator iter = ms_SocketStuff.find( socket );
|
|
|
|
if ( iter == ms_SocketStuff.end() ) {
|
2005-03-19 23:14:27 +01:00
|
|
|
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 );
|
2005-04-20 14:13:20 +02:00
|
|
|
ms_SocketStuff.insert( pair< int, SocketStuff* >( socket, stuff ) );
|
2005-03-19 23:14:27 +01:00
|
|
|
} /* Associate */
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/*static*/ CookieRef*
|
|
|
|
SocketMgr::CookieRefForSocket( int socket )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
MutexLock ml( &ms_SocketStuffMutex );
|
2005-03-25 03:59:44 +01:00
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
SocketMap::iterator iter = ms_SocketStuff.find( socket );
|
|
|
|
if ( iter != ms_SocketStuff.end() ) {
|
2005-03-25 03:59:44 +01:00
|
|
|
SocketStuff* stuff = iter->second;
|
|
|
|
return stuff->m_cref;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/* static */ pthread_mutex_t*
|
|
|
|
SocketMgr::GetWriteMutexForSocket( int socket )
|
2005-03-25 03:59:44 +01:00
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
MutexLock ml( &ms_SocketStuffMutex );
|
|
|
|
SocketMap::iterator iter = ms_SocketStuff.find( socket );
|
|
|
|
if ( iter != ms_SocketStuff.end() ) {
|
2005-03-25 03:59:44 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
/* static */ void
|
|
|
|
SocketMgr::RemoveSocketRefs( int socket )
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
CookieRef* cref = CookieRefForSocket( socket );
|
2005-03-21 06:30:12 +01:00
|
|
|
if ( cref != NULL ) {
|
2005-03-19 23:14:27 +01:00
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
MutexLock ml( &ms_SocketStuffMutex );
|
|
|
|
SocketMap::iterator iter = ms_SocketStuff.find( socket );
|
|
|
|
assert( iter != ms_SocketStuff.end() );
|
2005-03-25 03:59:44 +01:00
|
|
|
delete iter->second;
|
2005-04-20 14:13:20 +02:00
|
|
|
ms_SocketStuff.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
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
} /* RemoveSocketRefs */
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
SocketMgr::PrintSocketInfo( int socket, string& out )
|
|
|
|
{
|
|
|
|
CookieRef* me = SocketMgr::CookieRefForSocket( socket );
|
|
|
|
assert( me );
|
|
|
|
|
|
|
|
char buf[64];
|
|
|
|
|
|
|
|
snprintf( buf, sizeof(buf), "* socket: %d\n", socket );
|
|
|
|
out += buf;
|
|
|
|
|
|
|
|
snprintf( buf, sizeof(buf), " in cookie: %s\n", me->Name().c_str() );
|
|
|
|
out += buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* static */ SocketsIterator
|
|
|
|
SocketMgr::MakeSocketsIterator()
|
|
|
|
{
|
|
|
|
SocketsIterator iter( ms_SocketStuff.begin() );
|
|
|
|
return iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* SocketsIterator class
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
SocketsIterator::SocketsIterator( SocketMap::iterator iter )
|
|
|
|
: m_iter( iter )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SocketsIterator::Next()
|
|
|
|
{
|
|
|
|
int socket = m_iter->first;
|
|
|
|
++m_iter;
|
|
|
|
return socket;
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* CookieRef class
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-03-25 03:59:44 +01:00
|
|
|
CookieRef::CookieRef(string s)
|
2005-04-20 14:13:20 +02:00
|
|
|
: m_name(s),
|
|
|
|
m_totalSent(0)
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
pthread_rwlock_init( &m_sockets_rwlock, NULL );
|
2005-03-19 23:14:27 +01:00
|
|
|
m_connectionID = ms_nextConnectionID++; /* needs a mutex!!! */
|
|
|
|
}
|
|
|
|
|
|
|
|
CookieRef::~CookieRef()
|
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
/* get rid of any sockets still contained */
|
|
|
|
XWThreadPool* tPool = XWThreadPool::GetTPool();
|
|
|
|
|
|
|
|
for ( ; ; ) {
|
|
|
|
RWWriteLock rwl( &m_sockets_rwlock );
|
2005-06-23 06:26:44 +02:00
|
|
|
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
|
2005-04-20 14:13:20 +02:00
|
|
|
|
|
|
|
if ( iter == m_hostSockets.end() ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-06-23 06:26:44 +02:00
|
|
|
int socket = iter->second.m_socket;
|
2005-04-20 14:13:20 +02:00
|
|
|
tPool->CloseSocket( socket );
|
|
|
|
m_hostSockets.erase( iter );
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_destroy( &m_sockets_rwlock );
|
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 );
|
2005-04-20 14:13:20 +02:00
|
|
|
RWWriteLock ml( &m_sockets_rwlock );
|
2005-06-23 06:26:44 +02:00
|
|
|
HostRec hr(socket);
|
|
|
|
m_hostSockets.insert( pair<HostID,HostRec>(srcID,hr) );
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CookieRef::SocketForHost( HostID dest )
|
|
|
|
{
|
|
|
|
int socket;
|
2005-06-23 06:26:44 +02:00
|
|
|
map<HostID,HostRec>::iterator iter = m_hostSockets.find( dest );
|
2005-03-19 23:14:27 +01:00
|
|
|
if ( iter == m_hostSockets.end() ) {
|
|
|
|
socket = -1;
|
|
|
|
} else {
|
2005-06-23 06:26:44 +02:00
|
|
|
socket = iter->second.m_socket;
|
2005-03-19 23:14:27 +01:00
|
|
|
logf( "socketForHost(%x) => %d", dest, socket );
|
|
|
|
}
|
|
|
|
logf( "returning socket=%d for hostid=%x", socket, dest );
|
|
|
|
return socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::Remove( int socket )
|
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
int count;
|
|
|
|
{
|
|
|
|
RWWriteLock rwl( &m_sockets_rwlock );
|
|
|
|
|
|
|
|
count = CountSockets();
|
|
|
|
assert( count > 0 );
|
2005-06-23 06:26:44 +02:00
|
|
|
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
|
2005-04-20 14:13:20 +02:00
|
|
|
while ( iter != m_hostSockets.end() ) {
|
2005-06-23 06:26:44 +02:00
|
|
|
if ( iter->second.m_socket == socket ) {
|
2005-04-20 14:13:20 +02:00
|
|
|
m_hostSockets.erase(iter);
|
|
|
|
--count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++iter;
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
}
|
2005-03-25 03:59:44 +01:00
|
|
|
|
|
|
|
if ( count == 0 ) {
|
|
|
|
ForgetCref( this );
|
|
|
|
delete this;
|
|
|
|
}
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|
|
|
|
|
2005-06-23 06:26:44 +02:00
|
|
|
void
|
|
|
|
CookieRef::HandleHeartbeat( HostID id, int socket )
|
|
|
|
{
|
|
|
|
RWWriteLock rwl( &m_sockets_rwlock );
|
|
|
|
|
|
|
|
map<HostID,HostRec>::iterator iter = m_hostSockets.find(id);
|
|
|
|
assert( iter != m_hostSockets.end() );
|
|
|
|
|
|
|
|
/* PENDING If the message came on an unexpected socket, kill the
|
|
|
|
connection. An attack is the most likely explanation. */
|
|
|
|
assert( iter->second.m_socket == socket );
|
|
|
|
|
|
|
|
logf( "upping m_lastHeartbeat from %d to %d",
|
|
|
|
iter->second.m_lastHeartbeat, now() );
|
|
|
|
iter->second.m_lastHeartbeat = now();
|
|
|
|
} /* HandleHeartbeat */
|
|
|
|
|
|
|
|
void
|
|
|
|
CookieRef::CheckHeartbeats( time_t now, vector<int>* victims )
|
|
|
|
{
|
|
|
|
logf( "CookieRef::CheckHeartbeats" );
|
|
|
|
|
|
|
|
RWWriteLock rwl( &m_sockets_rwlock );
|
|
|
|
|
|
|
|
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
|
|
|
|
while ( iter != m_hostSockets.end() ) {
|
|
|
|
time_t last = iter->second.m_lastHeartbeat;
|
|
|
|
if ( (now - last) > HEARTBEAT * 2 ) {
|
|
|
|
victims->push_back( iter->second.m_socket );
|
|
|
|
}
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
logf( "CookieRef::CheckHeartbeats done" );
|
|
|
|
} /* CheckHeartbeats */
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
void
|
|
|
|
CookieRef::PrintCookieInfo( string& out )
|
|
|
|
{
|
|
|
|
out += "Name: ";
|
|
|
|
out += Name();
|
|
|
|
out += "\n";
|
|
|
|
out += "ID: ";
|
|
|
|
char buf[64];
|
|
|
|
snprintf( buf, sizeof(buf), "%d\n", GetCookieID() );
|
|
|
|
out += buf;
|
|
|
|
|
|
|
|
snprintf( buf, sizeof(buf), "Bytes sent: %d\n", m_totalSent );
|
|
|
|
out += buf;
|
|
|
|
|
|
|
|
/* n messages */
|
|
|
|
/* n bytes */
|
|
|
|
/* open since when */
|
|
|
|
/* sockets */
|
|
|
|
|
|
|
|
} /* PrintCookieInfo */
|
|
|
|
|
2005-03-19 23:14:27 +01:00
|
|
|
/* static */ CookieMapIterator
|
2005-04-20 14:13:20 +02:00
|
|
|
CookieRef::GetCookieIterator()
|
2005-03-19 23:14:27 +01:00
|
|
|
{
|
|
|
|
CookieMapIterator iter;
|
|
|
|
return iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CookieMapIterator:: CookieMapIterator()
|
|
|
|
: _iter( gCookieMap.begin() )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-04-20 14:13:20 +02:00
|
|
|
CookieID
|
2005-03-19 23:14:27 +01:00
|
|
|
CookieMapIterator::Next()
|
|
|
|
{
|
2005-04-20 14:13:20 +02:00
|
|
|
CookieID id = 0;
|
2005-03-19 23:14:27 +01:00
|
|
|
if ( _iter != gCookieMap.end() ) {
|
2005-03-25 03:59:44 +01:00
|
|
|
CookieRef* cref = _iter->second;
|
2005-04-20 14:13:20 +02:00
|
|
|
id = cref->GetCookieID();
|
2005-03-19 23:14:27 +01:00
|
|
|
++_iter;
|
|
|
|
}
|
2005-04-20 14:13:20 +02:00
|
|
|
return id;
|
2005-03-19 23:14:27 +01:00
|
|
|
}
|