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