1 | /*************************************** 2 | $Revision: 1.22 $ 3 | 4 | Example code: A server for a client to connect to. 5 | 6 | Status: NOT REVUED, NOT TESTED 7 | 8 | Authors: Chris Ottrey, Joao Damas 9 | 10 | +html+ <DL COMPACT> 11 | +html+ <DT>Online References: 12 | +html+ <DD><UL> 13 | +html+ <LI>Based on <A HREF="http://iii.ripe.net/dbase/coding/new.code/progress/ottrey/code/java/src/DBServer.java">DBServer.java</A> 14 | +html+ </UL> 15 | +html+ </DL> 16 | 17 | ******************/ /****************** 18 | Modification History: 19 | ottrey (02/03/1999) Created. 20 | ottrey (08/03/1999) Modified. 21 | joao (22/06/1999) Modified. 22 | ******************/ /****************** 23 | Copyright (c) 1999 RIPE NCC 24 | 25 | All Rights Reserved 26 | 27 | Permission to use, copy, modify, and distribute this software and its 28 | documentation for any purpose and without fee is hereby granted, 29 | provided that the above copyright notice appear in all copies and that 30 | both that copyright notice and this permission notice appear in 31 | supporting documentation, and that the name of the author not be 32 | used in advertising or publicity pertaining to distribution of the 33 | software without specific, written prior permission. 34 | 35 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 37 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 38 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 39 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 40 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 41 | ***************************************/ 42 | #include <sys/socket.h> 43 | #include <netinet/in.h> 44 | 45 | #include <sys/wait.h> 46 | #include <ctype.h> 47 | 48 | #include "thread.h" 49 | #include "rxroutines.h" 50 | #include "socket.h" 51 | /* 52 | #include "objects.h" 53 | */ 54 | #include "constants.h" 55 | #include "mysql_driver.h" 56 | #include "access_control.h" 57 | #include "ud.h" 58 | 59 | #define RIPE_REG 17 60 | 61 | static void put_inet_sql(rx_tree_t *mytree) { 62 | SQ_row_t *row; 63 | int retrieved_objects=0; 64 | 65 | SQ_connection_t *con; 66 | SQ_result_set_t *result; 67 | 68 | char *str=NULL; 69 | int no_cols; 70 | int objnr=1; 71 | 72 | /* Make connection */ 73 | con = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password()); 74 | 75 | result = SQ_execute_query(SQ_STORE, con, CO_get_in_query()); 76 | 77 | if (result == NULL) { 78 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con)); 79 | } 80 | else { 81 | printf("Initializing radix tree... go get a coffee.\n"); 82 | while ( (row = SQ_row_next(result)) != NULL ) { 83 | 84 | ip_range_t myrang; 85 | rx_dataleaf_t *leafptr; 86 | int in_id; 87 | int i; 88 | char *col[4]; 89 | 90 | memset(&myrang, 0, sizeof(ip_range_t)); 91 | myrang.begin.space = myrang.end.space = IP_V4; 92 | 93 | for(i=0; i<4; i++) { 94 | col[i] = SQ_get_column_string(result, row, i); 95 | if (col[i] == NULL) { 96 | die; 97 | } 98 | } 99 | 100 | // get the data: range and payload (id and netname) 101 | 102 | // begin of range 103 | if( col[1] == NULL || 104 | sscanf(col[1], "%u", &myrang.begin.words[0] ) < 1 ) { 105 | die; 106 | } 107 | 108 | // end of range 109 | 110 | if( col[2] == NULL || 111 | sscanf(col[2], "%u", &myrang.end.words[0] ) < 1 ) { 112 | die; 113 | } 114 | 115 | // fulltext id 116 | if( col[0] == NULL || sscanf(col[0], "%u", &in_id ) < 1 ) { 117 | die; 118 | } 119 | 120 | // netname 121 | if (col[3] == NULL) { 122 | /* XXX Dont die; */ 123 | col[3] = "NULL"; 124 | } 125 | 126 | /*** FILL IN ****************************************************/ 127 | 128 | if( wr_calloc( (void **)& leafptr, sizeof(rx_dataleaf_t), 1) 129 | != UT_OK) { 130 | die; 131 | } 132 | 133 | 134 | leafptr->data_key = in_id; 135 | 136 | // prepare output string for -K (inetnum: ip - ip \n) 137 | { 138 | char prstr[IP_RANGSTR_MAX]; 139 | 140 | if( IP_rang_b2a( &myrang, prstr, IP_RANGSTR_MAX) != IP_OK ) { 141 | die; // program error. 142 | } 143 | 144 | #define PAYLOAD_INETNUM_LENGTH strlen("inetnum:\t\n") 145 | 146 | leafptr->data_len = PAYLOAD_INETNUM_LENGTH + 1 + strlen(prstr); 147 | 148 | if( wr_calloc( (void **) & leafptr->data_ptr, leafptr->data_len, 1) 149 | != UT_OK) { 150 | die; 151 | } 152 | 153 | if( snprintf(leafptr->data_ptr, leafptr->data_len, 154 | "inetnum:\t%s\n", prstr ) 155 | > leafptr->data_len ) { 156 | // program error: the buffer is too short. 157 | die; 158 | } 159 | } 160 | 161 | /* 162 | leafptr->data_ptr = col[3]; 163 | leafptr->data_len = strlen(str)+1; 164 | */ 165 | 166 | if( RX_inum_node( RX_OPER_CRE, &myrang, mytree, leafptr ) != RX_OK ) { 167 | fprintf(stderr,"%d:\t%d\t%s\n", objnr, in_id, str); 168 | die; 169 | } 170 | 171 | /* 172 | printf("%d \t %s\n", in_id, str); 173 | */ 174 | 175 | /*** FREE ****************************************************/ 176 | 177 | for(i=0;i<4;i++) { 178 | wr_free(col[i]); 179 | } 180 | objnr++; 181 | } 182 | } 183 | SQ_free_result(result); 184 | 185 | /* Close connection */ 186 | SQ_close_connection(con); 187 | 188 | } /* put_inet_sql() */ 189 | 190 | static void put_route_sql(rx_tree_t *mytree) { 191 | SQ_row_t *row; 192 | int retrieved_objects=0; 193 | 194 | SQ_connection_t *con; 195 | SQ_result_set_t *result; 196 | 197 | int objnr=1; 198 | 199 | /* Make connection */ 200 | con = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password()); 201 | 202 | // compose the query 203 | 204 | result = SQ_execute_query(SQ_STORE, con, CO_get_rt_query()); 205 | 206 | if (result == NULL) { 207 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con)); 208 | } 209 | else { 210 | while ( (row = SQ_row_next(result)) != NULL ) { 211 | 212 | ip_prefix_t mypref; 213 | rx_dataleaf_t *leafptr; 214 | int rt_id; 215 | char *col[4]; 216 | int i; 217 | 218 | memset(&mypref, 0, sizeof(ip_prefix_t)); 219 | mypref.ip.space = IP_V4; 220 | 221 | for(i=0; i<4; i++) { 222 | col[i] = SQ_get_column_string(result, row, i); 223 | if (col[i] == NULL) { 224 | die; 225 | } 226 | } 227 | 228 | // get the data: prefix and payload (id and origin) 229 | 230 | // prefix ip 231 | if( sscanf(col[1], "%u", &mypref.ip.words[0] ) < 1 ) { 232 | die; 233 | } 234 | 235 | // prefix length 236 | if( sscanf(col[2], "%u", &mypref.bits ) < 1 ) { 237 | die; 238 | } 239 | 240 | // fulltext id 241 | if( sscanf(col[0], "%u", &rt_id ) < 1 ) { 242 | die; 243 | } 244 | 245 | /*** FILL IN ****************************************************/ 246 | 247 | // payload: goes into a dataleaf 248 | if( wr_calloc( (void **)& leafptr, sizeof(rx_dataleaf_t), 1) 249 | != UT_OK) { 250 | die; 251 | } 252 | 253 | leafptr->data_key = rt_id; 254 | 255 | // prepare output string for -K (route: prefix/len\norigin:col[3]) 256 | { 257 | char prstr[IP_PREFSTR_MAX]; 258 | 259 | if( IP_pref_b2a( &mypref, prstr, IP_PREFSTR_MAX) != IP_OK ) { 260 | die; // program error. 261 | } 262 | 263 | #define PAYLOAD_ROUTE_LENGTH strlen("route:\t/\norigin:\t\n") 264 | 265 | leafptr->data_len = PAYLOAD_ROUTE_LENGTH + 1 266 | + strlen(prstr) + strlen(col[3]); 267 | 268 | 269 | if( wr_calloc( (void **) & leafptr->data_ptr, leafptr->data_len, 1) 270 | != UT_OK) { 271 | die; 272 | } 273 | 274 | if( snprintf(leafptr->data_ptr, leafptr->data_len, 275 | "route:\t%s\norigin:\t%s\n", prstr, col[3] ) 276 | > leafptr->data_len ) { 277 | // program error: the buffer is too short. 278 | die; 279 | } 280 | } 281 | 282 | 283 | if( RX_bin_node( RX_OPER_CRE, &mypref, mytree, leafptr ) != RX_OK ) { 284 | fprintf(stderr,"%d:\t%d\t%s\n", objnr, rt_id, col[3]); 285 | die; 286 | } 287 | 288 | /*** FREE ****************************************************/ 289 | 290 | for(i=0;i<4;i++) { 291 | wr_free(col[i]); 292 | } 293 | 294 | objnr++; 295 | } 296 | } 297 | SQ_free_result(result); 298 | 299 | /* Close connection */ 300 | SQ_close_connection(con); 301 | 302 | } /* put_route_sql() */ 303 | 304 | /* XXX void radix_init(char *database) { */ 305 | static void radix_init() { 306 | er_path_t erlogstr; 307 | rx_tree_t *mytree; 308 | 309 | if (RX_tree_cre(RIPE_REG, IP_V4, RX_FAM_IN, "0.0.0.0/0", RX_MEM_RAMONLY, RX_SUB_NONE, &mytree) != RX_OK) { 310 | puts("error!!!"); 311 | } 312 | else { 313 | 314 | put_inet_sql(mytree); 315 | RX_attach2forest(mytree); 316 | 317 | if (RX_tree_cre(RIPE_REG, IP_V4, RX_FAM_RT, "0.0.0.0/0", RX_MEM_RAMONLY, RX_SUB_NONE, &mytree) != RX_OK) { 318 | puts("error!!!"); 319 | } 320 | else { 321 | 322 | put_route_sql(mytree); 323 | RX_attach2forest(mytree); 324 | } 325 | } 326 | 327 | erlogstr.fdes = stderr; 328 | /* 329 | erlogstr.asp = ASP_RX_SRCH_DET | ASP_RX_STKBLD_DET ; 330 | */ 331 | erlogstr.asp = 0; /* No debugging info. */ 332 | erlogstr.sev = ER_SEV_W; 333 | erlogstr.mode = ER_M_SEVCHAR | ER_M_TEXTLONG; 334 | 335 | ER_setpath(& erlogstr); 336 | 337 | } /* radix_init() */ 338 | 339 | 340 | /* SV_start() */ 341 | /*++++++++++++++++++++++++++++++++++++++ 342 | 343 | Start the server. 344 | 345 | More: 346 | +html+ <PRE> 347 | Authors: 348 | ottrey 349 | joao 350 | +html+ </PRE> 351 | +html+ Starts up the server. 352 | +html+ <OL> 353 | +html+ <LI> Create sockets on the necessary ports (whois, config and mirror) 354 | +html+ <LI> Start new threads for each service. 355 | +html+ </OL> 356 | +html+ <A HREF=".DBrc">.properties</A> 357 | 358 | ++++++++++++++++++++++++++++++++++++++*/ 359 | void SV_start() { 360 | int status; 361 | int whois_sock,config_sock,mirror_sock,update_sock; 362 | /* uint32_t whois_addr,sock_addr,mirror_addr; */ 363 | int whois_port = -1; 364 | int config_port = -1; 365 | /* int mirror_port = -1; */ 366 | int update_port = -1; 367 | int update_mode; 368 | sigset_t sset; 369 | 370 | 371 | /* Initialise the access control list. */ 372 | AC_build(); 373 | AC_acc_load(); 374 | 375 | /* Initialise the radix tree before allowing any socket connections. */ 376 | radix_init(); 377 | 378 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */ 379 | /* Get port information for each service */ 380 | whois_port = SK_atoport(CO_get_whois_port(), "tcp"); 381 | printf("XXX htons(whois_port)=%d\n", htons(whois_port)); 382 | if(whois_port == -1) { 383 | printf("Invalid service/port: %d\n", htons(whois_port)); 384 | exit(-1); 385 | } 386 | 387 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */ 388 | config_port = SK_atoport(CO_get_config_port(), "tcp"); 389 | printf("XXX htons(config_port)=%d\n", htons(config_port)); 390 | if(config_port == -1) { 391 | printf("Invalid service/port: %d\n", htons(config_port)); 392 | exit(-1); 393 | } 394 | /* Commented out for now. Remove comment when enabling mirroring 395 | mirror_port = SK_atoport(CO_get_mirror_port(), "tcp"); 396 | if(mirror_port == -1) { 397 | printf("Invalid service/port: %s\n", mirror_port); 398 | exit(-1); 399 | } 400 | */ 401 | 402 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */ 403 | update_port = SK_atoport(CO_get_update_port(), "tcp"); 404 | printf("XXX htons(update_port)=%d\n", htons(update_port)); 405 | if(update_port == -1) { 406 | printf("Invalid service/port: %d\n", htons(update_port)); 407 | exit(-1); 408 | } 409 | 410 | 411 | 412 | /* 6. Create a socket on the necessary ports/addresses and bind to them. */ 413 | /* whois socket */ 414 | whois_sock = SK_getsock(SOCK_STREAM, whois_port, INADDR_ANY); 415 | /* Currently binds to INADDR_ANY. Will need to get specific address */ 416 | /* whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */ 417 | /* config interface socket */ 418 | config_sock = SK_getsock(SOCK_STREAM, config_port, INADDR_ANY); 419 | /* nrt socket */ 420 | /* mirror_sock = SK_getsock(SOCK_STREAM,mirror_sock,mirror_addr); Remove comment when enabling mirroring */ 421 | /* update interface socket */ 422 | update_sock = SK_getsock(SOCK_STREAM, update_port, INADDR_ANY); 423 | 424 | 425 | /* Now.... accept() calls block until they get a connection 426 | so to listen on more than one port we need more 427 | than one thread */ 428 | 429 | 430 | 431 | /* Create master thread for whois threads */ 432 | TH_run(whois_sock, (void *)TH_do_whois); 433 | /* Create master thread for config threads */ 434 | TH_run(config_sock, (void *)TH_do_config); 435 | /* Create master thread for mirror threads */ 436 | /* Remove comment when enabling mirroring 437 | * TH_run(mirror_sock, (void *)TH_do_mirror); 438 | */ 439 | 440 | /* Get the mode of operation of the update layer */ 441 | update_mode=CO_get_update_mode(); 442 | if(IS_UPDATE(update_mode)) { 443 | /* we will play with dbupdate */ 444 | fprintf(stderr,"UPDATE mode\n"); 445 | TH_run1(update_sock, (void *)UD_do_updates); 446 | } 447 | else { 448 | /* start NRTM client and allow SIGINT & SIGTERM*/ 449 | // sigemptyset(&sset); 450 | // sigaddset(SIGINT, &sset); // not now, because do_whoisd is not working 451 | // pthread_sigmask(SIG_BLOCK, &sset, NULL); 452 | 453 | fprintf(stderr,"NRTM mode\n"); 454 | TH_run2((void *)UD_do_nrtm); 455 | } 456 | 457 | /* XXX Is this needed? */ 458 | pthread_exit(&status); 459 | 460 | } /* SV_start() */