1 | /*************************************** 2 | $Revision: 1.25 $ 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 | return(-1); 124 | } 125 | /* fprintf(stderr, "Sending Invitation\n"); */ 126 | 127 | /* Request all available serials (upto LAST), or SBUNCH of them */ 128 | if(upto_last==1) 129 | sprintf(line_buff, "-g %s:%d:%ld-LAST\n", source, nrtm->version, nrtm->current_serial+1); 130 | else if(upto_last==-1) /* persistent mirroring */ 131 | sprintf(line_buff, "-k -g %s:%d:%ld-LAST\n", source, nrtm->version, nrtm->current_serial+1); 132 | else 133 | sprintf(line_buff, "-g %s:%d:%ld-%ld\n", source, nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH); 134 | nwrite=SK_write(sockfd, line_buff, strlen(line_buff) ); 135 | if(nwrite != strlen(line_buff)) { 136 | ER_perror(FAC_UD, UD_FS, "cannot write"); 137 | return(-1); 138 | } 139 | fd=sockfd; 140 | network=1; 141 | /* fprintf(stderr, "Returning stream pointer\n"); */ 142 | } 143 | else { /* this is a file stream*/ 144 | network=0; 145 | close(sockfd); 146 | /* fprintf(stderr, "Trying file ...\n");*/ 147 | if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) { 148 | ER_perror(FAC_UD, UD_FS, "cannot open"); 149 | return(-1); 150 | } 151 | } 152 | return(fd); 153 | } 154 | 155 | 156 | 157 | /************************************************************ 158 | * void UD_do_nrtm() * 159 | * * 160 | * Processes NRTM stream * 161 | * * 162 | * It cycles requesting objects from the NRTM server, * 163 | * processing them and then sleeping a specified amount of * 164 | * time. * 165 | * * 166 | * It starts by requesting SBUNCH number of serials and does * 167 | * so untill no serials are received (actually a warning * 168 | * is received saying that the requested range is invalid) * 169 | * This approach avoids excessive load on the NRTM server * 170 | * * 171 | * After that it requests serials using LAST keyward keeping * 172 | * almost in sync with the server * 173 | * * 174 | ************************************************************/ 175 | 176 | void UD_do_nrtm(void *arg) 177 | { 178 | int source = (int)arg; 179 | UD_stream_t ud_stream; 180 | struct _nrtm *nrtm; 181 | int nrtm_delay; 182 | int do_update=1; 183 | int do_server; 184 | int nrtm_fd; 185 | int num_ok; 186 | int upto_last; 187 | char ta_activity[STR_M]; 188 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source); 189 | char *db_host, *db_name, *db_user, *db_passwd; 190 | int db_port; 191 | /* get source we are going to mirror */ 192 | char *source_name = ca_get_srcname(source_hdl); 193 | 194 | { /* set up the lohgging path */ 195 | int res; 196 | char *er_ud_def = ca_get_er_ud_def; /* something like 'RIPUPDLOG basename' */ 197 | char er_def[256]; 198 | char *erret = NULL; 199 | 200 | sprintf(er_def, "%s %s", er_ud_def, source_name); 201 | fprintf(stderr, "[%s]\n", er_def); 202 | if( (res = ER_macro_spec(er_def, &erret)) != 0 ) { 203 | fputs(erret, stderr); 204 | die; 205 | /* or some other error handling */ 206 | } 207 | free(erret); /* the response is allocated and must be freed */ 208 | free(er_ud_def); 209 | } 210 | 211 | nrtm=calloc(1, sizeof(struct _nrtm)); 212 | if(nrtm==NULL) { 213 | ER_perror(FAC_UD, UD_MEM, "cannot allocate memory"); 214 | die; 215 | } 216 | /* get mode of operation: protected/unprotected (dummy) */ 217 | memset(&ud_stream, 0, sizeof(ud_stream)); 218 | ud_stream.source_hdl=source_hdl; 219 | ud_stream.ud_mode=ca_get_srcmode(source_hdl); 220 | nrtm_delay=ca_get_srcnrtmdelay(source_hdl); 221 | /* Zero delay means persistent connection */ 222 | if (nrtm_delay==0) ud_stream.ud_mode |= B_PERSIST_MIRR; 223 | 224 | fprintf(stderr, "Mode of operation:\n"); 225 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n"); 226 | else fprintf(stderr, "* dummy not allowed\n"); 227 | 228 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n"); 229 | else if(IS_NRTM_CLNT(ud_stream.ud_mode)) { 230 | 231 | if(IS_PERSIST_MIRR(ud_stream.ud_mode))fprintf(stderr, "* NRTM: persistent conection\n"); 232 | else fprintf(stderr, "* NRTM\n"); 233 | } 234 | else fprintf(stderr, "* STATIC\n"); 235 | 236 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n"); 237 | else fprintf(stderr, "* running as a server\n"); 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(mysql_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 (current serial=%ld)", UD_TAG, nrtm->current_serial); 297 | 298 | /* Get file descriptor of the data stream (RPSL format, use mirror reflector to convert if needed)*/ 299 | nrtm_fd=get_NRTM_fd(nrtm, upto_last, source_name); 300 | if (nrtm_fd==-1) { 301 | ER_inf_va(FAC_UD, ASP_UD_OBJ, "%s Cannot open data stream. Trying...", UD_TAG); 302 | SV_sleep(PM_CONNECTION_TIMEOUT); 303 | continue; 304 | } 305 | 306 | 307 | /* make a record for thread accounting */ 308 | TA_add(nrtm_fd, "nrtm_clnt"); 309 | sprintf(ta_activity,"[%s]%ld->", source_name, nrtm->current_serial); 310 | TA_setactivity(ta_activity); 311 | 312 | 313 | ud_stream.condat.sock = nrtm_fd; 314 | ud_stream.log.num_ok=0; 315 | ud_stream.log.num_failed=0; 316 | 317 | 318 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s starting processing stream", UD_TAG); 319 | 320 | /***************** process stream ****************/ 321 | 322 | num_ok=UD_process_stream(&ud_stream); 323 | 324 | /***************** process stream ****************/ 325 | 326 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s processing stream finished", UD_TAG); 327 | 328 | /* close the socket of the NRTM stream */ 329 | close(ud_stream.condat.sock); 330 | 331 | 332 | 333 | ER_inf_va(FAC_UD, ASP_UD_OBJ, "%s forwarded to serial:%ld", UD_TAG, (nrtm->current_serial+num_ok)); 334 | 335 | /* set activity for thread record */ 336 | sprintf(ta_activity,"[%s]->%ld", source_name, (nrtm->current_serial+num_ok)); 337 | TA_setactivity(ta_activity); 338 | 339 | /* if we are NOT in persistent mode */ 340 | if(!IS_PERSIST_MIRR(ud_stream.ud_mode)) { 341 | /* Now we can process serials in normal way (upto LAST)*/ 342 | if(num_ok==0) upto_last=1; 343 | /* get delay */ 344 | nrtm_delay=ca_get_srcnrtmdelay(source_hdl); 345 | /* sleep the delay seconds or untill the shutdown requested */ 346 | SV_sleep(nrtm_delay); 347 | } /* otherwise - no delay at all */ 348 | 349 | } /* if do_updates */ 350 | else SV_sleep(TIMEOUT); 351 | 352 | 353 | TA_delete(); 354 | 355 | } while((do_server=CO_get_do_server())); /* main cycle */ 356 | 357 | /* fclose(ud_stream.log.logfile);*/ 358 | free(source_name); 359 | /* free data associated with nrtm structure */ 360 | if(nrtm) { 361 | free(nrtm->server); 362 | free(nrtm); 363 | } 364 | 365 | /* That's all. Close connection to the DB */ 366 | SQ_close_connection(ud_stream.db_connection); 367 | free(db_host); 368 | free(db_name); 369 | free(db_user); 370 | free(db_passwd); 371 | 372 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s NRTM client stopped", UD_TAG); 373 | } /* UD_do_nrtm() */ 374 | 375 | /************************************************************ 376 | * void UD_do_updates() * 377 | * * 378 | * Processes updates * 379 | * * 380 | * It cycles accepting connections and processing them * 381 | * (interactive server). This assures that there is only * 382 | * one write thread per database/source. * 383 | * * 384 | ************************************************************/ 385 | 386 | void UD_do_updates(void *arg) 387 | { 388 | int source = (int)arg; 389 | int listening_socket = SV_update_sock[source]; 390 | int connected_socket; 391 | UD_stream_t ud_stream; 392 | int do_update=1; 393 | int do_server; 394 | int num_ok; 395 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source); 396 | char *db_host, *db_name, *db_user, *db_passwd; 397 | int db_port; 398 | 399 | { /* set up the lohgging path */ 400 | /* get source we are going to update */ 401 | char *source_name = ca_get_srcname(source_hdl); 402 | int res; 403 | char *er_ud_def = ca_get_er_ud_def; /* something like 'RIPUPDLOG basename' */ 404 | char er_def[256]; 405 | char *erret = NULL; 406 | 407 | sprintf(er_def, "%s %s", er_ud_def, source_name); 408 | if( (res = ER_macro_spec(er_def, &erret)) != 0 ) { 409 | fputs(erret, stderr); 410 | die; 411 | /* or some other error handling */ 412 | } 413 | free(erret); /* the response is allocated and must be freed */ 414 | free(er_ud_def); 415 | free(source_name); 416 | } 417 | 418 | /* get mode of operation: protected/unprotected (dummy) */ 419 | memset(&ud_stream, 0, sizeof(ud_stream)); 420 | ud_stream.source_hdl=source_hdl; 421 | ud_stream.ud_mode=ca_get_srcmode(source_hdl); 422 | 423 | fprintf(stderr, "Mode of operation:\n"); 424 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n"); 425 | else fprintf(stderr, "* dummy not allowed\n"); 426 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n"); 427 | else fprintf(stderr, "* NRTM\n"); 428 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n"); 429 | else fprintf(stderr, "* running as a server\n"); 430 | 431 | 432 | /* get error log facility */ 433 | db_host = ca_get_srcdbmachine(source_hdl); 434 | db_port = ca_get_srcdbport(source_hdl); 435 | db_name = ca_get_srcdbname(source_hdl); 436 | db_user = ca_get_srcdbuser(source_hdl); 437 | db_passwd = ca_get_srcdbpassword(source_hdl); 438 | 439 | /* Connect to the database */ 440 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s making SQL connection to %s@%s ...", UD_TAG, db_name, db_host); 441 | ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd); 442 | 443 | if(! ud_stream.db_connection) { 444 | ER_perror(FAC_UD, UD_SQL, "no connection to SQL server\n"); 445 | die; 446 | } 447 | 448 | 449 | ud_stream.condat.rd_timeout.tv_sec=STREAM_TIMEOUT; 450 | ud_stream.num_skip=0; 451 | ud_stream.load_pass=0; 452 | ud_stream.nrtm=NULL; 453 | 454 | /*+++ main cycle +++*/ 455 | 456 | do { /* be alive while do_server is 1. do_server is turned off by SIGINT */ 457 | 458 | /* make a record for thread accounting */ 459 | TA_add(listening_socket, "update"); 460 | TA_setactivity("waiting"); 461 | 462 | 463 | /* accept connection */ 464 | connected_socket = SK_accept_connection(listening_socket); 465 | if(connected_socket==-1) break; 466 | 467 | 468 | /* make a record for thread accounting */ 469 | TA_delete(); /* Delete 'waiting' record */ 470 | TA_add(connected_socket, "update"); 471 | 472 | 473 | ud_stream.condat.sock = connected_socket; 474 | ud_stream.condat.rtc = 0; 475 | 476 | do_update=CO_get_do_update(); 477 | if(do_update) { 478 | 479 | TA_setactivity("suspended"); 480 | 481 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s Connection accepted...", UD_TAG); 482 | 483 | ud_stream.log.num_ok=0; 484 | ud_stream.log.num_failed=0; 485 | 486 | /* Check connection to the database and try to reconnect*/ 487 | if(mysql_ping(ud_stream.db_connection)) { 488 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s connection to SQL server timed out - reistablishing", UD_TAG); 489 | } 490 | 491 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s starting processing object", UD_TAG); 492 | 493 | /***************** process stream ****************/ 494 | 495 | num_ok=UD_process_stream(&ud_stream); 496 | 497 | /***************** process stream ****************/ 498 | 499 | ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s processing object finished", UD_TAG); 500 | 501 | /* close the socket of the NRTM stream */ 502 | close(ud_stream.condat.sock); 503 | 504 | } /* if do_update*/ 505 | else { /* Otherwise print a message*/ 506 | /* To display with 'show threads' */ 507 | TA_setactivity("suspended"); 508 | 509 | } 510 | /* make a record for thread accounting */ 511 | TA_delete(); 512 | 513 | do_server=CO_get_do_server(); 514 | 515 | } while (do_server); /* main cycle */ 516 | 517 | /* fclose(ud_stream.log.logfile); */ 518 | /* That's all. Close connection to the DB */ 519 | SQ_close_connection(ud_stream.db_connection); 520 | free(db_host); 521 | free(db_name); 522 | free(db_user); 523 | free(db_passwd); 524 | 525 | 526 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s update server stopped", UD_TAG); 527 | } /* UD_do_update() */ 528 | 529 | 530 | 531 |