modules/ud/ud_process_stream.c

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

FUNCTIONS

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

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

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