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 |