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() */