Source File ud/ud_process_stream.c

    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)
    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)
    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)
    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)
    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) {
    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) {
    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)
    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)
    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)
    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,
    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)
    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 |