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  | }