modules/ud/ud_process_stream.c

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

FUNCTIONS

This source file includes following functions.
  1. split_attribute
  2. reorder_attributes
  3. each_attribute_print
  4. print_object
  5. escape_apostrophes
  6. line_type
  7. report_transaction
  8. process_nrtm
  9. process_updates
  10. process_transaction
  11. UD_process_stream

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

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