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 |