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