1 | /*************************************** 2 | $Revision: 1.28 $ 3 | 4 | Radix payload (rp) - user level functions for storing data in radix trees 5 | 6 | rp_load = loading the radix trees with data on startup 7 | 8 | Status: NOT REVIEWED, TESTED 9 | 10 | Design and implementation by: Marek Bukowy 11 | 12 | ******************/ /****************** 13 | Copyright (c) 1999,2000,2001,2002 RIPE NCC 14 | 15 | All Rights Reserved 16 | 17 | Permission to use, copy, modify, and distribute this software and its 18 | documentation for any purpose and without fee is hereby granted, 19 | provided that the above copyright notice appear in all copies and that 20 | both that copyright notice and this permission notice appear in 21 | supporting documentation, and that the name of the author not be 22 | used in advertising or publicity pertaining to distribution of the 23 | software without specific, written prior permission. 24 | 25 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 26 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 27 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 28 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 29 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 30 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 31 | ***************************************/ 32 | 33 | #include "rip.h" 34 | 35 | static 36 | er_ret_t 37 | make_sql2pack(SQ_result_set_t *result, SQ_row_t *row, 38 | rp_upd_pack_t *pack, rp_attr_t attr, ip_space_t space, 39 | int colcount) 40 | { 41 | er_ret_t conv = RP_OK; 42 | rp_uni_t *uniptr = &(pack->uni); 43 | char *idptr; /* initially set to the 0'th column */ 44 | char *col[5]; 45 | unsigned i; 46 | 47 | dieif(colcount>5); /* size of the col array */ 48 | 49 | for(i=0; i<colcount; i++) { 50 | col[i] = SQ_get_column_string_nocopy(result, row, i); 51 | if (col[i] == NULL) { 52 | die; 53 | } 54 | } 55 | 56 | idptr = col[0]; 57 | 58 | pack->type = attr; 59 | pack->d.origin = NULL; 60 | switch( attr ) { 61 | case A_IN: 62 | /* 63 | read 0-2 from inetnum 64 | 0 - objectid 65 | 1 - begin 66 | 2 - end 67 | */ 68 | uniptr->space = IP_V4; 69 | conv = IP_rang_f2b_v4( &(uniptr->u.in), col[1], col[2] ); 70 | break; 71 | case A_RT: 72 | /* 73 | read 0-3 from route 74 | 0 - objectid 75 | 1 - prefix 76 | 2 - prefix_length 77 | 3 - origin 78 | */ 79 | uniptr->space = IP_V4; 80 | if( NOERR(conv = IP_pref_f2b_v4( &(uniptr->u.rt), col[1], col[2] ))) { 81 | pack->d.origin = UT_strdup(col[3]); 82 | } 83 | break; 84 | case A_DN: 85 | if( space == IP_V4 ) { 86 | /* 87 | read 0-3 from inaddr 88 | 0 - objectid 89 | 1 - prefix 90 | 2 - prefix_length 91 | 3 - domain 92 | */ 93 | conv = IP_pref_f2b_v4( &(uniptr->u.rt), col[1], col[2] ); 94 | uniptr->space = IP_pref_b2_space( &(uniptr->u.rt) ); 95 | pack->d.domain = UT_strdup(col[3]); 96 | } 97 | else { 98 | /* read 0-4 from ip6int 99 | 0 - objectid 100 | 1 - msb 101 | 2 - lsb 102 | 3 - prefix_length 103 | 4 - domain 104 | */ 105 | conv = IP_pref_f2b_v6( &(uniptr->u.rt), col[1], col[2], col[3] ); 106 | uniptr->space = IP_pref_b2_space( &(uniptr->u.rt) ); 107 | 108 | pack->d.domain = UT_strdup(col[4]); 109 | } 110 | break; 111 | case A_I6: 112 | /* 113 | read 0-3 from inaddr 114 | 0 - objectid 115 | 1 - msb 116 | 2 - lsb 117 | 3 - prefix_length 118 | */ 119 | conv = IP_pref_f2b_v6( &(uniptr->u.rt), col[1], col[2], col[3]); 120 | uniptr->space = IP_pref_b2_space( &(uniptr->u.rt) ); 121 | break; 122 | default: 123 | /* die; / * shouldn't have got here */ 124 | conv = IP_INVARG; 125 | } 126 | 127 | if( sscanf(idptr, "%lu", &(pack->key) ) < 1 ) { 128 | conv = IP_INVARG; 129 | } 130 | 131 | 132 | for(i=0; i<colcount; i++) { 133 | /* wr_free(col[i]);*/ ; 134 | } 135 | 136 | return conv; 137 | } 138 | 139 | static 140 | er_ret_t 141 | RP_sql_load_attr_space( rp_attr_t attr, ip_space_t space, 142 | rp_regid_t reg_id, SQ_connection_t *con 143 | ) 144 | { 145 | SQ_row_t *row; 146 | SQ_result_set_t *result; 147 | int objnr=0; 148 | rx_tree_t *mytree; 149 | rp_upd_pack_t pack; 150 | int colcount; 151 | int sizedebug = ER_is_traced(FAC_RP, ASP_RP_LOAD_DET); 152 | char *v4 = DF_attrcode_radix_load_v4(attr); 153 | char *v6 = DF_attrcode_radix_load_v6(attr); 154 | char *vu = (space == IP_V4) ? v4 : v6; 155 | char *srcnam = ca_get_srcname(reg_id); 156 | const char *attr_code; 157 | char *activity; 158 | 159 | dieif( vu == NULL /* loading query undefined */ ); 160 | #if 0 161 | if( attr==A_IN && space==IP_V4 ) { 162 | vu = "SELECT object_id,begin_in,end_in FROM inetnum WHERE thread_id = 0 AND begin_in >= 3238002688 AND end_in < 3254779904 "; 163 | } 164 | #endif 165 | 166 | dieif( RP_tree_get ( &mytree, reg_id, space, attr ) != RP_OK ); 167 | 168 | ER_inf_va(FAC_RP, ASP_RP_LOAD_DET, "loading using %s", vu); 169 | ER_dbg_va(FAC_RP, ASP_RP_LOAD_DET, "size before query = %x", sbrk(0)); 170 | 171 | attr_code = DF_get_attribute_code(attr); 172 | activity = UT_malloc(strlen(srcnam) + strlen(attr_code) + 32); 173 | sprintf(activity, "%s/%s, query ", srcnam, attr_code); 174 | TA_setactivity(activity); 175 | TA_increment(); 176 | 177 | if ( SQ_execute_query(con, vu, &result) == -1 ) { 178 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con)); 179 | die; 180 | } 181 | else { 182 | colcount = SQ_get_column_count(result); 183 | 184 | ER_dbg_va(FAC_RP, ASP_RP_LOAD_DET, 185 | "size after query = %x; columns = %d", sbrk(0), colcount); 186 | 187 | /* LOCKED when created, so no need to acquire lock here */ 188 | 189 | while ( (row = SQ_row_next(result)) != NULL 190 | && SQ_errno(con) == 0 ) { 191 | 192 | dieif( ! NOERR(make_sql2pack(result, row, &pack, attr, space, 193 | colcount)) ); 194 | 195 | if( ! NOERR(RP_pack_node_l(RX_OPER_CRE, &pack, mytree))) { 196 | fprintf(stderr,"%d:\t%ld\n", objnr, pack.key); 197 | die; 198 | } 199 | 200 | /* free allocated memory */ 201 | if( pack.d.origin != NULL ) { 202 | UT_free(pack.d.origin); 203 | pack.d.origin = NULL; 204 | } 205 | 206 | objnr++; 207 | 208 | if( sizedebug ) { 209 | ER_dbg_va(FAC_RP, ASP_RP_LOAD_DET, "size after object %d = %x", 210 | objnr, sbrk(0)); 211 | } 212 | 213 | if( objnr % 1000 == 0 ) { 214 | 215 | sprintf(activity, "%s/%s, %d done ", 216 | srcnam, attr_code, objnr); 217 | TA_setactivity(activity); 218 | } 219 | } 220 | /* XXX UNLOCK */ 221 | TH_release_write_lockw( &(mytree->rwlock) ); 222 | } 223 | 224 | if( SQ_errno(con) == 0 ) { 225 | SQ_free_result(result); 226 | } else { 227 | die; 228 | } 229 | 230 | ER_inf_va(FAC_RP, ASP_RP_LOAD_GEN, "loaded %d objects into %s", objnr, 231 | DF_get_attribute_code(attr) ); 232 | 233 | UT_free(activity); 234 | UT_free(srcnam); 235 | return RP_OK; 236 | } 237 | 238 | er_ret_t 239 | RP_sql_load_reg(rp_regid_t reg_id) 240 | { 241 | 242 | er_ret_t err; 243 | SQ_connection_t *con; 244 | char *dbhost = ca_get_srcdbmachine(reg_id); 245 | char *dbname = ca_get_srcdbname(reg_id); 246 | char *dbuser = ca_get_srcdbuser(reg_id); 247 | char *dbpass = ca_get_srcdbpassword(reg_id); 248 | char *srcnam = ca_get_srcname(reg_id); 249 | unsigned dbport = ca_get_srcdbport(reg_id); 250 | 251 | TA_add( 0, "rx load"); 252 | 253 | con = SQ_get_connection( dbhost, dbport, dbname, dbuser, dbpass ); 254 | 255 | dieif ( SQ_execute_query(con, "LOCK TABLES " 256 | "route READ, inetnum READ, inet6num READ, " 257 | "inaddr_arpa READ, domain READ, ip6int READ ", 258 | NULL) == -1 ); 259 | 260 | do { 261 | if( !NOERR(err=RP_sql_load_attr_space( A_RT, IP_V4, reg_id, con))) { 262 | break; 263 | } 264 | if( !NOERR(err=RP_sql_load_attr_space( A_IN, IP_V4, reg_id, con))) { 265 | break; 266 | } 267 | #ifndef NO_A_I6 268 | if( !NOERR(err=RP_sql_load_attr_space( A_I6, IP_V6, reg_id, con))) { 269 | break; 270 | } 271 | #endif 272 | #ifndef NO_A_DN 273 | if( !NOERR(err=RP_sql_load_attr_space( A_DN, IP_V4, reg_id, con))) { 274 | break; 275 | } 276 | if( !NOERR(err=RP_sql_load_attr_space( A_DN, IP_V6, reg_id, con))) { 277 | break; 278 | } 279 | #endif 280 | /* CONSTCOND */ 281 | } while(0); 282 | 283 | dieif ( SQ_execute_query(con, "UNLOCK TABLES", NULL) == -1 ); 284 | 285 | /* Close connection */ 286 | SQ_close_connection(con); 287 | 288 | TA_delete(); 289 | 290 | /* free junk */ 291 | UT_free(dbhost); 292 | UT_free(dbname); 293 | UT_free(dbuser); 294 | UT_free(dbpass); 295 | UT_free(srcnam); 296 | return err; 297 | } 298 | 299 | 300 | /* 301 | load the tree from an ascii file (short attr names). 302 | mainly for testing... 303 | */ 304 | er_ret_t 305 | RP_asc_load(char *filename, int maxobj, int operation, 306 | rp_regid_t reg_id) 307 | { 308 | er_ret_t err; 309 | FILE *fp; 310 | char buf[1024]; 311 | char fulltext[65536]; 312 | int objnr = 0; 313 | unsigned len, oldlen=0, ranlen; 314 | char rangstr[IP_RANGSTR_MAX]; 315 | int parsed = 0; 316 | int eor; /* end of record */ 317 | 318 | 319 | if( (fp = fopen(filename,"r")) == NULL ) { 320 | perror(filename); 321 | die; 322 | } 323 | 324 | do { 325 | fgets(buf, 128, fp); 326 | 327 | eor = ( strlen(buf) <= 1 || feof(fp) ); 328 | 329 | if( strlen(buf) > 1 ) { 330 | len = strlen(buf); 331 | dieif( oldlen+len+1 > 65536 ); /* object too long */ 332 | memcpy( fulltext+oldlen, buf, len); 333 | oldlen+=len; 334 | 335 | fulltext[oldlen]=0; 336 | } 337 | 338 | if( eor ) { /* end of object: put into the database. */ 339 | parsed++; 340 | 341 | /* see if it was just some whitespace junk and nothing more */ 342 | if( *fulltext==0 ) { 343 | continue; /* discard */ 344 | } 345 | 346 | /* check if it's a radix object */ 347 | do { 348 | char attrname[3]; 349 | A_Type_t attrcode; 350 | 351 | if( fulltext[0] == '*' && fulltext[3] == ':' ) { 352 | strncpy(attrname, fulltext+1, 2); 353 | attrname[2]=0; 354 | 355 | if(strcmp(attrname, "XX") == 0 ) { 356 | /* object deleted */ 357 | break; 358 | } 359 | 360 | if( (attrcode = DF_attribute_code2type( attrname )) == -1 ) { 361 | fprintf(stderr,"discarding a non-object:\n%s\n", fulltext); 362 | break; 363 | } 364 | 365 | if( DF_attrcode_has_radix_lookup(attrcode) == 0 ) { 366 | /* no interest to radix */ 367 | break; 368 | } 369 | 370 | /* copy and translate the range */ 371 | ranlen = index(fulltext+5,'\n')-fulltext-5; 372 | strncpy(rangstr, fulltext+5, ranlen); 373 | rangstr[ranlen]=0; 374 | 375 | if( NOERR(err=RP_asc_node(operation, rangstr, attrcode, reg_id, 376 | fulltext, strlen(fulltext)+1, 0L )) ) { 377 | objnr++; 378 | } 379 | else { 380 | die; /* error putting into the radix tree */ 381 | return err; 382 | } 383 | 384 | } 385 | /* CONSTCOND */ 386 | } while(0); 387 | 388 | *fulltext=0; 389 | oldlen=0; 390 | } 391 | } 392 | while(!feof(fp) && objnr<maxobj); 393 | 394 | return RP_OK; 395 | }