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