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