utils/history/recreate.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. process_arguments
  2. put_delete_before
  3. get_serial_interval
  4. generate_load_data
  5. serve_TCP
  6. fake_sources
  7. get_operation
  8. get_minimum_RIPE_serial
  9. wait_for_whoisd_completion
  10. process_timestamp_add
  11. process_timestamp_delete
  12. correct_timestamps
  13. main

   1 /***************************************
   2   $Revision: 1.1 $
   3 
   4   Recreate.  recreate.c - whois DB recreation via pseudo mirror server.
   5 
   6   Status: NOT REVIEWED, TESTED, COMPLETE
   7 
   8   Implementation by: Tiago Antao
   9 
  10   ******************/ /******************
  11   Copyright (c) 2002               RIPE NCC
  12  
  13   All Rights Reserved
  14   
  15   Permission to use, copy, modify, and distribute this software and its
  16   documentation for any purpose and without fee is hereby granted,
  17   provided that the above copyright notice appear in all copies and that
  18   both that copyright notice and this permission notice appear in
  19   supporting documentation, and that the name of the author not be
  20   used in advertising or publicity pertaining to distribution of the
  21   software without specific, written prior permission.
  22 
  23   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  24   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  25   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  26   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  27   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  28   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  29   ***************************************/
  30 
  31 
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <time.h>
  35 #include <regex.h>
  36 #include <rip.h>
  37 #include "miniconf.h"
  38 #include "dbsupport.h"
  39 #include "aconf.h"
  40 
  41 int  response_sock;
  42 long end_serial = 0;
  43 long serial_max;
  44 long serial_min;
  45 long requested_max;
  46 long requested_min;
  47 char source_name[100];
  48 long RIPE_serial_min;
  49 long updates_sent;
  50 
  51 /*
  52   process_arguments: proccesses command-line arguments.
  53 */
  54 void process_arguments(int argv, char** argc) {
     /* [<][>][^][v][top][bottom][index][help] */
  55   if (argv != 2 ) {
  56     printf("Usage: %s <serial>\n", argc[0]);
  57     exit(1);
  58   }
  59 
  60   end_serial = atol(argc[1]); //assume is number
  61   
  62   if (end_serial == 0) {
  63     printf("Usage: %s <serial>\n", argc[0]);
  64     exit(1);
  65   }
  66   
  67 }
  68 
  69 void put_delete_before(char* pkey, long timestamp, char* buffer) {
     /* [<][>][^][v][top][bottom][index][help] */
  70   SQ_result_set_t* rs;
  71   SQ_row_t*        row;
  72   char             query[200];
  73   char             ppkey[200];
  74   long             ts;
  75   char*            object;
  76 
  77   prepare_string_attribute(pkey,
  78                            ppkey);
  79   sprintf(query,
  80           "SELECT max(timestamp) FROM archive "
  81           " WHERE timestamp<%ld AND pkey='%s'",
  82           timestamp, ppkey);
  83   SQ_execute_query(archive_conn, query, &rs);
  84   row = SQ_row_next(rs);
  85   if (row==NULL) { //very bad
  86     printf ("Severe error with executing: %s\n", query);
  87     exit(1);
  88   }
  89   SQ_get_column_int(rs, row, 0, &ts);
  90   SQ_free_result(rs);
  91 
  92   sprintf(query,
  93           "SELECT object FROM archive WHERE timestamp=%ld "
  94           "   AND pkey='%s' AND operation=1",
  95           timestamp, pkey);
  96   SQ_execute_query(archive_conn, query, &rs);
  97   row = SQ_row_next(rs);
  98   if (row==NULL) { //bummer, it has to be on last of RIP DB
  99     SQ_free_result(rs);
 100     sprintf(query,
 101             "SELECT object FROM last WHERE pkey='%s'",
 102             pkey);
 103     SQ_execute_query(RIPE_conn, query, &rs);
 104     row = SQ_row_next(rs);
 105     if (row==NULL) { //very bad
 106       printf ("Severe error with executing: %s\n", query);
 107       exit(1);
 108     }
 109   }
 110   object = SQ_get_column_string_nocopy(rs, row, 0);
 111   sprintf(buffer, "DEL\n\n%s\n\n", object);
 112   SK_write(response_sock, buffer, strlen(buffer), NULL, NULL);
 113   SQ_free_result(rs);
 114 }
 115 
 116 /*
 117   get_serial_interval: gets the upper and lower bounds of available serials.
 118 */
 119 void get_serial_interval() {
     /* [<][>][^][v][top][bottom][index][help] */
 120   SQ_result_set_t* rs;
 121   SQ_row_t*        row;
 122   char             query[200];
 123 
 124   sprintf(query,
 125           "SELECT min(serial_id), max(serial_id) "
 126           "  FROM archive "
 127           " WHERE serial_id<=%ld ",
 128           end_serial);
 129   SQ_execute_query(archive_conn, query, &rs);
 130   row = SQ_row_next(rs);
 131   SQ_get_column_int(rs, row, 0, &serial_min);
 132   SQ_get_column_int(rs, row, 1, &serial_max);
 133   SQ_free_result(rs);
 134 }
 135 
 136 /*
 137   generate_load_data: generates and send data to be recreated.
 138 */
 139 void generate_load_data() {
     /* [<][>][^][v][top][bottom][index][help] */
 140   SQ_result_set_t* rs;
 141   SQ_row_t*        row;
 142   char             query[200];
 143   char*            object;
 144   long             operation;
 145   char*            pkey;
 146   long             timestamp;
 147   char             sbuffer[1000000]; // ridiculous but more bug proof?
 148 
 149 
 150   updates_sent = 0;
 151   sprintf(sbuffer,
 152           "%%START Version: 2 %s %ld-%ld\n\n",
 153           source_name, requested_min, serial_max);
 154   SK_write(response_sock, sbuffer, strlen(sbuffer), NULL, NULL);
 155   sprintf(query,
 156           "  SELECT object, operation, pkey, timestamp "
 157           "    FROM archive "
 158           "   WHERE serial_id<=%ld AND serial_id>=%ld "
 159           "     AND serial_id IS NOT NULL "
 160           "ORDER BY timestamp ASC, serial_id ASC ",
 161           // order because of special deletes (op=3)
 162           end_serial, requested_min);
 163   SQ_execute_query(archive_conn, query, &rs);
 164   while ((row = SQ_row_next(rs)) != NULL) {
 165     updates_sent++;
 166     object = SQ_get_column_string_nocopy(rs, row, 0);
 167     SQ_get_column_int(rs, row, 1, &operation);
 168     switch (operation) {
 169     case 1:
 170       sprintf(sbuffer, "ADD\n\n%s\n\n", object);
 171       SK_write(response_sock, sbuffer, strlen(sbuffer), NULL, NULL);
 172       break;
 173     case 2:
 174       sprintf(sbuffer, "DEL\n\n%s\n\n", object);
 175       SK_write(response_sock, sbuffer, strlen(sbuffer), NULL, NULL);
 176       break;
 177     case 3:
 178       pkey = SQ_get_column_string_nocopy(rs, row, 2);
 179       SQ_get_column_int(rs, row, 3, &timestamp);
 180       put_delete_before(pkey, timestamp, sbuffer);
 181       sprintf(sbuffer, "ADD\n\n%s\n\n", object);
 182       SK_write(response_sock, sbuffer, strlen(sbuffer), NULL, NULL);
 183       break;
 184     }
 185 
 186   }
 187   SQ_free_result(rs);
 188 
 189   sprintf(sbuffer,"%%END %s\n\n", source_name);
 190   SK_write(response_sock, sbuffer, strlen(sbuffer), NULL, NULL);
 191 }
 192 
 193 /*
 194   serve_TCP: creates a socket and accepts a connection.
 195 */
 196 void serve_TCP() {
     /* [<][>][^][v][top][bottom][index][help] */
 197   int sock;
 198 
 199   sock = SK_getsock(SOCK_STREAM, 24444, 128, INADDR_ANY);
 200   //printf("Accepting connections\n");
 201   response_sock = SK_accept_connection(sock);
 202 }
 203 
 204 /*
 205   fake_sources: fakes a source
 206 
 207   Irrelevant?
 208 */
 209 void fake_sources() {
     /* [<][>][^][v][top][bottom][index][help] */
 210   char line[100];
 211   sprintf(line, "RIPE:2:Y:%ld-%ld\n\n", serial_min, serial_max);
 212   SK_write(response_sock, line, strlen(line), NULL, NULL);
 213 }
 214 
 215 /*
 216   get_operation: gets the operation required by the client.
 217 
 218   Also puts the source name in a global variable if -g requested.
 219 */
 220 int get_operation() {
     /* [<][>][^][v][top][bottom][index][help] */
 221   char       line[201];
 222   regex_t    reg;
 223   regmatch_t match[3];
 224 
 225   bzero(line, 201);
 226   if (SK_gets(response_sock, line, 200)>=0) {
 227     if (strncmp(line,"-q sources", 10)==0) {
 228       return 0;
 229     }
 230     else {
 231       regcomp(&reg,"-g (.+):2:([0-9]+)-", REG_EXTENDED);
 232       if (regexec(&reg, line, 3, match, 0) != 0) {
 233         printf("match failed: %s\n", line);
 234         exit(1);
 235       }
 236       //printf("match OK: %s\n", line);
 237       bzero(source_name, 99);
 238       strncpy(source_name,
 239               line + match[1].rm_so,
 240               match[1].rm_eo - match[1].rm_so);
 241       requested_min = atol(line+match[2].rm_so);
 242       //printf("%sXX\n", line+match[2].rm_so);
 243       return 1;
 244     }
 245   }
 246   else {
 247     //printf("Input from client ended\n");
 248     exit(1);
 249   }
 250 }
 251 
 252 /*
 253   get_minimum_RIPE_serial: returns the minimum serial of recreate
 254 
 255   The minimum serial of recreate is the initial max + 1.
 256   Returns in a global variable.
 257 */
 258 void get_minimum_RIPE_serial() {
     /* [<][>][^][v][top][bottom][index][help] */
 259   SQ_result_set_t* rs;
 260   SQ_row_t*        row;
 261   long             result;
 262 
 263   SQ_execute_query(RIPE_conn,
 264                    "SELECT max(serial_id) FROM serials",
 265                    &rs);
 266 
 267   row = SQ_row_next(rs);
 268 
 269   if (SQ_get_column_int(rs, row, 0, &result) == 0) {
 270     RIPE_serial_min = result + 1;
 271   }
 272   else {
 273     RIPE_serial_min = 1;
 274   }
 275 
 276   SQ_free_result(rs);
 277 }
 278 
 279 /*
 280   wait_for_whoisd_completion: as named
 281 
 282   As we know the serial when we started and the number of updates sent
 283   we know which number should be the max on serials.
 284   We wait for it.
 285 */
 286 void wait_for_whoisd_completion() {
     /* [<][>][^][v][top][bottom][index][help] */
 287   SQ_result_set_t* rs;
 288   SQ_row_t*        row;
 289   long             current_serial=0;
 290 
 291   while (current_serial<RIPE_serial_min+updates_sent) {
 292     SQ_execute_query(RIPE_conn,
 293                      "SELECT max(serial_id) FROM serials",
 294                      &rs);
 295     
 296     row = SQ_row_next(rs);
 297     
 298     if (SQ_get_column_int(rs, row, 0, &current_serial) != 0) {
 299       current_serial = 0;
 300     }
 301     
 302     SQ_free_result(rs);
 303     sleep(1); //ALWAYS wait
 304   }
 305 }
 306 
 307 /*
 308   process_timestamp_add: patches the timestmap of an add
 309 */
 310 void process_timestamp_add(SQ_result_set_t* rs,
     /* [<][>][^][v][top][bottom][index][help] */
 311                            SQ_row_t*        row,
 312                            long             timestamp) {
 313   long atlast;
 314   long seq_id;
 315   long object_id;
 316   char upd[200];
 317 
 318   SQ_get_column_int(rs, row, 0, &object_id);
 319   SQ_get_column_int(rs, row, 1, &seq_id);
 320   SQ_get_column_int(rs, row, 2, &atlast);
 321 
 322   if (atlast) {
 323     sprintf(upd,
 324             "UPDATE last SET timestamp=%ld WHERE object_id=%ld",
 325             timestamp, object_id);
 326   }
 327   else {
 328     sprintf(upd,
 329             "UPDATE history "
 330             "   SET timestamp=%ld "
 331             " WHERE object_id=%ld AND sequence_id=%ld",
 332             timestamp, object_id, seq_id);
 333   }
 334   SQ_execute_query(RIPE_conn, upd, NULL);
 335 }
 336 
 337 /*
 338   process_timestamp_delete: patches the timestamp of a delete
 339 */
 340 void process_timestamp_delete(SQ_result_set_t* rs,
     /* [<][>][^][v][top][bottom][index][help] */
 341                               SQ_row_t*        row,
 342                               long             timestamp) {
 343   long object_id;
 344   char upd[200];
 345 
 346   SQ_get_column_int(rs, row, 0, &object_id);
 347 
 348   sprintf(upd,
 349           "UPDATE last "
 350           "   SET timestamp=%ld "
 351           " WHERE object_id=%ld AND object=''",
 352           timestamp, object_id);
 353   SQ_execute_query(RIPE_conn, upd, NULL);
 354 }
 355 
 356 /*
 357   correct_timestamps:
 358 */
 359 void correct_timestamps() {
     /* [<][>][^][v][top][bottom][index][help] */
 360   SQ_result_set_t* RIPE_rs;
 361   SQ_row_t*        RIPE_row;
 362   char             RIPE_query[200];
 363   SQ_result_set_t* archive_rs;
 364   SQ_row_t*        archive_row;
 365   char             archive_query[200];
 366   long             operation;
 367   long             timestamp;
 368 
 369   sprintf(RIPE_query,
 370           "  SELECT object_id, sequence_id, atlast "
 371           "    FROM serials "
 372           "   WHERE serial_id>=%ld "
 373           "ORDER BY serial_id ",
 374           RIPE_serial_min);
 375   SQ_execute_query(RIPE_conn, RIPE_query, &RIPE_rs);
 376 
 377   sprintf(archive_query,
 378           "  SELECT timestamp, operation "
 379           "    FROM archive "
 380           "   WHERE serial_id<=%ld AND serial_id>=%ld "
 381           "     AND serial_id IS NOT NULL "
 382           "ORDER BY timestamp ASC, serial_id ASC ",
 383           end_serial, requested_min);
 384   SQ_execute_query(archive_conn, archive_query, &archive_rs);
 385 
 386   while((archive_row = SQ_row_next(archive_rs)) != NULL) {
 387     SQ_get_column_int(archive_rs, archive_row, 0, &timestamp);
 388     SQ_get_column_int(archive_rs, archive_row, 1, &operation);
 389     if (operation==3) {
 390       RIPE_row = SQ_row_next(RIPE_rs);
 391       if (RIPE_row == NULL) {
 392         printf("serials are incomplete irt archive\n");
 393         exit(1);
 394       } 
 395       process_timestamp_delete(RIPE_rs, RIPE_row, timestamp);
 396       operation = 1;
 397     }
 398     RIPE_row = SQ_row_next(RIPE_rs);
 399     if (RIPE_row == NULL) {
 400       printf("serials are incomplete irt archive\n");
 401       exit(1);
 402     }
 403     if (operation==1) {
 404       process_timestamp_add(RIPE_rs, RIPE_row, timestamp);
 405     }
 406     else {
 407       process_timestamp_delete(RIPE_rs, RIPE_row, timestamp);
 408     }
 409 
 410   }
 411   RIPE_row = SQ_row_next(RIPE_rs);
 412   if (RIPE_row != NULL) {
 413     printf("archive is incomplete irt serials\n");
 414     exit(1);
 415   }
 416 
 417   SQ_free_result(RIPE_rs);
 418   SQ_free_result(archive_rs);
 419 }
 420 
 421 /*
 422   main: recreate entry point.
 423 
 424   Determine biggest serial on process start (on RIPE DB)
 425   Get serials available (on archive DB)
 426   Wait for TCP connection
 427   while(1)
 428    switch (whoisd request)
 429      0: fake_sources (-g & -q)
 430      1: generate_load_data
 431         wait for whois completion
 432         patch timestamps
 433 */
 434 int main (int argv, char** argc) {
     /* [<][>][^][v][top][bottom][index][help] */
 435   process_arguments(argv, argc);
 436   read_configuration();
 437   get_db_connections();
 438 
 439   get_minimum_RIPE_serial();
 440   get_serial_interval();
 441   serve_TCP();
 442   while (1) {
 443     switch (get_operation()) {
 444     case 0:
 445       fake_sources();
 446       break;
 447     case 1:
 448       generate_load_data();
 449       wait_for_whoisd_completion();
 450       correct_timestamps();
 451       return 0;
 452     }
 453   }
 454 
 455   //close_dbs();
 456 
 457   return 0;
 458 }

/* [<][>][^][v][top][bottom][index][help] */