Source File modules/ud/ud_main.c

    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  |