1 | /*************************************** 2 | $Revision: 1.16 $ 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,2001,2002 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 | 39 | #include "rip.h" 40 | 41 | #include <stdio.h> 42 | 43 | void pm_get_source_info(GString *gbuff, ip_addr_t *client_address, char *source, ca_dbSource_t *source_hdl); 44 | 45 | /************************************************************ 46 | * PM_get_minmax_serial() * 47 | * * 48 | * Returns the min or max serial number. * 49 | * * 50 | * Returns: * 51 | * min (max=0) or max (max=1) serial number * 52 | * -1 in case of an error * 53 | * * 54 | * Note: * 55 | * min serial= MIN(serial_id)+1 * 56 | * MIN(serial_id) represents legacy RIPE.CURRENSERIAL * 57 | * of the snapshot * 58 | * * 59 | *************************************************************/ 60 | long PM_get_minmax_serial(SQ_connection_t *sql_connection, int max) 61 | { 62 | char query[STR_M]; 63 | SQ_result_set_t *sql_result; 64 | SQ_row_t *sql_row; 65 | char *sql_str; 66 | long current_serial; 67 | char *minmax; 68 | int sql_err; 69 | 70 | if(max==1)minmax="max"; else minmax="min"; 71 | 72 | /* get the lock to ensure that queries are not stopped */ 73 | /* which means access to the database is allowed */ 74 | PW_record_query_start(); 75 | 76 | sprintf(query, "SELECT %s(serial_id) FROM serials ", minmax); 77 | 78 | //fprintf(stderr, "D:<get_field_str>:query: %s\n", query); 79 | sql_err = SQ_execute_query(sql_connection, query, &sql_result); 80 | 81 | if(sql_err) { 82 | ER_perror(FAC_PM, PM_NOSQLC,"%s[%s]", SQ_error(sql_connection), query); 83 | die; 84 | } 85 | 86 | 87 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 88 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 89 | 90 | /* We must process all the rows of the result,*/ 91 | /* otherwise we'll have them as part of the next qry */ 92 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 93 | ER_perror(FAC_PM, PM_NOSQLC,"duplicate PK [%s]", query); 94 | if(sql_str) UT_free(sql_str); sql_str=NULL; 95 | } 96 | } 97 | else sql_str=NULL; 98 | 99 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 100 | 101 | if(sql_str) { 102 | current_serial = atol(sql_str); 103 | if(max!=1)current_serial++; 104 | UT_free(sql_str); 105 | } 106 | else current_serial=-1; 107 | 108 | /* release the lock */ 109 | PW_record_query_end(); 110 | 111 | 112 | return(current_serial); 113 | 114 | } 115 | 116 | /************************************************************ 117 | * int atlast(long serial_number) 118 | * -1 - sql error 119 | * 120 | ***********************************************************/ 121 | 122 | static int atlast(SQ_connection_t *sql_connection, long serial_number) 123 | { 124 | char *sql_str; 125 | char str_id[STR_S]; 126 | int atlast=-1; 127 | 128 | sprintf(str_id, "%ld", serial_number); 129 | sql_str= get_field_str(sql_connection, "atlast", "serials", "serial_id", str_id, NULL); 130 | if(sql_str) { 131 | atlast = atoi(sql_str); 132 | UT_free(sql_str); 133 | } 134 | 135 | return(atlast); 136 | 137 | } 138 | 139 | 140 | /************************************************************ 141 | * int getop(long serial_number) 142 | * -1 - sql error 143 | * 144 | * **********************************************************/ 145 | 146 | static int getop(SQ_connection_t *sql_connection, long serial_number) 147 | { 148 | char *sql_str; 149 | char str_id[STR_S]; 150 | int op=-1; 151 | 152 | sprintf(str_id, "%ld", serial_number); 153 | sql_str= get_field_str(sql_connection, "operation", "serials", "serial_id", str_id, NULL); 154 | if(sql_str) { 155 | op = atoi(sql_str); 156 | UT_free(sql_str); 157 | } 158 | 159 | return(op); 160 | 161 | } 162 | 163 | 164 | /************************************************************ 165 | * char *PM_get_serial_object() * 166 | * * 167 | * Returns text block corresponding to the requested serial * 168 | * * 169 | * Returns: * 170 | * operation (ADD/DEL) and text object * 171 | * NULL in case of an error * 172 | * * 173 | * Note: * 174 | * returned string should be freed by the caller * 175 | * * 176 | *************************************************************/ 177 | char *PM_get_serial_object(SQ_connection_t *sql_connection, long serial_number, int *operation) 178 | { 179 | char *table; 180 | SQ_result_set_t * sql_result; 181 | SQ_row_t *sql_row; 182 | char *sql_str; 183 | char query[STR_M]; 184 | int sql_err; 185 | int location; 186 | 187 | /* get the lock to ensure that queries are not stopped */ 188 | /* which means access to the database is allowed */ 189 | PW_record_query_start(); 190 | 191 | switch(location=atlast(sql_connection, serial_number)){ 192 | 193 | case 0: table="history"; 194 | break; 195 | case 1: table="last"; 196 | break; 197 | case 2: table="failed_transaction"; 198 | break; 199 | default: return(NULL); 200 | 201 | } 202 | 203 | if(location == 2) 204 | sprintf(query, "SELECT object FROM %s " 205 | "WHERE serial_id=%ld ", 206 | table, serial_number); 207 | else 208 | sprintf(query, "SELECT %s.object FROM %s, serials " 209 | "WHERE serials.serial_id=%ld " 210 | "AND serials.object_id=%s.object_id " 211 | "AND serials.sequence_id=%s.sequence_id ", table, table, serial_number, table, table); 212 | 213 | 214 | sql_err = SQ_execute_query(sql_connection, query, &sql_result); 215 | 216 | if(sql_err) { 217 | ER_perror(FAC_PM, PM_NOSQLC,"%s[%s]", SQ_error(sql_connection), query); 218 | die; 219 | } 220 | 221 | 222 | if ((sql_row = SQ_row_next(sql_result)) != NULL) { 223 | sql_str = SQ_get_column_string(sql_result, sql_row, 0); 224 | 225 | /* We must process all the rows of the result,*/ 226 | /* otherwise we'll have them as part of the next qry */ 227 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) { 228 | ER_perror(FAC_PM, PM_NOSQLC,"duplicate PK [%s]", query); 229 | if(sql_str) UT_free(sql_str); sql_str=NULL; 230 | } 231 | } 232 | else sql_str=NULL; 233 | 234 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; } 235 | 236 | *operation=getop(sql_connection, serial_number); 237 | 238 | /* release the lock */ 239 | PW_record_query_end(); 240 | 241 | return(sql_str); 242 | 243 | } 244 | 245 | /************************************************************ 246 | * void pm_get_source_info() * 247 | * * 248 | * Fills supplied buffer with information about the source * 249 | * * 250 | * Returns text block corresponding to the requested source * 251 | * Format: * 252 | * <source>:<can_mirror>:min_serial-max_serial * 253 | * source - name of the source (e.g. RIPE, RADB, etc.) * 254 | * can_mirror * 255 | * 'Y' if the client is allowed to mirror the source * 256 | * 'N' if not * 257 | * 'N' if there is no serials (then the range starts at 0)* 258 | * * 259 | * * 260 | *************************************************************/ 261 | void pm_get_source_info(GString *gbuff, ip_addr_t *client_address, char *source, ca_dbSource_t *source_hdl) 262 | { 263 | 264 | char *db_host = ca_get_srcdbmachine(source_hdl); 265 | int db_port = ca_get_srcdbport(source_hdl); 266 | char *db_name = ca_get_srcdbname(source_hdl); 267 | char *db_user = ca_get_srcdbuser(source_hdl); 268 | char *db_passwd = ca_get_srcdbpassword(source_hdl); 269 | int version = ca_get_srcnrtmprotocolvers(source_hdl); 270 | SQ_connection_t *db_connection; 271 | long min_serial, max_serial; 272 | char can_mirror; 273 | 274 | /* Connect to the database */ 275 | db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd); 276 | min_serial=PM_get_oldest_serial(db_connection); 277 | max_serial=PM_get_current_serial(db_connection) - SAFE_BACKLOG; 278 | 279 | /* If it cannot be morrored at all - N, but range starts with 0 */ 280 | /* If the client is allowed to mirror - Y */ 281 | /* Otherwise - N */ 282 | if(min_serial>max_serial) { 283 | can_mirror='N'; 284 | min_serial=0; 285 | } 286 | else { 287 | if(AA_can_mirror(client_address, source )) can_mirror='Y'; 288 | else can_mirror='N'; 289 | } 290 | g_string_sprintfa(gbuff, "%s:%d:%c:%lu-%lu\n", source, version, can_mirror, min_serial, max_serial); 291 | 292 | UT_free(db_host); 293 | UT_free(db_name); 294 | UT_free(db_user); 295 | UT_free(db_passwd); 296 | SQ_close_connection(db_connection); 297 | } 298 | 299 | /************************************************************ 300 | * GString *PM_get_nrtm_sources() * 301 | * * 302 | * Fills supplied buffer with information about the sources * 303 | * * 304 | * * 305 | * Note: * 306 | * returned GString should be freed by the caller * 307 | * * 308 | *************************************************************/ 309 | GString *PM_get_nrtm_sources(ip_addr_t *client_address, char *source) 310 | { 311 | GString *gbuff=g_string_sized_new(STR_L); 312 | int nsource; 313 | ca_dbSource_t *source_hdl; 314 | 315 | if(source){ 316 | source_hdl = ca_get_SourceHandleByName(source); 317 | if (source_hdl)pm_get_source_info(gbuff, client_address, source, source_hdl); 318 | } else 319 | for(nsource=0; (source_hdl = ca_get_SourceHandleByPosition(nsource))!=NULL ; nsource++){ 320 | source=ca_get_srcname(source_hdl); 321 | pm_get_source_info(gbuff, client_address, source, source_hdl); 322 | UT_free(source); 323 | } 324 | /* one extra line, another one will be put bt PW or PM */ 325 | g_string_sprintfa(gbuff, "\n"); 326 | return(gbuff); 327 | }