/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- get_NRTM_fd
- UD_do_nrtm
- UD_do_updates
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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