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