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