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