## modules/ud/ud_process_stream.c

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

## FUNCTIONS

This source file includes following functions.

1. ud_replace_autonic
2. reorder_attr
3. ud_reorder_attributes
4. ud_split_names
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.62 $
       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,2001,2002                    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
      34 #include "rip.h"
      35 #include "syntax_api.h"
      36
      37
      38 #include <sys/types.h>
      39 #include <sys/socket.h>
      40 #include <netdb.h>
      41 #include <arpa/inet.h>
      42 #include <unistd.h>
      43 #include <sys/stat.h>
      44 #include <fcntl.h>
      45 #include <string.h>
      46
      47
      48 typedef enum _Line_Type_t {
      49  LINE_ATTRIBUTE,
      50  LINE_COMMENT,
      51  LINE_EMPTY,
      52  LINE_EOF,
      53  LINE_ADD,
      54  LINE_UPD,
      55  LINE_DEL,
      56  LINE_OVERRIDE_ADD,
      57  LINE_OVERRIDE_UPD,
      58  LINE_OVERRIDE_DEL,
      59  LINE_ACK
      60 } Line_Type_t;
      61
      62 /* Maximum number of objects(serials) we can consume at a time */
      63 #define SBUNCH 1000
      64
      65 static int report_transaction(Transaction_t *tr, long transaction_id, Log_t *log, ut_timer_t *psotime, char *reason);
      66 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, int operation);
      67 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, int operation);
      68 static int process_transaction(UD_stream_t *ud_stream, GString *obj_buff, int operation, long transaction_id);
      69
      70 static GString *escape_apostrophes(GString *text);
      71 static nic_handle_t *ud_replace_autonic(Transaction_t *tr, rpsl_object_t *object);
      72 static void reorder_attr(void *element_data, void *ptr);
      73 static void ud_reorder_attributes(rpsl_object_t *object);
      74
      75
      76 /******************************************************************
      77 * ud_replace_autonic()                                            *
      78 *                                                                 *
      79 * Checks if nic handle is an AUTO one (XX*-SRS)                   *
      80 * So it tries to assign a nic handle and if successfull           *
      81 * substitutes the attribute value                                 *
      82 *                                                                 *
      83 ******************************************************************/
      84 static nic_handle_t *ud_replace_autonic(Transaction_t *tr, rpsl_object_t *object)
         /* [<][>][^][v][top][bottom][index][help] */
      85 {
      86 nic_handle_t *nh_ptr=NULL;
      87 rpsl_attr_t *nic_hdl, *nic_hdl_old;
      88 GList *nic_hdl_list, *nic_hdl_first;
      89 gint ofs;
      90 char *nic_submitted, *nic_db;
      91
      92  nic_hdl_list = rpsl_object_get_attr(object, "nic-hdl");
      93  nic_hdl_first =g_list_first(nic_hdl_list);
      94  nic_submitted = rpsl_attr_get_clean_value((rpsl_attr_t *)nic_hdl_first->data);
      95
      96  /* check if it is an auto NIC handle and replace it with a real one */
      97  if(NH_parse(nic_submitted, &nh_ptr) == 0) {
      98   /* this is an AUTO nic handle */
      99   /* Try to allocate it */
     100   if(NH_check(nh_ptr, tr->sql_connection)>0){
     101     /* Convert nh to the database format */
     102     nic_db = NH_convert(nh_ptr);
     103     /* we need to make a copy as we free the whole list later */
     104     nic_hdl = rpsl_attr_copy((rpsl_attr_t *)nic_hdl_first->data);
     105     rpsl_attr_replace_value(nic_hdl, nic_db);
     106     UT_free(nic_db);
     107   }
     108   /* replace this attribute in the object */
     109   ofs = rpsl_attr_get_ofs(nic_hdl);
     110   /* remove attribute from object and free it */
     111   nic_hdl_old = rpsl_object_remove_attr(object, ofs, NULL);
     112   if(nic_hdl_old) rpsl_attr_delete(nic_hdl_old);
     113   else die;
     114   rpsl_object_add_attr(object, nic_hdl, ofs, NULL);
     115  }/* if this was an AUTO nic handle */
     116
     117
     118  UT_free(nic_submitted);
     119
     120  rpsl_attr_delete_list(nic_hdl_list);
     121  return(nh_ptr);
     122 }
     123
     124 static void reorder_attr(void *element_data, void *ptr)
         /* [<][>][^][v][top][bottom][index][help] */
     125 {
     126 rpsl_attr_t *attr = (rpsl_attr_t *)element_data;
     127 rpsl_object_t *object = (rpsl_object_t *)ptr;
     128 int ofs;
     129
     130   /* move the attribute to the beginning
     131      so that all mnt-by are at the beginning of the object */
     132   ofs = rpsl_attr_get_ofs(attr);
     133   attr = rpsl_object_remove_attr(object, ofs, NULL);
     134   if (attr) rpsl_object_add_attr(object, attr, 1, NULL);
     135   else die;
     136 }
     137
     138 /******************************************************************
     139 * reorder attributes                                              *
     140 *  . mnt-by should go before member-of to allow correct           *
     141 *      membership autorization (still done in RIPupd)             *
     142 *  . nic-hdl should go before any admin-c, tech-c to prevent      *
     143 *       errrors in self referencing role objects                  *
     144 ******************************************************************/
     145 static void ud_reorder_attributes(rpsl_object_t *object)
         /* [<][>][^][v][top][bottom][index][help] */
     146 {
     147 GList *mnt_by_list, *nic_hdl_list;
     148  /* get the list of mnt-by attributes */
     149  mnt_by_list = rpsl_object_get_attr(object, "mnt-by");
     150  /* reorder so that all mnt-by are at the beginning of the object */
     151  if(mnt_by_list != NULL) {
     152   g_list_foreach(mnt_by_list, reorder_attr, object);
     153
     154   /* free GList only, not members as they are stored in the object */
     155   rpsl_attr_delete_list(mnt_by_list);
     156  }
     157
     158  /* move nic-hdl to the beginning */
     159  nic_hdl_list = rpsl_object_get_attr(object, "nic-hdl");
     160  if(nic_hdl_list != NULL) {
     161   g_list_foreach(nic_hdl_list, reorder_attr, object);
     162
     163   /* free GList only, not members as they are stored in the object */
     164   rpsl_attr_delete_list(nic_hdl_list);
     165  }
     166
     167
     168 }
     169
     170 /******************************************************************
     171 * split the role or person attribute value into multiple names    *
     172 *                                                                 *
     173 * destroys the original object and builds a new one (only for     *
     174 * C_RO or C_PN                                                    *
     175 ******************************************************************/
     176
     177 static rpsl_object_t *ud_split_names(rpsl_object_t *object)
         /* [<][>][^][v][top][bottom][index][help] */
     178 {
     179 const rpsl_attr_t *attr;
     180 gchar **names;
     181 const GList *old_attrs;
     182 GList *p;
     183 GString *new_obj;
     184 rpsl_object_t *ret_val;
     185 C_Type_t class_type;
     186 int i;
     187
     188   class_type = rpsl_get_class_id(rpsl_object_get_class(object));
     189   if ((class_type != C_PN) && (class_type != C_RO)) return object;
     190
     191   /* get the list of person or role attribute */
     192   attr = rpsl_object_get_attr_by_ofs(object, 0);
     193
     194   /* split the names into words */
     195   names = g_strsplit(rpsl_attr_get_value(attr), " ", 0);
     196   new_obj =  g_string_new("");
     197
     198   /* replace the value of the first attribute */
     199   for (i=0; names[i] != NULL; i++) {
     200       g_string_sprintfa(new_obj, "%s:%s\n", rpsl_attr_get_name(attr), names[i]);
     201   }
     202
     203   g_strfreev(names);
     204
     205   /* copy all other attributes */
     206   old_attrs = rpsl_object_get_all_attr(object);
     207   for (p=g_list_next(old_attrs); p != NULL; p = g_list_next(p)) {
     208       g_string_sprintfa(new_obj, "%s:%s\n", rpsl_attr_get_name(p->data), rpsl_attr_get_value(p->data));
     209   }
     210
     211   ret_val = rpsl_object_init(new_obj->str);
     212   g_string_free(new_obj, TRUE);
     213   rpsl_object_delete(object);
     214   return ret_val;
     215
     216
     217 }
     218
     219
     220 /******************************************************************
     221 * GString *escape_apostrophes()                                   *
     222 * Escapes apostrophes in the text so they do not confuse printf   *
     223 * functions and don't corrupt SQL queries                         *
     224 *                                                                 *
     225 * *****************************************************************/
     226 static GString *escape_apostrophes(GString *text) {
         /* [<][>][^][v][top][bottom][index][help] */
     227   int i;
     228   for (i=0; i < text->len; i++) {
     229     if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
     230       text = g_string_insert_c(text, i, '\\');
     231       i++;
     232     }
     233   }
     234  return(text);
     235 } /* escape_apostrophes() */
     236
     237
     238 /******************************************************************
     239 * Line_Type_t line_type(e)                                        *
     240 * Determines the line type analysing the first letters            *
     241 *                                                                 *
     242 * ****************************************************************/
     243 static Line_Type_t line_type(const char *line, long *transaction_id) {
         /* [<][>][^][v][top][bottom][index][help] */
     244
     245   if (strncmp(line, "# EOF", 4) == 0) return(LINE_EOF);
     246   if (strncmp(line, "#", 1) == 0)     return(LINE_COMMENT);
     247   if (strcmp(line, "\n") == 0)        return(LINE_EMPTY);
     248
     249   if (strncmp(line, "ACK", 3) == 0) {
     250     *transaction_id = atol(line+3);
     251     return(LINE_ACK);
     252   }
     253   if (strncmp(line, "ADD_OVERRIDE", 12) == 0) {
     254     *transaction_id = atol(line+12);
     255     return(LINE_OVERRIDE_ADD);
     256   }
     257   if (strncmp(line, "UPD_OVERRIDE", 12) == 0) {
     258     *transaction_id = atol(line+12);
     259     return(LINE_OVERRIDE_UPD);
     260   }
     261   if (strncmp(line, "DEL_OVERRIDE", 12) == 0) {
     262     *transaction_id = atol(line+12);
     263     return(LINE_OVERRIDE_DEL);
     264   }
     265
     266   if (strncmp(line, "ADD", 3) == 0) {
     267     *transaction_id = atol(line+3);
     268     return(LINE_ADD);
     269   }
     270   if (strncmp(line, "UPD", 3) == 0) {
     271     *transaction_id = atol(line+3);
     272     return(LINE_UPD);
     273   }
     274   if (strncmp(line, "DEL", 3) == 0) {
     275     *transaction_id = atol(line+3);
     276     return(LINE_DEL);
     277   }
     278
     279 /* Otherwise this is an attribute */
     280     return(LINE_ATTRIBUTE);
     281
     282 } /* line_type() */
     283
     284
     285 /******************************************************************
     286 * report_transaction()                                            *
     287 *                                                                 *
     288 * Prints error report to the log                                  *
     289 *                                                                 *
     290 * reason - additional message that will be included               *
     291 *                                                                 *
     292 * *****************************************************************/
     293 static int report_transaction(Transaction_t *tr, long transaction_id,  Log_t *log, ut_timer_t *psotime, char *reason)
         /* [<][>][^][v][top][bottom][index][help] */
     294 {
     295 int result=0;
     296 ut_timer_t fotime;
     297 float timediff;
     298 const char *class_name = DF_class_type2name(tr->class_type);
     299 char *primary_key = tr->K->str;
     300
     301
     302  /* calculate statistics */
     303   UT_timeget(&fotime);
     304   timediff = UT_timediff(psotime, &fotime);
     305
     306  if(tr->succeeded==0) {
     307   result=tr->error;
     308   log->num_failed++;
     309   ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] %.2fs FAILED [%s:%s][%s]", transaction_id, timediff, class_name, primary_key, reason);
     310   if(result & ERROR_U_OBJ) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: referential integrity error", transaction_id);
     311   if(result & ERROR_U_AUT) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: authentication error", transaction_id);
     312   if(result & ERROR_U_BADOP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: unsupported operation", transaction_id);
     313   if(result & ERROR_U_COP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: conflicting operation", transaction_id);
     314   if(result & ERROR_U_NSUP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: this type is not supported", transaction_id);
     315   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: details [%s]", transaction_id, (tr->error_script)->str);
     316   result=1; /* # of failures */
     317  }
     318  else {
     319   result=0;
     320   log->num_ok++;
     321   ER_inf_va(FAC_UD, ASP_UD_OBJ, "[%ld] %.2fs OK     [%s:%s][%s]", transaction_id, timediff, class_name, primary_key, reason);
     322   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: details [%s]", transaction_id, (tr->error_script)->str);
     323  }
     324
     325  return(result);
     326 }/* report_transaction() */
     327
     328
     329
     330 /************************************************************
     331 * process_nrtm()                                            *
     332 *                                                           *
     333 * Process object in NRTM client mode                        *
     334 *                                                           *
     335 * nrtm - pointer to _nrtm structure                         *
     336 * log - pointer to Log_t structure                          *
     337 * object_name - name of the object                          *
     338 * operation - operation code (OP_ADD/OP_DEL)                *
     339 *                                                           *
     340 * Returns:                                                  *
     341 * 1  - okay                                                 *
     342 * <0 - error                                                *
     343 *                                                           *
     344 ************************************************************/
     345
     346 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, int operation)
         /* [<][>][^][v][top][bottom][index][help] */
     347 {
     348 int result=0;
     349 int dummy=0;
     350 struct _nrtm *nrtm = ud_stream->nrtm;
     351 long serial_id;
     352 Log_t *log_ptr= &(ud_stream->log);
     353 ut_timer_t sotime;
     354 int ta_upd_nhr;
     355
     356     /* Start timer for statistics */
     357     UT_timeget(&sotime);
     358
     359   /* We allow NRTM updates for some inconsistent objects                  */
     360   /* One of the examples is reference by name which looks like nic-handle */
     361   /* For this purpose we allow dummy creation when updating an object     */
     362   /* We also check for dummy allowance when deleting an object            */
     363   /* this is done to allow deletion of person objects referenced by name  */
     364
     365   tr->mode|=B_DUMMY;
     366   if(IS_NO_NHR(tr->mode))ta_upd_nhr=0; else ta_upd_nhr = TA_UPD_NHR;
     367
     368   switch (operation) {
     369
     370   case OP_ADD:
     371     if(nrtm->tr){ /* DEL ADD => saved*/
     372       if(tr->object_id==0) {
     373         /* object does not exist in the DB */
     374         /* delete the previous(saved) object*/
     375         object_process(nrtm->tr);
     376         /* create DEL serial */
     377         UD_lock_serial(nrtm->tr);
     378         serial_id = UD_create_serial(nrtm->tr);
     379         CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
     380         UD_commit_serial(nrtm->tr);
     381         UD_unlock_serial(nrtm->tr);
     382         /* Mark TR as clean */
     383         TR_mark_clean(nrtm->tr);
     384         /* log the transaction */
     385         result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
     386
     387         transaction_free(nrtm->tr); nrtm->tr=NULL;
     388
     389         /* Create an object and update NHR */
     390         tr->action=(TA_CREATE | ta_upd_nhr);
     391         /* restart the timer for statistics */
     392         UT_timeget(&sotime);
     393         object_process(tr); /* create a new one*/
     394         /* create ADD serial */
     395         UD_lock_serial(tr);
     396         serial_id = UD_create_serial(tr);
     397         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     398         UD_commit_serial(tr);
     399         UD_unlock_serial(tr);
     400         /* Mark TR as clean */
     401         TR_mark_clean(tr);
     402         /* log the transaction */
     403         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
     404       }
     405       else {
     406       /* object already exists in the DB - update or dummy replacement*/
     407         /*compare the two, may be we may collapse operations*/
     408         if(tr->object_id==nrtm->tr->object_id) {
     409           /* DEL-ADD ->> UPDATE */
     410           transaction_free(nrtm->tr); nrtm->tr=NULL;
     411           tr->action=TA_UPD_CLLPS;
     412           object_process(tr);
     413           /* create DEL+ADD serial records */
     414           UD_lock_serial(tr);
     415           tr->action=TA_DELETE; serial_id = UD_create_serial(tr);
     416           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:DEL(UPD)");
     417
     418           /* restart the timer for statistics */
     419           UT_timeget(&sotime);
     420           tr->sequence_id++;
     421           tr->action=TA_CREATE; serial_id = UD_create_serial(tr);
     422           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     423           UD_commit_serial(tr);
     424           UD_unlock_serial(tr);
     425           /* Mark TR as clean */
     426           TR_mark_clean(tr);
     427           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD(UPD)");
     428         }
     429         else { /* this should be a dummy object in the database(that we are going to replace with the real one */
     430         /* or an interleaved operation*/
     431           object_process(nrtm->tr); /* delete the previous(saved) object*/
     432           /* create a DEL serial record */
     433           UD_lock_serial(nrtm->tr);
     434           serial_id = UD_create_serial(nrtm->tr);
     435           CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
     436           UD_commit_serial(nrtm->tr);
     437           UD_unlock_serial(nrtm->tr);
     438           /* Mark TR as clean */
     439           TR_mark_clean(nrtm->tr);
     440           /* log the transaction */
     441           result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
     442
     443
     444           transaction_free(nrtm->tr); nrtm->tr=NULL;
     445
     446           /* restart the timer for statistics */
     447           UT_timeget(&sotime);
     448
     449           tr->action=TA_UPDATE;
     450           /* check if we are replacing a dummy object */
     451           dummy=isdummy(tr);
     452           if(dummy==1) tr->action = TA_UPD_DUMMY;
     453           object_process(tr); /* create a new one*/
     454           /* For serials this is CREATE operation. Increase sequence to have it correct in serals */
     455           if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }
     456           /* create ADD serial record */
     457           UD_lock_serial(tr);
     458           serial_id = UD_create_serial(tr);
     459           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     460           UD_commit_serial(tr);
     461           UD_unlock_serial(tr);
     462           /* Mark TR as clean */
     463           TR_mark_clean(tr);
     464           /* log the transaction */
     465           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
     466
     467         }
     468       }
     469     }
     470     else { /* ADD ADD =>brand new object*/
     471       if(tr->object_id==0) {
     472 /*      fprintf(stderr,"CREATE new\n");*/
     473         /* Create an object and update NHR */
     474         tr->action=(TA_CREATE | ta_upd_nhr);
     475         object_process(tr);
     476         /* create ADD serial */
     477         UD_lock_serial(tr);
     478         serial_id = UD_create_serial(tr);
     479         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     480         UD_commit_serial(tr);
     481         UD_unlock_serial(tr);
     482
     483         /* Mark TR as clean */
     484         TR_mark_clean(tr);
     485         /* log the transaction */
     486         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
     487       }
     488       else { /* object already exists in the database */
     489         /* this may happen because of dummies*/
     490         /* or with some implementations of mirroring protocol that have atomic update */
     491         /* instead of add + del */
     492         tr->action=TA_UPDATE;
     493         dummy=isdummy(tr);
     494         if(dummy==1) tr->action = TA_UPD_DUMMY;
     495         object_process(tr);
     496         /* For serials this is CREATE operation. Increase sequence to have it correct in serals */
     497         if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }
     498         /* create ADD serial record */
     499         UD_lock_serial(tr);
     500         serial_id = UD_create_serial(tr);
     501         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     502         UD_commit_serial(tr);
     503         UD_unlock_serial(tr);
     504         /* Mark TR as clean */
     505         TR_mark_clean(tr);
     506         /* log the transaction */
     507         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
     508
     509       }
     510     }
     511     break;
     512
     513   case OP_DEL:
     514     if(nrtm->tr){ /*DEL DEL =>saved */
     515       /* check this is not a deletion of the same object twice */
     516       /* this should not happen but we cannot trust foreign sources */
     517       /* in such case process saved transaction but fail the current one */
     518       if(nrtm->tr->object_id == tr->object_id) tr->object_id=0;
     519
     520       object_process(nrtm->tr); /* delete the previous(saved) object*/
     521       /* create DEL serial record */
     522       UD_lock_serial(nrtm->tr);
     523       serial_id = UD_create_serial(nrtm->tr);
     524       CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
     525       UD_commit_serial(nrtm->tr);
     526       UD_unlock_serial(nrtm->tr);
     527       /* Mark TR as clean */
     528       TR_mark_clean(nrtm->tr);
     529       /* log the transaction */
     530       result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
     531
     532       transaction_free(nrtm->tr); nrtm->tr=NULL;
     533     }
     534     /* save the real object (not a dummy one ) */
     535     if(tr->object_id>0 && !isdummy(tr)){
     536       /* save the object*/
     537       tr->action=(TA_DELETE | ta_upd_nhr);
     538       nrtm->tr=tr;
     539       return(0);
     540     }
     541     else { /* this is an error - Trying to DEL non-existing object*/
     542       tr->succeeded=0; tr->error|=ERROR_U_COP;
     543       tr->action=(TA_DELETE | ta_upd_nhr);
     544       /* create and initialize TR record for crash recovery */
     545       TR_create_record(tr);
     546       /* create DEL serial record anyway */
     547       UD_lock_serial(tr);
     548       serial_id = UD_create_serial(tr);
     549       CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     550       UD_commit_serial(tr);
     551       UD_unlock_serial(tr);
     552       /* Mark TR as clean */
     553       TR_mark_clean(tr);
     554       /* log the transaction */
     555       result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:DEL: non-existing object");
     556
     557     }
     558     break;
     559
     560   default:
     561     tr->succeeded=0; tr->error |=ERROR_U_BADOP;
     562     break;
     563   }
     564
     565  /* Free resources */
     566   transaction_free(tr);
     567
     568   return(result);
     569 } /* process_nrtm() */
     570
     571
     572
     573 /************************************************************
     574 * process_updates()                                         *
     575 *                                                           *
     576 * Process object in update mode                             *
     577 *                                                           *
     578 * ud_stream - pointer to UD_stream structure                *
     579 * object_name - name of the object                          *
     580 * operation - operation code (OP_ADD/OP_DEL)                *
     581 *                                                           *
     582 * Note:                                                     *
     583 * Frees tr and tr->obj on exit                              *
     584 *                                                           *
     585 * Returns:                                                  *
     586 * 0  - okay                                                 *
     587 * <0- number of failed objects                              *
     588 *                                                           *
     589 ************************************************************/
     590
     591 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, int operation)
         /* [<][>][^][v][top][bottom][index][help] */
     592 {
     593 int result=0;
     594 Log_t *log_ptr= &(ud_stream->log);
     595 int dummy=0;
     596 ut_timer_t sotime;
     597 int ta_upd_nhr;
     598 char *reason;
     599
     600     /* Start timer for statistics */
     601     UT_timeget(&sotime);
     602     if(IS_NO_NHR(tr->mode))ta_upd_nhr=0; else ta_upd_nhr = TA_UPD_NHR;
     603
     604     switch(operation) {
     605     /* Compare operations and report an error if they do not match */
     606     case OP_ADD:
     607       if(tr->object_id!=0) { /* trying to create, but object exists */
     608         tr->succeeded=0; tr->error|=ERROR_U_COP;
     609         reason="U:ADD:object already exists";
     610         g_string_sprintfa(tr->error_script,"E[%d]:NEW requested but object already exists\n" ,ERROR_U_COP);
     611         UD_ack(tr); /* Send a NACK */
     612       } else {
     613        /* Action: create the object and update NHR */
     614         tr->action=(TA_CREATE | ta_upd_nhr);
     615         reason="U:ADD";
     616         object_process(tr);
     617       }
     618       break;
     619     case OP_UPD:
     620       if(tr->object_id==0) { /* trying to update non-existing object*/
     621         tr->succeeded=0; tr->error|=ERROR_U_COP;
     622         reason="U:UPD:non-existing object";
     623         g_string_sprintfa(tr->error_script,"E[%d]:UPD requested but no existing object found\n" ,ERROR_U_COP);
     624         UD_ack(tr); /* Send a NACK */
     625       } else {
     626         tr->action=TA_UPDATE;
     627         reason="U:UPD";
     628         dummy=isdummy(tr);
     629         if(dummy==1) tr->action = TA_UPD_DUMMY;
     630         object_process(tr);
     631       }
     632       break;
     633
     634     case OP_DEL:
     635       if(tr->object_id==0) { /* trying t delete non-existing object*/
     636         tr->succeeded=0; tr->error|=ERROR_U_COP;
     637         reason="U:DEL:non-existing object";
     638         g_string_sprintfa(tr->error_script,"E[%d]:DEL requested but no existing object found\n" ,ERROR_U_COP);
     639         UD_ack(tr);
     640       } else {
     641         tr->action=(TA_DELETE | ta_upd_nhr);
     642         reason="U:DEL";
     643         object_process(tr);
     644       }
     645       break;
     646
     647     default:
     648       /* bad operation for this mode if not standalone */
     649       if(IS_STANDALONE(tr->mode)) {
     650         if(tr->object_id==0){
     651           tr->action=(TA_CREATE | ta_upd_nhr);
     652           reason="U:ADD";
     653         }
     654         else {
     655           tr->action=TA_UPDATE;
     656           reason="U:UPD";
     657         }
     658         object_process(tr);
     659       }
     660       else {
     661         tr->succeeded=0;
     662         tr->error|=ERROR_U_BADOP;
     663         g_string_sprintfa(tr->error_script,"E[%d]:Unknown operation requested\n" ,ERROR_U_BADOP);
     664         reason="U:bad operation";
     665         UD_ack(tr); /* Send a NACK */
     666       }
     667       break;
     668     }
     669    /* If not in standalone mode create serial and copy error transcript */
     670     if(!IS_STANDALONE(tr->mode)) {
     671       if(tr->succeeded){
     672               /* we don't want to generate DEL serial for dummy replacement*/
     673               if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }
     674               UD_lock_serial(tr);
     675               UD_create_serial(tr);
     676               CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     677               UD_commit_serial(tr);
     678               UD_unlock_serial(tr);
     679               /* Mark the TR as clean */
     680               TR_mark_clean(tr);
     681       }
     682     }
     683
     684    /* Make a report. U stands for update stream. No reason */
     685     result=report_transaction(tr, tr->transaction_id, log_ptr, &sotime, reason);
     686
     687    /* Free resources */
     688 /*    rpsl_object_delete(tr->object); */
     689     transaction_free(tr);
     690
     691     return(result);
     692
     693 } /* process_updates() */
     694
     695
     696 /************************************************************
     697 *                                                           *
     698 * int process_transaction()                                 *
     699 *                                                           *
     700 * Processes the transaction                                 *
     701 *                                                           *
     702 * ud_stream - pointer to UD_stream_t structure              *
     703 *                                                           *
     704 * Returns:                                                  *
     705 * 0 - no error                                              *
     706 * <0- number of failed objects                              *
     707 *                                                           *
     708 ************************************************************/
     709
     710 /* It frees the obj */
     711
     712 static int process_transaction(UD_stream_t *ud_stream,
         /* [<][>][^][v][top][bottom][index][help] */
     713                          GString *g_obj_buff,
     714                          int operation,
     715                         long transaction_id)
     716 {
     717 Transaction_t *tr = NULL;
     718 int result;
     719 nic_handle_t *nh_ptr=NULL;
     720 rpsl_object_t *submitted_object=NULL, *sql_object=NULL;
     721 const GList *rpsl_err_list;
     722 gchar *object_txt, *flat_object_txt;
     723 ut_timer_t sotime;
     724 long serial_id;
     725
     726
     727  /* check if the requested transaction has already been processed */
     728  /* this may happen in case of crash. If so, just send an ack and return */
     729  if(TR_check(ud_stream->db_connection, transaction_id, (ud_stream->condat).sock))return(1);
     730
     731  /* escape apostrophes, otherwise sql will be confused */
     732  g_obj_buff=escape_apostrophes(g_obj_buff);
     733
     734  /* check if it is an object and init it */
     735  if ((submitted_object=rpsl_object_init(g_obj_buff->str))==NULL) return(-1);
     736
     737 /* start new transaction now */
     738  tr = transaction_new(ud_stream->db_connection, rpsl_get_class_id(rpsl_object_get_class(submitted_object)));
     739  if (tr == NULL) die;
     740
     741  tr->mode = ud_stream->ud_mode;
     742  tr->load_pass = ud_stream->load_pass;
     743  tr->source_hdl = ud_stream->source_hdl;
     744  tr->socket = (ud_stream->condat).sock;
     745  tr->transaction_id = transaction_id;
     746  tr->object = submitted_object;
     747
     748  UT_timeget(&sotime);
     749
     750
     751  /* check for syntax errors (with whois_rip syntax set) */
     752  if((rpsl_err_list = rpsl_object_errors(submitted_object)) != NULL) {
     753  int num_err = 0;
     754  gboolean is_garbage = FALSE;
     755  gboolean is_only_comments = FALSE;
     756
     757
     758  /* check the severity of the errors */
     759  /* we need to catch: */
     760  /* template errors - missing primary keys _only_ */
     761  /* attribute syntax errors - just to abort without processing */
     762   do {
     763      const rpsl_attr_t *attr;
     764      const rpsl_error_t *err = rpsl_err_list->data;
     765      gboolean is_important_error = FALSE;
     766
     767      switch (err->code) {
     768       /* totally bogus object, or missing primary keys */
     769       case RPSL_ERR_ONLYCOMMENTS:
     770            is_only_comments = TRUE;
     771       case RPSL_ERR_MISSINGKEY:
     772       case RPSL_ERR_BADCLASS:
     773       case RPSL_ERR_UNKNOWNCLASS:
     774            is_garbage = TRUE;
     775            is_important_error = TRUE;
     776            break;
     777       /* inappropriate, duplicate attributes */
     778       case RPSL_ERR_ATTRNOTALLOWED:
     779            attr = rpsl_object_get_attr_by_ofs(submitted_object, err->attr_num);
     780            if (rpsl_attr_is_key(submitted_object, rpsl_attr_get_name(attr))) {
     781               is_important_error = TRUE;
     782            }
     783            break;
     784       /* bad and single attribuets that have multiple appearance in the object are dangerous */
     785       case RPSL_ERR_BADATTR:
     786       case RPSL_ERR_ATTRSINGLE:
     787            is_important_error = TRUE;
     788            break;
     789
     790      }
     791      /* report error */
     792      /* no need to have an extended report */
     793      /* basically for debuggung purposes   */
     794      /* it will never be passed to the user */
     795      if (is_important_error) {
     796         g_string_sprintfa(tr->error_script,"E[%d]:%s\n", ERROR_U_OBJ, err->descr);
     797         num_err++;
     798      }
     799      rpsl_err_list = g_list_next(rpsl_err_list);
     800   } while (rpsl_err_list != NULL);
     801
     802   if (num_err > 0) {
     803      tr->succeeded = 0;
     804      tr->error |= ERROR_U_OBJ;
     805     /* garbage just ignore */
     806     if (is_garbage){
     807       if(!is_only_comments)
     808         ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "garbage in NRTM stream [%s]", g_obj_buff->str);
     809     } else {
     810       ER_dbg_va(FAC_UD, ASP_UD_UPDLOG,"Malformed object:[%s]\n%s\n",tr->error_script->str, g_obj_buff->str);
     811       /* we cannot process this object and store it in the database */
     812       /* but in case of NRTM this indicates a malformed stream */
     813       /* we try our best to be in sync with the master, so we need to store */
     814       /* this block (maybe object) in failed_transaction */
     815       if(IS_NRTM_CLNT(ud_stream->ud_mode)){
     816         object_txt = rpsl_object_get_text(submitted_object, RPSL_STD_COLUMN);
     817         tr->object_txt = object_txt;
     818         if(operation==OP_DEL) tr->action=TA_DELETE; else tr->action=TA_CREATE;
     819         UD_lock_serial(tr);
     820         serial_id = UD_create_serial(tr);
     821         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     822         UD_commit_serial(tr);
     823         UD_unlock_serial(tr);
     824         /* Mark TR as clean */
     825         TR_mark_clean(tr);
     826         /* log the transaction */
     827         result=report_transaction(tr, serial_id, &ud_stream->log, &sotime, "M:---");
     828       }
     829     }
     830     UD_ack(tr);
     831     transaction_free(tr);
     832     return(-1);
     833   }
     834  }/* checked for syntax errors */
     835
     836
     837  /* If we maintain NHR, for person and role objects */
     838  /* check and replace the AUTO nic handle */
     839  if(!IS_NO_NHR(ud_stream->ud_mode)){
     840     if((tr->class_type == C_PN) || (tr->class_type == C_RO)) {
     841       nh_ptr = ud_replace_autonic(tr, submitted_object);
     842       /* NULL nh_ptr indicates a problem with a NIC handle */
     843       if(nh_ptr == NULL) {
     844         tr->succeeded = 0;
     845         tr->error |= ERROR_U_OBJ;
     846         g_string_sprintfa(tr->error_script,"E[%d]:Wrong NIC handle format\n", ERROR_U_OBJ);
     847         ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"Malformed object:[Wrong NIC handle]\n%s\n", g_obj_buff->str);
     848         /* we cannot process this object and store it in the database */
     849         /* but in case of NRTM this indicates a malformed stream */
     850         /* we try our best to be in sync with the master, so we need to store */
     851         /* this block (maybe object) in failed_transaction */
     852         if(IS_NRTM_CLNT(ud_stream->ud_mode)){
     853           object_txt = rpsl_object_get_text(submitted_object, RPSL_STD_COLUMN);
     854           tr->object_txt = object_txt;
     855           if(operation==OP_DEL) tr->action=TA_DELETE; else tr->action=TA_CREATE;
     856           UD_lock_serial(tr);
     857           serial_id = UD_create_serial(tr);
     858           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     859           UD_commit_serial(tr);
     860           UD_unlock_serial(tr);
     861           /* Mark TR as clean */
     862           TR_mark_clean(tr);
     863           /* log the transaction */
     864           result=report_transaction(tr, serial_id, &ud_stream->log, &sotime, "M:---");
     865         }
     866         UD_ack(tr);
     867         transaction_free(tr);
     868         return(-1);
     869       }
     870     }
     871  }
     872
     873    /* normalize the object (reorder and split attributes */
     874  sql_object = rpsl_object_copy_flattened(submitted_object);
     875
     876  /* put nic-hdl and mnt-by at the top of the list */
     877  ud_reorder_attributes(sql_object);
     878
     879  /* split the names */
     880   sql_object = ud_split_names(sql_object);
     881
     882  /* save the original text of submitted object */
     883  object_txt = rpsl_object_get_text(submitted_object, RPSL_STD_COLUMN);
     884
     885  tr->object = sql_object;
     886  tr->object_txt = object_txt; /* needs to be freed */
     887  tr->nh = nh_ptr;
     888
     889 /* We perform no commit/rollback in the loader mode, so thread_id should be set to 0 */
     890  if(IS_STANDALONE(tr->mode)){ tr->thread_ins=0; tr->thread_upd=0; }
     891
     892 /* For the first load pass we only create objects */
     893
     894  if(tr->load_pass==1) {
     895          /* still we need to fill tr->K (last.pkey) field */
     896          /* tr->load_pass ==1 will trigger this behaviour in ud_each_primary_key_select */
     897          g_list_foreach((GList *)rpsl_object_get_all_attr(tr->object), ud_each_primary_key_select, tr);
     898          tr->object_id=0;
     899  }
     900  else tr->object_id=get_object_id(tr);
     901
     902  /* check if error has been detected */
     903  /*XXX replace error codes with symbolic consts */
     904  if(tr->object_id==-2) { /* Object erorr - wrong syntax in one of the PK */
     905     ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"Malformed object:[%s]\n%s\n",tr->error_script->str, g_obj_buff->str);
     906     UD_ack(tr);
     907     /* this object is not deleted by transaction_delete() */
     908     rpsl_object_delete(submitted_object);
     909     transaction_free(tr);
     910     return(-1);
     911  }
     912
     913 /* Object cannot be retrieved */
     914  if(tr->object_id==-1) { /* DB error*/
     915     tr->succeeded=0;
     916     tr->error |= ERROR_U_DBS;
     917     ER_perror(FAC_UD, UD_SQL, "Object cannot be retrieved:[%s]", tr->object_txt);
     918     die;
     919  }
     920
     921 /* Process transaction. tr and obj are freed inside the process_* functions */
     922 /* tr is freed there because in NRTM we need to save a transaction for later processing */
     923  if(IS_UPDATE(ud_stream->ud_mode))
     924  /* We are in update mode */
     925     result=process_updates(ud_stream, tr, operation);
     926  else
     927  /* We are in NRTM mode */
     928     result=process_nrtm(ud_stream, tr, operation);
     929
     930
     931  /* free the original submitted object */
     932  rpsl_object_delete(submitted_object);
     933  return(result);
     934
     935 }
     936
     937
     938 /************************************************************
     939 *                                                           *
     940 * int UD_process_stream(UD_stream_t *ud_stream)             *
     941 *                                                           *
     942 * Processes the stream                                      *
     943 *                                                           *
     944 * ud_stream - pointer to UD_stream_t structure              *
     945 *                                                           *
     946 * Returns:                                                  *
     947 * in update mode (!standalone)(1 object processed):         *
     948 * 1 - no error                                              *
     949 * <0- errors                                                *
     950 *                                                           *
     951 * in NRTM & standalone modes                                *
     952 * total number of object processed                          *
     953 *                                                           *
     954 ************************************************************/
     955
     956 int UD_process_stream(UD_stream_t *ud_stream)
         /* [<][>][^][v][top][bottom][index][help] */
     957 {
     958   char line_buff[STR_XXL];
     959   SQ_connection_t *sql_connection;
     960   struct _nrtm *nrtm;
     961   Log_t *log_ptr= &(ud_stream->log);
     962   ut_timer_t stime, ftime, sotime;
     963   float obj_second1, obj_second10, timediff;
     964   int result=0;
     965   int operation=0;
     966   int interrupt=0;
     967   int do_update;
     968   int default_ud_mode = ud_stream->ud_mode;
     969   Line_Type_t linetype;
     970   Transaction_t *tr;
     971   long transaction_id=0; /* transaction_id (to be supplied by DBupdate and stored in Database) */
     972   long serial_id;
     973   GString *g_obj_buff;
     974
     975   nrtm=ud_stream->nrtm;
     976
     977   if ((g_obj_buff = g_string_sized_new(STR_XXL)) == NULL){
     978         ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
     979      die;
     980   }
     981
     982   /* Check connection to the database */
     983   if(SQ_ping(ud_stream->db_connection)) {
     984    ER_perror(FAC_UD, UD_SQL, "%s", SQ_error(ud_stream->db_connection));
     985    die;
     986   }
     987   sql_connection=ud_stream->db_connection;
     988
     989   UT_timeget(&stime);
     990
     991  /* Main loop. Reading input stream line by line */
     992  /* Empty line signals to start processing an object, if we have it */
     993   while (SK_cd_gets(&ud_stream->condat, line_buff, sizeof(line_buff))>0) {
     994
     995
     996     switch (linetype=line_type(line_buff, &transaction_id)) {
     997
     998       case LINE_COMMENT:
     999       case LINE_EOF:
    1000       break;
    1001
    1002       case LINE_ACK:
    1003        tr = transaction_new(ud_stream->db_connection, 0);
    1004        tr->transaction_id=transaction_id;
    1005        TR_delete_record(tr);
    1006        transaction_free(tr);
    1007       break;
    1008
    1009
    1010       case LINE_ADD:
    1011       /* restore the default operation mode */
    1012        operation=OP_ADD;
    1013        ud_stream->ud_mode=default_ud_mode;
    1014       break;
    1015
    1016       case LINE_OVERRIDE_ADD:
    1017       /* for override - switch the dummy bit on */
    1018        operation=OP_ADD;
    1019        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
    1020       break;
    1021
    1022       case LINE_UPD:
    1023       /* restore the default operation mode */
    1024        operation=OP_UPD;
    1025        ud_stream->ud_mode=default_ud_mode;
    1026       break;
    1027
    1028       case LINE_OVERRIDE_UPD:
    1029       /* for override - switch the dummy bit on */
    1030        operation=OP_UPD;
    1031        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
    1032       break;
    1033
    1034       case LINE_DEL:
    1035       /* restore the default operation mode */
    1036        operation=OP_DEL;
    1037        ud_stream->ud_mode=default_ud_mode;
    1038       break;
    1039
    1040       case LINE_OVERRIDE_DEL:
    1041       /* for override - switch the dummy bit on */
    1042        operation=OP_DEL;
    1043        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
    1044       break;
    1045
    1046       case LINE_EMPTY:
    1047        /* start processing the object */
    1048         /* escape apostrophes, otherwise sql will be confused */
    1049          /* XXX */
    1050 /*       print_object(obj); */
    1051          /* check if we have collected something */
    1052          if(g_obj_buff->len >0){
    1053 #if 0
    1054            /* no operation suggest a garbage in the stream - just ignore it */
    1055            if(IS_NRTM_CLNT(ud_stream->ud_mode) && (operation==OP_NOOP)) {
    1056                ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "garbage in NRTM stream");
    1057            } else
    1058 #endif
    1059            {
    1060              /* start new transaction now */
    1061              result=process_transaction(ud_stream, g_obj_buff, operation, transaction_id);
    1062              /* process_transaction() frees tr and obj structures, */
    1063              /* so make sure we'll not reference these objects in the future */
    1064              operation=OP_NOOP;
    1065              transaction_id=0;
    1066            }
    1067            ud_stream->ud_mode=default_ud_mode;
    1068            if ((g_obj_buff = g_string_truncate(g_obj_buff,0)) == NULL){
    1069                  ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
    1070                  die;
    1071            }
    1072          }
    1073          /* this is a good place for quick interrupt */
    1074          do_update=CO_get_do_update();
    1075          if (do_update) interrupt=0; else interrupt=1;
    1076
    1077       break;
    1078
    1079       default:
    1080        /* this may be an object - fill the buffer */
    1081         g_string_sprintfa(g_obj_buff, "%s", line_buff);
    1082         break;
    1083     } /* switch */
    1084
    1085     /* Finish processing if interrupt has been set */
    1086     if (interrupt) break;
    1087   } /* Main loop of data stream processing : while */
    1088
    1089
    1090  /* Some postprocessing */
    1091   if(IS_NRTM_CLNT(ud_stream->ud_mode)){
    1092   /* We are in NRTM mode */
    1093   /* Clean up */
    1094   /* In NRTM mode there may be a saved object that is unprocessed */
    1095    if(nrtm->tr){ /*saved backlog?*/
    1096 /*XXX Do nothing with this backlog; next time we connect we will process it */
    1097 #if 0
    1098     /* restart the timer for statistics */
    1099     UT_timeget(&sotime);
    1100     object_process(nrtm->tr); /* delete the previous(saved) object*/
    1101 /*    result=report_transaction(nrtm->tr, &(ud_stream->log), nrtm->object_name,
    1102                               "NRTM:DEL:While deleting previous(saved) object"); */
    1103     /* create DEL serial record no matter what the result is */
    1104     UD_lock_serial(nrtm->tr);
    1105     serial_id = UD_create_serial(nrtm->tr);
    1106     CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
    1107     UD_commit_serial(nrtm->tr);
    1108     UD_unlock_serial(nrtm->tr);
    1109     /* Mark TR as clean */
    1110     TR_mark_clean(nrtm->tr);
    1111     /* log the transaction */
    1112     result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
    1113 #endif
    1114     transaction_free(nrtm->tr); nrtm->tr=NULL;
    1115    }
    1116   }
    1117
    1118  /* That's all. Free GString */
    1119   g_string_free(g_obj_buff, TRUE);
    1120
    1121
    1122  /* Calculate some statistics */
    1123   UT_timeget(&ftime);
    1124   timediff = UT_timediff(&stime, &ftime);
    1125   obj_second1 = (float)(log_ptr->num_ok)/timediff;
    1126   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/timediff;
    1127
    1128   /* Print the report */
    1129   if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode))) {
    1130
    1131    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s ******** report **********", UD_TAG);
    1132    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s %d objects OK (%7.4f obj/s)", UD_TAG, log_ptr->num_ok, obj_second1);
    1133    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s %d objects failed", UD_TAG, log_ptr->num_failed);
    1134    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s average processing time %7.4f obj/s (%6.2f obj/min)", UD_TAG,
    1135                           obj_second10, obj_second10*60);
    1136    result=log_ptr->num_ok+log_ptr->num_failed;
    1137   }
    1138   return(result);
    1139
    1140 } /* UD_process_stream */
    1141

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