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