new files to track how long it's been since data's been received from

a UDP address.  The idea's that when there's too long a gap the
address has likely been recycled and we shouldn't send replies to
packets received before the reset.
This commit is contained in:
Eric House 2013-07-22 07:26:14 -07:00
parent 6418513a6d
commit acca4d14d4
5 changed files with 156 additions and 2 deletions

View file

@ -34,6 +34,7 @@ SRC = \
devmgr.cpp \
udpqueue.cpp \
udpack.cpp \
udpager.cpp \
xwrelay.cpp \
# STATIC ?= -static

89
xwords4/relay/udpager.cpp Normal file
View file

@ -0,0 +1,89 @@
/* -*- compile-command: "make -k -j3"; -*- */
/*
* Copyright 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.
*/
#include <glib.h>
#include "udpager.h"
#include "configs.h"
#include "mlock.h"
static UDPAger* s_instance = NULL;
/* static */ UDPAger*
UDPAger::Get()
{
if ( NULL == s_instance ) {
s_instance = new UDPAger();
}
return s_instance;
} /* Get */
UDPAger::UDPAger()
{
if ( !RelayConfigs::GetConfigs()-> GetValueFor( "UDP_RECYLE_INTERVAL",
&m_maxInterval ) ) {
assert(0);
}
logf( XW_LOGINFO, "read %d from configs for UDP_RECYLE_INTERVAL",
m_maxInterval );
m_maxInterval *= 1000; // make it milliseconds
pthread_mutex_init( &m_addrTimeMapLock, NULL );
}
// An address is valid as long as we keep hearing from it within a certain
// frequency. When we hear from it but it's been too long, assume it's new
// and give it a new timestamp.
void
UDPAger::Refresh( const AddrInfo* addr )
{
const AddrInfo::AddrUnion* saddr = addr->saddr();
uint32_t readWhen = addr->created();
gchar* b64 = g_base64_encode( (unsigned char*)&saddr->u.addr,
sizeof(saddr->u.addr) );
MutexLock ml( &m_addrTimeMapLock );
map<AddrInfo::AddrUnion, AgePair*>::iterator iter =
m_addrTimeMap.find( *saddr );
if ( m_addrTimeMap.end() == iter ) { // it's new; just insert
AgePair* ap = new AgePair( readWhen, readWhen );
m_addrTimeMap.insert( pair<AddrInfo::AddrUnion,
AgePair*>(*saddr, ap ) );
logf( XW_LOGINFO, "%s: adding '%s'", __func__, b64 );
} else {
AgePair* ap = iter->second;
assert( ap->lastSeen() <= readWhen );
int interval = readWhen - ap->lastSeen();
if ( m_maxInterval >= interval ) {
logf( XW_LOGINFO, "%s: refreshing '%s'; last seen %d "
"milliseconds ago", __func__, b64, interval );
ap->update( readWhen );
} else {
logf( XW_LOGINFO, "%s: RESETTING '%s'; last seen %d "
"milliseconds ago", __func__, b64, interval );
delete ap;
iter->second = new AgePair( readWhen, readWhen );
}
}
g_free( b64 );
}

60
xwords4/relay/udpager.h Normal file
View file

@ -0,0 +1,60 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 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.
*
* 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 _UDPAGER_H_
#define _UDPAGER_H_
#include <map>
#include "addrinfo.h"
using namespace std;
class UDPAger {
public:
static UDPAger* Get();
UDPAger();
void Refresh( const AddrInfo* addr );
private:
class AgePair {
public:
AgePair( uint32_t created, uint32_t lastSeen ) {
m_created = created;
m_lastSeen = lastSeen;
}
void update( uint32_t lastSeen ) { m_lastSeen = lastSeen; }
uint32_t lastSeen() { return m_lastSeen; }
private:
uint32_t m_created;
uint32_t m_lastSeen;
};
/* Map socket addresses against times, moving the time forward only
when it's been too long since we saw it. */
int m_maxInterval; /* config: how long since we heard */
map<AddrInfo::AddrUnion, AgePair*> m_addrTimeMap;
pthread_mutex_t m_addrTimeMapLock;
};
#endif

View file

@ -27,7 +27,9 @@ GAME_PORTS=10997
DEVICE_PORTS=10998
# Port for per-device UDP interface (experimental)
UDPPORT=10997
UDP_PORT=10997
# How long after we've read from an address before we assume it's recycled
UDP_RECYLE_INTERVAL=60
# default 5
SOCK_TIMEOUT_SECONDS=5

View file

@ -80,6 +80,7 @@
#include "devmgr.h"
#include "udpqueue.h"
#include "udpack.h"
#include "udpager.h"
typedef struct _UDPHeader {
uint32_t packetID;
@ -1499,6 +1500,7 @@ read_udp_packet( int udpsock )
#endif
AddrInfo addr( udpsock, &saddr, false );
UDPAger::Get()->Refresh( &addr );
UdpQueue::get()->handle( &addr, buf, nRead, handle_udp_packet );
}
}
@ -1744,7 +1746,7 @@ main( int argc, char** argv )
(void)cfg->GetValueFor( "CTLPORT", &ctrlport );
}
if ( -1 == udpport ) {
(void)cfg->GetValueFor( "UDPPORT", &udpport );
(void)cfg->GetValueFor( "UDP_PORT", &udpport );
}
#ifdef DO_HTTP
if ( httpport == 0 ) {