modules/ud/ud_process_stream.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. ud_parse_init
  2. ud_parse_free
  3. split_attribute
  4. reorder_attributes
  5. each_attribute_print
  6. print_object
  7. escape_apostrophes
  8. line_type
  9. UD_parse_object
  10. report_transaction
  11. process_nrtm
  12. process_updates
  13. process_transaction
  14. 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 

/* [<][>][^][v][top][bottom][index][help] */