1    | /***************************************
2    |   $Revision: 1.40 $
3    | 
4    |   Wrapper for NRTM client
5    | 
6    |   Status: NOT REVUED, NOT TESTED
7    | 
8    |  Author(s):       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   | 
36   | #include <sys/types.h>
37   | #include <sys/socket.h>
38   | #include <netinet/in.h>
39   | #include <arpa/inet.h>
40   | #include <fcntl.h>
41   | #include <signal.h>
42   | #include <sys/poll.h>
43   | 
44   | 
45   | /* here we store sockets for update threads */
46   | /* they are from SV module */
47   | extern int SV_update_sock[];
48   | 
49   | /* here is the shutdown pipe for update threads */
50   | /* also from SV module (apologies for breaking encapsulation) */
51   | extern int SV_shutdown_recv_fd;
52   | 
53   | /* Response time to swtching updates on and off */
54   | #define TIMEOUT 60 
55   | 
56   | /* timeout between successive attempts to establish connection with server */
57   | #define PM_CONNECTION_TIMEOUT 10 
58   | 
59   | /* Maximum number of objects(serials) we can consume at a time */
60   | #define SBUNCH 1000
61   | 
62   | /* Timeout in seconds when reading (writing) from DBupdate */
63   | #define STREAM_TIMEOUT 120
64   | 
65   | /************************************************************
66   | * int get_NRTM_fd()                                         *
67   | *                                                           *
68   | * Gets the NRTM stream                                      *
69   | *                                                           *
70   | * First tries to request the serials from the NRTM server   *
71   | * If the name of the server appears to be not a network name*
72   | * it tries to open the file with this name                  *
73   | *                                                           *
74   | * nrtm - pointer to _nrtm structure                         *
75   | * upto_last - if==1 then requests to download serials using *
76   | * LAST keyword                                              *
77   | *                                                           *
78   | * Returns:                                                  *
79   | * A file descriptor for a data stream                       *
80   | * -1 - error                                                *
81   | *                                                           *
82   | ************************************************************/
83   | int get_NRTM_fd(struct _nrtm *nrtm, int upto_last, char *source)
84   | {
85   | int sockfd;
86   | struct hostent *hptr;
87   | struct sockaddr_in serv_addr;
88   | struct in_addr *paddr;
89   | char host_info[STR_XXL];
90   | GString *line_buff;
91   | int fd;
92   | int ret;
93   | struct hostent result;
94   | int error;
95   | int network;
96   | 
97   | /* fprintf(stderr, "Making connection to NRTM server ...\n");*/
98   |  if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){
99   |    ER_perror(FAC_UD, UD_FS, "cannot create socket");
100  |    return(-1);
101  |  }  
102  | #ifdef __linux__
103  |  if(gethostbyname_r(nrtm->server,  &result, host_info, sizeof(host_info), &hptr, &error)<0)  hptr=NULL;
104  | #else/* default is Solaris implementation */
105  |  hptr=gethostbyname_r(nrtm->server,  &result, host_info, sizeof(host_info), &error);
106  | #endif
107  | 
108  |  /* Check if it is a network stream or a file */
109  |  if (hptr) { /* this is a network stream*/
110  |    paddr=(struct in_addr *)hptr->h_addr;
111  |    bzero(&serv_addr, sizeof(serv_addr));
112  |    serv_addr.sin_family=AF_INET;
113  |    serv_addr.sin_port=nrtm->port;
114  |    memcpy(&serv_addr.sin_addr, paddr, sizeof(struct in_addr));
115  | /*   fprintf(stderr,"Trying %s port %d\n", inet_ntoa(serv_addr.sin_addr), nrtm->port);*/
116  |    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))==-1) {
117  |      ER_perror(FAC_UD, UD_FS, "cannot connect, errno:%d", errno); 
118  |      close(sockfd);
119  |      return(-1);
120  |    }  
121  | /*   fprintf(stderr, "Sending Invitation\n"); */
122  |    
123  |    /* Request all available serials (upto LAST), or SBUNCH of them */
124  |    line_buff = g_string_sized_new(STR_L);
125  |    if(upto_last==1)
126  |       g_string_sprintf(line_buff, "-g %s:%d:%ld-LAST\n", source, nrtm->version, nrtm->current_serial+1);
127  |    else if(upto_last==-1) /* persistent mirroring */
128  |       g_string_sprintf(line_buff, "-k -g %s:%d:%ld-LAST\n", source, nrtm->version, nrtm->current_serial+1);
129  |    else
130  |       g_string_sprintf(line_buff, "-g %s:%d:%ld-%ld\n", source, nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH);   
131  |    ret=SK_write(sockfd, line_buff->str, line_buff->len, NULL, NULL );
132  |    g_string_free(line_buff, TRUE);
133  |    if(ret != 1) { 
134  | 	   ER_perror(FAC_UD, UD_FS, "cannot write");
135  | 	   close(sockfd);
136  | 	   return(-1); 
137  |    }
138  |    fd=sockfd;
139  |    network=1;
140  | /*   fprintf(stderr, "Returning stream pointer\n"); */
141  |  }
142  |  else { /* this is a file stream*/
143  |    network=0;
144  |    close(sockfd);
145  | /*   fprintf(stderr, "Trying file ...\n");*/
146  |    if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) {
147  |       ER_perror(FAC_UD, UD_FS, "cannot open");	   
148  |       return(-1);
149  |    }  
150  |  }  
151  |  return(fd);
152  | } 
153  | 
154  | 
155  | 
156  | /************************************************************
157  | *  void UD_do_nrtm()                                        *
158  | *                                                           *
159  | * Processes NRTM stream                                     *
160  | *                                                           *
161  | * It cycles requesting objects from the NRTM server,        * 
162  | * processing them and then sleeping a specified amount of   *
163  | * time.                                                     *
164  | *                                                           *
165  | * It starts by requesting SBUNCH number of serials and does *
166  | * so untill no serials are received (actually a warning     *
167  | * is received saying that the requested range is invalid)   *
168  | * This approach avoids excessive load on the NRTM server    *
169  | *                                                           *
170  | * After that it requests serials using LAST keyward keeping *
171  | * almost in sync with the server                            *
172  | *                                                           *
173  | ************************************************************/
174  |  
175  | void UD_do_nrtm(void *arg)
176  | {
177  | int source = (int)arg;
178  | UD_stream_t ud_stream;
179  | struct _nrtm *nrtm;
180  | int nrtm_delay;
181  | int do_update=1;
182  | int do_server;
183  | int nrtm_fd;
184  | int num_ok;
185  | int upto_last;
186  | GString *ta_activity;
187  | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source);
188  | char *db_host, *db_name, *db_user, *db_passwd;
189  | int db_port;
190  | /* get source we are going to mirror */
191  | char *source_name = ca_get_srcname(source_hdl);  
192  | 
193  |   { /* set up the lohgging path */
194  |    int res;
195  |    char *er_ud_def = ca_get_er_ud_def; /* something like 'RIPUPDLOG basename' */
196  |    GString *er_def;
197  |    char *erret = NULL;
198  | 
199  |    er_def = g_string_sized_new(256);
200  |    g_string_sprintf(er_def, "%s %s", er_ud_def, source_name);
201  |    fprintf(stderr, "[%s]\n", er_def->str);
202  |    if( (res = ER_macro_spec(er_def->str, &erret)) != 0 ) {
203  |         fputs(erret, stderr);
204  |         die;
205  |         /* or some other error handling */
206  |    }     
207  |    UT_free(erret); /* the response is allocated and must be freed */
208  |    g_string_free(er_def, TRUE);
209  |    UT_free(er_ud_def);
210  |   }  
211  | 
212  |   /* load the dictionary */
213  |   rpsl_load_dictionary(RPSL_DICT_CORE);
214  |          
215  |   nrtm=UT_calloc(1, sizeof(struct _nrtm));
216  |   if(nrtm==NULL) {
217  | 	  ER_perror(FAC_UD, UD_MEM, "cannot allocate memory");
218  | 	  die;
219  |   }	  
220  | /* get mode of operation: protected/unprotected (dummy) */
221  |   memset(&ud_stream, 0, sizeof(ud_stream));
222  |   ud_stream.source_hdl=source_hdl;
223  |   ud_stream.ud_mode=ca_get_srcmode(source_hdl);
224  |   nrtm_delay=ca_get_srcnrtmdelay(source_hdl);
225  |   /* Zero delay means persistent connection */
226  |   if (nrtm_delay==0) ud_stream.ud_mode |= B_PERSIST_MIRR;
227  | 
228  |   fprintf(stderr, "Mode of operation:\n");
229  |   if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n"); 
230  |   else fprintf(stderr, "* dummy not allowed\n");
231  |   
232  |   if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n");
233  |   else if(IS_NRTM_CLNT(ud_stream.ud_mode)) {
234  | 	   
235  | 	   if(IS_PERSIST_MIRR(ud_stream.ud_mode))fprintf(stderr, "* NRTM: persistent conection\n");
236  | 	   else fprintf(stderr, "* NRTM\n");
237  | 	}   
238  |         else fprintf(stderr, "* STATIC\n");
239  |   
240  |   if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n");
241  |    else fprintf(stderr, "* running as a server\n");
242  |   
243  |   if(IS_NO_NHR(ud_stream.ud_mode))fprintf(stderr, "* NHR is not maintained\n");
244  |    else fprintf(stderr, "* NHR is maintained\n");
245  | 
246  | 
247  | /* get mirror server */
248  |   nrtm->server=ca_get_srcnrtmhost(source_hdl);
249  | 
250  |   
251  | /* get mirror port */
252  |   nrtm->port = htons(ca_get_srcnrtmport(source_hdl));
253  |   printf("XXX nrtm_port=%d\n", ntohs(nrtm->port));
254  | 
255  | /* get mirror version */
256  |   nrtm->version=ca_get_srcnrtmprotocolvers(source_hdl);
257  |  
258  | 
259  | /* get error log facility */
260  | /*   logfilename=ca_get_srcnrtmlog(source_hdl); */
261  | 
262  |    db_host = ca_get_srcdbmachine(source_hdl);
263  |    db_port = ca_get_srcdbport(source_hdl);
264  |    db_name = ca_get_srcdbname(source_hdl);
265  |    db_user = ca_get_srcdbuser(source_hdl);
266  |    db_passwd = ca_get_srcdbpassword(source_hdl);
267  |   
268  | /* Connect to the database */
269  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s making SQL connection to %s@%s ...", UD_TAG, db_name, db_host);
270  |   ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
271  |      
272  |  
273  |   if(! ud_stream.db_connection) {
274  |     ER_perror(FAC_UD, UD_SQL, "no connection to SQL server");
275  |     die;
276  |   }
277  |   	
278  |   ud_stream.num_skip=0;
279  |   ud_stream.load_pass=0;
280  |   ud_stream.nrtm=nrtm;
281  |   
282  |   if(IS_PERSIST_MIRR(ud_stream.ud_mode))upto_last=-1; /* the faster the better */
283  |   else upto_last=0; /* let's start gradually if the backlog is > SBUNCH (1000) serials*/
284  | 
285  | /*+++ main cycle +++*/
286  | 
287  |  do {
288  |   do_update=CO_get_do_update();
289  |   if(do_update) {
290  |  
291  |    /* Check connection to the database and try to reconnect */
292  |    if(SQ_ping(ud_stream.db_connection)) {
293  |     ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s connection to SQL server timed out - reistablishing", UD_TAG);
294  |    }
295  | 
296  |   /* get current serial */
297  |    nrtm->current_serial=PM_get_current_serial(ud_stream.db_connection);
298  |    
299  |    if(nrtm->current_serial == -1) {
300  |       ER_perror(FAC_UD, UD_SQL, "cannot obtain current serial: %ld", nrtm->current_serial);
301  |      die;
302  |    }
303  | 
304  |    ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s connecting to NRTM server [%s:%d] (current serial=%ld)", 
305  |                                     UD_TAG, nrtm->server, ntohs(nrtm->port), nrtm->current_serial);
306  | 
307  |   /* Get file descriptor of the data stream (RPSL format, use mirror reflector to convert if needed)*/
308  |     nrtm_fd=get_NRTM_fd(nrtm, upto_last, source_name);
309  |     if (nrtm_fd==-1) { 
310  |      ER_inf_va(FAC_UD, ASP_UD_OBJ, "%s Cannot open data stream. Trying...", UD_TAG);
311  |      SV_sleep(PM_CONNECTION_TIMEOUT);
312  |      continue;
313  |     }  
314  | 
315  |    
316  |     /* make a record for thread accounting */
317  |     TA_add(nrtm_fd, "nrtm_clnt");
318  |     ta_activity = g_string_sized_new(STR_M);
319  |     g_string_sprintf(ta_activity, "[%s]%ld->", 
320  |                      source_name, nrtm->current_serial);
321  |     TA_setactivity(ta_activity->str);
322  |    
323  |    
324  |    ud_stream.condat.sock = nrtm_fd;
325  |    ud_stream.log.num_ok=0; 
326  |    ud_stream.log.num_failed=0;
327  |   
328  | 
329  |    ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s starting processing stream", UD_TAG);
330  | 
331  | /***************** process stream ****************/
332  | 
333  |       num_ok=UD_process_stream(&ud_stream);
334  |   
335  | /***************** process stream ****************/
336  |   
337  |    ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s processing stream finished", UD_TAG);
338  |    
339  |   /* close the socket of the NRTM stream */
340  |    close(ud_stream.condat.sock);
341  |    
342  |   
343  | 
344  |    ER_inf_va(FAC_UD, ASP_UD_OBJ, "%s forwarded to serial:%ld", UD_TAG, (nrtm->current_serial+num_ok));
345  |    
346  |    /* set activity for thread record */
347  |    g_string_sprintf(ta_activity, "[%s]->%ld", 
348  |                     source_name, (nrtm->current_serial+num_ok));
349  |    TA_setactivity(ta_activity->str);
350  |    g_string_free(ta_activity, TRUE);
351  | 
352  | /* if we are NOT in persistent mode */
353  |    if(!IS_PERSIST_MIRR(ud_stream.ud_mode)) {
354  |      /* Now we can process serials in normal way (upto LAST)*/ 
355  |      if(num_ok==0) upto_last=1;
356  |      /* get delay */
357  |      nrtm_delay=ca_get_srcnrtmdelay(source_hdl);
358  |    } else 
359  |      /* we need to delay the next attempt not to have a birst of requests */
360  |      nrtm_delay=TIMEOUT; 
361  |      /* sleep the delay seconds or untill the shutdown requested */
362  |      SV_sleep(nrtm_delay);
363  |    
364  |   } /* if do_updates */
365  |   else SV_sleep(TIMEOUT); 
366  |   
367  | 
368  |   TA_delete();
369  |   
370  |  } while((do_server=CO_get_do_server()));  /* main cycle */
371  | 
372  | /*   fclose(ud_stream.log.logfile);*/
373  |    UT_free(source_name);
374  | /* free data associated with nrtm structure */         
375  |  if(nrtm) {
376  |    UT_free(nrtm->server);
377  |    UT_free(nrtm);
378  |  }
379  |  
380  |  /* That's all. Close connection to the DB */ 
381  |  SQ_close_connection(ud_stream.db_connection);
382  |  UT_free(db_host);
383  |  UT_free(db_name);
384  |  UT_free(db_user);
385  |  UT_free(db_passwd);
386  | 
387  |  ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s NRTM client stopped", UD_TAG); 
388  | } /* UD_do_nrtm() */
389  | 
390  | /************************************************************
391  | *  void UD_do_updates()                                     *
392  | *                                                           *
393  | * Processes updates                                         *
394  | *                                                           *
395  | * It cycles accepting connections and processing them       * 
396  | * (interactive server). This assures that there is only     *
397  | * one write thread per database/source.                     *
398  | *                                                           *
399  | ************************************************************/
400  |    
401  | void UD_do_updates(void *arg)
402  | {
403  | int source = (int)arg;
404  | int listening_socket = SV_update_sock[source];
405  | int connected_socket;
406  | UD_stream_t ud_stream;
407  | int do_update=1;
408  | int num_ok;
409  | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source);
410  | char *db_host, *db_name, *db_user, *db_passwd;
411  | int db_port;
412  | ip_addr_t address;
413  | char *source_name;
414  | struct pollfd pfd[2];
415  | 
416  |    source_name = ca_get_srcname(source_hdl);  
417  | 
418  |   { /* set up the lohgging path */
419  |    /* get source we are going to update */
420  |    int res;
421  |    char *er_ud_def = ca_get_er_ud_def; /* something like 'RIPUPDLOG basename' */
422  |    GString *er_def;
423  |    char *erret = NULL;
424  |    
425  | 
426  |    er_def = g_string_sized_new(256);
427  |    g_string_sprintf(er_def, "%s %s", er_ud_def, source_name);
428  |    if( (res = ER_macro_spec(er_def->str, &erret)) != 0 ) {
429  |         fputs(erret, stderr);
430  |         die;
431  |         /* or some other error handling */
432  |    }     
433  |    UT_free(erret); /* the response is allocated and must be freed */
434  |    g_string_free(er_def, TRUE);
435  |    UT_free(er_ud_def);
436  |   } 
437  | 
438  |   /* load the dictionary */
439  |     rpsl_load_dictionary(RPSL_DICT_CORE);
440  |     
441  | 
442  | /* get mode of operation: protected/unprotected (dummy) */
443  |   memset(&ud_stream, 0, sizeof(ud_stream));
444  |   ud_stream.source_hdl=source_hdl;
445  |   ud_stream.ud_mode=ca_get_srcmode(source_hdl);
446  | 
447  |   fprintf(stderr, "Mode of operation:\n");
448  |   if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n"); 
449  |    else fprintf(stderr, "* dummy not allowed\n");
450  |   if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n");
451  |    else fprintf(stderr, "* NRTM\n");
452  |   if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n");
453  |    else fprintf(stderr, "* running as a server\n");
454  | 
455  | 
456  | /* get the database */
457  |   db_host = ca_get_srcdbmachine(source_hdl);
458  |   db_port = ca_get_srcdbport(source_hdl);
459  |   db_name = ca_get_srcdbname(source_hdl);
460  |   db_user = ca_get_srcdbuser(source_hdl);
461  |   db_passwd = ca_get_srcdbpassword(source_hdl);
462  |   
463  | /* Connect to the database */
464  |   ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s making SQL connection to %s@%s ...", UD_TAG, db_name, db_host);
465  |   ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
466  |    
467  |   if(! ud_stream.db_connection) {
468  |    ER_perror(FAC_UD, UD_SQL, "no connection to SQL server\n");
469  |    die;
470  |   }
471  |   	
472  | 
473  |   ud_stream.condat.rd_timeout.tv_sec=STREAM_TIMEOUT;
474  |   ud_stream.num_skip=0;
475  |   ud_stream.load_pass=0;
476  |   ud_stream.nrtm=NULL;
477  | 
478  |   /* set up poll structure */
479  |   pfd[0].fd = listening_socket;
480  |   pfd[0].events = POLLIN;
481  |   pfd[1].fd = SV_shutdown_recv_fd;
482  |   pfd[1].events = POLLIN;
483  |  
484  | /*+++ main cycle +++*/
485  | 
486  | do { /* be alive while do_server is 1. do_server is turned off by SIGINT */
487  |  
488  |    /* make a record for thread accounting */
489  |    TA_add(listening_socket, "update");
490  |    TA_setactivity("waiting");
491  | 
492  |    /* check for input */
493  |    if (poll(pfd, 2, -1) == -1) {
494  |         ER_perror(FAC_SV, 1, "UD_do_updates got error %d on poll; %s",
495  |                   errno, strerror(errno));
496  |         continue;
497  |    }
498  | 
499  |    /* shutdown */
500  |    if (pfd[1].revents != 0) break;
501  |  
502  |    /* accept connection */
503  |    connected_socket = SK_accept_connection(listening_socket);
504  |    if(connected_socket==-1) continue;
505  |    
506  |    /* check if the client is authorised to update */
507  |    SK_getpeerip(connected_socket, &address);
508  |    if(!AA_can_ripupdate(&address, source_name)){
509  |    char *hostaddress;
510  |    sk_conn_st condat;
511  |    char buff[STR_L];
512  |     
513  |     memset( &condat, 0, sizeof(sk_conn_st));
514  |     condat.wr_timeout.tv_sec=STREAM_TIMEOUT;
515  |     condat.sock = connected_socket;
516  |     SK_getpeerip(connected_socket, &(condat.rIP));
517  |     memcpy( &(condat.eIP), &(condat.rIP), sizeof(ip_addr_t));
518  |     hostaddress = SK_getpeername(connected_socket);
519  |     condat.ip = hostaddress;
520  |     
521  |     ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%s] --  Not authorized to update the source %s", hostaddress, source_name);
522  |     sprintf(buff, "\n%%ERROR:406: not authorized to update the database\n\n\n");
523  |     SK_cd_puts(&condat, buff);
524  |     SK_cd_close(&(condat));
525  |     
526  |     UT_free(hostaddress);
527  |     /* start the next loop */
528  |     continue;
529  |    }
530  |     
531  |    /* make a record for thread accounting */
532  |    TA_delete(); /* Delete 'waiting' record */
533  |    TA_add(connected_socket, "update");
534  | 
535  | 
536  |    ud_stream.condat.sock = connected_socket;
537  |    ud_stream.condat.rtc = 0;
538  | 
539  |    
540  |    ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s Connection accepted...", UD_TAG);
541  |   
542  |    ud_stream.log.num_ok=0; 
543  |    ud_stream.log.num_failed=0;
544  |  
545  |   
546  |    while((do_update=CO_get_do_update())!=1) {
547  | 	   TA_setactivity("suspended");
548  | 	   /* if shutdown was requested - break */
549  | 	   if(SV_sleep(3*TIME_SLICE)) break;
550  |    }
551  | 
552  |    if(do_update) {
553  |      /* Check connection to the database and try to reconnect*/
554  |      if(SQ_ping(ud_stream.db_connection)) {
555  |        ER_perror(FAC_UD, UD_SQL, "%s", SQ_error(ud_stream.db_connection));
556  |        die;
557  |      }
558  | 
559  |      ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s starting processing object", UD_TAG);
560  |   
561  |      /***************** process stream ****************/
562  | 
563  |       num_ok=UD_process_stream(&ud_stream);
564  | 
565  |      /***************** process stream ****************/    
566  |   
567  |       ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s processing object finished", UD_TAG);
568  |   
569  |      /* close the socket of the NRTM stream */
570  |      close(ud_stream.condat.sock);
571  |     
572  |    }  /* if do_update*/
573  | 
574  |    
575  |    TA_delete();
576  | 
577  | } while (CO_get_do_server());  /* main cycle */
578  |   
579  | /*   fclose(ud_stream.log.logfile); */
580  |  /* That's all. Close connection to the DB */ 
581  |  SQ_close_connection(ud_stream.db_connection);
582  |  UT_free(db_host);
583  |  UT_free(db_name);
584  |  UT_free(db_user);
585  |  UT_free(db_passwd);
586  |  UT_free(source_name);
587  | 
588  | 
589  |  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s update server stopped", UD_TAG);
590  | } /* UD_do_update() */
591  | 
592  | 
593  | 
594  |