mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-18 22:26:30 +01:00
add udp socket and protocol for use over it so that a device can
manage a single connection to the relay for all of its games. Works so far to the extent that the game's playable with all boards on the same device (with checkins about to come) as long as all boards are open. (Client doesn't handle opening closed games yet.)
This commit is contained in:
parent
5a51af489a
commit
7fec736947
16 changed files with 370 additions and 46 deletions
|
@ -31,6 +31,7 @@ SRC = \
|
||||||
tpool.cpp \
|
tpool.cpp \
|
||||||
cidlock.cpp \
|
cidlock.cpp \
|
||||||
addrinfo.cpp \
|
addrinfo.cpp \
|
||||||
|
devmgr.cpp \
|
||||||
xwrelay.cpp \
|
xwrelay.cpp \
|
||||||
|
|
||||||
# STATIC ?= -static
|
# STATIC ?= -static
|
||||||
|
|
|
@ -32,7 +32,10 @@ AddrInfo::equals( const AddrInfo& other ) const
|
||||||
if ( isTCP() ) {
|
if ( isTCP() ) {
|
||||||
equal = m_socket == other.m_socket;
|
equal = m_socket == other.m_socket;
|
||||||
} else {
|
} else {
|
||||||
assert(0); /* later.... */
|
assert( m_socket == other.m_socket ); /* both same UDP socket */
|
||||||
|
/* what does equal mean on udp addresses? Same host, or same host AND game */
|
||||||
|
equal = m_clientToken == other.m_clientToken
|
||||||
|
&& 0 == memcmp( &m_saddr, &other.m_saddr, sizeof(m_saddr) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return equal;
|
return equal;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
class AddrInfo {
|
class AddrInfo {
|
||||||
public:
|
public:
|
||||||
|
@ -32,31 +33,45 @@ class AddrInfo {
|
||||||
struct sockaddr_in addr_in;
|
struct sockaddr_in addr_in;
|
||||||
} AddrUnion;
|
} AddrUnion;
|
||||||
|
|
||||||
|
/* Those constructed without params are only valid after another copied on
|
||||||
|
top of it */
|
||||||
AddrInfo() {
|
AddrInfo() {
|
||||||
memset( this, 0, sizeof(*this) );
|
|
||||||
m_socket = -1;
|
|
||||||
m_isValid = false;
|
m_isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddrInfo( bool isTCP, int socket, const AddrUnion* saddr ) {
|
AddrInfo( int socket, const AddrUnion* saddr ) {
|
||||||
m_isValid = true;
|
construct( socket, saddr, true );
|
||||||
m_isTCP = isTCP;
|
}
|
||||||
m_socket = socket;
|
|
||||||
memcpy( &m_saddr, saddr, sizeof(m_saddr) );
|
AddrInfo( int socket, uint32_t clientToken, const AddrUnion* saddr ) {
|
||||||
|
construct( socket, saddr, false );
|
||||||
|
m_clientToken = clientToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIsTCP( bool val ) { m_isTCP = val; }
|
void setIsTCP( bool val ) { m_isTCP = val; }
|
||||||
bool isTCP() const { return m_isTCP; } /* later UDP will be here too */
|
bool isTCP() const { return m_isTCP; } /* later UDP will be here too */
|
||||||
int socket() const { assert(m_isValid); return m_socket; }
|
int socket() const { assert(m_isValid); return m_socket; }
|
||||||
|
uint32_t clientToken() const { assert(m_isValid); return m_clientToken; }
|
||||||
struct in_addr sin_addr() const { return m_saddr.addr_in.sin_addr; }
|
struct in_addr sin_addr() const { return m_saddr.addr_in.sin_addr; }
|
||||||
|
const struct sockaddr* sockaddr() const { assert(m_isValid); return &m_saddr.addr; }
|
||||||
|
|
||||||
bool equals( const AddrInfo& other ) const;
|
bool equals( const AddrInfo& other ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void construct( int socket, const AddrUnion* saddr, bool isTCP ) {
|
||||||
|
memset( this, 0, sizeof(*this) );
|
||||||
|
|
||||||
|
m_socket = socket;
|
||||||
|
m_isTCP = isTCP;
|
||||||
|
memcpy( &m_saddr, saddr, sizeof(m_saddr) );
|
||||||
|
m_isValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
// AddrInfo& operator=(const AddrInfo&); // Prevent assignment
|
// AddrInfo& operator=(const AddrInfo&); // Prevent assignment
|
||||||
int m_socket;
|
int m_socket;
|
||||||
bool m_isTCP;
|
bool m_isTCP;
|
||||||
bool m_isValid;
|
bool m_isValid;
|
||||||
|
uint32_t m_clientToken; /* must be 32 bit */
|
||||||
AddrUnion m_saddr;
|
AddrUnion m_saddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,7 @@ CookieRef::_PutMsg( HostID srcID, const AddrInfo* addr, HostID destID,
|
||||||
void
|
void
|
||||||
CookieRef::_Disconnect( const AddrInfo* addr, HostID hostID )
|
CookieRef::_Disconnect( const AddrInfo* addr, HostID hostID )
|
||||||
{
|
{
|
||||||
logf( XW_LOGINFO, "%s(socket=%d, hostID=%d)", __func__, socket, hostID );
|
logf( XW_LOGINFO, "%s(hostID=%d)", __func__, hostID );
|
||||||
|
|
||||||
CRefEvent evt( XWE_DISCONN, addr );
|
CRefEvent evt( XWE_DISCONN, addr );
|
||||||
evt.u.discon.srcID = hostID;
|
evt.u.discon.srcID = hostID;
|
||||||
|
@ -636,7 +636,7 @@ CookieRef::handleEvents()
|
||||||
/* Assumption: has mutex!!!! */
|
/* Assumption: has mutex!!!! */
|
||||||
while ( m_eventQueue.size () > 0 ) {
|
while ( m_eventQueue.size () > 0 ) {
|
||||||
XW_RELAY_STATE nextState;
|
XW_RELAY_STATE nextState;
|
||||||
DBMgr::DevIDRelay devID;
|
DevIDRelay devID;
|
||||||
CRefEvent evt = m_eventQueue.front();
|
CRefEvent evt = m_eventQueue.front();
|
||||||
m_eventQueue.pop_front();
|
m_eventQueue.pop_front();
|
||||||
|
|
||||||
|
@ -848,7 +848,6 @@ CookieRef::send_stored_messages( HostID dest, const AddrInfo* addr )
|
||||||
|
|
||||||
assert( dest > 0 && dest <= 4 );
|
assert( dest > 0 && dest <= 4 );
|
||||||
assert( -1 != addr->socket() );
|
assert( -1 != addr->socket() );
|
||||||
assert( addr->isTCP() );
|
|
||||||
|
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
unsigned char buf[MAX_MSG_LEN];
|
unsigned char buf[MAX_MSG_LEN];
|
||||||
|
@ -867,9 +866,9 @@ CookieRef::send_stored_messages( HostID dest, const AddrInfo* addr )
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
||||||
DBMgr::DevIDRelay* devIDp )
|
DevIDRelay* devIDp )
|
||||||
{
|
{
|
||||||
DBMgr::DevIDRelay devID = DBMgr::DEVID_NONE;
|
DevIDRelay devID = DBMgr::DEVID_NONE;
|
||||||
int nPlayersH = evt->u.con.nPlayersH;
|
int nPlayersH = evt->u.con.nPlayersH;
|
||||||
int seed = evt->u.con.seed;
|
int seed = evt->u.con.seed;
|
||||||
|
|
||||||
|
@ -1038,7 +1037,7 @@ CookieRef::cancelAllConnectedTimer()
|
||||||
|
|
||||||
void
|
void
|
||||||
CookieRef::sendResponse( const CRefEvent* evt, bool initial,
|
CookieRef::sendResponse( const CRefEvent* evt, bool initial,
|
||||||
const DBMgr::DevIDRelay* devID )
|
const DevIDRelay* devID )
|
||||||
{
|
{
|
||||||
/* Now send the response */
|
/* Now send the response */
|
||||||
unsigned char buf[1 /* cmd */
|
unsigned char buf[1 /* cmd */
|
||||||
|
@ -1191,7 +1190,6 @@ void
|
||||||
CookieRef::notifyOthers( const AddrInfo* addr, XWRelayMsg msg, XWREASON why )
|
CookieRef::notifyOthers( const AddrInfo* addr, XWRelayMsg msg, XWREASON why )
|
||||||
{
|
{
|
||||||
assert( addr->socket() != 0 );
|
assert( addr->socket() != 0 );
|
||||||
assert( addr->isTCP() );
|
|
||||||
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
RWReadLock rrl( &m_socketsRWLock );
|
RWReadLock rrl( &m_socketsRWLock );
|
||||||
|
|
|
@ -219,11 +219,11 @@ class CookieRef {
|
||||||
void handleEvents();
|
void handleEvents();
|
||||||
|
|
||||||
void sendResponse( const CRefEvent* evt, bool initial,
|
void sendResponse( const CRefEvent* evt, bool initial,
|
||||||
const DBMgr::DevIDRelay* devID );
|
const DevIDRelay* devID );
|
||||||
void sendAnyStored( const CRefEvent* evt );
|
void sendAnyStored( const CRefEvent* evt );
|
||||||
void initPlayerCounts( const CRefEvent* evt );
|
void initPlayerCounts( const CRefEvent* evt );
|
||||||
bool increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
bool increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp,
|
||||||
DBMgr::DevIDRelay* devID );
|
DevIDRelay* devID );
|
||||||
void updateAck( HostID hostID, bool keep );
|
void updateAck( HostID hostID, bool keep );
|
||||||
void dropPending( int seed );
|
void dropPending( int seed );
|
||||||
|
|
||||||
|
|
|
@ -249,10 +249,10 @@ DBMgr::AllDevsAckd( const char* const connName )
|
||||||
|
|
||||||
// Return DevIDRelay for device, adding it to devices table IFF it's not
|
// Return DevIDRelay for device, adding it to devices table IFF it's not
|
||||||
// already there.
|
// already there.
|
||||||
DBMgr::DevIDRelay
|
DevIDRelay
|
||||||
DBMgr::RegisterDevice( const DevID* host )
|
DBMgr::RegisterDevice( const DevID* host )
|
||||||
{
|
{
|
||||||
DBMgr::DevIDRelay devID;
|
DevIDRelay devID;
|
||||||
assert( host->m_devIDType != ID_TYPE_NONE );
|
assert( host->m_devIDType != ID_TYPE_NONE );
|
||||||
int ii;
|
int ii;
|
||||||
bool success;
|
bool success;
|
||||||
|
@ -261,7 +261,7 @@ DBMgr::RegisterDevice( const DevID* host )
|
||||||
devID = getDevID( host );
|
devID = getDevID( host );
|
||||||
|
|
||||||
// If it's not present *and* of type ID_TYPE_RELAY, we can do nothing.
|
// If it's not present *and* of type ID_TYPE_RELAY, we can do nothing.
|
||||||
// Fail.
|
// Otherwise proceed.
|
||||||
if ( DEVID_NONE == devID && ID_TYPE_RELAY < host->m_devIDType ) {
|
if ( DEVID_NONE == devID && ID_TYPE_RELAY < host->m_devIDType ) {
|
||||||
// loop until we're successful inserting the unique key. Ship with this
|
// loop until we're successful inserting the unique key. Ship with this
|
||||||
// coming from random, but test with increasing values initially to make
|
// coming from random, but test with increasing values initially to make
|
||||||
|
@ -269,7 +269,7 @@ DBMgr::RegisterDevice( const DevID* host )
|
||||||
for ( success = false, ii = 0; !success; ++ii ) {
|
for ( success = false, ii = 0; !success; ++ii ) {
|
||||||
assert( 10 > ii ); // better to check that we're looping BECAUSE
|
assert( 10 > ii ); // better to check that we're looping BECAUSE
|
||||||
// of uniqueness problem.
|
// of uniqueness problem.
|
||||||
devID = (DBMgr::DevIDRelay)random();
|
devID = (DevIDRelay)random();
|
||||||
if ( DEVID_NONE == devID ) {
|
if ( DEVID_NONE == devID ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -327,13 +327,14 @@ DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion,
|
||||||
const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = %d,"
|
const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = %d,"
|
||||||
" clntVers[%d] = %d,"
|
" clntVers[%d] = %d,"
|
||||||
" seeds[%d] = %d, addrs[%d] = \'%s\', %s"
|
" seeds[%d] = %d, addrs[%d] = \'%s\', %s"
|
||||||
" mtimes[%d]='now', ack[%d]=\'%c\'"
|
" tokens[%d] = %d, mtimes[%d]='now', ack[%d]=\'%c\'"
|
||||||
" WHERE connName = '%s'";
|
" WHERE connName = '%s'";
|
||||||
string query;
|
string query;
|
||||||
char* ntoa = inet_ntoa( addr->sin_addr() );
|
char* ntoa = inet_ntoa( addr->sin_addr() );
|
||||||
string_printf( query, fmt, newID, nToAdd, newID, clientVersion,
|
string_printf( query, fmt, newID, nToAdd, newID, clientVersion,
|
||||||
newID, seed, newID, ntoa, devIDBuf.c_str(), newID,
|
newID, seed, newID, ntoa, devIDBuf.c_str(),
|
||||||
newID, ackd?'A':'a', connName );
|
newID, addr->clientToken(), newID, newID, ackd?'A':'a',
|
||||||
|
connName );
|
||||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query.c_str() );
|
logf( XW_LOGINFO, "%s: query: %s", __func__, query.c_str() );
|
||||||
|
|
||||||
execSql( query );
|
execSql( query );
|
||||||
|
@ -632,10 +633,10 @@ DBMgr::readArray( const char* const connName, int arr[] ) /* len 4 */
|
||||||
PQclear( result );
|
PQclear( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
DBMgr::DevIDRelay
|
DevIDRelay
|
||||||
DBMgr::getDevID( const char* connName, int hid )
|
DBMgr::getDevID( const char* connName, int hid )
|
||||||
{
|
{
|
||||||
DBMgr::DevIDRelay devID;
|
DevIDRelay devID;
|
||||||
const char* fmt = "SELECT devids[%d] FROM " GAMES_TABLE " WHERE connName='%s'";
|
const char* fmt = "SELECT devids[%d] FROM " GAMES_TABLE " WHERE connName='%s'";
|
||||||
string query;
|
string query;
|
||||||
string_printf( query, fmt, hid, connName );
|
string_printf( query, fmt, hid, connName );
|
||||||
|
@ -643,29 +644,28 @@ DBMgr::getDevID( const char* connName, int hid )
|
||||||
|
|
||||||
PGresult* result = PQexec( getThreadConn(), query.c_str() );
|
PGresult* result = PQexec( getThreadConn(), query.c_str() );
|
||||||
assert( 1 == PQntuples( result ) );
|
assert( 1 == PQntuples( result ) );
|
||||||
devID = (DBMgr::DevIDRelay)strtoul( PQgetvalue( result, 0, 0 ), NULL, 10 );
|
devID = (DevIDRelay)strtoul( PQgetvalue( result, 0, 0 ), NULL, 10 );
|
||||||
PQclear( result );
|
PQclear( result );
|
||||||
return devID;
|
return devID;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBMgr::DevIDRelay
|
DevIDRelay
|
||||||
DBMgr::getDevID( const DevID* devID )
|
DBMgr::getDevID( const DevID* devID )
|
||||||
{
|
{
|
||||||
DBMgr::DevIDRelay rDevID = DEVID_NONE;
|
DevIDRelay rDevID = DEVID_NONE;
|
||||||
DevIDType devIDType = devID->m_devIDType;
|
DevIDType devIDType = devID->m_devIDType;
|
||||||
string query;
|
string query;
|
||||||
assert( ID_TYPE_NONE < devIDType );
|
assert( ID_TYPE_NONE < devIDType );
|
||||||
const char* asStr = devID->m_devIDString.c_str();
|
|
||||||
if ( ID_TYPE_RELAY == devIDType ) {
|
if ( ID_TYPE_RELAY == devIDType ) {
|
||||||
// confirm it's there
|
// confirm it's there
|
||||||
DBMgr::DevIDRelay cur = strtoul( asStr, NULL, 16 );
|
DevIDRelay cur = devID->asRelayID();
|
||||||
if ( DEVID_NONE != cur ) {
|
if ( DEVID_NONE != cur ) {
|
||||||
const char* fmt = "SELECT id FROM " DEVICES_TABLE " WHERE id=%d";
|
const char* fmt = "SELECT id FROM " DEVICES_TABLE " WHERE id=%d";
|
||||||
string_printf( query, fmt, cur );
|
string_printf( query, fmt, cur );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char* fmt = "SELECT id FROM " DEVICES_TABLE " WHERE devtype=%d and devid = '%s'";
|
const char* fmt = "SELECT id FROM " DEVICES_TABLE " WHERE devtype=%d and devid = '%s'";
|
||||||
string_printf( query, fmt, devIDType, asStr );
|
string_printf( query, fmt, devIDType, devID->m_devIDString.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( 0 < query.size() ) {
|
if ( 0 < query.size() ) {
|
||||||
|
@ -673,7 +673,7 @@ DBMgr::getDevID( const DevID* devID )
|
||||||
PGresult* result = PQexec( getThreadConn(), query.c_str() );
|
PGresult* result = PQexec( getThreadConn(), query.c_str() );
|
||||||
assert( 1 >= PQntuples( result ) );
|
assert( 1 >= PQntuples( result ) );
|
||||||
if ( 1 == PQntuples( result ) ) {
|
if ( 1 == PQntuples( result ) ) {
|
||||||
rDevID = (DBMgr::DevIDRelay)strtoul( PQgetvalue( result, 0, 0 ), NULL, 10 );
|
rDevID = (DevIDRelay)strtoul( PQgetvalue( result, 0, 0 ), NULL, 10 );
|
||||||
}
|
}
|
||||||
PQclear( result );
|
PQclear( result );
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ class DBMgr {
|
||||||
/* DevIDs on various platforms are stored in devices table. This is the
|
/* DevIDs on various platforms are stored in devices table. This is the
|
||||||
key, and used in msgs and games tables as a shorter way to refer to
|
key, and used in msgs and games tables as a shorter way to refer to
|
||||||
them. */
|
them. */
|
||||||
typedef unsigned int DevIDRelay;
|
|
||||||
static const DevIDRelay DEVID_NONE = 0;
|
static const DevIDRelay DEVID_NONE = 0;
|
||||||
|
|
||||||
static DBMgr* Get();
|
static DBMgr* Get();
|
||||||
|
@ -62,7 +61,7 @@ class DBMgr {
|
||||||
char* connNameBuf, int bufLen, int* nPlayersHP );
|
char* connNameBuf, int bufLen, int* nPlayersHP );
|
||||||
bool AllDevsAckd( const char* const connName );
|
bool AllDevsAckd( const char* const connName );
|
||||||
|
|
||||||
DevIDRelay RegisterDevice( const DevID* hosts );
|
DevIDRelay RegisterDevice( const DevID* host );
|
||||||
|
|
||||||
HostID AddDevice( const char* const connName, HostID curID, int clientVersion,
|
HostID AddDevice( const char* const connName, HostID curID, int clientVersion,
|
||||||
int nToAdd, unsigned short seed, const AddrInfo* addr,
|
int nToAdd, unsigned short seed, const AddrInfo* addr,
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#define _DEVID_H_
|
#define _DEVID_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "xwrelay.h"
|
#include "xwrelay.h"
|
||||||
|
|
||||||
/* DevID protocol.
|
/* DevID protocol.
|
||||||
|
@ -52,11 +54,18 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class DevID {
|
class DevID {
|
||||||
public:
|
public:
|
||||||
DevID() { m_devIDType = ID_TYPE_NONE; }
|
DevID() { m_devIDType = ID_TYPE_NONE; }
|
||||||
|
DevID(DevIDType typ) { m_devIDType = typ; }
|
||||||
|
DevIDRelay asRelayID() const {
|
||||||
|
assert( ID_TYPE_RELAY == m_devIDType );
|
||||||
|
return strtoul( m_devIDString.c_str(), NULL, 16 );
|
||||||
|
}
|
||||||
string m_devIDString;
|
string m_devIDString;
|
||||||
DevIDType m_devIDType;
|
DevIDType m_devIDType;
|
||||||
};
|
};
|
||||||
|
|
61
xwords4/relay/devmgr.cpp
Normal file
61
xwords4/relay/devmgr.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/* -*- 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 "devmgr.h"
|
||||||
|
#include "mlock.h"
|
||||||
|
|
||||||
|
static DevMgr* s_instance = NULL;
|
||||||
|
|
||||||
|
/* static */ DevMgr*
|
||||||
|
DevMgr::Get()
|
||||||
|
{
|
||||||
|
if ( s_instance == NULL ) {
|
||||||
|
s_instance = new DevMgr();
|
||||||
|
}
|
||||||
|
return s_instance;
|
||||||
|
} /* Get */
|
||||||
|
|
||||||
|
void
|
||||||
|
DevMgr::Remember( DevIDRelay devid, const AddrInfo::AddrUnion* saddr )
|
||||||
|
{
|
||||||
|
time_t now = time( NULL );
|
||||||
|
MutexLock ml( &m_mapLock );
|
||||||
|
UDPAddrRec rec( saddr, now );
|
||||||
|
m_devAddrMap.insert( pair<DevIDRelay,UDPAddrRec>( devid, rec ) );
|
||||||
|
logf( XW_LOGINFO, "dev->addr map now contains %d entries", m_devAddrMap.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // not used yet
|
||||||
|
const AddrInfo::AddrUnion*
|
||||||
|
DevMgr::get( DevIDRelay devid )
|
||||||
|
{
|
||||||
|
const AddrInfo::AddrUnion* result = NULL;
|
||||||
|
MutexLock ml( &m_mapLock );
|
||||||
|
map<DevIDRelay,UDPAddrRec>::iterator iter;
|
||||||
|
iter = m_devAddrMap.find( devid );
|
||||||
|
if ( m_devAddrMap.end() != iter ) {
|
||||||
|
result = &iter->second.m_addr;
|
||||||
|
logf( XW_LOGINFO, "%s: found addr for %.8x; is %d seconds old", __func__,
|
||||||
|
devid, time(NULL) - iter->second.m_added );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
54
xwords4/relay/devmgr.h
Normal file
54
xwords4/relay/devmgr.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/* -*-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 _DEVMGR_H_
|
||||||
|
#define _DEVMGR_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "xwrelay_priv.h"
|
||||||
|
#include "addrinfo.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class DevMgr {
|
||||||
|
public:
|
||||||
|
static DevMgr* Get();
|
||||||
|
void Remember( DevIDRelay devid, const AddrInfo::AddrUnion* saddr );
|
||||||
|
const AddrInfo::AddrUnion* get( DevIDRelay devid );
|
||||||
|
|
||||||
|
private:
|
||||||
|
DevMgr() { pthread_mutex_init( &m_mapLock, NULL ); }
|
||||||
|
~DevMgr() { pthread_mutex_destroy( &m_mapLock ); }
|
||||||
|
|
||||||
|
class UDPAddrRec {
|
||||||
|
public:
|
||||||
|
UDPAddrRec( const AddrInfo::AddrUnion* addr, time_t tim ) {
|
||||||
|
m_addr = *addr; m_added = tim;
|
||||||
|
}
|
||||||
|
AddrInfo::AddrUnion m_addr;
|
||||||
|
time_t m_added;
|
||||||
|
};
|
||||||
|
|
||||||
|
map<DevIDRelay,UDPAddrRec> m_devAddrMap;
|
||||||
|
pthread_mutex_t m_mapLock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -26,7 +26,7 @@ QUERY="WHERE NOT -NTOTAL = sum_array(nperdevice)"
|
||||||
echo "Device (pid) count: $(pidof xwords | wc | awk '{print $2}')"
|
echo "Device (pid) count: $(pidof xwords | wc | awk '{print $2}')"
|
||||||
echo "Row count:" $(psql -t xwgames -c "select count(*) FROM games $QUERY;")
|
echo "Row count:" $(psql -t xwgames -c "select count(*) FROM games $QUERY;")
|
||||||
|
|
||||||
echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,devids,ack,nsent "\
|
echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,addrs,tokens,ack,nsent "\
|
||||||
"FROM games $QUERY ORDER BY NOT dead, connname LIMIT $LIMIT;" \
|
"FROM games $QUERY ORDER BY NOT dead, connname LIMIT $LIMIT;" \
|
||||||
| psql xwgames
|
| psql xwgames
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,16 @@ GAME_PORTS=10997
|
||||||
# What ports do we listen on for per-device incoming connections?
|
# What ports do we listen on for per-device incoming connections?
|
||||||
DEVICE_PORTS=10998
|
DEVICE_PORTS=10998
|
||||||
|
|
||||||
|
# Port for per-device UDP interface (experimental)
|
||||||
|
UDPPORT=10997
|
||||||
|
|
||||||
# default 5
|
# default 5
|
||||||
SOCK_TIMEOUT_SECONDS=5
|
SOCK_TIMEOUT_SECONDS=5
|
||||||
|
|
||||||
# And the control port is?
|
# And the control port is?
|
||||||
CTLPORT=11000
|
CTLPORT=11000
|
||||||
|
|
||||||
|
|
||||||
# port for web interface
|
# port for web interface
|
||||||
WWW_PORT=11001
|
WWW_PORT=11001
|
||||||
#--- INADDR_ANY: 0x00000000
|
#--- INADDR_ANY: 0x00000000
|
||||||
|
|
|
@ -76,9 +76,11 @@
|
||||||
#include "lstnrmgr.h"
|
#include "lstnrmgr.h"
|
||||||
#include "dbmgr.h"
|
#include "dbmgr.h"
|
||||||
#include "addrinfo.h"
|
#include "addrinfo.h"
|
||||||
|
#include "devmgr.h"
|
||||||
|
|
||||||
static int s_nSpawns = 0;
|
static int s_nSpawns = 0;
|
||||||
static int g_maxsocks = -1;
|
static int g_maxsocks = -1;
|
||||||
|
static int g_udpsock = -1;
|
||||||
|
|
||||||
void
|
void
|
||||||
logf( XW_LogLevel level, const char* format, ... )
|
logf( XW_LogLevel level, const char* format, ... )
|
||||||
|
@ -334,6 +336,15 @@ denyConnection( const AddrInfo* addr, XWREASON err )
|
||||||
send_with_length_unsafe( addr, buf, sizeof(buf) );
|
send_with_length_unsafe( addr, buf, sizeof(buf) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
send_via_udp( int socket, const struct sockaddr *dest_addr,
|
||||||
|
const unsigned char* buf, int buflen )
|
||||||
|
{
|
||||||
|
ssize_t nSent = sendto( socket, buf, buflen,
|
||||||
|
0, /* flags */ dest_addr, sizeof(*dest_addr) );
|
||||||
|
return nSent;
|
||||||
|
}
|
||||||
|
|
||||||
/* No mutex here. Caller better be ensuring no other thread can access this
|
/* No mutex here. Caller better be ensuring no other thread can access this
|
||||||
* socket. */
|
* socket. */
|
||||||
bool
|
bool
|
||||||
|
@ -343,7 +354,7 @@ send_with_length_unsafe( const AddrInfo* addr, unsigned char* buf,
|
||||||
assert( !!addr );
|
assert( !!addr );
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
int socket = addr->socket();
|
int socket = addr->socket();
|
||||||
assert ( addr->isTCP() );
|
if ( addr->isTCP() ) {
|
||||||
unsigned short len = htons( bufLen );
|
unsigned short len = htons( bufLen );
|
||||||
ssize_t nSent = send( socket, &len, 2, 0 );
|
ssize_t nSent = send( socket, &len, 2, 0 );
|
||||||
if ( nSent == 2 ) {
|
if ( nSent == 2 ) {
|
||||||
|
@ -353,6 +364,20 @@ send_with_length_unsafe( const AddrInfo* addr, unsigned char* buf,
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t clientToken = addr->clientToken();
|
||||||
|
assert( 0 != clientToken );
|
||||||
|
unsigned char tmpbuf[1 + 1 + sizeof(clientToken) + bufLen];
|
||||||
|
tmpbuf[0] = XWREG_PROTO_VERSION;
|
||||||
|
tmpbuf[1] = XWRREG_MSG;
|
||||||
|
clientToken = htonl(clientToken);
|
||||||
|
memcpy( &tmpbuf[2], &clientToken, sizeof(clientToken) );
|
||||||
|
memcpy( &tmpbuf[2 + sizeof(clientToken)], buf, bufLen );
|
||||||
|
const struct sockaddr* saddr = addr->sockaddr();
|
||||||
|
send_via_udp( g_udpsock, saddr, tmpbuf, sizeof(tmpbuf) );
|
||||||
|
logf( XW_LOGINFO, "sent %d bytes on UDP socket %d", bufLen, socket );
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
if ( !ok ) {
|
if ( !ok ) {
|
||||||
logf( XW_LOGERROR, "%s(socket=%d) failed", __func__, socket );
|
logf( XW_LOGERROR, "%s(socket=%d) failed", __func__, socket );
|
||||||
|
@ -1046,6 +1071,94 @@ handle_proxy_packet( unsigned char* buf, int len, const AddrInfo* addr )
|
||||||
}
|
}
|
||||||
} /* handle_proxy_packet */
|
} /* handle_proxy_packet */
|
||||||
|
|
||||||
|
static void
|
||||||
|
registerDevice( const DevID* devID, const AddrInfo::AddrUnion* saddr )
|
||||||
|
{
|
||||||
|
DevIDRelay relayID;
|
||||||
|
if ( ID_TYPE_RELAY != devID->m_devIDType ) { // known to us; just update the time
|
||||||
|
relayID = DBMgr::Get()->RegisterDevice( devID );
|
||||||
|
if ( ID_TYPE_NONE != relayID ) {
|
||||||
|
// send it back to the device
|
||||||
|
char idbuf[9];
|
||||||
|
int len = snprintf( idbuf, sizeof(idbuf), "%.8X", relayID );
|
||||||
|
logf( XW_LOGERROR, "%s: len(%s) => %d", __func__, idbuf, len );
|
||||||
|
unsigned char buf[1 + 1 + 2 + len];
|
||||||
|
buf[0] = XWREG_PROTO_VERSION;
|
||||||
|
buf[1] = XWRREG_REGRSP;
|
||||||
|
short lenNBO = htons(len);
|
||||||
|
memcpy( &buf[2], &lenNBO, sizeof(lenNBO));
|
||||||
|
memcpy( &buf[4], idbuf, len );
|
||||||
|
send_via_udp( g_udpsock, &saddr->addr, buf, sizeof(buf) );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
relayID = devID->asRelayID();
|
||||||
|
}
|
||||||
|
// Now let's map the address to the devid for future sending purposes.
|
||||||
|
DevMgr::Get()->Remember( relayID, saddr );
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will need to be done in a thread before there can be simulaneous
|
||||||
|
// connections.
|
||||||
|
static void
|
||||||
|
handle_udp_packet( int udpsock )
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
logf( XW_LOGINFO, "%s()", __func__ );
|
||||||
|
unsigned char buf[512];
|
||||||
|
AddrInfo::AddrUnion saddr;
|
||||||
|
memset( &saddr, 0, sizeof(saddr) );
|
||||||
|
socklen_t fromlen = sizeof(saddr.addr_in);
|
||||||
|
|
||||||
|
ssize_t nRead = recvfrom( udpsock, buf, sizeof(buf), 0 /*flags*/,
|
||||||
|
&saddr.addr, &fromlen );
|
||||||
|
if ( 2 <= nRead ) {
|
||||||
|
unsigned char* ptr = buf;
|
||||||
|
unsigned char* end = buf + nRead;
|
||||||
|
logf( XW_LOGINFO, "%s: recvfrom=>%d", __func__, nRead );
|
||||||
|
|
||||||
|
unsigned char proto = *ptr++;
|
||||||
|
if ( XWREG_PROTO_VERSION != 0 ) {
|
||||||
|
logf( XW_LOGERROR, "unexpected proto %d", __func__, (int) proto );
|
||||||
|
} else {
|
||||||
|
int msg = *ptr++;
|
||||||
|
switch( msg ) {
|
||||||
|
case XWRREG_REG: {
|
||||||
|
DevIDType typ = (DevIDType)*ptr++;
|
||||||
|
unsigned short idLen;
|
||||||
|
if ( !getNetShort( &ptr, end, &idLen ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( end - ptr > idLen ) {
|
||||||
|
logf( XW_LOGERROR, "full devID not received" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DevID devID( typ );
|
||||||
|
devID.m_devIDString.append( (const char*)ptr, idLen );
|
||||||
|
ptr += idLen;
|
||||||
|
registerDevice( &devID, &saddr );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XWRREG_MSG: {
|
||||||
|
uint32_t clientToken;
|
||||||
|
memcpy( &clientToken, ptr, sizeof(clientToken) );
|
||||||
|
ptr += sizeof(clientToken);
|
||||||
|
clientToken = ntohl( clientToken );
|
||||||
|
if ( 0 != clientToken ) {
|
||||||
|
AddrInfo addr( udpsock, clientToken, &saddr );
|
||||||
|
success = processMessage( ptr, end - ptr, &addr );
|
||||||
|
} else {
|
||||||
|
logf( XW_LOGERROR, "%s: dropping packet with token of 0" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logf( XW_LOGERROR, "%s: unexpected msg %d", __func__, msg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logf( XW_LOGINFO, "%s()=>%d", __func__, success );
|
||||||
|
}
|
||||||
|
|
||||||
/* From stack overflow, toward a snprintf with an expanding buffer.
|
/* From stack overflow, toward a snprintf with an expanding buffer.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -1134,6 +1247,7 @@ main( int argc, char** argv )
|
||||||
{
|
{
|
||||||
int port = 0;
|
int port = 0;
|
||||||
int ctrlport = 0;
|
int ctrlport = 0;
|
||||||
|
int udpport = 0;
|
||||||
#ifdef DO_HTTP
|
#ifdef DO_HTTP
|
||||||
int httpport = 0;
|
int httpport = 0;
|
||||||
const char* cssFile = NULL;
|
const char* cssFile = NULL;
|
||||||
|
@ -1156,7 +1270,7 @@ main( int argc, char** argv )
|
||||||
first. */
|
first. */
|
||||||
|
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
int opt = getopt(argc, argv, "h?c:p:m:n:f:l:t:s:w:"
|
int opt = getopt(argc, argv, "h?c:p:m:n:f:l:t:s:u:w:"
|
||||||
"DF" );
|
"DF" );
|
||||||
|
|
||||||
if ( opt == -1 ) {
|
if ( opt == -1 ) {
|
||||||
|
@ -1210,6 +1324,9 @@ main( int argc, char** argv )
|
||||||
case 't':
|
case 't':
|
||||||
nWorkerThreads = atoi( optarg );
|
nWorkerThreads = atoi( optarg );
|
||||||
break;
|
break;
|
||||||
|
case 'u':
|
||||||
|
udpport = atoi( optarg );
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage( argv[0] );
|
usage( argv[0] );
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
|
@ -1232,6 +1349,9 @@ main( int argc, char** argv )
|
||||||
if ( ctrlport == 0 ) {
|
if ( ctrlport == 0 ) {
|
||||||
(void)cfg->GetValueFor( "CTLPORT", &ctrlport );
|
(void)cfg->GetValueFor( "CTLPORT", &ctrlport );
|
||||||
}
|
}
|
||||||
|
if ( 0 == udpport ) {
|
||||||
|
(void)cfg->GetValueFor( "UDPPORT", &udpport );
|
||||||
|
}
|
||||||
#ifdef DO_HTTP
|
#ifdef DO_HTTP
|
||||||
if ( httpport == 0 ) {
|
if ( httpport == 0 ) {
|
||||||
(void)cfg->GetValueFor( "WWW_PORT", &httpport );
|
(void)cfg->GetValueFor( "WWW_PORT", &httpport );
|
||||||
|
@ -1371,6 +1491,19 @@ main( int argc, char** argv )
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( 0 != udpport ) {
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
g_udpsock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||||
|
saddr.sin_family = PF_INET;
|
||||||
|
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
saddr.sin_port = htons(udpport);
|
||||||
|
int err = bind( g_udpsock, (struct sockaddr*)&saddr, sizeof(saddr) );
|
||||||
|
if ( 0 != err ) {
|
||||||
|
logf( XW_LOGERROR, "bind()=>%s", strerror(errno) );
|
||||||
|
g_udpsock = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DO_HTTP
|
#ifdef DO_HTTP
|
||||||
HttpState http_state;
|
HttpState http_state;
|
||||||
int addr;
|
int addr;
|
||||||
|
@ -1404,6 +1537,9 @@ main( int argc, char** argv )
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
g_listeners.AddToFDSet( &rfds );
|
g_listeners.AddToFDSet( &rfds );
|
||||||
FD_SET( g_control, &rfds );
|
FD_SET( g_control, &rfds );
|
||||||
|
if ( -1 != g_udpsock ) {
|
||||||
|
FD_SET( g_udpsock, &rfds );
|
||||||
|
}
|
||||||
#ifdef DO_HTTP
|
#ifdef DO_HTTP
|
||||||
if ( -1 != g_http ) {
|
if ( -1 != g_http ) {
|
||||||
FD_SET( g_http, &rfds );
|
FD_SET( g_http, &rfds );
|
||||||
|
@ -1413,6 +1549,9 @@ main( int argc, char** argv )
|
||||||
if ( g_control > highest ) {
|
if ( g_control > highest ) {
|
||||||
highest = g_control;
|
highest = g_control;
|
||||||
}
|
}
|
||||||
|
if ( g_udpsock > highest ) {
|
||||||
|
highest = g_udpsock;
|
||||||
|
}
|
||||||
#ifdef DO_HTTP
|
#ifdef DO_HTTP
|
||||||
if ( g_http > highest ) {
|
if ( g_http > highest ) {
|
||||||
highest = g_http;
|
highest = g_http;
|
||||||
|
@ -1458,7 +1597,7 @@ main( int argc, char** argv )
|
||||||
"%s: accepting connection from %s on socket %d",
|
"%s: accepting connection from %s on socket %d",
|
||||||
__func__, inet_ntoa(saddr.addr_in.sin_addr), newSock );
|
__func__, inet_ntoa(saddr.addr_in.sin_addr), newSock );
|
||||||
|
|
||||||
AddrInfo addr( true, newSock, &saddr );
|
AddrInfo addr( newSock, &saddr );
|
||||||
tPool->AddSocket( perGame ? XWThreadPool::STYPE_GAME
|
tPool->AddSocket( perGame ? XWThreadPool::STYPE_GAME
|
||||||
: XWThreadPool::STYPE_PROXY,
|
: XWThreadPool::STYPE_PROXY,
|
||||||
&addr );
|
&addr );
|
||||||
|
@ -1471,6 +1610,12 @@ main( int argc, char** argv )
|
||||||
// run_ctrl_thread( g_control );
|
// run_ctrl_thread( g_control );
|
||||||
--retval;
|
--retval;
|
||||||
}
|
}
|
||||||
|
if ( FD_ISSET( g_udpsock, &rfds ) ) {
|
||||||
|
// This will need to be done in a separate thread, or pushed
|
||||||
|
// to the existing thread pool
|
||||||
|
handle_udp_packet( g_udpsock );
|
||||||
|
--retval;
|
||||||
|
}
|
||||||
#ifdef DO_HTTP
|
#ifdef DO_HTTP
|
||||||
if ( FD_ISSET( g_http, &rfds ) ) {
|
if ( FD_ISSET( g_http, &rfds ) ) {
|
||||||
FD_CLR( g_http, &rfds );
|
FD_CLR( g_http, &rfds );
|
||||||
|
|
|
@ -27,6 +27,37 @@
|
||||||
/* Set if device is acting a server; cleared if as client */
|
/* Set if device is acting a server; cleared if as client */
|
||||||
#define FLAGS_SERVER_BIT 0x01
|
#define FLAGS_SERVER_BIT 0x01
|
||||||
|
|
||||||
|
/* message types for the udp-based per-device (not per-game) protocol */
|
||||||
|
#define XWREG_PROTO_VERSION 0
|
||||||
|
#ifndef CANT_DO_TYPEDEF
|
||||||
|
typedef
|
||||||
|
#endif
|
||||||
|
enum { XWRREG_NONE /* 0 is an illegal value */
|
||||||
|
,XWRREG_REG /* dev->relay: device registers self and
|
||||||
|
self-selected (e.g. gcm) or assigned devid
|
||||||
|
format: proto: 1; this enum: 1; idType: 1,
|
||||||
|
idLen: 2, id: <idLen> */
|
||||||
|
|
||||||
|
,XWRREG_REGRSP /* relay->device: if non-relay-assigned devid
|
||||||
|
type was given, this gives the
|
||||||
|
relay-assigned one to be used from now on.
|
||||||
|
format: proto: 1, this enum: 1, idLen: 2, id: <idLen>
|
||||||
|
*/
|
||||||
|
|
||||||
|
,XWRREG_PING /* device->relay: keep the UDP connection
|
||||||
|
open. format: proto: 1, this enum: 1. */
|
||||||
|
|
||||||
|
,XWRREG_MSG /* dev->relay and relay->dev: norm: a message from a game to
|
||||||
|
the relay format: proto: 1, this enum: 1,
|
||||||
|
clientToken: 4, message<varies>*/
|
||||||
|
|
||||||
|
,XWRREG_MSGRSP /* relay->dev: conveys error on receipt of XWRREG_MSG */
|
||||||
|
}
|
||||||
|
#ifndef CANT_DO_TYPEDEF
|
||||||
|
XWRelayReg
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
#ifndef CANT_DO_TYPEDEF
|
#ifndef CANT_DO_TYPEDEF
|
||||||
typedef
|
typedef
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,6 +58,7 @@ cid integer
|
||||||
,mtimes TIMESTAMP(0)[]
|
,mtimes TIMESTAMP(0)[]
|
||||||
,addrs INET[]
|
,addrs INET[]
|
||||||
,devids INTEGER[]
|
,devids INTEGER[]
|
||||||
|
,tokens INTEGER[]
|
||||||
);
|
);
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,14 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "lstnrmgr.h"
|
#include "lstnrmgr.h"
|
||||||
#include "xwrelay.h"
|
#include "xwrelay.h"
|
||||||
#include "addrinfo.h"
|
#include "addrinfo.h"
|
||||||
|
|
||||||
typedef unsigned char HostID; /* see HOST_ID_SERVER */
|
typedef unsigned char HostID; /* see HOST_ID_SERVER */
|
||||||
|
typedef uint32_t DevIDRelay;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
XW_LOGERROR
|
XW_LOGERROR
|
||||||
|
|
Loading…
Reference in a new issue