1 | /*************************************** 2 | $Revision: 1.17 $ 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 | return; 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 | return; 240 | } 241 | 242 | free(db_host); 243 | free(db_name); 244 | free(db_user); 245 | free(db_passwd); 246 | free(logfilename); 247 | 248 | 249 | upto_last=0; /* let's start gradually if the backlog is > SBUNCH (1000) serials*/ 250 | 251 | /*+++ main cycle +++*/ 252 | 253 | do { 254 | do_update=CO_get_do_update(); 255 | if(do_update) { 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 | return; 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 | fprintf(stderr, "NRTM stopped\n"); 343 | 344 | } /* UD_do_nrtm() */ 345 | 346 | /************************************************************ 347 | * void UD_do_updates() * 348 | * * 349 | * Processes updates * 350 | * * 351 | * It cycles accepting connections and processing them * 352 | * (interactive server). This assures that there is only * 353 | * one write thread per database/source. * 354 | * * 355 | ************************************************************/ 356 | 357 | void UD_do_updates(void *arg) 358 | { 359 | int source = (int)arg; 360 | int listening_socket = SV_update_sock[source]; 361 | int connected_socket; 362 | UD_stream_t ud_stream; 363 | int do_update=1; 364 | int do_server; 365 | char *logfilename; 366 | FILE *file, *file_ack; 367 | int num_ok; 368 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source); 369 | char *db_host, *db_name, *db_user, *db_passwd; 370 | int db_port; 371 | 372 | 373 | 374 | /* get mode of operation: protected/unprotected (dummy) */ 375 | /* ud_stream.ud_mode=CO_get_update_mode(); */ 376 | ud_stream.source_hdl=source_hdl; 377 | ud_stream.ud_mode=ca_get_srcmode(source_hdl); 378 | 379 | fprintf(stderr, "Mode of operation:\n"); 380 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n"); 381 | else fprintf(stderr, "* dummy not allowed\n"); 382 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n"); 383 | else fprintf(stderr, "* NRTM\n"); 384 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n"); 385 | else fprintf(stderr, "* running as a server\n"); 386 | 387 | 388 | /* get error log facility */ 389 | logfilename=ca_get_srcnrtmlog(source_hdl); 390 | db_host = ca_get_srcdbmachine(source_hdl); 391 | db_port = ca_get_srcdbport(source_hdl); 392 | db_name = ca_get_srcdbname(source_hdl); 393 | db_user = ca_get_srcdbuser(source_hdl); 394 | db_passwd = ca_get_srcdbpassword(source_hdl); 395 | 396 | /* Connect to the database */ 397 | fprintf(stderr, "D: Making SQL connection to %s@%s ...", db_name, db_host); 398 | 399 | /* ud_stream.db_connection=SQ_get_connection2(); */ 400 | ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd); 401 | 402 | if(! ud_stream.db_connection) { 403 | fprintf(stderr, "D: ERROR: no SQL connection\n"); 404 | return; 405 | } 406 | 407 | fprintf(stderr, "OK\n"); 408 | 409 | ud_stream.num_skip=0; 410 | ud_stream.load_pass=0; 411 | ud_stream.nrtm=NULL; 412 | ud_stream.log.logfile = fopen(logfilename, "a+"); 413 | if(!ud_stream.log.logfile){ 414 | fprintf(stderr, "D: ERROR: cannot open log file %s\n", logfilename); 415 | return; 416 | } 417 | 418 | free(db_host); 419 | free(db_name); 420 | free(db_user); 421 | free(db_passwd); 422 | free(logfilename); 423 | 424 | 425 | /*+++ main cycle +++*/ 426 | 427 | do { /* be alive while do_server is 1. do_server is turned off by SIGINT */ 428 | 429 | /* make a record for thread accounting */ 430 | TA_add(listening_socket, "update"); 431 | TA_setactivity("waiting"); 432 | 433 | 434 | /* accept connection */ 435 | connected_socket = SK_accept_connection(listening_socket); 436 | if(connected_socket==-1) break; 437 | 438 | 439 | /* make a record for thread accounting */ 440 | TA_delete(); /* Delete 'waiting' record */ 441 | TA_add(connected_socket, "update"); 442 | 443 | file=fdopen(connected_socket, "r"); 444 | file_ack=fdopen(connected_socket, "w"); 445 | 446 | do_update=CO_get_do_update(); 447 | if(do_update) { 448 | 449 | TA_setactivity("suspended"); 450 | 451 | fprintf(stderr, "Connection accepted...\n"); 452 | 453 | if ((file==NULL) || (file_ack==NULL)) { 454 | fprintf(stderr, "Cannot open data stream. Closing connction\n"); 455 | return; 456 | } 457 | fprintf(stderr, "Connection accepted...\n"); 458 | 459 | ud_stream.stream=file; 460 | ud_stream.log.num_ok=0; 461 | ud_stream.log.num_failed=0; 462 | 463 | 464 | fprintf(stderr, "starting processing object\n"); 465 | 466 | num_ok=UD_process_stream(&ud_stream); 467 | 468 | fprintf(stderr, "processing object finished\n"); 469 | 470 | if(num_ok==1) { 471 | fprintf(file_ack, "%%ERROR 0\n"); 472 | fprintf(stderr, "%%ERROR 0\n"); 473 | } 474 | else { 475 | num_ok=(-1)*num_ok; 476 | fprintf(file_ack, "%%ERROR %d\n",num_ok); 477 | fprintf(stderr, "%%ERROR %d\n",num_ok); 478 | fprintf(file_ack, "Transaction had the following problems:\n"); 479 | if(num_ok & ERROR_U_MEM) fprintf(file_ack, "Memory allocation error\n"); 480 | /* if(num_ok & ERROR_U_DBS) fprintf(file_ack, "Database (SQL) error\n");*/ 481 | /* if(num_ok & ERROR_U_OBJ) fprintf(file_ack, "Object (RF) error\n");*/ 482 | /* if(num_ok & ERROR_U_AUT) fprintf(file_ack, "Object authentication error\n");*/ 483 | if(num_ok & ERROR_U_BADOP) fprintf(file_ack, "Bad operation\n"); 484 | if(num_ok & ERROR_U_COP) fprintf(file_ack, "Conflicting operation\n"); 485 | if(num_ok & ERROR_U_NSUP) fprintf(file_ack, "Object of this type is not supported\n"); 486 | if(num_ok & ERROR_U_BUG) fprintf(file_ack, "Software bug - report to <ripe-dbm@ripe.net>\n"); 487 | } 488 | if(ud_stream.error_script)fprintf(file_ack, "%s\n", ud_stream.error_script); 489 | 490 | if(ud_stream.error_script) free(ud_stream.error_script); 491 | 492 | fflush(file_ack); fclose(file_ack); 493 | fclose(file); 494 | } /* if do_update*/ 495 | else { /* Otherwise print a message*/ 496 | /* To display with 'show threads' */ 497 | TA_setactivity("suspended"); 498 | 499 | fprintf(file_ack, "%%ERROR 1000\n%%Updates are suspended\n"); 500 | fflush(file_ack); fclose(file_ack); 501 | fclose(file); 502 | } 503 | /* make a record for thread accounting */ 504 | TA_delete(); 505 | 506 | do_server=CO_get_do_server(); 507 | 508 | } while (do_server); /* main cycle */ 509 | 510 | fclose(ud_stream.log.logfile); 511 | /* That's all. Close connection to the DB */ 512 | SQ_close_connection(ud_stream.db_connection); 513 | 514 | 515 | fprintf(stderr, "server stopped\n"); 516 | 517 | } /* UD_do_update() */ 518 | 519 | 520 | 521 |