Source File modules/ud/ud_main.c

    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  |