+ if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "delete rte skipped: %s\n", ts_field );
+ }
+}
+
+/*
+ Given the tokens from an mme_ar (meid add/replace) entry, add the entries.
+ the 'owner' which should be the dns name or IP address of an enpoint
+ the meid_list is a space separated list of me IDs
+
+ This function assumes the caller has vetted the pointers as needed.
+
+ For each meid in the list, an entry is pushed into the hash which references the owner
+ endpoint such that when the meid is used to route a message it references the endpoint
+ to send messages to.
+*/
+static void parse_meid_ar( route_table_t* rtab, char* owner, char* meid_list, int vlevel ) {
+ char* tok;
+ int ntoks;
+ char* tokens[128];
+ int i;
+ int state;
+ endpoint_t* ep; // endpoint struct for the owner
+
+ owner = clip( owner ); // ditch extra whitespace and trailing comments
+ meid_list = clip( meid_list );
+
+ ntoks = uta_tokenise( meid_list, tokens, 128, ' ' );
+ for( i = 0; i < ntoks; i++ ) {
+ if( (ep = rt_ensure_ep( rtab, owner )) != NULL ) {
+ state = rmr_sym_put( rtab->hash, tokens[i], RT_ME_SPACE, ep ); // slam this one in if new; replace if there
+ if( DEBUG || (vlevel > 1) ) rmr_vlog_force( RMR_VL_DEBUG, "parse_meid_ar: add/replace meid: %s owned by: %s state=%d\n", tokens[i], owner, state );
+ } else {
+ rmr_vlog( RMR_VL_WARN, "rmr parse_meid_ar: unable to create an endpoint for owner: %s", owner );
+ }
+ }
+}
+
+/*
+ Given the tokens from an mme_del, delete the listed meid entries from the new
+ table. The list is a space separated list of meids.
+
+ The meids in the hash reference endpoints which are never deleted and so
+ the only thing that we need to do here is to remove the meid from the hash.
+
+ This function assumes the caller has vetted the pointers as needed.
+*/
+static void parse_meid_del( route_table_t* rtab, char* meid_list, int vlevel ) {
+ char* tok;
+ int ntoks;
+ char* tokens[128];
+ int i;
+
+ if( rtab->hash == NULL ) {
+ return;
+ }
+
+ meid_list = clip( meid_list );
+
+ ntoks = uta_tokenise( meid_list, tokens, 128, ' ' );
+ for( i = 0; i < ntoks; i++ ) {
+ rmr_sym_del( rtab->hash, tokens[i], RT_ME_SPACE ); // and it only took my little finger to blow it away!
+ if( DEBUG || (vlevel > 1) ) rmr_vlog_force( RMR_VL_DEBUG, "parse_meid_del: meid deleted: %s\n", tokens[i] );
+ }
+}
+
+/*
+ Parse a partially parsed meid record. Tokens[0] should be one of:
+ meid_map, mme_ar, mme_del.
+*/
+static void meid_parser( uta_ctx_t* ctx, char** tokens, int ntoks, int vlevel ) {
+ if( tokens == NULL || ntoks < 1 ) {
+ return; // silent but should never happen
+ }
+
+ if( ntoks < 2 ) { // must have at least two for any valid request record
+ rmr_vlog( RMR_VL_ERR, "meid_parse: not enough tokens on %s record\n", tokens[0] );
+ return;
+ }
+
+ if( strcmp( tokens[0], "meid_map" ) == 0 ) { // start or end of the meid map update
+ tokens[1] = clip( tokens[1] );
+ if( *(tokens[1]) == 's' ) {
+ if( ctx->new_rtable != NULL ) { // one in progress? this forces it out
+ if( DEBUG > 1 || (vlevel > 1) ) rmr_vlog_force( RMR_VL_DEBUG, "meid map start: dropping incomplete table\n" );
+ uta_rt_drop( ctx->new_rtable );
+ }
+
+ ctx->new_rtable = uta_rt_clone_all( ctx->rtable ); // start with a clone of everything (mtype, endpoint refs and meid)
+ ctx->new_rtable->mupdates = 0;
+ if( DEBUG || (vlevel > 1) ) rmr_vlog_force( RMR_VL_DEBUG, "meid_parse: meid map start found\n" );
+ } else {
+ if( strcmp( tokens[1], "end" ) == 0 ) { // wrap up the table we were building
+ if( ntoks > 2 ) { // meid_map | end | <count> |??? given
+ if( ctx->new_rtable->mupdates != atoi( tokens[2] ) ) { // count they added didn't match what we received
+ rmr_vlog( RMR_VL_ERR, "meid_parse: meid map update had wrong number of records: received %d expected %s\n", ctx->new_rtable->mupdates, tokens[2] );
+ uta_rt_drop( ctx->new_rtable );
+ ctx->new_rtable = NULL;
+ return;
+ }
+
+ if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "meid_parse: meid map update ended; found expected number of entries: %s\n", tokens[2] );
+ }
+
+ if( ctx->new_rtable ) {
+ uta_rt_drop( ctx->old_rtable ); // time to drop one that was previously replaced
+ ctx->old_rtable = ctx->rtable; // currently active becomes old and allowed to 'drain'
+ ctx->rtable = ctx->new_rtable; // one we've been adding to becomes active
+ ctx->new_rtable = NULL;
+ if( DEBUG > 1 || (vlevel > 1) ) rmr_vlog_force( RMR_VL_DEBUG, "end of meid map noticed\n" );
+
+ if( vlevel > 0 ) {
+ rmr_vlog_force( RMR_VL_DEBUG, "old route table:\n" );
+ rt_stats( ctx->old_rtable );
+ rmr_vlog_force( RMR_VL_DEBUG, "new route table:\n" );
+ rt_stats( ctx->rtable );
+ }
+ } else {
+ if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "end of meid map noticed, but one was not started!\n" );
+ ctx->new_rtable = NULL;
+ }
+ }
+ }
+
+ return;
+ }
+
+ if( ! ctx->new_rtable ) { // for any other mmap entries, there must be a table in progress or we punt
+ if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "meid update/delte (%s) encountered, but table update not started\n", tokens[0] );
+ return;
+ }
+
+ if( strcmp( tokens[0], "mme_ar" ) == 0 ) {
+ if( ntoks < 3 || tokens[1] == NULL || tokens[2] == NULL ) {
+ rmr_vlog( RMR_VL_ERR, "meid_parse: mme_ar record didn't have enough tokens found %d\n", ntoks );
+ return;
+ }
+ parse_meid_ar( ctx->new_rtable, tokens[1], tokens[2], vlevel );
+ ctx->new_rtable->mupdates++;
+ }
+
+ if( strcmp( tokens[0], "mme_del" ) == 0 ) {
+ if( ntoks < 2 ) {
+ rmr_vlog( RMR_VL_ERR, "meid_parse: mme_del record didn't have enough tokens\n" );
+ return;
+ }
+ parse_meid_del( ctx->new_rtable, tokens[1], vlevel );
+ ctx->new_rtable->mupdates++;