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