1 | /***************************************
2 |
3 | $Revision: 1.27 $
4 |
5 | Core functions for update lower layer
6 |
7 | Status: NOT REVUED, NOT TESTED
8 |
9 | Author(s): Chris Ottrey, Andrei Robachevsky
10 |
11 | ******************/ /******************
12 | Modification History:
13 | andrei (17/01/2000) Created.
14 | ******************/ /******************
15 | Copyright (c) 2000 RIPE NCC
16 |
17 | All Rights Reserved
18 |
19 | Permission to use, copy, modify, and distribute this software and its
20 | documentation for any purpose and without fee is hereby granted,
21 | provided that the above copyright notice appear in all copies and that
22 | both that copyright notice and this permission notice appear in
23 | supporting documentation, and that the name of the author not be
24 | used in advertising or publicity pertaining to distribution of the
25 | software without specific, written prior permission.
26 |
27 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
28 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
29 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
30 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
31 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 | ***************************************/
34 | #include "ud.h"
35 | #include "ud_int.h"
36 |
37 | static int perform_update(Transaction_t *tr);
38 |
39 | static int perform_create(Transaction_t *tr);
40 |
41 | static void each_primary_key_select(void *element_data, void *result_ptr);
42 |
43 | static void each_attribute_process(void *element_data, void *tr_ptr);
44 |
45 | static void update_attr(Attribute_t *attr, Transaction_t *tr);
46 |
47 | static int create_dummy(Attribute_t *attr, Transaction_t *tr);
48 |
49 | static int auth_member_of(Attribute_t *attr, Transaction_t *tr);
50 |
51 | /***************************************************
52 | * char *s_split(char *line) *
53 | * *
54 | * Consequently returns words of the 'line' *
55 | * When there are no words it returns NULL *
56 | * You need to retreive all words ! *
57 | * *
58 | * NB This function damages 'line' replacing *
59 | * whitespace with '\0' *
60 | * *************************************************/
61 | #define ATTR_DELIMITERS " ,"
62 |
63 |
64 | /**********************************************************
65 | * Attribute expansion/conversion functions *
66 | ***********************************************************/
67 | /* Convert ifaddr attribute into numbers */
68 | er_ret_t convert_if(char *avalue, unsigned int *pif_address)
69 | {
70 | char *delim;
71 | ip_addr_t ip_addr;
72 | er_ret_t ret;
73 |
74 | if ((delim=index(avalue, ' '))!=NULL) *delim='\0';
75 | ret=IP_addr_a2v4(avalue, &ip_addr, pif_address );
76 | return(ret);
77 | }
78 |
79 |
80 | /* Convert refer attribute. Free host after use ! */
81 | char *convert_rf(char *avalue, int *type, int *port)
82 | {
83 | char *delim, *token;
84 | char buff[STR_M];
85 | char *host;
86 |
87 | host=NULL;
88 | strcpy(buff, avalue);
89 | g_strchug(buff);
90 | delim=index(buff, ' ');
91 | *delim='\0';
92 | delim++;
93 |
94 | /* convert the type */
95 | if(strcmp(buff, S_RIPE)==0)*type=RF_RIPE;
96 | else if(strcmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC;
97 | else if(strcmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE;
98 | else if(strcmp(buff, S_CLIENTADDERSS)==0)*type=RF_CLIENTADDRESS;
99 |
100 | token=delim;
101 | g_strchug(token);
102 | delim=index(token, ' ');
103 | if(delim){
104 | *delim='\0';
105 | delim++;
106 | }
107 | /* convert the hostname */
108 | host = g_strdup(token);
109 |
110 | /* convert port number */
111 | if(delim){
112 | token=delim;
113 | *port = atoi(token);
114 | if (*port==0) *port=RF_DEF_PORT; /* default port number*/
115 | } else *port=RF_DEF_PORT;
116 | return(host);
117 | }
118 |
119 |
120 | /* Convert AS# into integer */
121 | static int convert_as(char *as)
122 | {
123 | char *ptr;
124 | ptr=as; ptr++; ptr++;
125 | return(atoi(ptr));
126 | }
127 |
128 | /* Convert AS range (AS4321 - AS5672) into numbers */
129 | int convert_as_range(const char *as_range, int *begin, int *end)
130 | {
131 | char *range;
132 | char *token=as_range;
133 |
134 | range=g_strdup(as_range);
135 | token=range;
136 | *begin=convert_as(strsep(&token, " -"));
137 | *end=convert_as(strsep(&token, " -"));
138 | free(range);
139 | return(0);
140 | }
141 |
142 | /* Convert time in ASCII format (19991224) into time_t unix time */
143 | time_t convert_time(char *asc_time)
144 | {
145 | struct tm tm;
146 | char buf[STR_S];
147 | char *ptr;
148 |
149 |
150 | bzero(&tm, sizeof(tm));
151 |
152 | strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
153 | tm.tm_year = atoi(buf) - 1900;
154 |
155 | strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
156 | tm.tm_mon = atoi(buf) - 1;
157 |
158 | strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
159 | tm.tm_mday = atoi(buf);
160 |
161 | return(mktime(&tm));
162 |
163 | }
164 |
165 |
166 | /************************************************************
167 | * char *get_set_name() *
168 | * *
169 | * Returns set name for the specified object class *
170 | * *
171 | * **********************************************************/
172 | static char *get_set_name(C_Type_t class_type)
173 | {
174 | switch(class_type){
175 | case C_RT: return("route_set");
176 | case C_AN: return("as_set");
177 | default: return(NULL);
178 | }
179 | }
180 |
181 |
182 | /************************************************************
183 | * long get_object_id() *
184 | * Queries the database for an object. *
185 | * For constructing a query uses each_primary_key_select() *
186 | * *
187 | * Returns: *
188 | * >0 - object exists, returns object_id *
189 | * 0 - object does not exist *
190 | * -1 - error (f.e. more than one object with the same PK) *
191 | * Error code is stored in tr->error *
192 | * *
193 | * **********************************************************/
194 | long get_object_id(Transaction_t *tr)
195 | {
196 | Object_t *obj;
197 | SQ_result_set_t *sql_result;
198 | SQ_row_t *sql_row;
199 | char *sql_str;
200 | GString *query;
201 | long object_id=0;
202 | int sql_err;
203 |
204 | obj=tr->object;
205 |
206 | if ((query = g_string_sized_new(STR_XL)) == NULL){
207 | fprintf(stderr, "E: cannot allocate gstring\n");
208 | tr->succeeded=0;
209 | tr->error |= ERROR_U_MEM;
210 | die;
211 | }
212 |
213 | /* compose query */
214 | g_string_sprintf(query, "SELECT object_id FROM %s WHERE",DF_get_class_sql_table(obj->type));
215 | /* add all primary keys */
216 | g_slist_foreach(obj->attributes, each_primary_key_select, query);
217 | /* truncate the last ' AND '*/
218 | g_string_truncate(query, (query->len) - 4);
219 |
220 | /* execute query */
221 | sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
222 | g_string_free(query, TRUE);
223 |
224 | /* in case of an error copy error code and return */
225 | if(sql_err) {
226 | fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
227 | tr->succeeded=0;
228 | tr->error |= ERROR_U_DBS;
229 | die;
230 | }
231 |
232 | /* Fetch the row */
233 | if ((sql_row = SQ_row_next(sql_result)) != NULL) {
234 | /* Object exists */
235 | #define OBJECT_ID 0
236 | sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
237 | if (sql_str != NULL) {
238 | object_id = atol(sql_str);
239 | free(sql_str);
240 | }
241 |
242 | /* We must process all the rows of the result */
243 | /* otherwise we'll have them as part of the next qry */
244 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
245 | } else
246 | object_id=0; /* object does not exist*/
247 |
248 | SQ_free_result(sql_result);
249 | return(object_id);
250 | }
251 |
252 |
253 | /************************************************************
254 | * get_qresult_str() *
255 | * *
256 | * Returns string containing query result *
257 | * *
258 | * *
259 | * Returns: *
260 | * String containing the result.Needs to be freed after use *
261 | * NULL in case of an error *
262 | * - SQL error *
263 | * - if query returns more than one string (row) *
264 | * *
265 | *************************************************************/
266 | char *get_qresult_str(SQ_connection_t *sql_connection, char *query)
267 | {
268 | SQ_result_set_t *sql_result;
269 | SQ_row_t *sql_row;
270 | char *sql_str;
271 | int sql_err;
272 |
273 |
274 | /*fprintf(stderr, "D:<get_field_str>:query: %s\n", query);*/
275 | sql_err=SQ_execute_query(sql_connection, query, &sql_result);
276 |
277 | if(sql_err) {
278 | fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
279 | die;
280 | }
281 |
282 |
283 | if ((sql_row = SQ_row_next(sql_result)) != NULL) {
284 | sql_str = SQ_get_column_string(sql_result, sql_row, 0);
285 |
286 | /* We must process all the rows of the result,*/
287 | /* otherwise we'll have them as part of the next qry */
288 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
289 | fprintf(stderr, "E:<get_field_str> error : Dupl PK[%s]\n", query);
290 | if(sql_str)free(sql_str); sql_str=NULL;
291 | }
292 | }
293 | else sql_str=NULL;
294 |
295 | SQ_free_result(sql_result);
296 | return(sql_str);
297 | }
298 |
299 |
300 |
301 | /************************************************************
302 | * get_field_str() *
303 | * *
304 | * Returns string containing the field. *
305 | * field - field name to be retrieved *
306 | * ref_tbl_name - name of the table containing the field *
307 | * ref_name - reference name *
308 | * attr_value - reference value *
309 | * condition - additional condition ( f.e. 'AND dummy=0' *
310 | * *
311 | * Returns: *
312 | * String containing the field. Needs to be freed after use *
313 | * NULL in case of an error *
314 | * *
315 | *************************************************************/
316 | char *get_field_str(SQ_connection_t *sql_connection, char *field,
317 | char *ref_tbl_name, char *ref_name,
318 | char * attr_value, char *condition)
319 | {
320 | char query[STR_L];
321 |
322 | sprintf(query, "SELECT %s FROM %s "
323 | "WHERE %s='%s' ",
324 | field, ref_tbl_name, ref_name, attr_value);
325 | if (condition)strcat(query, condition);
326 |
327 | return( get_qresult_str(sql_connection, query));
328 |
329 | }
330 |
331 | /************************************************************
332 | * long get_sequence_id(Transaction_t *tr)
333 | * >0 - success
334 | * -1 - sql error
335 | *
336 | * **********************************************************/
337 |
338 | long get_sequence_id(Transaction_t *tr)
339 | {
340 | char *sql_str;
341 | char str_id[STR_M];
342 | long sequence_id=-1;
343 |
344 |
345 | sprintf(str_id, "%ld", tr->object_id);
346 | sql_str= get_field_str(tr->sql_connection, "sequence_id", "last", "object_id", str_id, NULL);
347 | if(sql_str) {
348 | sequence_id = atol(sql_str);
349 | /* fprintf(stderr, "D: Retrieved set serial id = %ld\n", sequence_id);*/
350 | free(sql_str);
351 | }
352 |
353 | return(sequence_id);
354 |
355 | }
356 |
357 |
358 | /************************************************************
359 | * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
360 | * >0 - success
361 | * -1 - sql error
362 | *
363 | * **********************************************************/
364 |
365 | static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition)
366 | {
367 | char *sql_str;
368 | long ref_id=-1;
369 |
370 | /*fprintf(stderr, "D:<get_ref_id>: entering...\n");*/
371 |
372 | sql_str= get_field_str(tr->sql_connection, "object_id", ref_tbl_name, ref_name, attr_value, condition);
373 | if(sql_str) {
374 | ref_id = atol(sql_str);
375 | /* fprintf(stderr, "D: Retrieved set serial id = %ld\n", ref_id);*/
376 | free(sql_str);
377 | }
378 | return(ref_id);
379 | }
380 |
381 |
382 | /************************************************************
383 | * int isdummy()
384 | *
385 | * Returns 1 if the object in question is a dummy,
386 | * otherwise returns 0.
387 | *
388 | * In case of error:
389 | * -1 - sql error or object does not exist
390 | *
391 | ***********************************************************/
392 |
393 | int isdummy(Transaction_t *tr)
394 | {
395 | char *sql_str;
396 | char str_id[STR_M];
397 | int object_type=-1;
398 |
399 | sprintf(str_id, "%ld", tr->object_id);
400 | sql_str= get_field_str(tr->sql_connection, "object_type", "last", "object_id", str_id, NULL);
401 | if(sql_str) {
402 | object_type = atoi(sql_str);
403 | free(sql_str);
404 | }
405 |
406 | if (object_type==-1) die;
407 | if (object_type==DUMMY_TYPE) return(1);
408 | else return(0);
409 |
410 | }
411 |
412 | /* it may be either a legacy name reference, or a nic-handle */
413 | /* we rely on other parsers/syntax checkers, so no surprises */
414 | /* thus, the check is simple - if there is a space - not a nh */
415 | static int isnichandle(char *name)
416 | {
417 | if(index(name, ' ')) return(0);
418 | else return(1);
419 | /* return(MA_isset(WK_new(name), WK_NIC_HDL)); */
420 | }
421 |
422 |
423 | /************************************************************
424 | * process_reverse_domain() *
425 | * *
426 | * Tries to insert additional data for reverse domains *
427 | * This data includes prefix and perfix length for reverse *
428 | * delegation block. It is stored in inaddr_arpa table for *
429 | * IPv4 and ip6int table for IPv6 address spaces *
430 | * *
431 | * Returns: *
432 | * 0 success *
433 | * -1 sql error *
434 | * *
435 | *************************************************************/
436 |
437 | static int process_reverse_domain(Transaction_t *tr,
438 | ip_prefix_t *prefptr,
439 | int op)
440 | {
441 | unsigned prefix, prefix_length; /* ipv4 */
442 | ip_v6word_t high, low; /* ipv6 */
443 | char query[STR_L];
444 | int num;
445 | int sql_err;
446 |
447 |
448 | if( IP_pref_b2_space(prefptr) == IP_V4 ) { /* ipv4 */
449 | if(op==0) { /* insert record */
450 | IP_revd_b2v4(prefptr, &prefix, &prefix_length);
451 | sprintf(query, "INSERT INTO inaddr_arpa SET thread_id=%d, object_id=%ld, prefix=%u, prefix_length=%d ",
452 | tr->thread_ins, tr->object_id, prefix, prefix_length);
453 | }
454 | else {
455 | /* update record */
456 | sprintf(query, "UPDATE inaddr_arpa SET thread_id=%d WHERE object_id=%ld ",
457 | tr->thread_upd, tr->object_id);
458 | }
459 | }
460 | else { /* ipv6 */
461 | if(op==0) { /* insert record */
462 | IP_revd_b2v6(prefptr, &high, &low, &prefix_length);
463 | sprintf(query, "INSERT INTO ip6int SET thread_id=%d, object_id=%ld, high=%llu, low=%llu, prefix_length=%d ",
464 | tr->thread_ins, tr->object_id, high, low, prefix_length);
465 | }
466 | else {
467 | /* update record */
468 | sprintf(query, "UPDATE ip6int SET thread_id=%d WHERE object_id=%ld ",
469 | tr->thread_upd, tr->object_id);
470 | }
471 | }
472 |
473 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
474 | num = mysql_affected_rows(tr->sql_connection);
475 |
476 | /* Check for errors */
477 | if (sql_err) {
478 | fprintf(stderr, "E: insert inaddr:%s[%s]\n", SQ_error(tr->sql_connection), query);
479 | die;
480 | }
481 | /* If nothing was affected then WHERE clause returned nothing - DB error */
482 | if(num == 0) {
483 | fprintf(stderr, "E: insert inaddr:no effect [%s]\n", query);
484 | die;
485 | }
486 | return(0);
487 | }
488 |
489 | #define insert_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 0)
490 | #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
491 |
492 |
493 | /************************************************************
494 | * auth_member_of() *
495 | * *
496 | * Function that checks the authorization for membership *
497 | * (i.e. if the object is authorized to be a memeber by *
498 | * mbrs-by-ref attribute of the set is refers by member-of *
499 | * attribute). *
500 | * First checks if 'mbrs-by-ref: ANY' *
501 | * If not then checks that maintner referenced by *
502 | * mbrs-by-ref attribute of the set is the one in mnt-by. *
503 | * *
504 | * Returns: *
505 | * 0 success *
506 | * 1 not allowed *
507 | * -1 SQL error *
508 | * *
509 | *************************************************************/
510 | static int auth_member_of(Attribute_t *attr, Transaction_t *tr)
511 | {
512 | GString *query;
513 | char *set_name;
514 | char *qresult;
515 |
516 | /* Check if set has mbrs_by_ref==ANY
517 | In such case mbrs_by_ref.mnt_id==0
518 | */
519 |
520 | if ((query = g_string_sized_new(STR_XL)) == NULL){
521 | tr->succeeded=0;
522 | tr->error |= ERROR_U_MEM;
523 | fprintf(stderr, "E: cannot allocate gstring\n");
524 | die;
525 | }
526 |
527 | set_name = get_set_name(tr->class_type);
528 | /* fprintf(stderr, "D:<auth_member_of>: Got set name: %s\n", set_name); */
529 |
530 | /* Check if the set protects itself with mbrs-by-ref attribute */
531 | g_string_sprintf(query,"SELECT COUNT(*) FROM mbrs_by_ref, %s "
532 | "WHERE mbrs_by_ref.object_id=%s.object_id "
533 | "AND %s.%s='%s' ",
534 | set_name, set_name, set_name, set_name, attr->value);
535 |
536 | qresult = get_qresult_str(tr->sql_connection, query->str);
537 | /* should be '0' if there is no mbrs-by-ref attribute */
538 | if (strcmp(qresult, "0")==0){
539 | /* there is no mbrs-by-ref attribute - so we cannot go ahead */
540 | fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n",query->str);
541 | g_string_free(query, TRUE);
542 | return(1);
543 | }
544 | else free(qresult);
545 |
546 | /* Check if membership is protected by the keyword "ANY" */
547 | /* There is a dummy mntmer object in the database corresponding to "ANY" */
548 | /* Its object_id==0 */
549 | /* EXAMPLE:
550 |
551 | SELECT route_set.object_id
552 | FROM mbrs_by_ref, route_set
553 | WHERE mbrs_by_ref.object_id=route_set.object_id
554 | AND route_set.route_set=<setname>
555 | AND mbrs_by_ref.mnt_id=0
556 | */
557 | g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
558 | "WHERE mbrs_by_ref.object_id=%s.object_id "
559 | "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ",
560 | set_name, set_name, set_name, set_name, set_name, attr->value);
561 | /* fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);*/
562 |
563 | qresult = get_qresult_str(tr->sql_connection, query->str);
564 | /* if such record exists - go ahead */
565 | if(qresult) {
566 | free(qresult);
567 | g_string_free(query, TRUE);
568 | return(0);
569 | }
570 |
571 | /* Now check if our mnt_by belongs to mbrs_by_ref list of the set */
572 | /* we search only mnt_by.thread_id!=0 to check against new/updated mnt-by attribute */
573 | g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM route_set, mbrs_by_ref, mnt_by "
574 | "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
575 | "AND mnt_by.object_id=%ld "
576 | "AND %s.object_id=mbrs_by_ref.object_id "
577 | "AND %s.%s='%s' "
578 | "AND mnt_by.thread_id!=0 ",
579 | tr->object_id, set_name, set_name, set_name, attr->value);
580 |
581 | /* fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str); */
582 |
583 | qresult = get_qresult_str(tr->sql_connection, query->str);
584 | /* If our mntner is listed (non-empty result) membership is authorized */
585 | if (qresult) {
586 | free(qresult);g_string_free(query, TRUE);
587 | return(0);
588 | } else {
589 | fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n", query->str);
590 | g_string_free(query, TRUE);
591 | return(1);
592 | }
593 | }/* auth_member_of() */
594 |
595 |
596 | /************************************************************
597 | * create_dummy() *
598 | * *
599 | * Function that creates a dummy object (that is one that *
600 | * is referenced from an object but does not *
601 | * exist in the database). *
602 | * Dummy object exists only in relevant main and 'last' *
603 | * tables. Its creation is controlled by tr->dummy_allowed. *
604 | * Queries for the dummies are defined in Dummy[] array. *
605 | * *
606 | * Returns: *
607 | * 0 success *
608 | * 1 no rf integrity and dummy not allowed *
609 | * -1 SQL error *
610 | * *
611 | *************************************************************/
612 | static int create_dummy(Attribute_t *attr, Transaction_t *tr)
613 | {
614 | const char *query_fmt;
615 | long dummy_id;
616 | char query[STR_L];
617 | int result=0;
618 | char *set_name;
619 | char *p_name;
620 | int query_type;
621 | long timestamp;
622 | char str_id[STR_M];
623 | gchar *attr_value=NULL;
624 | int sql_err;
625 | char *token=NULL;
626 |
627 | query_fmt = DF_get_dummy_query(attr->type);
628 | if (strcmp(query_fmt, "") == 0) {
629 | fprintf(stderr, "E:<create_dummy>: empty query string\n");
630 | return(1);
631 | }
632 |
633 | /* We allow creating dummy sets in any mode */
634 | /* For others attributes return if we are in protected mode */
635 | if ((attr->type!=A_MO) && (tr->dummy != 1)) return(1);
636 |
637 | /* Insert dummy in the last table */
638 | sprintf(str_id, "%ld", tr->object_id);
639 | timestamp=time(NULL);
640 | sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'",
641 | tr->thread_ins, timestamp, DUMMY_TYPE, str_id);
642 | /* fprintf(stderr, "D: making dummy entry in the last table\n %s\n", query);*/
643 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
644 |
645 | /* Check for errors */
646 | if (sql_err) {
647 | fprintf(stderr, "E: dummy->last:[%s]\n", query);
648 | die;
649 | }
650 |
651 | /* insert dummy in the main table */
652 | dummy_id=mysql_insert_id(tr->sql_connection);
653 | /* Record dummy's object_id, it'll be needed in commit/rollback */
654 | tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++;
655 |
656 | /* compose the query */
657 | query_type=DF_get_dummy_query_type(attr->type);
658 | switch (query_type) {
659 |
660 | /* person_role */
661 | case UD_AX_PR:
662 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
663 | break;
664 |
665 | /* maintner */
666 | case UD_AX_MT:
667 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
668 | break;
669 |
670 | /* as_set, route_set */
671 | case UD_AX_MO:
672 | set_name = get_set_name(tr->class_type);
673 | sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);
674 | break;
675 |
676 | default:
677 | fprintf(stderr, "E: query not defined for this type of attribute[%d]\n", attr->type);
678 | die;
679 | break;
680 | }
681 |
682 | /*fprintf(stderr, "D: query: %s\n", query);*/
683 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
684 | /*fprintf(stderr, "D: query: %d rows affected\n", num);*/
685 | if (sql_err) {
686 | fprintf(stderr, "E: dummy->main:%s[%s]\n", SQ_error(tr->sql_connection), query);
687 | die;
688 | }
689 |
690 | /* for legacy person/role reference (without nic-handle) create records in names table */
691 | if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){
692 | /* parse the names */
693 | /*fprintf(stderr,"adding names for dummy\n");*/
694 | query_fmt = DF_get_insert_query(A_PN);
695 | attr_value = g_strdup(attr->value);
696 | token = attr_value;
697 | while((p_name=strsep(&token, " "))){
698 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
699 | /* fprintf(stderr, "D: query: %s\n", query);*/
700 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
701 | if (sql_err)
702 | if(SQ_errno(tr->sql_connection) != ER_DUP_ENTRY) {
703 | fprintf(stderr, "E: insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query);
704 | result=-1;
705 | }
706 | }
707 | free(attr_value);
708 | }
709 | return(result);
710 | }
711 |
712 | /************************************************************
713 | * update_attr() *
714 | * *
715 | * Function that updates an attribute if it already exists. *
716 | * Called from each_attribute_proces() function if it *
717 | * cannot insert the row. *
718 | * Queries for the attributes are defined in Update[] array. *
719 | * *
720 | * Returns: Nothing. Error code is stored in tr->error. *
721 | * *
722 | *************************************************************/
723 | static void update_attr(Attribute_t *attr, Transaction_t *tr)
724 | {
725 | int num;
726 | const char *query_fmt;
727 | char *set_name;
728 | unsigned int if_address;
729 | char * rf_host;
730 | int rf_port, rf_type;
731 | char *a_value;
732 | int sq_info[3];
733 | char * condition;
734 | char *sq_error;
735 | char query[STR_XL];
736 | ip_prefix_t dn_pref;
737 | int sql_err;
738 | char *token;
739 | char *mu_mntner;
740 |
741 |
742 | /* It may be needed to update second attribute stored in the main table, like inetnum, filter-set, etc. */
743 | if((tr->load_pass!=0)&&(DF_get_update_query_type(attr->type)!=UD_MA_U2)) return;
744 |
745 | /* fprintf(stderr, "D: updating attribute...\n");*/
746 |
747 | /* Do some additional processing for reverse domains */
748 | /* XXX Later we will implement this under UD_MA_DN case */
749 | if ((attr->type == A_DN) && (IP_revd_e2b(&dn_pref, attr->value)==IP_OK)) {
750 | if(update_reverse_domain(tr, &dn_pref) !=0 ){
751 | tr->error|=ERROR_U_DBS;
752 | tr->succeeded=0;
753 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
754 | ERROR_U_DBS, attr->type, attr->value, SQ_error(tr->sql_connection));
755 | }
756 | }
757 |
758 | /* query_fmt = Update[attr->type].qry; */
759 | query_fmt = DF_get_update_query(attr->type);
760 |
761 | if (strcmp(query_fmt, "") == 0) return;
762 |
763 | switch (DF_get_update_query_type(attr->type)) {
764 | case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
765 | break;
766 | case UD_MA_PR:
767 | sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
768 | break;
769 | case UD_MA_U2: /* save the new value of the attribute for commit*/
770 | /* this is necessary for filter(filter-set), netname (inet?num), */
771 | /* local-as(inet-rtr) attributes, as they are another field in the record */
772 | if((tr->load_pass != 0)){
773 | /* for fast loader we need to update the field as we have no commit */
774 | sprintf(query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attr->value, tr->object_id);
775 | }
776 | else {
777 | tr->save=g_strdup(attr->value);
778 | /* fprintf(stderr, "ALLOCATED [%s]\n", tr->save); */
779 | return;
780 | }
781 | break;
782 | case UD_AX_PR:
783 | /* This is for non-conformant admin-c, etc.*/
784 | a_value=attr->value;
785 | if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
786 |
787 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
788 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
789 | get_ref_id(tr, "person_role", "nic_hdl", attr->value, condition));
790 | break;
791 | case UD_AX_MT:
792 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
793 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
794 | get_ref_id(tr, "mntner", "mntner", attr->value, condition));
795 | break;
796 | case UD_AX_MU: /* for mnt_routes table*/
797 | a_value=g_strdup(attr->value);
798 | token = a_value;
799 | mu_mntner=strsep(&token, " ");
800 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
801 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
802 | get_ref_id(tr, "mntner", "mntner", mu_mntner, condition));
803 | free(a_value);
804 | break;
805 | case UD_AX_MO:
806 | set_name = get_set_name(tr->class_type);
807 | /* fprintf(stderr, "D: retrieved set name: %s\n", set_name);*/
808 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
809 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
810 | get_ref_id(tr, set_name, set_name, attr->value, condition));
811 | break;
812 | case UD_AX_MR:
813 | if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
814 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
815 | get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
816 | else {
817 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
818 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
819 | get_ref_id(tr, "mntner", "mntner", attr->value, condition));
820 | }
821 | break;
822 | case UD_LEAF_:
823 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
824 | break;
825 | case UD_LF_IF:
826 | /* Convert ascii ip -> numeric one */
827 | convert_if(attr->value, &if_address);
828 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
829 | break;
830 | case UD_LF_RF:
831 | rf_host=convert_rf(attr->value, &rf_type, &rf_port);
832 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
833 | if(rf_host)free(rf_host);
834 | break;
835 | case UD_LF_AY:
836 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
837 | break;
838 | default:
839 | fprintf(stderr, "E:<e_a_u> query not defined for this type of attribute:[%d]\n", attr->type);
840 | tr->error|=ERROR_U_BUG;
841 | tr->succeeded=0;
842 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
843 | break;
844 | }
845 | /* fprintf(stderr, "D: update: [%s]", query); */
846 |
847 | /* Execute the query */
848 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
849 | if(sql_err) { /* an error occured*/
850 | /* Error - copy the error condition and return */
851 | sq_error=SQ_error(tr->sql_connection);
852 | fprintf(stderr, "E:<each_attribute_create> %s:[%s]\n", sq_error, query);
853 | tr->error|=ERROR_U_DBS;
854 | tr->succeeded=0;
855 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
856 | die;
857 | }
858 | else {
859 | /* Query OK */
860 | num = mysql_affected_rows(tr->sql_connection);
861 | if(num == 0) { /* check for duplicates*/
862 | SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/
863 | if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) {
864 | /* Condition with zero duplicates and matches may occur when the object is a dummy */
865 | /* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */
866 | /* In such case we will append "AND dummy=0" to the query, which won't */
867 | /* return a match if the object in question is a dummy */
868 | fprintf(stderr, "E: Dummy prevents update: [%s]\n", query);
869 | tr->error|=ERROR_U_OBJ;
870 | tr->succeeded=0;
871 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy update\n" ,ERROR_U_OBJ, attr->type, attr->value);
872 | } /* else duplicate entry - silently drop it */
873 | }
874 | /* For member_of attribute we need to check membership claim in protected mode */
875 | if ((attr->type == A_MO) && (tr->dummy!=1)){
876 | /* fprintf(stderr, "D:<e_a_p>: need to auth membership\n");*/
877 | if(auth_member_of(attr, tr)!=0){
878 | tr->error|=ERROR_U_AUT;
879 | tr->succeeded=0;
880 | fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
881 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);
882 | }
883 | }
884 | }
885 | return;
886 | }/* update_attr() */
887 |
888 |
889 | /************************************************************
890 | * each_attribute_proces() *
891 | * *
892 | * Main function that processes object attributes one by one.*
893 | * Called from g_slist_foreach() function. *
894 | * First it tries to insert an attribute. *
895 | * If an error it assumes that attribute is already in *
896 | * a table and calls update_attr() to update it. *
897 | * Queries for the attributes are defined in Insert[] array. *
898 | * *
899 | * Returns: Nothing. Error code is stored in tr->error. *
900 | * *
901 | *************************************************************/
902 | static void each_attribute_process(void *element_data, void *tr_ptr)
903 | {
904 | int num;
905 | const char *query_fmt;
906 | int query_type;
907 | int do_query;
908 | Attribute_t *attr = element_data;
909 | Transaction_t *tr = (Transaction_t *)tr_ptr;
910 | unsigned int prefix, prefix_length, if_address;
911 | unsigned int begin_in, end_in;
912 | ip_v6word_t high, low;
913 |
914 | int begin_as, end_as;
915 | char query[STR_XL];
916 | char * set_name;
917 | char * rf_host; /* needs to be freed after use*/
918 | int rf_type, rf_port;
919 | char *a_value;
920 | int sq_info[3];
921 | char *mu_mntner, *mu_prefix;
922 | int dummy_err;
923 | char *sq_error;
924 | ip_prefix_t dn_pref;
925 | int sql_err;
926 | int res;
927 | char *token;
928 |
929 | /* In this structure we keep data for the radix tree */
930 | /* XXX now we are keeping this in tr structure */
931 |
932 | /* we still want to continue to collect all possible errors*/
933 | /* if(tr->succeeded == 0) return; */
934 |
935 | /* To switch off querying for some types of attributes */
936 | do_query=1;
937 |
938 | /* Determine the query type */
939 | query_type=DF_get_insert_query_type(attr->type);
940 |
941 | /* For loadind pass #1 we need to process only main tables */
942 | if(tr->load_pass==1){
943 | switch(query_type) {
944 | case UD_MAIN_:
945 | case UD_MA_U2:
946 | case UD_MA_PR:
947 | case UD_MA_RT:
948 | case UD_MA_IN:
949 | case UD_MA_I6:
950 | case UD_MA_OR:
951 | case UD_MA_AK:
952 | break;
953 | default: return; /* return for other than MAIN tables*/
954 | }
955 | }
956 |
957 | query_fmt = DF_get_insert_query(attr->type);
958 |
959 | /* return if no query is defined for this attribute */
960 | if (strcmp(query_fmt, "") == 0) return;
961 |
962 | /* compose the query depending on the attribute */
963 | switch (query_type) {
964 | case UD_MAIN_: /* for MAIN tables */
965 | if (ACT_UPDATE(tr->action)) do_query=0;
966 | else
967 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
968 | break;
969 | case UD_MA_OR: /* for the origin attribute */
970 | if (ACT_UPDATE(tr->action)) do_query=0;
971 | else {
972 | sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
973 | tr->action |= TA_UPD_RX;
974 | RP_pack_set_orig(attr->type, tr->packptr, attr->value);
975 | }
976 | break;
977 | case UD_MA_PR: /* for person_role table*/
978 | if (ACT_UPDATE(tr->action)) do_query=0;
979 | else
980 | sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id, attr->value);
981 |
982 | /* check if we need to update NHR */
983 | if (ACT_UPD_NHR(tr->action)) {
984 | /* Check if we can allocate it */
985 | res = NH_check(tr->nh, tr->sql_connection);
986 | if(res == -1) { /* we cannot allocate this NIC handle (DB error) */
987 | tr->succeeded=0;
988 | tr->error |= ERROR_U_DBS;
989 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attr->type, attr->value);
990 | die;
991 | }
992 | else
993 | if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */
994 | tr->succeeded=0;
995 | tr->error |= ERROR_U_OBJ;
996 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle already in use\n", ERROR_U_OBJ, attr->type, attr->value);
997 | return;
998 | }
999 | }
1000 | break;
1001 | case UD_MA_RT: /* for route table*/
1002 | if (ACT_UPDATE(tr->action)) do_query=0;
1003 | else {
1004 | tr->action |= TA_UPD_RX;
1005 | RP_pack_set_pref4(attr->type, attr->value, tr->packptr, &prefix, &prefix_length);
1006 | /*fprintf(stderr, "D: route: %u/%u\n", prefix, prefix_length); */
1007 | sprintf(query, query_fmt, tr->thread_ins,
1008 | tr->object_id, prefix, prefix_length);
1009 | }
1010 | break;
1011 | case UD_MA_IN: /* for inetnum table*/
1012 | if (ACT_UPDATE(tr->action)) do_query=0;
1013 | else {
1014 | tr->action |= TA_UPD_RX;
1015 | RP_pack_set_rang(attr->type, attr->value, tr->packptr, &begin_in, &end_in);
1016 | /* XXX error handling ? */
1017 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
1018 | }
1019 | break;
1020 | case UD_MA_I6: /* for inet6num table*/
1021 | if (ACT_UPDATE(tr->action)) do_query=0;
1022 | else {
1023 | tr->action |= TA_UPD_RX;
1024 | RP_pack_set_pref6(attr->type, attr->value, tr->packptr, &high, &low, &prefix_length);
1025 | /* XXX error handling ? */
1026 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length);
1027 | }
1028 | break;
1029 | case UD_MA_U2: /* This is actually an update - go to update_attr - this is more natural */
1030 | do_query=0;
1031 | break;
1032 | case UD_MA_AK: /* for as_block table*/
1033 | if (ACT_UPDATE(tr->action)) do_query=0;
1034 | else {
1035 | convert_as_range(attr->value, &begin_as, &end_as);
1036 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
1037 | }
1038 | break;
1039 | case UD_AUX__: /* for AUX tables*/
1040 | if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
1041 | if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
1042 |
1043 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1044 | if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
1045 | break;
1046 | case UD_AX_MO: /* for member_of table*/
1047 | set_name = get_set_name(tr->class_type);
1048 | /* fprintf(stderr, "D: retrieved set name: %s\n", set_name);*/
1049 | sprintf(query, query_fmt, tr->thread_ins,
1050 | tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
1051 | break;
1052 | case UD_AX_MR: /* for mbrs_by_ref table*/
1053 | if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
1054 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
1055 | else
1056 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1057 | break;
1058 | case UD_AX_MU: /* for mnt_routes table*/
1059 | a_value=g_strdup(attr->value);
1060 | token = a_value;
1061 | mu_mntner=strsep(&token, " ");
1062 | mu_prefix=token;
1063 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, mu_mntner);
1064 | free(a_value);
1065 | if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
1066 | break;
1067 | case UD_LEAF_: /* for LEAF tables*/
1068 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
1069 | break;
1070 | case UD_LF_OT: /* for LEAF tables containing object_type field*/
1071 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1072 | break;
1073 | case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/
1074 | if(tr->dummy!=1){
1075 | if(strncmp("PGPKEY", attr->value, 6)==0) {
1076 | if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) {
1077 | fprintf(stderr, "E:<e_a_p>: No key-cert object.\n");
1078 | tr->error|=ERROR_U_OBJ;
1079 | tr->succeeded=0;
1080 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
1081 | return;
1082 | }
1083 | }
1084 | }
1085 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1086 | break;
1087 | case UD_LF_IF: /* for ifaddr tables*/
1088 | /* Convert ascii ip -> numeric one*/
1089 | convert_if(attr->value, &if_address);
1090 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, if_address);
1091 | break;
1092 | case UD_LF_RF: /* for refer table*/
1093 | rf_host=convert_rf(attr->value, &rf_type, &rf_port);
1094 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port);
1095 | if(rf_host)free(rf_host);
1096 | break;
1097 | case UD_LF_AY: /* for auth_override table*/
1098 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
1099 | break;
1100 | default:
1101 | fprintf(stderr, "E: query not defined for this type of attribute\n");
1102 | tr->succeeded=0;
1103 | tr->error |= ERROR_U_BUG;
1104 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attr->type, attr->value);
1105 | die;
1106 | break;
1107 | }
1108 |
1109 | /* fprintf(stderr, "D: insert: [%s]", query); */
1110 |
1111 |
1112 | /* Make the query. For primary keys go straight to updates if we are updating the object */
1113 | if(do_query){
1114 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1115 | }
1116 | else {
1117 | update_attr(attr, tr);
1118 | return;
1119 | }
1120 |
1121 | /* fprintf(stderr, "D: query: %d rows affected\n", num);*/
1122 | if (sql_err) {
1123 | /* we received an error */
1124 | if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/
1125 | if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/
1126 | update_attr(attr, tr);
1127 | return;
1128 | }
1129 | /* Otherwise this is a duplicate attribute, just ignore it */
1130 | /* In the future if we are more stringent, checks may be added here */
1131 | }
1132 | else { /* Other errors reveal a database/server problem*/
1133 | sq_error=SQ_error(tr->sql_connection);
1134 | tr->error|=ERROR_U_DBS;
1135 | tr->succeeded=0;
1136 | fprintf(stderr, "E:<each_attribute_create>: %s: [%s]\n", sq_error, query);
1137 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
1138 | }
1139 | } /* if error occured */
1140 | else {
1141 | /* If the query was successful */
1142 | num = mysql_affected_rows(tr->sql_connection);
1143 | if(num>0){ /* this is OK*/
1144 | /* Do some additional processing for member_of attribute */
1145 | if ((attr->type == A_MO) && (tr->dummy!=1)){
1146 | /* fprintf(stderr, "D:<e_a_p>: need to auth membership\n");*/
1147 | if(auth_member_of(attr, tr)!=0){
1148 | tr->error|=ERROR_U_AUT;
1149 | tr->succeeded=0;
1150 | fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
1151 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);
1152 | }
1153 | }
1154 | else
1155 | /* Do some additional processing for reverse zones domains */
1156 | if ((attr->type == A_DN)
1157 | && IP_revd_e2b(&dn_pref, attr->value)==IP_OK ) {
1158 |
1159 | if(insert_reverse_domain(tr, &dn_pref) != 0 ) {
1160 | tr->error|=ERROR_U_DBS;
1161 | tr->succeeded=0;
1162 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1163 | ERROR_U_DBS, attr->type, attr->value,
1164 | SQ_error(tr->sql_connection));
1165 | die;
1166 | }
1167 | else {
1168 | /* save data for the radix tree update */
1169 | tr->action |= TA_UPD_RX;
1170 | RP_pack_set_revd(attr->type, attr->value, tr->packptr);
1171 | }
1172 | }
1173 | return;
1174 | }
1175 | if(num == 0) {
1176 | /* this could be an empty update or a null select */
1177 | SQ_get_info(tr->sql_connection, sq_info);
1178 | if (sq_info[SQL_DUPLICATES]>0) {
1179 | if (sq_info[SQL_DUPLICATES]>1) {
1180 | fprintf(stderr, "E: Update: Too many duplicates for query: [%s]\n", query);
1181 | tr->error|=ERROR_U_DBS;
1182 | tr->succeeded=0;
1183 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:duplicates\n" ,ERROR_U_DBS, attr->type, attr->value);
1184 | die;
1185 | }
1186 | update_attr(attr, tr);
1187 | }
1188 | else {
1189 |
1190 | /* try to create dummy and repeat original query*/
1191 |
1192 | /* fprintf(stderr, "W: no ref. integrity. Trying to create dummy...");*/
1193 |
1194 | dummy_err = create_dummy(attr, tr);
1195 | if (dummy_err == 0) {
1196 | /* fprintf(stderr, "D: ... dummy OK\n");*/
1197 | g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
1198 | /* fprintf(stderr, "D: repeating query: %s\n", query);*/
1199 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1200 | num = mysql_affected_rows(tr->sql_connection);
1201 | if (sql_err) {
1202 | sq_error=SQ_error(tr->sql_connection);
1203 | fprintf(stderr, "E: re-insert query:%s[%s]\n", sq_error, query);
1204 | tr->error|=ERROR_U_DBS;
1205 | tr->succeeded=0;
1206 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1207 | ERROR_U_DBS, attr->type, attr->value, sq_error);
1208 | }
1209 | if (num==0) {
1210 | fprintf(stderr, "E: re-insert query:%s[%s]\n", "", query);
1211 | tr->error|=ERROR_U_DBS;
1212 | tr->succeeded=0;
1213 | fprintf(stderr, "E: re-insert query: [%s]\n", query);
1214 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" ,
1215 | ERROR_U_DBS, attr->type, attr->value);
1216 | }
1217 | }
1218 | else
1219 | if(dummy_err == 1) {
1220 | tr->error |= ERROR_U_OBJ;
1221 | tr->succeeded=0;
1222 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not allowed\n" ,ERROR_U_OBJ, attr->type, attr->value);
1223 | }
1224 | else {
1225 | tr->error|=ERROR_U_DBS;
1226 | tr->succeeded=0;
1227 | fprintf(stderr, "E:<each_attribute_create>: dummy not created\n");
1228 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not created\n" ,ERROR_U_DBS, attr->type, attr->value);
1229 | }
1230 | } /* RI*/
1231 | }/* if num == 0*/
1232 | } /* if the query was successful */
1233 |
1234 | return;
1235 | } /* each_attribute_process() */
1236 |
1237 |
1238 |
1239 | /************************************************************
1240 | * each_primary_key_select() *
1241 | * *
1242 | * Function that forms a query for an object (w prinary keys)*
1243 | * Called from g_slist_foreach() function. *
1244 | * Primary keys are defined in Select[] array. *
1245 | * *
1246 | * Returns: Nothing. *
1247 | * *
1248 | *************************************************************/
1249 | static void each_primary_key_select(void *element_data, void *result_ptr)
1250 | {
1251 | Attribute_t *attr = element_data;
1252 | GString *result = (GString *)result_ptr;
1253 | const char *query_fmt;
1254 | unsigned int prefix, prefix_length;
1255 | unsigned int begin_in, end_in;
1256 | int begin_as, end_as;
1257 | ip_prefix_t prefstr;
1258 | ip_range_t rangstr;
1259 | ip_v6word_t i6_msb, i6_lsb;
1260 |
1261 | query_fmt = DF_get_select_query(attr->type);
1262 |
1263 | if (strcmp(query_fmt, "") != 0) {
1264 | switch (DF_get_select_query_type(attr->type)) {
1265 | case UD_MAIN_:
1266 | g_string_sprintfa(result, query_fmt, attr->value);
1267 | break;
1268 | case UD_MA_RT:
1269 | IP_pref_a2v4(attr->value, &prefstr, &prefix, &prefix_length);
1270 | g_string_sprintfa(result, query_fmt, prefix, prefix_length);
1271 | break;
1272 | case UD_MA_IN:
1273 | IP_rang_a2v4(attr->value, &rangstr, &begin_in, &end_in);
1274 | g_string_sprintfa(result, query_fmt, begin_in, end_in);
1275 | break;
1276 | case UD_MA_I6:
1277 | IP_pref_a2v6(attr->value, &prefstr, &i6_msb, &i6_lsb, &prefix_length);
1278 | g_string_sprintfa(result, query_fmt, i6_msb, i6_lsb, prefix_length);
1279 | break;
1280 | case UD_MA_AK:
1281 | convert_as_range(attr->value, &begin_as, &end_as);
1282 | g_string_sprintfa(result, query_fmt, begin_as, end_as);
1283 | break;
1284 | default:
1285 | fprintf(stderr, "E:<e_p_k_s>: query not defined for this type of attribute:[%d]\n", attr->type);
1286 | die;
1287 |
1288 | break;
1289 | }
1290 | }
1291 | }
1292 |
1293 | /************************************************************
1294 | * perform_create(const Object_t *obj, Transaction_t *tr) *
1295 | * *
1296 | * Procedure for creating a new object. *
1297 | * First inserts object into 'last' table and gets object_id.*
1298 | * Then processes all attributes. *
1299 | * *
1300 | * Returns: tr->succeeded: >0 success, 0 - error *
1301 | * Error code is stored in tr->error. *
1302 | * *
1303 | *************************************************************/
1304 | static int perform_create(Transaction_t *tr)
1305 | {
1306 | Object_t *obj;
1307 | char *str;
1308 | GString *query;
1309 | long timestamp;
1310 | int sql_err;
1311 |
1312 |
1313 | if ((query = g_string_sized_new(STR_XL)) == NULL){
1314 | tr->succeeded=0;
1315 | tr->error |= ERROR_U_MEM;
1316 | fprintf(stderr, "E: cannot allocate gstring\n");
1317 | die;
1318 | }
1319 |
1320 |
1321 | obj=tr->object;
1322 |
1323 | str = (obj->object)->str;
1324 | timestamp=time(NULL);
1325 | tr->sequence_id=1; /* we start with 1*/
1326 | g_string_sprintf(query, "INSERT INTO last SET thread_id=0, timestamp=%ld, sequence_id=1, object_type=%d, object='%s' ",
1327 | timestamp, tr->class_type, str);
1328 |
1329 | sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1330 |
1331 | /* Check for affected rows. One row should be affected . */
1332 | if (sql_err) {
1333 | tr->error|=ERROR_U_DBS;
1334 | tr->succeeded=0;
1335 | fprintf(stderr, "E ERROR!<perform_create>: INSERT last failed:%s\n", SQ_error(tr->sql_connection));
1336 | g_string_sprintfa(tr->error_script,"E[%d][:]:%s\n" ,ERROR_U_DBS, SQ_error(tr->sql_connection));
1337 | }
1338 | else {
1339 | /* Get generated (autoincrement) object_id */
1340 | tr->object_id=mysql_insert_id(tr->sql_connection);
1341 | g_slist_foreach(obj->attributes, each_attribute_process, tr);
1342 | }
1343 | g_string_free(query, TRUE);
1344 | return(tr->succeeded);
1345 | } /* perform_create() */
1346 |
1347 | /************************************************************
1348 | * perform_update(Transaction_t *tr) *
1349 | * *
1350 | * Procedure for updating (existing) object. *
1351 | * First processes all attributes. *
1352 | * Then saves previous object in 'history' and updates *
1353 | * 'last' table. *
1354 | * *
1355 | * Returns: tr->succeeded: >0 success, 0 - error *
1356 | * Error code is stored in tr->error. *
1357 | * *
1358 | *************************************************************/
1359 | static int perform_update(Transaction_t *tr)
1360 | {
1361 | Object_t *obj;
1362 | char *str;
1363 | GString *query;
1364 | int num;
1365 | long sequence_id;
1366 | long timestamp;
1367 | char *sq_error;
1368 | int sql_err;
1369 |
1370 |
1371 | obj=tr->object;
1372 |
1373 | /* process each attribute one by one */
1374 | g_slist_foreach(obj->attributes, each_attribute_process, tr);
1375 |
1376 | /* If we've already failed or this is fast load - just return */
1377 | if((tr->succeeded == 0) || (tr->load_pass != 0)) return(tr->succeeded);
1378 |
1379 | /* No return: thread_id=0 */
1380 | /* Do it only if previous transactions finished well */
1381 | if ((query = g_string_sized_new(STR_XL)) == NULL){
1382 | tr->succeeded=0;
1383 | tr->error |= ERROR_U_MEM;
1384 | fprintf(stderr, "E: cannot allocate gstring\n");
1385 | die;
1386 | }
1387 | /* copy object to the history table */
1388 | /*fprintf(stderr, "INSERT history\n"); */
1389 | g_string_sprintf(query,"INSERT history "
1390 | "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
1391 | "FROM last "
1392 | "WHERE object_id=%ld ", tr->object_id);
1393 |
1394 | sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1395 |
1396 | /* Check for affected rows. One row should be affected . */
1397 | num = mysql_affected_rows(tr->sql_connection);
1398 | if (num < 1) {
1399 | tr->error|=ERROR_U_DBS;
1400 | tr->succeeded=0;
1401 | if (sql_err) {
1402 | sq_error=SQ_error(tr->sql_connection);
1403 | fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]%s\n", num, query, sq_error);
1404 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed:%s\n" ,ERROR_U_DBS, sq_error);
1405 | }
1406 | else {
1407 | fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query);
1408 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed\n" ,ERROR_U_DBS);
1409 | /* This is to check that this is really could happen */
1410 | die;
1411 | }
1412 | g_string_free(query, TRUE);
1413 | return(tr->succeeded);
1414 | }
1415 |
1416 | /* get sequence number */
1417 |
1418 | sequence_id = get_sequence_id(tr);
1419 | if(sequence_id==-1) {
1420 | fprintf(stderr, "E ERROR!<perform_update> cannot get sequence_id\n");
1421 | tr->error|=ERROR_U_DBS;
1422 | tr->succeeded=0;
1423 | g_string_sprintfa(tr->error_script,"E[%d][:]:cannot get seq ID\n" ,ERROR_U_DBS);
1424 | g_string_free(query, TRUE);
1425 | return(tr->succeeded);
1426 | }
1427 | else tr->sequence_id=sequence_id; /* save it for rollback*/
1428 |
1429 |
1430 | /* Insert new version into the last */
1431 |
1432 | /* Put a timestamp */
1433 | str = (obj->object)->str;
1434 | timestamp=time(NULL);
1435 | tr->sequence_id++;
1436 |
1437 | /*fprintf(stderr, "UPDATE last\n"); */
1438 | /* If we are here - it's almost commit. Otherwise this row will not be updated at all. */
1439 | g_string_sprintf(query, "UPDATE last "
1440 | "SET thread_id=0, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s' "
1441 | "WHERE object_id=%ld ",
1442 | tr->sequence_id, timestamp, tr->class_type, str, tr->object_id);
1443 |
1444 | sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1445 |
1446 | /* Check for affected rows. One row should be affected */
1447 | num = mysql_affected_rows(tr->sql_connection);
1448 | if (num < 1) {
1449 | tr->error|=ERROR_U_DBS;
1450 | tr->succeeded=0;
1451 | if(sql_err) {
1452 | fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]%s\n", num, query, SQ_error(tr->sql_connection));
1453 | g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection));
1454 | }
1455 | else {
1456 | fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query);
1457 | g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed\n" ,ERROR_U_DBS);
1458 | /* This is to check that this is really could happen */
1459 | die;
1460 | }
1461 | g_string_free(query, TRUE);
1462 | return(tr->succeeded);
1463 | }
1464 | g_string_free(query, TRUE);
1465 | return(tr->succeeded);
1466 | } /* perform_update() */
1467 |
1468 |
1469 |
1470 |
1471 | /************************************************************
1472 | * int object_process(Transaction_t *tr) *
1473 | * *
1474 | * This is the interface between core and upper layer *
1475 | * All it gets is Transaction *tr, which contains all *
1476 | * necessary information, including the object in its *
1477 | * internal representation. *
1478 | * *
1479 | * Returns: tr->succeeded: >0 success, 0 - error *
1480 | * Error code is stored in tr->error. *
1481 | * *
1482 | *************************************************************/
1483 | int object_process(Transaction_t *tr)
1484 | {
1485 | int res;
1486 | char nic[MAX_NH_LENGTH];
1487 |
1488 | if(ACT_DELETE(tr->action)){
1489 | fprintf(stderr, "D: Action: Delete...");
1490 | delete(tr);
1491 | /* Commit nic-handle deletion to the repository */
1492 | if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1493 | res = NH_free(tr->nh, tr->sql_connection);
1494 | if(res == -1) {
1495 | tr->succeeded=0;
1496 | tr->error |= ERROR_U_DBS;
1497 | g_string_sprintfa(tr->error_script,"E[%d][]:cannot delete nic-handle\n", ERROR_U_DBS);
1498 | return(tr->succeeded);
1499 | }
1500 | else if(res == 0) {
1501 | tr->succeeded=0;
1502 | tr->error |= ERROR_U_OBJ;
1503 | g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle not found\n", ERROR_U_OBJ);
1504 | return(tr->succeeded);
1505 | }
1506 | }
1507 | return(tr->succeeded); /*commit is not needed*/
1508 | }
1509 | else if(ACT_UPDATE(tr->action)){
1510 | fprintf(stderr, "D: Action: Update...");
1511 | perform_update(tr);
1512 | /* Commit nic-handle allocation (if any) to the repository if we are replacing dummy*/
1513 | if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1514 | /* convert nh to DB nIC handle before registration */
1515 | /* because there nh will bee freed */
1516 | NH_convert(nic, tr->nh);
1517 | res = NH_register(tr->nh, tr->sql_connection);
1518 | if(res == -1) {
1519 | tr->succeeded=0;
1520 | tr->error |= ERROR_U_DBS;
1521 | g_string_sprintfa(tr->error_script,"E[%d][]:cannot allocate nic-handle\n", ERROR_U_DBS);
1522 | }
1523 | else if(res == 0) {
1524 | tr->succeeded=0;
1525 | tr->error |= ERROR_U_OBJ;
1526 | g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle already in use\n", ERROR_U_OBJ);
1527 | }
1528 | else { /* copy the NH to the report to return to DBupdate */
1529 | /* Convert nh to the database format */
1530 | g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1531 | }
1532 | }
1533 | }
1534 | else if(ACT_CREATE(tr->action)){
1535 | fprintf(stderr, "D: Action: Create...");
1536 | perform_create(tr);
1537 | /* Commit nic-handle allocation (if any) to the repository */
1538 | if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1539 | /* convert nh to DB nIC handle before registration */
1540 | /* because there nh will bee freed */
1541 | NH_convert(nic, tr->nh);
1542 | res = NH_register(tr->nh, tr->sql_connection);
1543 | if(res == -1) {
1544 | tr->succeeded=0;
1545 | tr->error |= ERROR_U_DBS;
1546 | g_string_sprintfa(tr->error_script,"E[%d][]:cannot allocate nic-handle\n", ERROR_U_DBS);
1547 | }
1548 | else if(res == 0) {
1549 | tr->succeeded=0;
1550 | tr->error |= ERROR_U_OBJ;
1551 | g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle already in use\n", ERROR_U_OBJ);
1552 | }
1553 | else { /* copy the NH to the report to return to DBupdate */
1554 | g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1555 | }
1556 | }
1557 |
1558 | }
1559 | else {
1560 | fprintf(stderr, "D: Action: Unknown...");
1561 | tr->succeeded=0;
1562 | tr->error|=ERROR_U_BADOP;
1563 | return(tr->succeeded);
1564 | }
1565 |
1566 | if(tr->load_pass == 0) { /* not for fast loader*/
1567 | if (tr->succeeded == 1) {
1568 | /*fprintf(stderr, "D: Commit transaction...\n"); */
1569 | commit(tr);
1570 | }
1571 | else {
1572 | /*fprintf(stderr, "D: Roll back transaction...\n"); */
1573 | rollback(tr);
1574 | }
1575 | }
1576 | return(tr->succeeded);
1577 | } /* object_process() */
1578 |