modules/ud/ud_process_stream.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- ud_parse_init
- ud_parse_free
- split_attribute
- reorder_attributes
- each_attribute_print
- print_object
- escape_apostrophes
- line_type
- UD_parse_object
- report_transaction
- process_nrtm
- process_updates
- process_transaction
- UD_process_stream
1 /***************************************
2 $Revision: 1.35 $
3
4 Functions to process data stream( file, network socket, etc.)
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 <sys/types.h>
34 #include <sys/socket.h>
35 #include <netdb.h>
36 #include <arpa/inet.h>
37 #include <unistd.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include "constants.h"
42 #include "query_command.h"
43 #include "ud.h"
44 #include "ud_int.h"
45
46 typedef enum _Line_Type_t {
47 LINE_ATTRIBUTE,
48 LINE_COMMENT,
49 LINE_EMPTY,
50 LINE_EOF,
51 LINE_ADD,
52 LINE_UPD,
53 LINE_DEL,
54 LINE_OVERRIDE_ADD,
55 LINE_OVERRIDE_UPD,
56 LINE_OVERRIDE_DEL,
57 LINE_PLUS
58 } Line_Type_t;
59
60 /* Maximum number of objects(serials) we can consume at a time */
61 #define SBUNCH 1000
62
63 static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason);
64 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation);
65 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation);
66 static int process_transaction(UD_stream_t *ud_stream,Object_t *obj,char *object_name,nic_handle_t *nh, int operation);
67
68 /* Delimiters that separate list members, both RPS(,) and legacy( ) */
69 #define ATTR_DELIMITERS " ,"
70
71
72 void ud_parse_init(Obj_parse_t *parse){
/* [<][>][^][v][top][bottom][index][help] */
73 bzero(parse, sizeof(Obj_parse_t));
74 parse->start_object=1;
75 }
76
77 void ud_parse_free(Obj_parse_t *parse){
/* [<][>][^][v][top][bottom][index][help] */
78 free(parse->object_name);
79 }
80
81
82
83 static GSList *split_attribute(GSList *attr_list, A_Type_t attr_type, char *attr_value){
/* [<][>][^][v][top][bottom][index][help] */
84 char *token;
85 char *split;
86 char *value, *n;
87 Attribute_t *attr_split;
88 GSList *the_list = attr_list;
89
90 /* check for line continuation (+) */
91 if (strncmp(attr_value, "+", 1) == 0) attr_value++;
92 /* check for end-of-line comments */
93 n = index(attr_value, '#');
94 /* if there is no comment check for trailing \n */
95 if(n == NULL) n = index(attr_value, '\n');
96 /* now copy the clean value into the attribute */
97 if(n == NULL) value = g_strdup(attr_value);
98 else value = g_strndup(attr_value, (n - attr_value));
99
100 token=value;
101 while((split=strsep(&token, ATTR_DELIMITERS))){
102 attr_split = attribute_new1(attr_type, split);
103 if (attr_split) the_list = g_slist_append(the_list, attr_split);
104 }
105 free(value);
106 return(the_list);
107 }
108
109 /************************************************************
110 * *
111 * The function to reorder attributes in the List *
112 * nic-hdl and mnt-by should come first *
113 * *
114 * should return 0 if they are equal, a negative value if *
115 * the first element comes before the second, or a positive *
116 * value if the first element comes after the second *
117 * *
118 ************************************************************/
119 static gint reorder_attributes(const void *element1, const void *element2)
/* [<][>][^][v][top][bottom][index][help] */
120 {
121 Attribute_t *attr1 = (Attribute_t *)element1;
122 Attribute_t *attr2 = (Attribute_t *)element2;
123 gint order = -1;
124
125 if(attr2->type == A_MB) order= 1;
126 if(attr1->type == A_MB) order= -1;
127 if(attr2->type == A_NH) order= 1;
128 if(attr1->type == A_NH) order= -1;
129
130 return(order);
131
132 }
133
134 /* XXX */
135 static void each_attribute_print(void *element_data, void *tr_ptr)
/* [<][>][^][v][top][bottom][index][help] */
136 {
137
138 Attribute_t *attr = (Attribute_t *)element_data;
139
140 fprintf(stderr, "[%d|%s]\n", attr->type, attr->value);
141
142 }
143
144 /* XXX */
145 static void print_object(Object_t *obj)
/* [<][>][^][v][top][bottom][index][help] */
146 {
147 g_slist_foreach(obj->attributes, each_attribute_print, NULL);
148 fprintf(stderr, ">>>>>\n%s\n", obj->object->str);
149 }
150
151
152 /******************************************************************
153 * GString *escape_apostrophes() *
154 * Escapes apostrophes in the text so they do not confuse printf *
155 * functions and don't corrupt SQL queries *
156 * *
157 * *****************************************************************/
158 GString *escape_apostrophes(GString *text) {
/* [<][>][^][v][top][bottom][index][help] */
159 int i;
160 for (i=0; i < text->len; i++) {
161 if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
162 text = g_string_insert_c(text, i, '\\');
163 i++;
164 }
165 }
166 return(text);
167 } /* escape_apostrophes() */
168
169
170 /******************************************************************
171 * Line_Type_t line_type(e) *
172 * Determines the line type analysing the first letters *
173 * *
174 * ****************************************************************/
175 static Line_Type_t line_type(const char *line) {
/* [<][>][^][v][top][bottom][index][help] */
176 Line_Type_t result = -1;
177
178 if (strncmp(line, "# EOF", 4) == 0) {
179 result = LINE_EOF;
180 }
181 else if (strncmp(line, "#", 1) == 0) {
182 result = LINE_COMMENT;
183 }
184 else if (strcmp(line, "\n") == 0) {
185 result = LINE_EMPTY;
186 }
187 else if (strcmp(line, "ADD\n") == 0) {
188 result = LINE_ADD;
189 }
190 else if (strcmp(line, "UPD\n") == 0) {
191 result = LINE_UPD;
192 }
193 else if (strcmp(line, "DEL\n") == 0) {
194 result = LINE_DEL;
195 }
196 else if (strcmp(line, "ADD_OVERRIDE\n") == 0) {
197 result = LINE_OVERRIDE_ADD;
198 }
199 else if (strcmp(line, "UPD_OVERRIDE\n") == 0) {
200 result = LINE_OVERRIDE_UPD;
201 }
202 else if (strcmp(line, "DEL_OVERRIDE\n") == 0) {
203 result = LINE_OVERRIDE_DEL;
204 }
205 else if (strncmp(line, "+", 1) == 0) {
206 result = LINE_PLUS;
207 }
208 else {
209 result = LINE_ATTRIBUTE;
210 }
211
212 return result;
213 } /* line_type() */
214
215 /******************************************************************
216 * Object_t *UD_parse_object() *
217 * *
218 * Parses the object accepting line by line *
219 * *
220 * ****************************************************************/
221 Object_t *UD_parse_object(SQ_connection_t *sql_connection, Obj_parse_t *parse, char *line_buff)
/* [<][>][^][v][top][bottom][index][help] */
222 {
223 GString *g_line_buff;
224 Attribute_t *class_attr, *attr;
225 char *a_value, *ptr;
226 char nic[MAX_NH_LENGTH];
227
228
229 if (parse->start_object == 1) {
230 parse->obj = object_new(line_buff);
231 }
232 if (parse->obj) {
233
234 if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){
235 fprintf(stderr, "E: cannot allocate gstring\n");
236 die;
237 }
238
239 g_string_sprintf(g_line_buff, "%s", line_buff);
240 /* escape apostrophes in the input line */
241 g_line_buff=escape_apostrophes(g_line_buff);
242
243 if(parse->start_object == 1){
244 /* If this is the first attribute(==object name/type) */
245 parse->start_object=0;
246 parse->object_name = g_strndup(g_line_buff->str, g_line_buff->len);
247 *(parse->object_name+g_line_buff->len-1)='\0';
248 fprintf(stderr, "D: object: [%s] ", parse->object_name);
249 /* Create an attribute - the first one determines a class */
250 parse->class_attr_list=NULL; /* Initialize the list that will hold splitted class attribute */
251 class_attr = attribute_new(g_line_buff->str);
252 if (class_attr == NULL) die; /* Should not happen */
253 if((class_attr->type==A_PN)||(class_attr->type==A_RO)){
254 /* split names */
255 parse->class_attr_list = split_attribute(parse->class_attr_list, class_attr->type, class_attr->value);
256 attribute_free(class_attr, NULL);
257 } else {
258 parse->class_attr_list = g_slist_append(parse->class_attr_list, class_attr);
259 }
260 /* do nothing more with this attribute - we will prepend it at the end */
261 }
262 else {
263 attr = attribute_new(g_line_buff->str);
264
265 if (attr) {
266 parse->a_type=attr->type;
267 a_value=attr->value;
268 if(parse->a_type==A_NH) {
269 /* Parse the string into nh structure */
270 /* In case of an AUTO NIC handle check the ID in the database */
271 /* Possible errors leave to core processing */
272 if(NH_parse(attr->value, &parse->nh_ptr) == 0) {
273 /* fprintf(stderr, "D:parsing NIC: [%s]\n", attr->value); */
274 /* Check if we can allocate it */
275 if(NH_check(parse->nh_ptr, sql_connection)>0){
276 /* Convert nh to the database format */
277 NH_convert(nic, parse->nh_ptr);
278 /* fprintf(stderr, "D:NIC:[%s]\n", nic); */
279 /* Replace NIC handle in the string which is copied to the text object */
280 sprintf(line_buff, g_line_buff->str);
281 ptr = strstr(line_buff, attr->value);
282 /* parse new attribute string */
283 strcpy(ptr, nic);
284 g_string_sprintf(g_line_buff, line_buff);
285 g_string_sprintfa(g_line_buff, "\n");
286 /* Update the attribute */
287 attribute_upd(attr, attr->type, nic);
288 /* fprintf(stderr, "D:attribute updated\n"); */
289 }
290 }
291 } /* NHR stuff */
292 }
293 else
294 a_value=g_line_buff->str;
295
296 if (parse->a_type>=0) { /* This indicates that the input line contains the value of the attribute */
297 switch (parse->a_type) {
298 /*these attributes may appear several on the line - split them*/
299 case A_PN: /* person */
300 case A_RO: /* role */
301 case A_MR: /* mbrs-by-ref */
302 case A_MB: /* mnt-by */
303 case A_MO: /* member-of */
304 case A_SD: /* sub-dom */
305 case A_RZ: /* rev-srv */
306 case A_NS: /* nserver */
307 parse->obj->attributes = split_attribute(parse->obj->attributes, parse->a_type, a_value);
308 if (attr) attribute_free(attr, NULL);
309 attr=NULL;
310 break;
311 default: break;
312 }
313 /* g_string_sprintfa(obj->object, "%s", g_line_buff->str); */
314 if(attr)parse->obj->attributes = g_slist_append(parse->obj->attributes, attr);
315 }
316 } /* if not start_object (not the first/class attribute) */
317 /* copy the line into object no matter whether it is an attribute or not (continualtion, etc.) */
318 g_string_sprintfa(parse->obj->object, "%s", g_line_buff->str);
319 g_string_free(g_line_buff, TRUE);
320 }/* if (obj) */
321 return(parse->obj);
322 }
323
324 /******************************************************************
325 * report_transaction() *
326 * *
327 * Prints error report to the log *
328 * *
329 * reason - additional message that will be included *
330 * *
331 * *****************************************************************/
332 static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason)
/* [<][>][^][v][top][bottom][index][help] */
333 {
334 int result=0;
335
336 if(tr->succeeded==0) {
337 result=tr->error;
338 log->num_failed++;
339 fprintf(stderr, "FAILED[%s][%s(%d)](%d/%d)\n ", obj_name, reason, result, log->num_failed, (log->num_failed)+(log->num_ok));
340 fprintf(log->logfile, "*FAILED[%s][%s](%d/%d)\n ", obj_name, reason, log->num_failed, (log->num_failed)+(log->num_ok));
341 if(result & ERROR_U_MEM) fprintf(log->logfile, "\t*Memory allocation error\n");
342 if(result & ERROR_U_DBS) fprintf(log->logfile, "\t*Database (SQL) error\n");
343 if(result & ERROR_U_OBJ) fprintf(log->logfile, "\t*Object (RF) error\n");
344 if(result & ERROR_U_AUT) fprintf(log->logfile, "\t*Object authentication error\n");
345 if(result & ERROR_U_BADOP) fprintf(log->logfile, "\t*Bad operation\n");
346 if(result & ERROR_U_COP) fprintf(log->logfile, "\t*Conflicting operation\n");
347 if(result & ERROR_U_NSUP) fprintf(log->logfile, "\t*Object of this type is not supported\n");
348 if(result & ERROR_U_BUG) fprintf(log->logfile, "\t*Software bug - report to <ripe-dbm@ripe.net>\n");
349 fprintf(log->logfile, "%s", (tr->error_script)->str);
350 result=(-1)*result;
351 fflush(log->logfile);
352 }
353 else {
354 result=1;
355 log->num_ok++;
356 fprintf(stderr, "OK(%d/%d)\n", log->num_ok, (log->num_failed)+(log->num_ok));
357 }
358
359 return(result);
360 }/* report_transaction() */
361
362
363
364 /************************************************************
365 * process_nrtm() *
366 * *
367 * Process object in NRTM client mode *
368 * *
369 * nrtm - pointer to _nrtm structure *
370 * log - pointer to Log_t structure *
371 * object_name - name of the object *
372 * operation - operation code (OP_ADD/OP_DEL) *
373 * *
374 * Returns: *
375 * 1 - okay *
376 * <0 - error *
377 * *
378 ************************************************************/
379
380 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation)
/* [<][>][^][v][top][bottom][index][help] */
381 {
382 int result=0;
383 int dummy=0;
384 struct _nrtm *nrtm = ud_stream->nrtm;
385 Log_t *log_ptr= &(ud_stream->log);
386
387 /* We allow NRTM updates for some inconsistent objects */
388 /* One of the examples is reference by name which looks like nic-handle */
389 /* For this purpose we allow dummy creation when updating an object */
390 /* We also check for dummy allowance when deleting an object */
391 /* this is done to allow deletion of person objects referenced by name */
392
393 tr->dummy=1;
394
395 switch (operation) {
396
397 case OP_ADD:
398 if(nrtm->tr){ /* DEL ADD => saved*/
399 if(tr->object_id==0) {
400 /* object does not exist in the DB */
401 object_process(nrtm->tr); /* delete the previous(saved) object*/
402 result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
403 /* create DEL serial */
404 create_serial(nrtm->tr);
405 object_free(nrtm->tr->object);
406 transaction_free(nrtm->tr); nrtm->tr=NULL;
407 /* Create an object and update NHR */
408 tr->action=(TA_CREATE | TA_UPD_NHR);
409 /* fprintf(stderr,"CREATE next\n"); */
410 object_process(tr); /* create a new one*/
411 result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new");
412 /* create ADD serial */
413 create_serial(tr);
414 }
415 else {
416 /* object already exists in the DB - update or dummy replacement*/
417 if(tr->object_id==nrtm->tr->object_id) {/*compare the two, may be we may collapse operations*/
418 object_free(nrtm->tr->object);
419 transaction_free(nrtm->tr); nrtm->tr=NULL;
420 /* fprintf(stderr,"DEL-ADD ->> UPDATE\n");*/
421 tr->action=TA_UPDATE;
422 object_process(tr);
423 report_transaction(tr, log_ptr, object_name,"NRTM:upd");
424 result=report_transaction(tr, log_ptr, object_name,"NRTM:upd");
425 /* create DEL+ADD serial records */
426 tr->action=TA_DELETE; create_serial(tr);
427 tr->action=TA_CREATE; create_serial(tr);
428 }
429 else { /* this should be a dummy object in the database(that we are going to replace with the real one */
430 /* or an interleaved operation*/
431 /* fprintf(stderr,"DEL previous\n");*/
432 object_process(nrtm->tr); /* delete the previous(saved) object*/
433 result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
434 /* create a DEL serial record */
435 create_serial(nrtm->tr);
436 object_free(nrtm->tr->object);
437 transaction_free(nrtm->tr); nrtm->tr=NULL;
438 tr->action=TA_UPDATE;
439 dummy=isdummy(tr);
440 /* If we are replacing dummy with a real object update NHR */
441 if(dummy==1) tr->action |= TA_UPD_NHR;
442 /* fprintf(stderr,"UPDATE next(dummy)\n"); */
443 object_process(tr); /* create a new one*/
444 result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new");
445 /* For serials this is CREATE operation */
446 if(dummy==1) tr->action=TA_CREATE;
447 /* create ADD serial record */
448 create_serial(tr);
449 }
450 }
451 }
452 else { /* ADD ADD =>brand new object*/
453 if(tr->object_id==0) {
454 /* fprintf(stderr,"CREATE new\n");*/
455 /* Create an object and update NHR */
456 tr->action=(TA_CREATE | TA_UPD_NHR);
457 object_process(tr);
458 result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");
459 /* create ADD serial */
460 create_serial(tr);
461 }
462 else { /* object already exists in the database */
463 /* this may happen because of dummies*/
464 /* or with some implementations of mirroring protocol that have atomic update */
465 /* instead of add + del */
466 /* fprintf(stderr,"CREATE new\n");*/
467 tr->action=TA_UPDATE;
468 dummy=isdummy(tr);
469 /* If we are replacing dummy with a real object update NHR */
470 if(dummy==1) tr->action |= TA_UPD_NHR;
471 object_process(tr);
472 result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");
473 if(dummy==1) tr->action=TA_CREATE; /* we don't want to generate DEL serial for dummy replacement*/
474 /* create ADD serial record */
475 create_serial(tr);
476 }
477 }
478 break;
479
480 case OP_DEL:
481 if(nrtm->tr){ /*DEL DEL =>saved */
482 /* fprintf(stderr,"DEL previous\n");*/
483 object_process(nrtm->tr); /* delete the previous(saved) object*/
484 result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object");
485 /* create DEL serial record */
486 create_serial(nrtm->tr);
487 object_free(nrtm->tr->object);
488 transaction_free(nrtm->tr); nrtm->tr=NULL;
489 }
490 if(tr->object_id>0){ /* save the object*/
491 fprintf(stderr,"SAVED\n");
492 tr->action=TA_DELETE;
493 nrtm->tr=tr;
494 strcpy(nrtm->object_name, object_name);
495 return(1);
496 }
497 else { /* this is an error - Trying to DEL non-existing object*/
498 tr->succeeded=0; tr->error|=ERROR_U_COP;
499 result=report_transaction(tr, log_ptr, object_name, "NRTM:OOS:Trying to DEL non-existing object");
500 /* create DEL serial record anyway */
501 tr->action=TA_DELETE;
502 create_serial(tr);
503 }
504 break;
505
506 default:
507 tr->succeeded=0; tr->error |=ERROR_U_BADOP;
508 break;
509 }
510
511 /* Free resources */
512 object_free(tr->object);
513 transaction_free(tr);
514
515 return(result);
516 } /* process_nrtm() */
517
518
519
520 /************************************************************
521 * process_updates() *
522 * *
523 * Process object in update mode *
524 * *
525 * ud_stream - pointer to UD_stream structure *
526 * object_name - name of the object *
527 * operation - operation code (OP_ADD/OP_DEL) *
528 * *
529 * Note: *
530 * Frees tr and tr->obj on exit *
531 * *
532 * Returns: *
533 * 1 - okay *
534 * <0 - error *
535 * *
536 ************************************************************/
537
538 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation)
/* [<][>][^][v][top][bottom][index][help] */
539 {
540 int result=0;
541 Log_t *log_ptr= &(ud_stream->log);
542 int dummy=0;
543
544 switch(operation) {
545 /* Compare operations and report an error if they do not match */
546 case OP_ADD:
547 if(tr->object_id!=0) { /* trying to create, but object exists */
548 tr->succeeded=0; tr->error|=ERROR_U_COP;
549 } else {
550 /* Action: create the object and update NHR */
551 tr->action=(TA_CREATE | TA_UPD_NHR);
552 object_process(tr);
553 }
554 break;
555 case OP_UPD:
556 if(tr->object_id==0) { /* trying to update non-existing object*/
557 tr->succeeded=0; tr->error|=ERROR_U_COP;
558 } else {
559 tr->action=TA_UPDATE;
560 dummy=isdummy(tr);
561 /* If we are replacing dummy with a real object update NHR */
562 if(dummy==1) tr->action |= TA_UPD_NHR;
563 object_process(tr);
564 }
565 break;
566
567 case OP_DEL:
568 if(tr->object_id==0) { /* trying t delete non-existing object*/
569 tr->succeeded=0; tr->error|=ERROR_U_COP;
570 } else {
571 tr->action=TA_DELETE;
572 object_process(tr);
573 }
574 break;
575
576 default:
577 /* bad operation for this mode if not standalone */
578 if(tr->standalone) {
579 if(tr->object_id==0)tr->action=TA_CREATE; else tr->action=TA_UPDATE;
580 object_process(tr);
581 }
582 else {
583 tr->succeeded=0;
584 tr->error|=ERROR_U_BADOP;
585 }
586 break;
587 }
588 /* Make a report */
589 result=report_transaction(tr, log_ptr, object_name, "RIPupd:");
590
591 /* If not in standalone mode create serial and copy error transcript */
592 if(!tr->standalone) {
593 if(result==1)create_serial(tr);
594 ud_stream->error_script=g_strdup((tr->error_script)->str);
595 }
596
597 /* Free resources */
598 object_free(tr->object);
599 transaction_free(tr);
600
601 return(result);
602
603 } /* process_updates() */
604
605
606 /************************************************************
607 * *
608 * int process_transaction() *
609 * *
610 * Processes the transaction *
611 * *
612 * ud_stream - pointer to UD_stream_t structure *
613 * *
614 * Returns: *
615 * 1 - no error *
616 * <0- errors *
617 * *
618 ************************************************************/
619
620 /* It frees the obj */
621
622 static int process_transaction(UD_stream_t *ud_stream,
/* [<][>][^][v][top][bottom][index][help] */
623 Object_t *obj,
624 char *object_name,
625 nic_handle_t *nh,
626 int operation)
627 {
628 Transaction_t *tr = NULL;
629 Log_t *log_ptr = &(ud_stream->log);
630 Attribute_t *attr=NULL;
631 int result;
632
633 /* start new transaction now */
634 tr = transaction_new(ud_stream->db_connection, obj->type);
635
636 /* Return with error if transaction cannot be created */
637 if (tr == NULL) die;
638
639 tr->standalone=IS_STANDALONE(ud_stream->ud_mode);
640 tr->dummy=IS_DUMMY_ALLOWED(ud_stream->ud_mode);
641 tr->load_pass=ud_stream->load_pass;
642 tr->object=obj;
643 tr->nh=nh;
644 tr->source_hdl=ud_stream->source_hdl;
645
646 /* We perform no commit/rollback in the loader mode, so thread_id should be set to 0 */
647 if(ud_stream->load_pass!=0) { tr->thread_ins=0; tr->thread_upd=0; }
648
649 /* For the first load pass we only create objects */
650 if(ud_stream->load_pass==1) tr->object_id=0;
651 else tr->object_id=get_object_id(tr);
652
653 /* Object cannot be retrieved */
654 if(tr->object_id==-1) { /* DB error*/
655 tr->succeeded=0;
656 tr->error |= ERROR_U_DBS;
657 report_transaction(tr, log_ptr, object_name, "Object cannot be retrieved");
658 transaction_free(tr);
659 object_free(obj);
660 die;
661 }
662 /* save the name of person/role as we need it for referential */
663 /* integrity check when deleting the object against names. */
664 /* This is needed to support legacy references by name rather */
665 /* then by nic_hdl */
666 if((tr->class_type==C_PN) || (tr->class_type==C_RO)){
667 attr = attribute_new(object_name);
668
669 if (attr==NULL) {
670 tr->succeeded=0;
671 tr->error |= ERROR_U_MEM;
672 report_transaction(tr, log_ptr, object_name, "Cannot allocate memory");
673 transaction_free(tr);
674 object_free(obj);
675 die;
676 }
677
678 /* Save the value */
679 tr->save=g_strdup(attr->value);
680 /* fprintf(stderr, "Allocated [%s]\n", tr->save); */
681 attribute_free(attr, NULL);
682 }
683
684 /* Process transaction. tr and obj are freed inside the process_* functions */
685
686 if(IS_UPDATE(ud_stream->ud_mode))
687 /* We are in update mode */
688 result=process_updates(ud_stream, tr, object_name, operation);
689 else
690 /* We are in NRTM mode */
691 result=process_nrtm(ud_stream, tr, object_name, operation);
692
693 return(result);
694
695 }
696
697
698 /************************************************************
699 * *
700 * int UD_process_stream(UD_stream_t *ud_stream) *
701 * *
702 * Processes the stream *
703 * *
704 * ud_stream - pointer to UD_stream_t structure *
705 * *
706 * Returns: *
707 * in update mode (!standalone)(1 object processed): *
708 * 1 - no error *
709 * <0- errors *
710 * *
711 * in NRTM & standalone modes *
712 * total number of object processed *
713 * *
714 ************************************************************/
715
716 int UD_process_stream(UD_stream_t *ud_stream)
/* [<][>][^][v][top][bottom][index][help] */
717 {
718 char line_buff[STR_XXL];
719 /* GString *g_line_buff; */
720 GSList *class_attr_list = NULL;
721 Attribute_t *class_attr;
722 Attribute_t *attr;
723 nic_handle_t *nh_ptr = NULL; /* To save NIC handle structure */
724 Object_t *obj = NULL;
725 SQ_connection_t *sql_connection;
726 int start_object;
727 int a_type;
728 char *a_value;
729 char *ptr;
730 /* here we will store the parsed nic-hdl in required format */
731 char nic[MAX_NH_LENGTH];
732 struct _nrtm *nrtm;
733 Log_t *log_ptr= &(ud_stream->log);
734 time_t stime, ftime;
735 double obj_second1, obj_second10;
736 int result;
737 int operation=0;
738 int interrupt=0;
739 int do_update;
740 int default_ud_mode = ud_stream->ud_mode;
741 Line_Type_t linetype;
742
743 Obj_parse_t obj_parse; /* the structure used to parse a text object */
744 ud_parse_init(&obj_parse);
745
746 nrtm=ud_stream->nrtm;
747 start_object = 1;
748 a_type=-1;
749
750
751 /* Allocate line bufer */
752 /* if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){
753 fprintf(stderr, "E: cannot allocate gstring\n");
754 die;
755 }
756 */
757 /* Check connection to the database */
758 if(mysql_ping(ud_stream->db_connection)) {
759 fprintf(stderr, "D: ERROR: no SQL connection\n");
760 /* g_string_free(g_line_buff, TRUE);*/
761 return(-1);
762 }
763
764 fprintf(stderr, "OK\n");
765 sql_connection=ud_stream->db_connection;
766
767 /* This is useful for loading DB from huge disk file. */
768 /* We may start from <num_skip>th object */
769 /* num_skip=ud_stream->num_skip; */
770 /* if(num_skip>0) fprintf(stderr, "skipping %lu records\n", num_skip); */
771
772 /* Start timer for statistics */
773 stime=time(NULL);
774
775 /* Main loop. Reading input stream line by line */
776 /* Empty line signals to start processing an object, if we have it */
777 while (fgets(line_buff, STR_XXL, ud_stream->stream) != NULL) {
778
779 switch (linetype=line_type(line_buff)) {
780 case LINE_PLUS:
781 case LINE_ATTRIBUTE:
782
783 obj = UD_parse_object(ud_stream->db_connection, &obj_parse, line_buff);
784
785 break;
786
787 case LINE_COMMENT:
788 break;
789
790 case LINE_EOF:
791 break;
792
793 case LINE_ADD:
794 /* restore the default operation mode */
795 operation=OP_ADD;
796 ud_stream->ud_mode=default_ud_mode;
797 break;
798
799 case LINE_OVERRIDE_ADD:
800 /* for override - switch the dummy bit on */
801 operation=OP_ADD;
802 ud_stream->ud_mode=default_ud_mode|B_DUMMY;
803 break;
804
805 case LINE_UPD:
806 /* restore the default operation mode */
807 operation=OP_UPD;
808 ud_stream->ud_mode=default_ud_mode;
809 break;
810
811 case LINE_OVERRIDE_UPD:
812 /* for override - switch the dummy bit on */
813 operation=OP_UPD;
814 ud_stream->ud_mode=default_ud_mode|B_DUMMY;
815 break;
816
817 case LINE_DEL:
818 /* restore the default operation mode */
819 operation=OP_DEL;
820 ud_stream->ud_mode=default_ud_mode;
821 break;
822
823 case LINE_OVERRIDE_DEL:
824 /* for override - switch the dummy bit on */
825 operation=OP_DEL;
826 ud_stream->ud_mode=default_ud_mode|B_DUMMY;
827 break;
828
829 case LINE_EMPTY:
830 /* start processing the object */
831 if ((obj=obj_parse.obj)) { /* if not just garbage*/
832 /* reorder some attributes */
833 obj->attributes = g_slist_sort(obj->attributes, reorder_attributes);
834 /* prepend the class attribute */
835 obj->attributes = g_slist_concat(obj_parse.class_attr_list, obj->attributes);
836 /* XXX */
837 /* print_object(obj); */
838
839 /* start new transaction now */
840 result=process_transaction(ud_stream, obj, obj_parse.object_name, obj_parse.nh_ptr, operation);
841
842 /* process_transaction() frees tr and obj structures, */
843 /* so make sure we'll not reference these objects in the future */
844 operation=OP_NOOP;
845 ud_stream->ud_mode=default_ud_mode;
846 ud_parse_free(&obj_parse);
847
848 /* this is a good place for quick interrupt */
849 do_update=CO_get_do_update();
850 if (do_update) interrupt=0; else interrupt=1;
851 /* we still need to exit in update server mode (only 1 object at a time */
852 if (IS_UPDATE(ud_stream->ud_mode) && (!IS_STANDALONE(ud_stream->ud_mode))) interrupt=1;
853 } /* if this is a real object */
854 /* initialize the parsing structure */
855 ud_parse_init(&obj_parse);
856
857 break;
858
859 default:
860 fprintf(stderr, "ERROR: Bad line type\n");
861 } /* switch */
862
863 /* Finish processing if interrupt has been set */
864 if (interrupt) break;
865 } /* while */
866
867 /* Some postprocessing */
868 if(!IS_UPDATE(ud_stream->ud_mode)){
869 /* We are in NRTM mode */
870 /* Clean up */
871 fclose(ud_stream->stream);
872 /* In NRTM mode there may be a saved object that is unprocessed */
873 if(nrtm->tr){ /*saved backlog?*/
874 object_process(nrtm->tr); /* delete the previous(saved) object*/
875 result=report_transaction(nrtm->tr, &(ud_stream->log), nrtm->object_name,
876 "NRTM:DEL:While deleting previous(saved) object");
877 /* create DEL serial record no matter what the result is */
878 create_serial(nrtm->tr);
879 object_free(nrtm->tr->object);
880 transaction_free(nrtm->tr); nrtm->tr=NULL;
881 }
882 }
883
884 /* That's all. Free GString */
885 /* g_string_free(g_line_buff, TRUE);*/
886
887
888 /* Calculate some statistics */
889 ftime=time(NULL);
890 obj_second1 = (float)(log_ptr->num_ok)/(ftime-stime);
891 obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/(ftime-stime);
892
893 /* Print the report */
894 if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode))) {
895 /* printf("\n\n******** report **********\n%d objects OK\n%d objects failed\n",
896 log_ptr->num_ok, log_ptr->num_failed); */
897 fprintf(log_ptr->logfile,"\n******** report **********\n");
898 fprintf(log_ptr->logfile," %d objects OK (%5.2f obj/s)\n", log_ptr->num_ok, obj_second1);
899 fprintf(log_ptr->logfile," %d objects failed\n", log_ptr->num_failed);
900 fprintf(log_ptr->logfile," average processing time %5.2f obj/s (%5.2f obj/min)\n",
901 obj_second10, obj_second10*60);
902 result=log_ptr->num_ok+log_ptr->num_failed;
903 }
904 return(result);
905
906 } /* UD_process_stream */
907