1    | /***************************************
2    |   $Revision: 1.7 $
3    | 
4    |   Functions to process data stream( file, network socket, etc.)
5    | 
6    |   Status: NOT REVUED, NOT TESTED
7    | 
8    |  Author(s):       Chris Ottrey, Andrei Robachevsky
9    | 
10   |   ******************/ /******************
11   |   Modification History:
12   |         andrei (17/01/2000) Created.
13   |   ******************/ /******************
14   |   Copyright (c) 2000                              RIPE NCC
15   |  
16   |   All Rights Reserved
17   |   
18   |   Permission to use, copy, modify, and distribute this software and its
19   |   documentation for any purpose and without fee is hereby granted,
20   |   provided that the above copyright notice appear in all copies and that
21   |   both that copyright notice and this permission notice appear in
22   |   supporting documentation, and that the name of the author not be
23   |   used in advertising or publicity pertaining to distribution of the
24   |   software without specific, written prior permission.
25   |   
26   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32   |  ***************************************/
33   | #include <sys/types.h>
34   | #include <sys/socket.h>
35   | #include <netdb.h>
36   | #include <arpa/inet.h>
37   | #include <unistd.h>
38   | #include <sys/stat.h>
39   | #include <fcntl.h>
40   | #include "ud.h"
41   | #include "ud_int.h"
42   | 
43   | typedef enum _Line_Type_t {
44   |  LINE_ATTRIBUTE,
45   |  LINE_COMMENT,
46   |  LINE_EMPTY,
47   |  LINE_EOF,
48   |  LINE_ADD,
49   |  LINE_UPD,
50   |  LINE_DEL
51   | } Line_Type_t;
52   | 
53   | /* Maximum number of objects(serials) we can consume at a time */
54   | #define SBUNCH	1000
55   | 
56   | static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason);
57   | static char *s_split(char *line);
58   | 
59   | static int process_nrtm(Transaction_t *tr, struct _nrtm *nrtm, Log_t *log, char *object_name, int operation);
60   | static int process_updates(Transaction_t *tr, Log_t *log, char *object_name, int operation, int standalone);
61   | 
62   | 
63   | 
64   | 
65   | /* temporary files to download serials */              
66   | char tmpfile1[STR_S], tmpfile2[STR_S];
67   | 
68   | FILE *get_NRTM_stream(struct _nrtm *nrtm, int upto_last)
69   | {
70   | int sockfd;
71   | struct hostent *hptr;
72   | struct sockaddr_in serv_addr;
73   | struct in_addr	*paddr;
74   | char line_buff[STR_XXL];
75   | FILE *fp;
76   | int fd;
77   | int fdtmp;
78   | int nread, nwrite;
79   | struct hostent result;
80   | int error;
81   | 
82   | 
83   |  fprintf(stderr, "Making connection to NRTM server ...\n");
84   |  if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){
85   |    perror("socket");
86   |    return(NULL);
87   |  }  
88   | // hptr=gethostbyname(nrtm->server);
89   |  hptr=gethostbyname_r(nrtm->server,  &result, line_buff, sizeof(line_buff), &error);
90   |  if (hptr) { // this is a network stream
91   |    paddr=(struct in_addr *)hptr->h_addr;
92   |    bzero(&serv_addr, sizeof(serv_addr));
93   |    serv_addr.sin_family=AF_INET;
94   |    serv_addr.sin_port=nrtm->port;
95   |    memcpy(&serv_addr.sin_addr, paddr, sizeof(struct in_addr));
96   |    fprintf(stderr,"Trying %s port %d\n", inet_ntoa(serv_addr.sin_addr), nrtm->port);
97   |    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))==-1) { 
98   |      perror("connect");
99   |      return(NULL);
100  |    }  
101  |    fprintf(stderr, "Sending Invitation\n");
102  |    if(upto_last)
103  |       sprintf(line_buff, "-g RIPE:%d:%d-LAST\n", nrtm->version, nrtm->current_serial+1);
104  |    else
105  |       sprintf(line_buff, "-g RIPE:%d:%d-%d\n", nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH);   
106  |    write(sockfd, line_buff, strlen(line_buff));
107  |    fd=sockfd;
108  |    fprintf(stderr, "%s", line_buff);
109  |    fprintf(stderr, "Returning stream pointer\n");
110  |  }
111  |  else { // this is a file stream
112  |    fprintf(stderr, "Trying file ...\n");
113  |    if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) {
114  |      perror("open");
115  |      return(NULL);
116  |    }  
117  |  }  
118  | 
119  | /* make temporary files */
120  |  sprintf(tmpfile1, "temp.XXXX");
121  | 
122  |  if((fdtmp=mkstemp(tmpfile1))==-1) {
123  |    perror("mkstemp");
124  |    close(fd);
125  |    return(NULL);
126  |  }  
127  |  while ((nread=read(fd, line_buff, sizeof(line_buff)))) {
128  |    if(nread==-1) return(NULL);
129  |    nwrite=write(fdtmp, line_buff,nread);
130  |    if(nread != nwrite) return(NULL);
131  | }
132  |  
133  |  close(fd); close(fdtmp);
134  |  
135  |  sprintf(tmpfile2, "%s.2", tmpfile1);
136  |  
137  |  sprintf(line_buff, "cat %s | ./ripe2rpsl > %s", tmpfile1, tmpfile2);
138  |  if (system(line_buff)!=0) return(NULL);
139  |  if((fp=fopen(tmpfile2, "r+"))==NULL)return(NULL);
140  |  
141  |  unlink(tmpfile1);
142  |  
143  |  return(fp);
144  |  
145  | }
146  | 
147  | /******************************************************************
148  | * report_transaction()                                            *
149  | *                                                                 * 
150  | * Prints error report to the log                                  *
151  | *                                                                 *
152  | * reason - additional message thet will be included               *
153  | *                                                                 *
154  | * *****************************************************************/
155  | static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason)
156  | {
157  | int result=0;
158  | 
159  |  if(tr->succeeded==0) {
160  |   result=tr->error;
161  |   log->num_failed++;
162  |   printf("FAILED[%s][%s(%d)](%d/%d)\n ", obj_name, reason, result, log->num_failed, (log->num_failed)+(log->num_ok));	
163  |   fprintf(log->logfile, "*FAILED[%s][%s](%d/%d)\n ", obj_name, reason, log->num_failed, (log->num_failed)+(log->num_ok));
164  |   if(result & ERROR_U_MEM) fprintf(log->logfile, "\t*Memory allocation error\n");
165  |   if(result & ERROR_U_DBS) fprintf(log->logfile, "\t*Database (SQL) error\n");
166  |   if(result & ERROR_U_OBJ) fprintf(log->logfile, "\t*Object (RF) error\n");
167  |   if(result & ERROR_U_AUT) fprintf(log->logfile, "\t*Object authentication error\n");
168  |   if(result & ERROR_U_BADOP) fprintf(log->logfile, "\t*Bad operation\n");
169  |   if(result & ERROR_U_COP) fprintf(log->logfile, "\t*Conflicting operation\n");
170  |   if(result & ERROR_U_NSUP) fprintf(log->logfile, "\t*Object of this type is not supported\n");
171  |   if(result & ERROR_U_BUG) fprintf(log->logfile, "\t*Software bug - report to <ripe-dbm@ripe.net>\n");
172  |   fprintf(log->logfile, "%s", (tr->error_script)->str);
173  |   result=(-1)*result;                                                
174  |   fflush(log->logfile);
175  |  }
176  |  else {
177  |   result=1;
178  |   log->num_ok++;
179  |   printf("OK(%d/%d)\n", log->num_ok, (log->num_failed)+(log->num_ok));
180  |  }
181  |                                                                                                                                                 
182  |  return(result);
183  | }
184  | 
185  | /******************************************************************
186  | * char *s_split(char *line)                                       *
187  | * consequently returns words (separated by whitespace in the line)*
188  | * NULL - end. You need to retreive all words !                    *
189  | *                                                                 *
190  | * *****************************************************************/
191  | static char *s_split(char *line)
192  | {
193  | static char *delim;
194  | static char *token=NULL;
195  | 
196  |  if(token==NULL)token=line;
197  |  else token=delim;
198  |  
199  |  if(token==NULL)return(token);
200  |  while(isspace((int)*token))token++;
201  |  delim=token;
202  |  
203  |  while(!isspace((int)*delim)) {
204  |  	if((*delim)=='\0'){
205  |  		if(delim==token)token=NULL;
206  |  		delim=NULL; return(token);
207  |  	}
208  |  	delim++;
209  |  }
210  |  *delim='\0'; delim++;
211  |  return(token);
212  | 
213  | }
214  | 
215  | 
216  | 
217  | GString *escape_apostrophes(GString *text) {
218  |   int i;
219  |   for (i=0; i < text->len; i++) {
220  |     if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
221  |       text = g_string_insert_c(text, i, '\\');
222  |       i++;
223  |     }
224  |   }
225  |  return(text); 
226  | } /* escape_apostrophes() */
227  | 
228  | static Line_Type_t line_type(const char *line) {
229  |   Line_Type_t result = -1;
230  | 
231  |   if (strncmp(line, "# EOF", 4) == 0) {
232  |     result = LINE_EOF;
233  |   }
234  |   else if (strncmp(line, "#", 1) == 0) {
235  |     result = LINE_COMMENT;
236  |   }
237  |   else if (strcmp(line, "\n") == 0) {
238  |     result = LINE_EMPTY;
239  |   }
240  |   else if (strncmp(line, "ADD", 3) == 0) {
241  |     result = LINE_ADD;
242  |   }
243  |   else if (strncmp(line, "UPD", 3) == 0) {
244  |     result = LINE_UPD;
245  |   }
246  |   else if (strncmp(line, "DEL", 3) == 0) {
247  |     result = LINE_DEL;
248  |   }
249  |   else {
250  |     result = LINE_ATTRIBUTE;
251  |   }
252  | 
253  |   return result;
254  | } /* line_type() */
255  | 
256  | 
257  | 
258  | 
259  | /************************************************************
260  | * process_nrtm()                                            *
261  | *                                                           *
262  | * Process object in NRTM client mode                        *
263  | *                                                           *
264  | * nrtm - pointer to _nrtm structure                         *
265  | * log - pointer to Log_t structure                          *
266  | * object_name - name of the object                          * 
267  | * operation - operation code (OP_ADD/OP_DEL)                *
268  | *                                                           *
269  | * Returns:                                                  *
270  | * 1  - okay                                                 *
271  | * <0 - error                                                *
272  | *                                                           *
273  | ************************************************************/
274  | 
275  | static int process_nrtm(Transaction_t *tr, struct _nrtm *nrtm, Log_t *log, char *object_name, int operation)
276  | {
277  | int error=0;
278  | //fprintf(stderr,"NRTM mode\n");
279  |   
280  |   switch (operation) {
281  |   
282  |   case OP_ADD:
283  |     if(nrtm->tr){ //saved?
284  |       if(tr->object_id==0) {
285  | //      fprintf(stderr,"DEL previous\n");
286  |         object_process(nrtm->tr); // delete the previous(saved) object
287  |         error=report_transaction(nrtm->tr, log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
288  |         object_free(nrtm->tr->object);
289  |         transaction_free(nrtm->tr); nrtm->tr=NULL;
290  |         tr->action=TR_CREATE;
291  | //      fprintf(stderr,"CREATE next\n"); 
292  |         object_process(tr);	// create a new one
293  |         error=report_transaction(tr, log, object_name, "NRTM:ADD:While creating new");
294  |       }
295  |       else { //compare the two, may be we may collapse operations
296  |         if(tr->object_id==nrtm->tr->object_id) {
297  |           object_free(nrtm->tr->object);
298  |           transaction_free(nrtm->tr); nrtm->tr=NULL;
299  | //        fprintf(stderr,"DEL-ADD ->> UPDATE\n");
300  |           tr->action=TR_UPDATE;
301  |           object_process(tr);
302  |           report_transaction(tr, log, object_name,"NRTM:upd");
303  |           error=report_transaction(tr, log, object_name,"NRTM:upd");
304  |         }
305  |         else { // this should be a dummy object in the database or an interleaved operation
306  | //        fprintf(stderr,"DEL previous\n");
307  |           object_process(nrtm->tr); // delete the previous(saved) object
308  |           error=report_transaction(nrtm->tr, log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
309  |           object_free(nrtm->tr->object);
310  |           transaction_free(nrtm->tr); nrtm->tr=NULL;
311  |           tr->action=TR_UPDATE;
312  | //        fprintf(stderr,"UPDATE next(dummy)\n"); 
313  |           object_process(tr);	// create a new one
314  |           error=report_transaction(tr, log, object_name, "NRTM:ADD:While creating new");
315  |         }
316  |       }
317  |     }
318  |     else { // brand new object
319  |       if(tr->object_id==0) {
320  | //      fprintf(stderr,"CREATE new\n");
321  |         tr->action=TR_CREATE;
322  |         object_process(tr);
323  |         error=report_transaction(tr, log, object_name,"NRTM:ADD:While creating new");
324  |       }
325  |       else { // this may happen because of dummies
326  | //      fprintf(stderr,"CREATE new\n");
327  |         tr->action=TR_UPDATE;
328  |         object_process(tr);
329  |         error=report_transaction(tr, log, object_name,"NRTM:ADD:While creating new");
330  |       } 
331  |     }
332  |     break;
333  |     
334  |   case OP_DEL:
335  |     if(nrtm->tr){ //saved?
336  | //    fprintf(stderr,"DEL previous\n");
337  |       object_process(nrtm->tr); // delete the previous(saved) object
338  |       error=report_transaction(nrtm->tr, log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object");
339  |       object_free(nrtm->tr->object);
340  |       transaction_free(nrtm->tr); nrtm->tr=NULL;
341  |     }
342  |     if(tr->object_id>0){ // save the object
343  | //    fprintf(stderr,"SAVE del object\n");
344  |       tr->action=TR_DELETE;
345  |       nrtm->tr=tr;
346  |       strcpy(nrtm->object_name, object_name);
347  |       return(error);
348  |     }
349  |     else { // this is an error
350  |       tr->succeeded=0; tr->error|=ERROR_U_COP;
351  |       error=report_transaction(tr, log, object_name, "NRTM:OOS:Trying to DEL non-existing object");
352  | //    fprintf(stderr,"Lost sync. Skipping\n");
353  |     }
354  |     break;
355  |   
356  |   default:
357  |     tr->succeeded=0; tr->error |=ERROR_U_BADOP;
358  |     break;  
359  |   }
360  |   
361  |   object_free(tr->object);
362  |   transaction_free(tr);
363  |   return(error);
364  | } /* process_nrtm() */
365  | 
366  | 
367  | 
368  | /************************************************************
369  | * process_updates()                                         *
370  | *                                                           *
371  | * Process object in update mode                             *
372  | *                                                           *
373  | * nrtm - pointer to _nrtm structure                         *
374  | * log - pointer to Log_t structure                          *
375  | * object_name - name of the object                          *
376  | * operation - operation code (OP_ADD/OP_DEL)                *
377  | * standalone - if the program is executed standalone        *
378  | *                                                           *
379  | * Returns:                                                  *
380  | * 1  - okay                                                 *
381  | * <0 - error                                                *
382  | *                                                           * 
383  | ************************************************************/
384  | 
385  | static int process_updates(Transaction_t *tr, Log_t *log, char *object_name, int operation, int standalone)
386  | {
387  | int error=0;
388  | 
389  |     switch(operation) {
390  |     
391  |     case OP_ADD:
392  |     case OP_UPD:
393  |              if(tr->object_id==0) tr->action=TR_CREATE; else tr->action=TR_UPDATE;
394  | 	     object_process(tr);
395  | 	     break;
396  | 
397  |     case OP_DEL:	       
398  | 	     if(tr->object_id==0) { // trying t delete non-existing object
399  | 	       tr->succeeded=0; tr->error|=ERROR_U_COP;
400  | 	     } else {
401  | 	       tr->action=TR_DELETE;
402  | 	       object_process(tr);
403  | 	     }
404  | 	     break;
405  | 	               
406  |     default:	               
407  |       /* bad operation for this mode if not standalone */
408  | 	     if(standalone) {
409  | 	       if(tr->object_id==0)tr->action=TR_CREATE; else tr->action=TR_UPDATE;
410  | 	       object_process(tr);
411  | 	     }
412  | 	     else {
413  | 	       tr->succeeded=0; 
414  | 	       tr->error|=ERROR_U_BADOP; 
415  | 	     }
416  | 	     break;
417  |     }
418  |     error=report_transaction(tr, log, object_name, "UPD");
419  |     
420  |     return(error);
421  | 	       
422  | } /* process_updates() */
423  | 
424  | /************************************************************
425  | *                                                           *
426  | * int UD_process_stream(UD_stream_t *ud_stream)             *
427  | *                                                           *
428  | * Processes the stream                                      *
429  | *                                                           *
430  | * ud_stream - pointer to UD_stream_t structure              *
431  | *                                                           *
432  | * Returns:                                                  *
433  | * in update mode (!standalone)(1 object processed):         *
434  | * 1 - no error                                              *
435  | * <0- errors                                                *
436  | *                                                           *
437  | * in NRTM & standalone modes                                *
438  | * total number of object processed                          *
439  | *                                                           *
440  | ************************************************************/
441  | 
442  | int UD_process_stream(UD_stream_t *ud_stream)
443  | {
444  |   FILE *logfile;
445  |   char line_buff[STR_XXL], object_name[STR_XXL];
446  |   GString *g_line_buff; // needed to escape apostrophes
447  | 
448  |   Attribute_t *attr, *attr_split;
449  |   Attribute_t *mnt_by; // we need this for reordering mnt_by and member_of (member_of should come after)
450  |   Attribute_t *nic_hdl; // we need this for reordering nic_hdl and admin_c, etc. (admin_c should come after)
451  |   Object_t *obj = NULL;
452  |   Transaction_t *tr = NULL;
453  |   SQ_connection_t *sql_connection;
454  |   int start_object;
455  |   int a_type;
456  |   char *s_attr;
457  |   long num_skip;
458  |   struct _nrtm *nrtm;
459  |   Log_t log;
460  |   time_t stime, ftime;
461  |   double obj_second1, obj_second10;
462  |   int standalone;
463  |   int error;
464  |   int operation=0;
465  |   
466  |   nrtm=ud_stream->nrtm;
467  |   standalone=IS_STANDALONE(ud_stream->ud_mode);
468  |   start_object = 1;
469  |   
470  |  if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){ fprintf(stderr, "E: cannot allocate gstring\n"); return(-1); }
471  | 
472  | 
473  | 
474  | fprintf(stderr, "D: Making SQL connection to %s@%s ...", ud_stream->db_name, ud_stream->db_host);
475  |   sql_connection = SQ_get_connection(ud_stream->db_host, ud_stream->db_port, 
476  |   					ud_stream->db_name, ud_stream->db_user, ud_stream->db_pswd);
477  |   if(!sql_connection) {
478  |    fprintf(stderr, "D: ERROR: no SQL connection\n");
479  |    return(-1);
480  |   }	
481  | fprintf(stderr, "OK\n");
482  | 
483  |   logfile = fopen(ud_stream->log, "a+");
484  |   log.logfile=logfile;
485  |   log.num_ok=0; log.num_failed=0;
486  | 
487  | /* This is useful for loading DB from huge disk file. */
488  |   num_skip=ud_stream->num_skip;
489  |   if(num_skip>0) fprintf(stderr, "skipping %lu records\n", num_skip);
490  | 
491  |  stime=time(NULL);
492  | 
493  | 	
494  |   while (fgets(line_buff, STR_XXL, ud_stream->stream) != NULL) {
495  | 
496  |     switch (line_type(line_buff)) {
497  |       case LINE_ATTRIBUTE:
498  |         if (start_object == 1) {
499  |           if(num_skip>0){ printf("\r%10lu", num_skip); num_skip--; log.num_ok++; break; } 
500  |           	
501  |           mnt_by=NULL;
502  |           nic_hdl=NULL;
503  |           strncpy(object_name, line_buff, strlen(line_buff)-1); 
504  |           *(object_name+strlen(line_buff)-1)='\0';
505  |           obj = object_new(line_buff);
506  |           if (obj) {
507  |             start_object = 0;
508  |             printf("D: object: [%s] ", object_name);
509  |           } 
510  |         }
511  |         if (obj != NULL) {
512  |           g_string_sprintf(g_line_buff, "%s", line_buff);
513  |           g_line_buff=escape_apostrophes(g_line_buff);
514  |           attr = attribute_new(g_line_buff->str);
515  |           g_string_sprintfa(obj->object, "%s", g_line_buff->str);
516  |           if (attr != NULL) {
517  |            switch (a_type=(attr->type)) {
518  |             case A_MB:	mnt_by=attr;
519  |             		break;
520  |             case A_NH:	nic_hdl=attr;
521  |             		break;
522  |             case A_PN:
523  |             case A_RO:
524  |             case A_MR:
525  |             case A_SD:
526  |             case A_RZ:
527  |             case A_NS: //these attributes may appear several on the line - split them
528  |             	while((s_attr=s_split(attr->value))){
529  |             	  attr_split = attribute_new1(a_type, s_attr);
530  |             	  obj->attributes = g_slist_append(obj->attributes, attr_split);
531  |             	}
532  |             	attribute_free(attr, NULL);
533  |             	attr=NULL;
534  |             	break;	
535  |             default:	break;		
536  |            }
537  |             if(attr){ obj->attributes = g_slist_append(obj->attributes, attr);  
538  |             }
539  |           }
540  |         } 
541  |       break;
542  | 
543  |       case LINE_COMMENT:
544  |       break;
545  | 
546  |       case LINE_EOF:
547  |       break;
548  |       
549  |       case LINE_ADD:
550  |       	operation=OP_ADD;
551  |       break;
552  |       
553  |       case LINE_UPD:
554  |         operation=OP_UPD;
555  |       break;  
556  |       
557  |       case LINE_DEL:
558  |       	operation=OP_DEL;
559  |       break;	
560  | 
561  |       case LINE_EMPTY:
562  |         start_object=1;
563  |         if (obj != NULL) {
564  | 	/* reorder some attributes */
565  | 	  if(mnt_by){
566  | 	  	obj->attributes = g_slist_remove(obj->attributes, mnt_by);
567  | 	  	obj->attributes = g_slist_insert(obj->attributes, mnt_by, 1);
568  | 	  }
569  | 	  if(nic_hdl){
570  | 		obj->attributes = g_slist_remove(obj->attributes, nic_hdl);
571  | 		obj->attributes = g_slist_insert(obj->attributes, nic_hdl, 1);
572  | 	  }
573  | 	  tr = transaction_new(sql_connection, obj->type);
574  | 	  if (tr != NULL) {
575  | 	    tr->standalone=standalone;
576  | 	    tr->dummy=IS_DUMMY_ALLOWED(ud_stream->ud_mode);
577  | 	    tr->load_pass=ud_stream->load_pass;
578  | 	    tr->object=obj;
579  | 	    if(ud_stream->load_pass) { tr->thread_ins=0; tr->thread_upd=0; }
580  | 	    if(ud_stream->load_pass==1) tr->object_id=0;
581  | 	    else tr->object_id=get_object_id(tr);
582  | 	    if(tr->object_id==-1) { // some error
583  | 	      tr->succeeded=0;
584  | 	      report_transaction(tr, &log, object_name, "DB error");
585  | 	      transaction_free(tr); tr=NULL;
586  | 	      object_free(obj); obj=NULL;
587  | 	      operation=OP_NOOP;
588  | 	      break;
589  | 	    }
590  | 	    else 
591  | 	     if(nrtm) { 	//NRTM mode
592  | 	       error=process_nrtm(tr, nrtm, &log, object_name, operation);
593  | 	       tr=NULL;
594  | 	       obj=NULL;
595  | 	       operation=OP_NOOP;
596  | 	     }
597  | 	     else {	//update mode
598  | 	       error=process_updates(tr, &log, object_name, operation, standalone);
599  | 	       if(!standalone) { /* copy the script */
600  | 	        ud_stream->error_script=g_strdup((tr->error_script)->str);
601  | 	        object_free(tr->object); obj=NULL;
602  | 	        transaction_free(tr); tr=NULL;
603  | 	        g_string_free(g_line_buff, TRUE);
604  | 	        SQ_close_connection(sql_connection);
605  | 	        fclose(logfile);
606  | 	        return(error);
607  | 	       }
608  | 	       else {
609  | 	        object_free(tr->object); obj=NULL;
610  | 	        transaction_free(tr); tr=NULL;
611  | 	        operation=OP_NOOP;
612  | 	       } 
613  | 	     }
614  | 	    /* this is a good place for quick inerrupt */
615  |           }  
616  |         }
617  |       break;
618  | 
619  |       default:
620  |         fprintf(stderr, "ERROR: Bad line type\n");
621  |     } /* switch */
622  |   } /* while */
623  |  
624  |   if(nrtm)
625  |    if(nrtm->tr){ //saved backlog?
626  |     object_process(nrtm->tr); // delete the previous(saved) object
627  |     report_transaction(nrtm->tr, &log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object");
628  |     object_free(nrtm->tr->object);
629  |     transaction_free(nrtm->tr); nrtm->tr=NULL;
630  |   }
631  |                                                                                                        
632  |  ftime=time(NULL);
633  |  obj_second1 = (float)(log.num_ok)/(ftime-stime);
634  |  obj_second10 = (float)(log.num_ok+log.num_failed)/(ftime-stime);
635  | 
636  |   SQ_close_connection(sql_connection);
637  |   g_string_free(g_line_buff, TRUE);
638  |   fclose(ud_stream->stream);
639  |   if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode)))unlink(tmpfile2);
640  |   printf("\n\n******** report **********\n%d objects OK\n%d objects failed\n", log.num_ok, log.num_failed);
641  |   fprintf(logfile,"\n******** report **********\n");
642  |   fprintf(logfile," %d objects OK (%5.2f obj/s)\n", log.num_ok, obj_second1);
643  |   fprintf(logfile," %d objects failed\n", log.num_failed);
644  |   fprintf(logfile," average processing time %5.2f obj/s (%5.2f obj/min)\n", obj_second10, obj_second10*60);
645  |   fclose(logfile);
646  |   return(log.num_ok+log.num_failed);
647  | 
648  | } /* UD_process_stream */
649  | 
650  | 
651  | 
652  |