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 |