1 | /***************************************
2 | $Revision: 1.18 $
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 |
58 | #define RIPE_REG 17
59 |
60 | static void put_inet_sql(rx_tree_t *mytree) {
61 | SQ_row_t *row;
62 | int retrieved_objects=0;
63 |
64 | SQ_connection_t *con;
65 | SQ_result_set_t *result;
66 |
67 | char *str=NULL;
68 | int no_cols;
69 | int i, objnr=1;
70 | int brk=0;
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 *cpy;
89 | char *col[4];
90 |
91 | memset(&myrang, 0, sizeof(ip_range_t));
92 | myrang.begin.space = myrang.end.space = IP_V4;
93 |
94 | for(i=0; i<4; i++) {
95 | col[i] = SQ_get_column_string(result, row, i);
96 | if (col[i] == NULL) {
97 | die;
98 | }
99 | }
100 |
101 | // get the data: range and payload (id and netname)
102 |
103 | // begin of range
104 | if( col[1] == NULL ||
105 | sscanf(col[1], "%u", &myrang.begin.words[0] ) < 1 ) {
106 | die;
107 | }
108 |
109 | // end of range
110 |
111 | if( col[2] == NULL ||
112 | sscanf(col[2], "%u", &myrang.end.words[0] ) < 1 ) {
113 | die;
114 | }
115 |
116 | // fulltext id
117 | if( col[0] == NULL || sscanf(col[0], "%u", &in_id ) < 1 ) {
118 | die;
119 | }
120 |
121 | // netname
122 | if (col[3] == NULL) {
123 | /* XXX Dont die; */
124 | col[3] = "NULL";
125 | }
126 |
127 | /*** FILL IN ****************************************************/
128 |
129 | if( wr_calloc( (void **)& leafptr, sizeof(rx_dataleaf_t), 1)
130 | != UT_OK) {
131 | die;
132 | }
133 |
134 |
135 | leafptr->data_key = in_id;
136 |
137 | // prepare output string for -K (inetnum: ip - ip \n)
138 | {
139 | char prstr[IP_RANGSTR_MAX];
140 |
141 | if( IP_rang_b2a( &myrang, prstr, IP_RANGSTR_MAX) != IP_OK ) {
142 | die; // program error.
143 | }
144 |
145 | #define PAYLOAD_INETNUM_LENGTH strlen("inetnum:\t\n")
146 |
147 | leafptr->data_len = PAYLOAD_INETNUM_LENGTH + 1 + strlen(prstr);
148 |
149 | if( wr_calloc( (void **) & leafptr->data_ptr, leafptr->data_len, 1)
150 | != UT_OK) {
151 | die;
152 | }
153 |
154 | if( snprintf(leafptr->data_ptr, leafptr->data_len,
155 | "inetnum:\t%s\n", prstr )
156 | > leafptr->data_len ) {
157 | // program error: the buffer is too short.
158 | die;
159 | }
160 | }
161 |
162 | /*
163 | leafptr->data_ptr = col[3];
164 | leafptr->data_len = strlen(str)+1;
165 | */
166 |
167 | if( RX_inum_node( RX_OPER_CRE, &myrang, mytree, leafptr ) != RX_OK ) {
168 | fprintf(stderr,"%d:\t%d\t%s\n", objnr, in_id, str);
169 | die;
170 | }
171 |
172 | /*
173 | printf("%d \t %s\n", in_id, str);
174 | */
175 |
176 | /*** FREE ****************************************************/
177 |
178 | for(i=0;i<4;i++) {
179 | free(col[i]);
180 | }
181 | objnr++;
182 | }
183 | }
184 | SQ_free_result(result);
185 |
186 | /* Close connection */
187 | SQ_close_connection(con);
188 |
189 | } /* put_inet_sql() */
190 |
191 | static void put_route_sql(rx_tree_t *mytree) {
192 | SQ_row_t *row;
193 | int retrieved_objects=0;
194 |
195 | SQ_connection_t *con;
196 | SQ_result_set_t *result;
197 |
198 | int objnr=1;
199 | int brk=0;
200 |
201 | char qry[1024];
202 |
203 | /* Make connection */
204 | con = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password());
205 |
206 | // compose the query
207 |
208 | result = SQ_execute_query(SQ_STORE, con, CO_get_rt_query());
209 |
210 | if (result == NULL) {
211 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
212 | }
213 | else {
214 | while ( (row = SQ_row_next(result)) != NULL ) {
215 |
216 | ip_prefix_t mypref;
217 | rx_dataleaf_t *leafptr;
218 | int rt_id;
219 | char *col[4];
220 | int i;
221 |
222 | memset(&mypref, 0, sizeof(ip_prefix_t));
223 | mypref.ip.space = IP_V4;
224 |
225 | for(i=0; i<4; i++) {
226 | col[i] = SQ_get_column_string(result, row, i);
227 | if (col[i] == NULL) {
228 | die;
229 | }
230 | }
231 |
232 | // get the data: prefix and payload (id and origin)
233 |
234 | // prefix ip
235 | if( sscanf(col[1], "%u", &mypref.ip.words[0] ) < 1 ) {
236 | die;
237 | }
238 |
239 | // prefix length
240 | if( sscanf(col[2], "%u", &mypref.bits ) < 1 ) {
241 | die;
242 | }
243 |
244 | // fulltext id
245 | if( sscanf(col[0], "%u", &rt_id ) < 1 ) {
246 | die;
247 | }
248 |
249 | /*** FILL IN ****************************************************/
250 |
251 | // payload: goes into a dataleaf
252 | if( wr_calloc( (void **)& leafptr, sizeof(rx_dataleaf_t), 1)
253 | != UT_OK) {
254 | die;
255 | }
256 |
257 | leafptr->data_key = rt_id;
258 |
259 | // prepare output string for -K (route: prefix/len\norigin:col[3])
260 | {
261 | char prstr[IP_PREFSTR_MAX];
262 |
263 | if( IP_pref_b2a( &mypref, prstr, IP_PREFSTR_MAX) != IP_OK ) {
264 | die; // program error.
265 | }
266 |
267 | #define PAYLOAD_ROUTE_LENGTH strlen("route:\t/\norigin:\t\n")
268 |
269 | leafptr->data_len = PAYLOAD_ROUTE_LENGTH + 1
270 | + strlen(prstr) + strlen(col[3]);
271 |
272 |
273 | if( wr_calloc( (void **) & leafptr->data_ptr, leafptr->data_len, 1)
274 | != UT_OK) {
275 | die;
276 | }
277 |
278 | if( snprintf(leafptr->data_ptr, leafptr->data_len,
279 | "route:\t%s\norigin:\t%s\n", prstr, col[3] )
280 | > leafptr->data_len ) {
281 | // program error: the buffer is too short.
282 | die;
283 | }
284 | }
285 |
286 |
287 | if( RX_bin_node( RX_OPER_CRE, &mypref, mytree, leafptr ) != RX_OK ) {
288 | fprintf(stderr,"%d:\t%d\t%s\n", objnr, rt_id, col[3]);
289 | die;
290 | }
291 |
292 | /*** FREE ****************************************************/
293 |
294 | for(i=0;i<4;i++) {
295 | free(col[i]);
296 | }
297 |
298 | objnr++;
299 | }
300 | }
301 | SQ_free_result(result);
302 |
303 | /* Close connection */
304 | SQ_close_connection(con);
305 |
306 | } /* put_route_sql() */
307 |
308 | /* XXX void radix_init(char *database) { */
309 | static void radix_init() {
310 | er_path_t erlogstr;
311 | rx_tree_t *mytree;
312 |
313 | 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) {
314 | puts("error!!!");
315 | }
316 | else {
317 |
318 | put_inet_sql(mytree);
319 | RX_attach2forest(mytree);
320 |
321 | 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) {
322 | puts("error!!!");
323 | }
324 | else {
325 |
326 | put_route_sql(mytree);
327 | RX_attach2forest(mytree);
328 | }
329 | }
330 |
331 | erlogstr.fdes = stderr;
332 | /*
333 | erlogstr.asp = ASP_RX_SRCH_DET | ASP_RX_STKBLD_DET ;
334 | */
335 | erlogstr.asp = 0; /* No debugging info. */
336 | erlogstr.sev = ER_SEV_W;
337 | erlogstr.mode = ER_M_SEVCHAR | ER_M_TEXTLONG;
338 |
339 | ER_setpath(& erlogstr);
340 |
341 | } /* radix_init() */
342 |
343 |
344 | /* SV_start() */
345 | /*++++++++++++++++++++++++++++++++++++++
346 |
347 | Start the server.
348 |
349 | More:
350 | +html+ <PRE>
351 | Authors:
352 | ottrey
353 | joao
354 | +html+ </PRE>
355 | +html+ Starts up the server.
356 | +html+ <OL>
357 | +html+ <LI> Create sockets on the necessary ports (whois, config and mirror)
358 | +html+ <LI> Start new threads for each service.
359 | +html+ </OL>
360 | +html+ <A HREF=".DBrc">.properties</A>
361 |
362 | ++++++++++++++++++++++++++++++++++++++*/
363 | void SV_start() {
364 | int status;
365 | int whois_sock,config_sock,mirror_sock; /* 7. */
366 | uint32_t whois_addr,sock_addr,mirror_addr;
367 | int whois_port = -1; /* 6. */
368 | int config_port = -1; /* 6. */
369 | int mirror_port = -1; /* 6. */
370 |
371 | /* Initialise the attributes. */
372 | /*
373 | AT_init();
374 | */
375 |
376 | /* Initialise the objects. */
377 | /*
378 | OB_init();
379 | */
380 |
381 | /* Initialise the access control list. */
382 | AC_build();
383 | AC_acc_load();
384 |
385 | /* Initialise the radix tree before allowing any socket connections. */
386 | radix_init();
387 |
388 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */
389 | /* Get port information for each service */
390 | whois_port = SK_atoport(CO_get_whois_port(), "tcp");
391 | printf("XXX whois_port=%d\n", whois_port);
392 | printf("XXX htons(whois_port)=%d\n", htons(whois_port));
393 | if(whois_port == -1) {
394 | printf("Invalid service/port: %s\n", whois_port);
395 | exit(-1);
396 | }
397 |
398 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */
399 | config_port = SK_atoport(CO_get_config_port(), "tcp");
400 | printf("XXX config_port=%d\n", config_port);
401 | printf("XXX htons(config_port)=%d\n", htons(config_port));
402 | if(config_port == -1) {
403 | printf("Invalid service/port: %s\n", config_port);
404 | exit(-1);
405 | }
406 | /* Commented out for now. Remove comment when enabling mirroring
407 | mirror_port = SK_atoport(CO_get_mirror_port(), "tcp");
408 | if(mirror_port == -1) {
409 | printf("Invalid service/port: %s\n", mirror_port);
410 | exit(-1);
411 | }
412 | */
413 |
414 | /* 6. Create a socket on the necessary ports/addresses and bind to them. */
415 | /* whois socket */
416 | whois_sock = SK_getsock(SOCK_STREAM, whois_port, INADDR_ANY);
417 | /* Currently binds to INADDR_ANY. Will need to get specific address */
418 | /* whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */
419 | /* config interface socket */
420 | config_sock = SK_getsock(SOCK_STREAM, config_port, INADDR_ANY);
421 | /* nrt socket */
422 | /* mirror_sock = SK_getsock(SOCK_STREAM,mirror_sock,mirror_addr); Remove comment when enabling mirroring */
423 |
424 | /* Now.... accept() calls block until they get a connection
425 | so to listen on more than one port we need more
426 | than one thread */
427 |
428 | /* Create master thread for whois threads */
429 | TH_run(whois_sock, (void *)TH_do_whois);
430 | /* Create master thread for config threads */
431 | TH_run(config_sock, (void *)TH_do_config);
432 | /* Create master thread for mirror threads */
433 | /* Remove comment when enabling mirroring
434 | TH_run(mirror_sock, (void *)TH_do_mirror);
435 | */
436 |
437 | /* XXX Is this needed? */
438 | pthread_exit(&status);
439 |
440 | } /* SV_start() */