From c75ecef2406c09cad8a864983c5608b7d8851213 Mon Sep 17 00:00:00 2001 From: Eric House Date: Tue, 29 Jan 2013 07:42:10 -0800 Subject: [PATCH] test deletion of games and generation of anonymous relayIDs --- xwords4/linux/cursesmain.c | 12 ++++++--- xwords4/linux/gamesdb.c | 7 ++++-- xwords4/linux/gamesdb.h | 2 +- xwords4/linux/gtkboard.c | 11 +++++--- xwords4/linux/gtkboard.h | 2 +- xwords4/linux/gtkmain.c | 42 +++++++++++++++++++++---------- xwords4/linux/linuxmain.c | 47 +++++++++++++++++++++-------------- xwords4/linux/linuxmain.h | 1 + xwords4/linux/linuxutl.c | 14 ++--------- xwords4/linux/main.h | 4 ++- xwords4/linux/relaycon.c | 51 ++++++++++++++++++++++++++++++++------ xwords4/linux/relaycon.h | 2 ++ 12 files changed, 132 insertions(+), 63 deletions(-) diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index 30225616f..3e6937ca3 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1769,14 +1769,18 @@ static void cursesDevIDChanged( void* closure, const XP_UCHAR* devID ) { CursesAppGlobals* globals = (CursesAppGlobals*)closure; - sqlite3* pDb = globals->cGlobals.pDb; + CommonGlobals* cGlobals = &globals->cGlobals; + sqlite3* pDb = cGlobals->pDb; if ( !!devID ) { XP_LOGF( "%s(devID=%s)", __func__, devID ); db_store( pDb, KEY_RDEVID, devID ); } else { XP_LOGF( "%s: bad relayid", __func__ ); db_remove( pDb, KEY_RDEVID ); - sendRelayReg( globals->cGlobals.params, pDb ); + + DevIDType typ; + const XP_UCHAR* devID = linux_getDevID( cGlobals->params, &typ ); + relaycon_reg( cGlobals->params, devID, typ ); } } @@ -1945,7 +1949,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) relaycon_init( params, &procs, &g_globals, params->connInfo.relay.relayName, params->connInfo.relay.defaultSendPort ); - sendRelayReg( params, g_globals.cGlobals.pDb ); + DevIDType typ; + const XP_UCHAR* devID = linux_getDevID( params, &typ ); + relaycon_reg( params, devID, typ ); GSList* games = listGames( g_globals.cGlobals.pDb ); if ( !!games ) { diff --git a/xwords4/linux/gamesdb.c b/xwords4/linux/gamesdb.c index d29e16b21..8107e7c0d 100644 --- a/xwords4/linux/gamesdb.c +++ b/xwords4/linux/gamesdb.c @@ -247,9 +247,10 @@ db_store( sqlite3* pDb, const gchar* key, const gchar* value ) sqlite3_finalize( ppStmt ); } -void +XP_Bool db_fetch( sqlite3* pDb, const gchar* key, gchar* buf, gint buflen ) { + XP_Bool found; char query[256]; snprintf( query, sizeof(query), "SELECT value from pairs where key = '%s'", key ); @@ -257,12 +258,14 @@ db_fetch( sqlite3* pDb, const gchar* key, gchar* buf, gint buflen ) int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL ); XP_ASSERT( SQLITE_OK == result ); result = sqlite3_step( ppStmt ); - if ( SQLITE_ROW == result ) { + found = SQLITE_ROW == result; + if ( found ) { getColumnText( ppStmt, 0, buf, buflen ); } else { buf[0] = '\0'; } sqlite3_finalize( ppStmt ); + return found; } void diff --git a/xwords4/linux/gamesdb.h b/xwords4/linux/gamesdb.h index 3272c3c20..2d34f96e3 100644 --- a/xwords4/linux/gamesdb.h +++ b/xwords4/linux/gamesdb.h @@ -52,7 +52,7 @@ void deleteGame( sqlite3* pDb, sqlite3_int64 rowid ); #define KEY_RDEVID "RDEVID" void db_store( sqlite3* dbp, const gchar* key, const gchar* value ); -void db_fetch( sqlite3* dbp, const gchar* key, gchar* buf, gint buflen ); +XP_Bool db_fetch( sqlite3* dbp, const gchar* key, gchar* buf, gint buflen ); void db_remove( sqlite3* dbp, const gchar* key ); #endif diff --git a/xwords4/linux/gtkboard.c b/xwords4/linux/gtkboard.c index baa6fa1c6..65a38c117 100644 --- a/xwords4/linux/gtkboard.c +++ b/xwords4/linux/gtkboard.c @@ -310,9 +310,11 @@ relay_status_gtk( void* closure, CommsRelayState state ) { XP_LOGF( "%s got status: %s", __func__, CommsRelayState2Str(state) ); GtkGameGlobals* globals = (GtkGameGlobals*)closure; - globals->cGlobals.state = state; - globals->stateChar = 'A' + COMMS_RELAYSTATE_ALLCONNECTED - state; - draw_gtk_status( globals->draw, globals->stateChar ); + if ( !!globals->draw ) { + globals->cGlobals.state = state; + globals->stateChar = 'A' + COMMS_RELAYSTATE_ALLCONNECTED - state; + draw_gtk_status( globals->draw, globals->stateChar ); + } } static void @@ -2570,9 +2572,10 @@ freeGlobals( GtkGameGlobals* globals ) XP_Bool loadGameNoDraw( GtkGameGlobals* globals, LaunchParams* params, - sqlite3* pDb, sqlite3_int64 rowid ) + sqlite3_int64 rowid ) { LOG_FUNC(); + sqlite3* pDb = params->pDb; initGlobalsNoDraw( globals, params ); TransportProcs procs; diff --git a/xwords4/linux/gtkboard.h b/xwords4/linux/gtkboard.h index 29436c4f5..5bffc2481 100644 --- a/xwords4/linux/gtkboard.h +++ b/xwords4/linux/gtkboard.h @@ -170,7 +170,7 @@ void initGlobals( GtkGameGlobals* globals, LaunchParams* params ); void freeGlobals( GtkGameGlobals* globals ); XP_Bool makeNewGame( GtkGameGlobals* globals ); XP_Bool loadGameNoDraw( GtkGameGlobals* globals, LaunchParams* params, - sqlite3* pDb, sqlite3_int64 rowid ); + sqlite3_int64 rowid ); void destroy_board_window( GtkWidget* widget, GtkGameGlobals* globals ); #endif /* PLATFORM_GTK */ diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index 1f381f394..cc3065f3b 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -208,7 +208,7 @@ handle_newgame_button( GtkWidget* XP_UNUSED(widget), void* closure ) freeGlobals( globals ); } else { GtkWidget* gameWindow = globals->window; - globals->cGlobals.pDb = apg->pDb; + globals->cGlobals.pDb = apg->params->pDb; globals->cGlobals.selRow = -1; recordOpened( apg, globals ); gtk_widget_show( gameWindow ); @@ -224,7 +224,7 @@ handle_open_button( GtkWidget* XP_UNUSED(widget), void* closure ) apg->params->needsNewGame = XP_FALSE; GtkGameGlobals* globals = malloc( sizeof(*globals) ); initGlobals( globals, apg->params ); - globals->cGlobals.pDb = apg->pDb; + globals->cGlobals.pDb = apg->params->pDb; globals->cGlobals.selRow = selRow; recordOpened( apg, globals ); gtk_widget_show( globals->window ); @@ -235,11 +235,20 @@ static void handle_delete_button( GtkWidget* XP_UNUSED(widget), void* closure ) { GtkAppGlobals* apg = (GtkAppGlobals*)closure; + LaunchParams* params = apg->params; guint len = apg->selRows->len; for ( guint ii = 0; ii < len; ++ii ) { sqlite3_int64 rowid = g_array_index( apg->selRows, sqlite3_int64, ii ); removeRow( apg, rowid ); - deleteGame( apg->pDb, rowid ); + deleteGame( params->pDb, rowid ); + + XP_UCHAR devIDBuf[64] = {0}; + db_fetch( params->pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) ); + if ( '\0' != devIDBuf[0] ) { + relaycon_deleted( params, devIDBuf, rowid ); + } else { + XP_LOGF( "%s: not calling relaycon_deleted: no relayID", __func__ ); + } } apg->selRows = g_array_set_size( apg->selRows, 0 ); updateButtons( apg ); @@ -301,7 +310,7 @@ makeGamesWindow( GtkAppGlobals* apg ) gtk_widget_show( list ); - GSList* games = listGames( apg->pDb ); + GSList* games = listGames( apg->params->pDb ); for ( GSList* iter = games; !!iter; iter = iter->next ) { sqlite3_int64* rowid = (sqlite3_int64*)iter->data; onNewData( apg, *rowid, XP_TRUE ); @@ -346,7 +355,7 @@ static void onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid, XP_Bool isNew ) { GameInfo gib; - if ( getGameInfo( apg->pDb, rowid, &gib ) ) { + if ( getGameInfo( apg->params->pDb, rowid, &gib ) ) { add_to_list( apg->listWidget, rowid, isNew, &gib ); } } @@ -400,7 +409,7 @@ gtkGotBuf( void* closure, const XP_U8* buf, XP_U16 len ) gameGotBuf( &globals->cGlobals, XP_TRUE, buf, len ); } else { GtkGameGlobals tmpGlobals; - if ( loadGameNoDraw( &tmpGlobals, apg->params, apg->pDb, gameToken ) ) { + if ( loadGameNoDraw( &tmpGlobals, apg->params, gameToken ) ) { gameGotBuf( &tmpGlobals.cGlobals, XP_FALSE, buf, len ); saveGame( &tmpGlobals.cGlobals ); } @@ -413,7 +422,7 @@ requestMsgs( gpointer data ) { GtkAppGlobals* apg = (GtkAppGlobals*)data; XP_UCHAR devIDBuf[64] = {0}; - db_fetch( apg->pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) ); + db_fetch( apg->params->pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) ); if ( '\0' != devIDBuf[0] ) { relaycon_requestMsgs( apg->params, devIDBuf ); } else { @@ -434,13 +443,17 @@ static void gtkDevIDChanged( void* closure, const XP_UCHAR* devID ) { GtkAppGlobals* apg = (GtkAppGlobals*)closure; + LaunchParams* params = apg->params; if ( !!devID ) { XP_LOGF( "%s(devID=%s)", __func__, devID ); - db_store( apg->pDb, KEY_RDEVID, devID ); + db_store( params->pDb, KEY_RDEVID, devID ); } else { XP_LOGF( "%s: bad relayid", __func__ ); - db_remove( apg->pDb, KEY_RDEVID ); - sendRelayReg( apg->params, apg->pDb ); + db_remove( params->pDb, KEY_RDEVID ); + + DevIDType typ; + const XP_UCHAR* devID = linux_getDevID( params, &typ ); + relaycon_reg( params, devID, typ ); } } @@ -494,7 +507,7 @@ gtkmain( LaunchParams* params ) apg.selRows = g_array_new( FALSE, FALSE, sizeof( sqlite3_int64 ) ); apg.params = params; - apg.pDb = openGamesDB( params->dbName ); + params->pDb = openGamesDB( params->dbName ); RelayConnProcs procs = { .msgReceived = gtkGotBuf, @@ -507,12 +520,15 @@ gtkmain( LaunchParams* params ) relaycon_init( params, &procs, &apg, params->connInfo.relay.relayName, params->connInfo.relay.defaultSendPort ); - sendRelayReg( params, apg.pDb ); + + DevIDType typ; + const XP_UCHAR* devID = linux_getDevID( params, &typ ); + relaycon_reg( params, devID, typ ); apg.window = makeGamesWindow( &apg ); gtk_main(); - closeGamesDB( apg.pDb ); + closeGamesDB( params->pDb ); relaycon_cleanup( params ); return 0; diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 8d5a28b99..ce9ff07c6 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -580,7 +580,8 @@ setOneSecondTimer( CommonGlobals* cGlobals ) #endif typedef enum { - CMD_SKIP_GAMEOVER + CMD_HELP + ,CMD_SKIP_GAMEOVER ,CMD_SHOW_OTHERSCORES ,CMD_HOSTIP ,CMD_DICT @@ -595,6 +596,7 @@ typedef enum { #ifdef XWFEATURE_DEVID ,CMD_DEVID ,CMD_RDEVID + ,CMD_NOANONDEVID #endif ,CMD_GAMESEED ,CMD_GAMEFILE @@ -678,7 +680,8 @@ typedef struct _CmdInfoRec { } CmdInfoRec; static CmdInfoRec CmdInfoRecs[] = { - { CMD_SKIP_GAMEOVER, false, "skip-final", "skip final scores display" } + { CMD_HELP, false, "help", "print usage" } + ,{ CMD_SKIP_GAMEOVER, false, "skip-final", "skip final scores display" } ,{ CMD_SHOW_OTHERSCORES, false, "show-other", "show robot/remote scores" } ,{ CMD_HOSTIP, true, "hostip", "remote host ip address (for direct connect)" } ,{ CMD_DICT, true, "game-dict", "dictionary name for game" } @@ -693,6 +696,8 @@ static CmdInfoRec CmdInfoRecs[] = { #ifdef XWFEATURE_DEVID ,{ CMD_DEVID, true, "devid", "device ID (for testing GCM stuff)" } ,{ CMD_RDEVID, true, "rdevid", "relay's converted device ID (for testing GCM stuff)" } + ,{CMD_NOANONDEVID, false, "no-anon-devid", + "override default of using anonymous devid registration when no id provided" } #endif ,{ CMD_GAMESEED, true, "game-seed", "game seed (for relay play)" } ,{ CMD_GAMEFILE, true, "file", "file to save to/read from" } @@ -851,24 +856,28 @@ linShiftFocus( CommonGlobals* cGlobals, XP_Key key, const BoardObjectType* order } /* linShiftFocus */ #endif -void -sendRelayReg( LaunchParams* params, sqlite3* pDb ) +const XP_UCHAR* +linux_getDevID( LaunchParams* params, DevIDType* typ ) { - XP_UCHAR devIDBuf[64] = {0}; - XP_UCHAR* devID; - DevIDType typ = ID_TYPE_RELAY; + const XP_UCHAR* result = NULL; + + /* commandline takes precedence over stored values */ + if ( !!params->rDevID ) { - devID = params->rDevID; - } else { - db_fetch( pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) ); - if ( '\0' != devIDBuf[0] ) { - devID = devIDBuf; - } else { - devID = params->devID; - typ = ID_TYPE_LINUX; - } + result = params->rDevID; + *typ = ID_TYPE_RELAY; + } else if ( !!params->devID ) { + result = params->devID; + *typ = ID_TYPE_LINUX; + } else if ( db_fetch( params->pDb, KEY_RDEVID, params->devIDStore, + sizeof(params->devIDStore) ) ) { + result = params->devIDStore; + *typ = ID_TYPE_RELAY; + } else if ( !params->noAnonDevid ) { + *typ = ID_TYPE_ANON; + result = ""; } - relaycon_reg( params, devID, typ ); + return result; } #ifdef XWFEATURE_RELAY @@ -1843,7 +1852,7 @@ main( int argc, char** argv ) short index; opt = getopt_long_only( argc, argv, "", longopts, NULL ); switch ( opt ) { - case '?': + case CMD_HELP: usage(argv[0], NULL); break; case CMD_SKIP_GAMEOVER: @@ -1906,6 +1915,8 @@ main( int argc, char** argv ) case CMD_RDEVID: mainParams.rDevID = optarg; break; + case CMD_NOANONDEVID: + mainParams.noAnonDevid = true; #endif case CMD_GAMESEED: mainParams.gameSeed = atoi(optarg); diff --git a/xwords4/linux/linuxmain.h b/xwords4/linux/linuxmain.h index 88a9681c4..7429b2fe2 100644 --- a/xwords4/linux/linuxmain.h +++ b/xwords4/linux/linuxmain.h @@ -106,6 +106,7 @@ void gameGotBuf( CommonGlobals* globals, XP_Bool haveDraw, const XP_U8* buf, XP_U16 len ); gboolean app_socket_proc( GIOChannel* source, GIOCondition condition, gpointer data ); +const XP_UCHAR* linux_getDevID( LaunchParams* params, DevIDType* typ ); /* void initParams( LaunchParams* params ); */ /* void freeParams( LaunchParams* params ); */ diff --git a/xwords4/linux/linuxutl.c b/xwords4/linux/linuxutl.c index 4cfba5a22..786ba8eb6 100644 --- a/xwords4/linux/linuxutl.c +++ b/xwords4/linux/linuxutl.c @@ -32,6 +32,7 @@ #include "linuxutl.h" #include "main.h" #include "linuxdict.h" +#include "linuxmain.h" #include "LocalizedStrIncludes.h" #ifdef DEBUG @@ -349,19 +350,8 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code ) static const XP_UCHAR* linux_util_getDevID( XW_UtilCtxt* uc, DevIDType* typ ) { - XP_UCHAR* result; CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; - if ( !!cGlobals->params->rDevID ) { - *typ = ID_TYPE_RELAY; - result = cGlobals->params->rDevID; - } else if ( !!cGlobals->params->devID ) { - *typ = ID_TYPE_LINUX; - result = cGlobals->params->devID; - } else { - *typ = ID_TYPE_NONE; - result = NULL; - } - return result; + return linux_getDevID( cGlobals->params, typ ); } static void diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h index d3b22c4e1..b28f26b36 100644 --- a/xwords4/linux/main.h +++ b/xwords4/linux/main.h @@ -55,6 +55,7 @@ typedef struct LaunchParams { GSList* dictDirs; char* fileName; char* dbName; + sqlite3* pDb; /* null unless opened */ XP_U16 saveFailPct; const XP_UCHAR* playerDictNames[MAX_NUM_PLAYERS]; #ifdef USE_SQLITE @@ -68,6 +69,8 @@ typedef struct LaunchParams { #ifdef XWFEATURE_DEVID char* devID; char* rDevID; + XP_Bool noAnonDevid; + XP_UCHAR devIDStore[16]; #endif VTableMgr* vtMgr; XP_U16 nLocalPlayers; @@ -231,7 +234,6 @@ typedef struct _SourceData { } SourceData; typedef struct _GtkAppGlobals { - sqlite3* pDb; GArray* selRows; LaunchParams* params; GSList* globalsList; diff --git a/xwords4/linux/relaycon.c b/xwords4/linux/relaycon.c index cc672aa69..4c3aaf753 100644 --- a/xwords4/linux/relaycon.c +++ b/xwords4/linux/relaycon.c @@ -43,8 +43,11 @@ static ssize_t sendIt( RelayConStorage* storage, const XP_U8* msgbuf, XP_U16 len static size_t addStrWithLength( XP_U8* buf, XP_U8* end, const XP_UCHAR* str ); static void getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf ); static XP_U16 getNetShort( const XP_U8** ptr ); +static XP_U32 getNetLong( const XP_U8** ptr ); static int writeHeader( XP_U8* dest, XWRelayReg cmd ); static bool readHeader( const XP_U8** buf, MsgHeader* header ); +static size_t writeDevID( XP_U8* buf, size_t len, const XP_UCHAR* str ); + void relaycon_init( LaunchParams* params, const RelayConnProcs* procs, @@ -73,15 +76,10 @@ relaycon_reg( LaunchParams* params, const XP_UCHAR* devID, DevIDType typ ) int indx = 0; RelayConStorage* storage = getStorage( params ); - XP_ASSERT( !!devID ); - XP_U16 idLen = XP_STRLEN( devID ); - XP_U16 lenNBO = XP_HTONS( idLen ); + XP_ASSERT( !!devID || typ == ID_TYPE_ANON ); indx += writeHeader( tmpbuf, XWPDEV_REG ); tmpbuf[indx++] = typ; - XP_MEMCPY( &tmpbuf[indx], &lenNBO, sizeof(lenNBO) ); - indx += sizeof(lenNBO); - XP_MEMCPY( &tmpbuf[indx], devID, idLen ); - indx += idLen; + indx += writeDevID( &tmpbuf[indx], sizeof(tmpbuf) - indx, devID ); sendIt( storage, tmpbuf, indx ); } @@ -154,6 +152,23 @@ relaycon_requestMsgs( LaunchParams* params, const XP_UCHAR* devID ) sendIt( storage, tmpbuf, indx ); } +void +relaycon_deleted( LaunchParams* params, const XP_UCHAR* devID, + XP_U32 gameToken ) +{ + LOG_FUNC(); + RelayConStorage* storage = getStorage( params ); + XP_U8 tmpbuf[128]; + int indx = 0; + indx += writeHeader( tmpbuf, XWPDEV_DELGAME ); + indx += writeDevID( &tmpbuf[indx], sizeof(tmpbuf) - indx, devID ); + gameToken = htonl( gameToken ); + memcpy( &tmpbuf[indx], &gameToken, sizeof(gameToken) ); + indx += sizeof( gameToken ); + + sendIt( storage, tmpbuf, indx ); +} + static void sendAckIf( RelayConStorage* storage, const MsgHeader* header ) { @@ -214,6 +229,11 @@ relaycon_receive( void* closure, int socket ) (*storage->procs.msgErrorMsg)( storage->procsClosure, buf ); break; } + case XWPDEV_ACK: { + XP_U32 packetID = getNetLong( &ptr ); + XP_LOGF( "got ack for packetID %ld", packetID ); + break; + } default: XP_LOGF( "%s: Unexpected cmd %d", __func__, header.cmd ); XP_ASSERT( 0 ); @@ -273,7 +293,7 @@ sendIt( RelayConStorage* storage, const XP_U8* msgbuf, XP_U16 len ) static size_t addStrWithLength( XP_U8* buf, XP_U8* end, const XP_UCHAR* str ) { - XP_U16 len = XP_STRLEN( str ); + XP_U16 len = !!str? XP_STRLEN( str ) : 0; if ( buf + len + sizeof(len) <= end ) { XP_U16 lenNBO = htons( len ); XP_MEMCPY( buf, &lenNBO, sizeof(lenNBO) ); @@ -283,6 +303,12 @@ addStrWithLength( XP_U8* buf, XP_U8* end, const XP_UCHAR* str ) return len + sizeof(len); } +static size_t +writeDevID( XP_U8* buf, size_t len, const XP_UCHAR* str ) +{ + return addStrWithLength( buf, buf + len, str ); +} + static XP_U16 getNetShort( const XP_U8** ptr ) { @@ -292,6 +318,15 @@ getNetShort( const XP_U8** ptr ) return ntohs( result ); } +static XP_U32 +getNetLong( const XP_U8** ptr ) +{ + XP_U32 result; + memcpy( &result, *ptr, sizeof(result) ); + *ptr += sizeof(result); + return ntohl( result ); +} + static void getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf ) { diff --git a/xwords4/linux/relaycon.h b/xwords4/linux/relaycon.h index f2498c519..8b21f6df5 100644 --- a/xwords4/linux/relaycon.h +++ b/xwords4/linux/relaycon.h @@ -40,6 +40,8 @@ XP_S16 relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen, XP_S16 relaycon_sendnoconn( LaunchParams* params, const XP_U8* buf, XP_U16 buflen, const XP_UCHAR* relayID, XP_U32 gameToken ); void relaycon_requestMsgs( LaunchParams* params, const XP_UCHAR* devID ); +void relaycon_deleted( LaunchParams* params, const XP_UCHAR* devID, + XP_U32 gameToken ); void relaycon_cleanup( LaunchParams* params ); #endif