1    | /***************************************
2    |   $Revision: 1.20 $
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                              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   | #include <rp.h>
33   | #include <mysql_driver.h>
34   | #include <constants.h>
35   | 
36   | #include "ca_configFns.h"
37   | #include "ca_dictSyms.h"
38   | #include "ca_macros.h"
39   | #include "ca_srcAttribs.h"
40   | 
41   | static
42   | er_ret_t
43   | make_sql2pack(SQ_result_set_t *result, SQ_row_t *row, 
44   | 	      rp_upd_pack_t *pack, rp_attr_t  attr, ip_space_t space, 
45   | 	      int colcount)
46   | {
47   |   er_ret_t   conv = RP_OK;
48   |   rp_uni_t   *uniptr = &(pack->uni);
49   |   char       *idptr; /* initially set to the 0'th column */
50   |   char       *col[5];
51   |   int        i;
52   | 
53   |   dieif(colcount>5); /* size of the col array */
54   | 
55   |   for(i=0; i<colcount; i++) {
56   |     col[i] = SQ_get_column_string_nocopy(result, row, i);
57   |     if (col[i] == NULL) {
58   |       die;
59   |     }
60   |   }
61   | 
62   |   idptr = col[0];
63   | 
64   |   pack->type = attr;
65   |   pack->d.origin = NULL;
66   |   switch( attr ) {
67   |   case A_IN:
68   |     /*
69   |       read 0-2 from inetnum
70   |       0 - objectid
71   |       1 - begin   
72   |       2 - end     
73   |     */
74   |     uniptr->space = IP_V4;
75   |     conv = IP_rang_f2b_v4( &(uniptr->u.in), col[1], col[2] );
76   |     break;
77   |   case A_RT:
78   |     /*
79   |       read 0-3 from route
80   |       0 - objectid 
81   |       1 - prefix    
82   |       2 - prefix_length   
83   |       3 - origin
84   |     */
85   |     uniptr->space = IP_V4;
86   |     if( NOERR(conv = IP_pref_f2b_v4( &(uniptr->u.rt), col[1], col[2] ))) {
87   |       dieif(wr_malloc( (void **) &(pack->d.origin), strlen(col[3])+1)
88   | 	    != UT_OK);
89   | 
90   |       strcpy(pack->d.origin, col[3]);
91   |     }
92   |     break;
93   |   case A_DN:
94   |     if( space == IP_V4 ) {
95   |     /*
96   |       read 0-3 from inaddr
97   |       0 - objectid 
98   |       1 - prefix
99   |       2 - prefix_length   
100  |       3 - domain
101  |     */
102  |       conv = IP_pref_f2b_v4( &(uniptr->u.rt), col[1], col[2] );
103  |       uniptr->space = IP_pref_b2_space( &(uniptr->u.rt) );
104  |       dieif(wr_malloc( (void **) &(pack->d.domain), strlen(col[3])+1)
105  | 	    != UT_OK);
106  |       strcpy(pack->d.domain, col[3]);
107  |     }
108  |     else {
109  |       /* read 0-4 from ip6int
110  | 	 0 - objectid 
111  | 	 1 - msb
112  | 	 2 - lsb
113  | 	 3 - prefix_length 
114  | 	 4 - domain
115  |     */
116  |       conv = IP_pref_f2b_v6( &(uniptr->u.rt), col[1], col[2], col[3] );
117  |       uniptr->space = IP_pref_b2_space( &(uniptr->u.rt) );
118  |     
119  |       dieif(wr_malloc( (void **) &(pack->d.domain), strlen(col[4])+1)
120  | 	    != UT_OK);
121  |       strcpy(pack->d.domain, col[4]);
122  |     }
123  |     break;
124  |   case A_I6: 
125  |     /*
126  |       read 0-3 from inaddr
127  |       0 - objectid 
128  |       1 - msb
129  |       2 - lsb
130  |       3 - prefix_length 
131  |     */
132  |     conv = IP_pref_f2b_v6( &(uniptr->u.rt), col[1], col[2], col[3]);
133  |     uniptr->space = IP_pref_b2_space( &(uniptr->u.rt) );
134  |     break;
135  |   default:
136  |     /*    die; / * shouldn't have got here */
137  |     conv = IP_INVARG;
138  |   }
139  |   
140  |   if( sscanf(idptr, "%lu", &(pack->key) ) < 1 ) {
141  |     conv = IP_INVARG;
142  |   }
143  |   
144  | 
145  |   for(i=0; i<colcount; i++) {
146  |     /*    wr_free(col[i]);*/ ;
147  |   }
148  |   
149  |   return conv;
150  | }
151  | 
152  | static
153  | er_ret_t
154  | RP_sql_load_attr_space( rp_attr_t attr, ip_space_t space, 
155  | 			rp_regid_t reg_id, SQ_connection_t *con
156  | 			)
157  | {
158  |   SQ_row_t *row;
159  |   SQ_result_set_t *result;
160  |   int objnr=0;
161  |   rx_tree_t   *mytree;
162  |   rp_upd_pack_t pack;
163  |   int colcount;
164  |   int sizedebug = ER_is_traced(FAC_RP, ASP_RP_LOAD_DET);
165  |   char *v4 = DF_attrcode_radix_load_v4(attr);
166  |   char *v6 = DF_attrcode_radix_load_v6(attr);
167  |   char *vu = (space == IP_V4) ? v4 : v6;
168  | 
169  |   dieif( vu == NULL /* loading query undefined */ );
170  |   
171  |   dieif( RP_tree_get ( &mytree, reg_id, space, attr ) != RP_OK );
172  |  
173  |   ER_inf_va(FAC_RP, ASP_RP_LOAD_DET, "loading using %s", vu);
174  |   ER_dbg_va(FAC_RP, ASP_RP_LOAD_DET, "size before query = %x", sbrk(0));
175  |   
176  |   if ( SQ_execute_query(con, vu, &result) == -1 ) {
177  |     fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
178  |     die;
179  |   }
180  |   else { 
181  |     colcount = SQ_get_column_count(result);
182  |     
183  |     ER_dbg_va(FAC_RP, ASP_RP_LOAD_DET, 
184  | 	      "size after query = %x; columns = %d", sbrk(0), colcount);
185  |     
186  |     /* LOCKED when created, so no need to acquire lock here */
187  |     
188  |     while ( (row = SQ_row_next(result)) != NULL 
189  | 	    && SQ_errno(con) == 0 ) {
190  |       
191  |       dieif( ! NOERR(make_sql2pack(result, row, &pack, attr, space, 
192  | 				   colcount)) );
193  |       
194  |       if( ! NOERR(RP_pack_node_l(RX_OPER_CRE, &pack, mytree))) {
195  | 	fprintf(stderr,"%d:\t%ld\n", objnr, pack.key);
196  | 	die;
197  |       }
198  |       
199  |       /* free allocated memory */
200  |       if( pack.d.origin != NULL ) {
201  | 	wr_free(pack.d.origin);
202  | 	pack.d.origin = NULL;
203  |       }
204  |       
205  |       objnr++;
206  |       
207  |       if( sizedebug ) {
208  | 	ER_dbg_va(FAC_RP, ASP_RP_LOAD_DET, "size after object %d = %x", 
209  | 		  objnr, sbrk(0));
210  |       }
211  |       
212  |     }
213  |     /* XXX UNLOCK */
214  |     TH_release_write_lock( &(mytree->rwlock) );
215  |   }
216  | 
217  |   if( SQ_errno(con) == 0 ) {
218  |       SQ_free_result(result);
219  |   } else {
220  |       die;
221  |   }
222  | 
223  |   ER_inf_va(FAC_RP, ASP_RP_LOAD_GEN, "loaded %d objects into %s", objnr,
224  | 	    DF_get_attribute_code(attr) );
225  |  
226  |   
227  |   return RP_OK;
228  | }
229  | 
230  | er_ret_t
231  | RP_sql_load_reg(rp_regid_t reg_id) 
232  | {
233  |   
234  |   er_ret_t err;
235  |   SQ_connection_t *con;
236  |   char *dbhost = ca_get_srcdbmachine(reg_id);
237  |   char *dbname = ca_get_srcdbname(reg_id);
238  |   char *dbuser = ca_get_srcdbuser(reg_id);
239  |   char *dbpass = ca_get_srcdbpassword(reg_id);
240  |   char *srcnam = ca_get_srcname(reg_id);
241  | 
242  |   con = SQ_get_connection( dbhost, ca_get_srcdbport(reg_id),
243  | 				      dbname, dbuser, dbpass );
244  | 
245  |   dieif ( SQ_execute_query(con, "LOCK TABLES     " 
246  |      "route READ, inetnum READ, inet6num READ,   "
247  |      "inaddr_arpa READ, domain READ, ip6int READ ",
248  | 			   NULL) == -1 );
249  | 
250  |   do {
251  |     if( !NOERR(err=RP_sql_load_attr_space( A_RT, IP_V4, reg_id, con))) {
252  |       break;
253  |     }
254  |     if( !NOERR(err=RP_sql_load_attr_space( A_IN, IP_V4, reg_id, con))) {
255  |       break;
256  |     }
257  |     if( !NOERR(err=RP_sql_load_attr_space( A_I6, IP_V6, reg_id, con))) {
258  |       break;
259  |     }
260  |     if( !NOERR(err=RP_sql_load_attr_space( A_DN, IP_V4, reg_id, con))) {
261  |       break;
262  |     }
263  |     if( !NOERR(err=RP_sql_load_attr_space( A_DN, IP_V6, reg_id, con))) {
264  |       break;
265  |     }
266  |     /* CONSTCOND */
267  |   } while(0);
268  | 
269  |   dieif ( SQ_execute_query(con, "UNLOCK TABLES", NULL) == -1 );
270  | 
271  |   /* Close connection */
272  |   SQ_close_connection(con);
273  | 
274  |   /* free junk */
275  |   wr_free(dbhost);
276  |   wr_free(dbname);
277  |   wr_free(dbuser);
278  |   wr_free(dbpass);
279  |   wr_free(srcnam);
280  |   return err;
281  | }
282  | 
283  | 
284  | /* 
285  |    load the tree from an ascii file (short attr names).
286  |    mainly for testing... 
287  | */
288  | er_ret_t
289  | RP_asc_load(char *filename, int maxobj, int operation, 
290  | 	    rp_regid_t reg_id)
291  | {
292  |   er_ret_t err;
293  |   FILE *fp;
294  |   char buf[1024];
295  |   char fulltext[65536];
296  |   int objnr = 0;
297  |   int len, oldlen=0;
298  |   int ranlen;
299  |   char rangstr[IP_RANGSTR_MAX];
300  |   int parsed = 0;
301  |   int eor; /* end of record */
302  | 
303  |   
304  |   if( (fp = fopen(filename,"r")) == NULL ) {
305  |     perror(filename);
306  |     die; 
307  |   }
308  |  
309  |   do {
310  |     fgets(buf, 128, fp);
311  | 
312  |     eor = ( strlen(buf) <= 1 || feof(fp) );
313  |       
314  |     if( strlen(buf) > 1 ) {
315  |       len = strlen(buf);
316  |       dieif( oldlen+len+1 > 65536 ); /* object too long */
317  |       memcpy( fulltext+oldlen, buf, len);
318  |       oldlen+=len;
319  |       
320  |       fulltext[oldlen]=0;
321  |     }
322  |     
323  |     if( eor ) {              /* end of object: put into the database. */
324  |       parsed++;
325  |       
326  |       /* see if it was just some whitespace junk and nothing more */
327  |       if( *fulltext==0 ) {
328  | 	continue;  /* discard */
329  |       }
330  | 
331  |       /* check if it's a radix object */
332  |       do {
333  | 	char attrname[3];
334  | 	A_Type_t attrcode;
335  | 	
336  | 	if( fulltext[0] == '*' &&  fulltext[3] == ':' ) {
337  | 	  strncpy(attrname, fulltext+1, 2);
338  | 	  attrname[2]=0;
339  | 	  
340  | 	  if(strcmp(attrname, "XX") == 0 ) {
341  | 	    /* object deleted */
342  | 	    break;
343  | 	  }
344  | 	  
345  | 	  if( (attrcode = DF_attribute_code2type( attrname )) == -1 ) {
346  | 	    fprintf(stderr,"discarding a non-object:\n%s\n", fulltext);
347  | 	    break;
348  | 	  }
349  | 	  
350  | 	  if( DF_attrcode_has_radix_lookup(attrcode) == 0 ) {
351  | 	    /* no interest to radix */
352  | 	    break;
353  | 	  }
354  | 	
355  | 	  /* copy and translate the range */
356  | 	  ranlen = index(fulltext+5,'\n')-fulltext-5;
357  | 	  strncpy(rangstr, fulltext+5, ranlen);
358  | 	  rangstr[ranlen]=0;
359  | 	       
360  | 	  if( NOERR(err=RP_asc_node(operation, rangstr, attrcode, reg_id,  
361  | 				    fulltext, strlen(fulltext)+1, 0L )) ) {
362  | 	    objnr++;
363  | 	  }
364  | 	  else {
365  | 	    die; /* error putting into the radix tree */
366  | 	    return err;
367  | 	  }
368  | 	  
369  | 	}
370  | 	/* CONSTCOND */
371  |       } while(0);
372  |       
373  |       *fulltext=0;
374  |       oldlen=0;
375  |     }
376  |   }
377  |   while(!feof(fp) && objnr<maxobj);  
378  | 
379  |   return RP_OK;
380  | }