1 | /***************************************
2 | $Revision: 1.27 $
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 | if( !NOERR(err=RP_sql_load_attr_space( A_I6, IP_V6, reg_id, con))) {
268 | break;
269 | }
270 | if( !NOERR(err=RP_sql_load_attr_space( A_DN, IP_V4, reg_id, con))) {
271 | break;
272 | }
273 | if( !NOERR(err=RP_sql_load_attr_space( A_DN, IP_V6, reg_id, con))) {
274 | break;
275 | }
276 | /* CONSTCOND */
277 | } while(0);
278 |
279 | dieif ( SQ_execute_query(con, "UNLOCK TABLES", NULL) == -1 );
280 |
281 | /* Close connection */
282 | SQ_close_connection(con);
283 |
284 | TA_delete();
285 |
286 | /* free junk */
287 | UT_free(dbhost);
288 | UT_free(dbname);
289 | UT_free(dbuser);
290 | UT_free(dbpass);
291 | UT_free(srcnam);
292 | return err;
293 | }
294 |
295 |
296 | /*
297 | load the tree from an ascii file (short attr names).
298 | mainly for testing...
299 | */
300 | er_ret_t
301 | RP_asc_load(char *filename, int maxobj, int operation,
302 | rp_regid_t reg_id)
303 | {
304 | er_ret_t err;
305 | FILE *fp;
306 | char buf[1024];
307 | char fulltext[65536];
308 | int objnr = 0;
309 | unsigned len, oldlen=0, ranlen;
310 | char rangstr[IP_RANGSTR_MAX];
311 | int parsed = 0;
312 | int eor; /* end of record */
313 |
314 |
315 | if( (fp = fopen(filename,"r")) == NULL ) {
316 | perror(filename);
317 | die;
318 | }
319 |
320 | do {
321 | fgets(buf, 128, fp);
322 |
323 | eor = ( strlen(buf) <= 1 || feof(fp) );
324 |
325 | if( strlen(buf) > 1 ) {
326 | len = strlen(buf);
327 | dieif( oldlen+len+1 > 65536 ); /* object too long */
328 | memcpy( fulltext+oldlen, buf, len);
329 | oldlen+=len;
330 |
331 | fulltext[oldlen]=0;
332 | }
333 |
334 | if( eor ) { /* end of object: put into the database. */
335 | parsed++;
336 |
337 | /* see if it was just some whitespace junk and nothing more */
338 | if( *fulltext==0 ) {
339 | continue; /* discard */
340 | }
341 |
342 | /* check if it's a radix object */
343 | do {
344 | char attrname[3];
345 | A_Type_t attrcode;
346 |
347 | if( fulltext[0] == '*' && fulltext[3] == ':' ) {
348 | strncpy(attrname, fulltext+1, 2);
349 | attrname[2]=0;
350 |
351 | if(strcmp(attrname, "XX") == 0 ) {
352 | /* object deleted */
353 | break;
354 | }
355 |
356 | if( (attrcode = DF_attribute_code2type( attrname )) == -1 ) {
357 | fprintf(stderr,"discarding a non-object:\n%s\n", fulltext);
358 | break;
359 | }
360 |
361 | if( DF_attrcode_has_radix_lookup(attrcode) == 0 ) {
362 | /* no interest to radix */
363 | break;
364 | }
365 |
366 | /* copy and translate the range */
367 | ranlen = index(fulltext+5,'\n')-fulltext-5;
368 | strncpy(rangstr, fulltext+5, ranlen);
369 | rangstr[ranlen]=0;
370 |
371 | if( NOERR(err=RP_asc_node(operation, rangstr, attrcode, reg_id,
372 | fulltext, strlen(fulltext)+1, 0L )) ) {
373 | objnr++;
374 | }
375 | else {
376 | die; /* error putting into the radix tree */
377 | return err;
378 | }
379 |
380 | }
381 | /* CONSTCOND */
382 | } while(0);
383 |
384 | *fulltext=0;
385 | oldlen=0;
386 | }
387 | }
388 | while(!feof(fp) && objnr<maxobj);
389 |
390 | return RP_OK;
391 | }