1    | /***************************************
2    |   $Revision: 1.14 $
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                              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   | #include <stdio.h>
39   | #include "ud_int.h" 
40   | #include "protocol_mirror.h"
41   | #include "protocol_whois.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)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  |   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  |        	  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  |        	  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)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  |        free(db_host);
293  |        free(db_name);
294  |        free(db_user);
295  |        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  |        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  | }