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