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