modules/ud/ud_core.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- convert_if
- convert_rf
- convert_as
- convert_as_range
- convert_time
- get_set_name
- get_object_id
- get_qresult_str
- get_field_str
- get_sequence_id
- get_ref_id
- isdummy
- isnichandle
- process_reverse_domain
- insert_reverse_domain
- update_reverse_domain
- auth_member_of
- create_dummy
- update_attr
- each_attribute_process
- each_primary_key_select
- perform_create
- perform_update
- object_process
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
489 #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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