1 | /*************************************** 2 | $Revision: 1.10 $ 3 | 4 | Near real-time mirror server module (pm). NRTM protocol. 5 | 6 | Status: NOT REVUED, NOT TESTED 7 | 8 | +html+ <DL COMPACT> 9 | +html+ <DT>Online References: 10 | +html+ <DD><UL> 11 | +html+ </UL> 12 | +html+ </DL> 13 | +html+ <PRE> 14 | Author: 15 | andrei 16 | +html+ </PRE> 17 | 18 | ******************/ /****************** 19 | Copyright (c) 2000 RIPE NCC 20 | 21 | All Rights Reserved 22 | 23 | Permission to use, copy, modify, and distribute this software and its 24 | documentation for any purpose and without fee is hereby granted, 25 | provided that the above copyright notice appear in all copies and that 26 | both that copyright notice and this permission notice appear in 27 | supporting documentation, and that the name of the author not be 28 | used in advertising or publicity pertaining to distribution of the 29 | software without specific, written prior permission. 30 | 31 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 32 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 33 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 34 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 35 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 36 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 37 | ***************************************/ 38 | #include <stdio.h> 39 | #include "ud_int.h" 40 | #include "protocol_mirror.h" 41 | 42 | void pm_get_source_info(GString *gbuff, ip_addr_t *client_address, char *source, ca_dbSource_t *source_hdl); 43 | 44 | /************************************************************ 45 | * PM_get_minmax_serial() * 46 | * * 47 | * Returns the min or max serial number. * 48 | * * 49 | * Returns: * 50 | * min (max=0) or max (max=1) serial number * 51 | * -1 in case of an error * 52 | * * 53 | * Note: * 54 | * min serial= MIN(serial_id)+1 * 55 | * MIN(serial_id) represents legacy RIPE.CURRENSERIAL * 56 | * of the snapshot * 57 | * * 58 | *************************************************************/ 59 | long PM_get_minmax_serial(SQ_connection_t *sql_connection, int max) 60 | { 61 | char query[STR_M]; 62 | SQ_result_set_t *sql_result; 63 | SQ_row_t *sql_row; 64 | char *sql_str; 65 | long current_serial; 66 | char *minmax; 67 | int sql_err; 68 | 69 | if(max==1)minmax="max"; else minmax="min"; 70 | 71 | sprintf(query, "SELECT %s(serial_id) FROM serials ", minmax); 72 | 73 | //fprintf(stderr, "D:<get_field_str>:query: %s\n", query); 74 | sql_err = SQ_execute_query(sql_connection, query, &sql_result); 75 | 76 | if(sql_err) { 77 | ER_perror(FAC_PM, PM_NOSQLC,"%s[%s]", SQ_error(sql_connection), query); 78 | die; 79 | } 80 | 81 | 82 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 83 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 84 | 85 | /* We must process all the rows of the result,*/ 86 | /* otherwise we'll have them as part of the next qry */ 87 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 88 | ER_perror(FAC_PM, PM_NOSQLC,"duplicate PK [%s]", query); 89 | if(sql_str)free(sql_str); sql_str=NULL; 90 | } 91 | } 92 | else sql_str=NULL; 93 | 94 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 95 | 96 | if(sql_str) { 97 | current_serial = atol(sql_str); 98 | if(max!=1)current_serial++; 99 | free(sql_str); 100 | } 101 | else current_serial=-1; 102 | 103 | return(current_serial); 104 | 105 | } 106 | 107 | /************************************************************ 108 | * int atlast(long serial_number) 109 | * -1 - sql error 110 | * 111 | ***********************************************************/ 112 | 113 | static int atlast(SQ_connection_t *sql_connection, long serial_number) 114 | { 115 | char *sql_str; 116 | char str_id[STR_S]; 117 | int atlast=-1; 118 | 119 | 120 | sprintf(str_id, "%ld", serial_number); 121 | sql_str= get_field_str(sql_connection, "atlast", "serials", "serial_id", str_id, NULL); 122 | if(sql_str) { 123 | atlast = atoi(sql_str); 124 | free(sql_str); 125 | } 126 | 127 | return(atlast); 128 | 129 | } 130 | 131 | 132 | /************************************************************ 133 | * int getop(long serial_number) 134 | * -1 - sql error 135 | * 136 | * **********************************************************/ 137 | 138 | static int getop(SQ_connection_t *sql_connection, long serial_number) 139 | { 140 | char *sql_str; 141 | char str_id[STR_S]; 142 | int op=-1; 143 | 144 | 145 | sprintf(str_id, "%ld", serial_number); 146 | sql_str= get_field_str(sql_connection, "operation", "serials", "serial_id", str_id, NULL); 147 | if(sql_str) { 148 | op = atoi(sql_str); 149 | free(sql_str); 150 | } 151 | 152 | return(op); 153 | 154 | } 155 | 156 | 157 | /************************************************************ 158 | * char *PM_get_serial_object() * 159 | * * 160 | * Returns text block corresponding to the requested serial * 161 | * * 162 | * Returns: * 163 | * operation (ADD/DEL) and text object * 164 | * NULL in case of an error * 165 | * * 166 | * Note: * 167 | * returned string should be freed by the caller * 168 | * * 169 | *************************************************************/ 170 | char *PM_get_serial_object(SQ_connection_t *sql_connection, long serial_number, int *operation) 171 | { 172 | char *table; 173 | SQ_result_set_t * sql_result; 174 | SQ_row_t *sql_row; 175 | char *sql_str; 176 | char query[STR_M]; 177 | int sql_err; 178 | int location; 179 | 180 | switch(location=atlast(sql_connection, serial_number)){ 181 | 182 | case 0: table="history"; 183 | break; 184 | case 1: table="last"; 185 | break; 186 | case 2: table="failed_transaction"; 187 | break; 188 | default: return(NULL); 189 | 190 | } 191 | 192 | if(location == 2) 193 | sprintf(query, "SELECT object FROM %s " 194 | "WHERE serial_id=%ld ", 195 | table, serial_number); 196 | else 197 | sprintf(query, "SELECT %s.object FROM %s, serials " 198 | "WHERE serials.serial_id=%ld " 199 | "AND serials.object_id=%s.object_id " 200 | "AND serials.sequence_id=%s.sequence_id ", table, table, serial_number, table, table); 201 | 202 | 203 | sql_err = SQ_execute_query(sql_connection, query, &sql_result); 204 | 205 | if(sql_err) { 206 | ER_perror(FAC_PM, PM_NOSQLC,"%s[%s]", SQ_error(sql_connection), query); 207 | die; 208 | } 209 | 210 | 211 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 212 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 213 | 214 | /* We must process all the rows of the result,*/ 215 | /* otherwise we'll have them as part of the next qry */ 216 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 217 | ER_perror(FAC_PM, PM_NOSQLC,"duplicate PK [%s]", query); 218 | if(sql_str)free(sql_str); sql_str=NULL; 219 | } 220 | } 221 | else sql_str=NULL; 222 | 223 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 224 | 225 | *operation=getop(sql_connection, serial_number); 226 | 227 | return(sql_str); 228 | 229 | } 230 | 231 | /************************************************************ 232 | * void pm_get_source_info() * 233 | * * 234 | * Fills supplied buffer with information about the source * 235 | * * 236 | * Returns text block corresponding to the requested source * 237 | * Format: * 238 | * <source>:<can_mirror>:min_serial-max_serial * 239 | * source - name of the source (e.g. RIPE, RADB, etc.) * 240 | * can_mirror * 241 | * 'Y' if the client is allowed to mirror the source * 242 | * 'N' if not * 243 | * 'N' if there is no serials (then the range starts at 0)* 244 | * * 245 | * * 246 | *************************************************************/ 247 | void pm_get_source_info(GString *gbuff, ip_addr_t *client_address, char *source, ca_dbSource_t *source_hdl) 248 | { 249 | 250 | char *db_host = ca_get_srcdbmachine(source_hdl); 251 | int db_port = ca_get_srcdbport(source_hdl); 252 | char *db_name = ca_get_srcdbname(source_hdl); 253 | char *db_user = ca_get_srcdbuser(source_hdl); 254 | char *db_passwd = ca_get_srcdbpassword(source_hdl); 255 | int version = ca_get_srcnrtmprotocolvers(source_hdl); 256 | SQ_connection_t *db_connection; 257 | long min_serial, max_serial; 258 | char can_mirror; 259 | 260 | /* Connect to the database */ 261 | db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd); 262 | min_serial=PM_get_oldest_serial(db_connection); 263 | max_serial=PM_get_current_serial(db_connection); 264 | 265 | /* If it cannot be morrored at all - N, but range starts with 0 */ 266 | /* If the client is allowed to mirror - Y */ 267 | /* Otherwise - N */ 268 | if(min_serial>max_serial) { 269 | can_mirror='N'; 270 | min_serial=0; 271 | } 272 | else { 273 | if(AA_can_mirror(client_address, source )) can_mirror='Y'; 274 | else can_mirror='N'; 275 | } 276 | g_string_sprintfa(gbuff, "%s:%d:%c:%lu-%lu\n", source, version, can_mirror, min_serial, max_serial); 277 | 278 | free(db_host); 279 | free(db_name); 280 | free(db_user); 281 | free(db_passwd); 282 | SQ_close_connection(db_connection); 283 | } 284 | 285 | /************************************************************ 286 | * GString *PM_get_nrtm_sources() * 287 | * * 288 | * Fills supplied buffer with information about the sources * 289 | * * 290 | * * 291 | * Note: * 292 | * returned GString should be freed by the caller * 293 | * * 294 | *************************************************************/ 295 | GString *PM_get_nrtm_sources(ip_addr_t *client_address, char *source) 296 | { 297 | GString *gbuff=g_string_sized_new(STR_L); 298 | int nsource; 299 | ca_dbSource_t *source_hdl; 300 | 301 | if(source){ 302 | source_hdl = ca_get_SourceHandleByName(source); 303 | if (source_hdl)pm_get_source_info(gbuff, client_address, source, source_hdl); 304 | } else 305 | for(nsource=0; (source_hdl = ca_get_SourceHandleByPosition(nsource))!=NULL ; nsource++){ 306 | source=ca_get_srcname(source_hdl); 307 | pm_get_source_info(gbuff, client_address, source, source_hdl); 308 | free(source); 309 | } 310 | 311 | g_string_sprintfa(gbuff, "\n\n"); 312 | return(gbuff); 313 | }