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