1    | /***************************************
2    |   $Revision: 1.10 $
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   | 
42   | void pm_get_source_info(GString *gbuff, ip_addr_t *client_address, char *source, ca_dbSource_t *source_hdl);
43   | 
44   | /************************************************************
45   | * PM_get_minmax_serial()                                    *
46   | *                                                           *
47   | * Returns the min or max serial number.                     *
48   | *                                                           *
49   | * Returns:                                                  *
50   | *  min (max=0) or max (max=1) serial number                 *
51   | *  -1 in case of an error                                   *
52   | *                                                           *
53   | * Note:                                                     *
54   | *  min serial= MIN(serial_id)+1                             *
55   | *  MIN(serial_id) represents legacy RIPE.CURRENSERIAL       *
56   | *  of the snapshot                                          *
57   | *                                                           *
58   | *************************************************************/
59   | long PM_get_minmax_serial(SQ_connection_t *sql_connection, int max)
60   | {
61   | char query[STR_M];
62   | SQ_result_set_t *sql_result;
63   | SQ_row_t *sql_row;
64   | char *sql_str;
65   | long current_serial;
66   | char *minmax;
67   | int sql_err;
68   | 
69   | if(max==1)minmax="max"; else minmax="min";
70   | 
71   |  sprintf(query, "SELECT %s(serial_id) FROM serials ", minmax);
72   | 
73   | //fprintf(stderr, "D:<get_field_str>:query: %s\n", query);
74   |  sql_err = SQ_execute_query(sql_connection, query, &sql_result);
75   |  
76   |  if(sql_err) {
77   |     ER_perror(FAC_PM, PM_NOSQLC,"%s[%s]", SQ_error(sql_connection), query);
78   |     die;
79   |  }
80   |         
81   | 	 
82   |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
83   | 	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
84   | 
85   |      /* We must process all the rows of the result,*/
86   |      /* otherwise we'll have them as part of the next qry */
87   | 	while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
88   | 	  ER_perror(FAC_PM, PM_NOSQLC,"duplicate PK [%s]", query);
89   | 	  if(sql_str)free(sql_str); sql_str=NULL;
90   | 	}
91   |  }
92   |  else sql_str=NULL;
93   |  
94   |  if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
95   |  
96   |  if(sql_str) {
97   |   current_serial = atol(sql_str);
98   |   if(max!=1)current_serial++; 
99   |   free(sql_str);
100  |  }
101  |  else current_serial=-1;
102  |  
103  |  return(current_serial);
104  |  
105  | }
106  | 
107  | /************************************************************
108  | * int atlast(long serial_number)
109  | * -1 - sql error
110  | *
111  | ***********************************************************/
112  | 
113  | static int atlast(SQ_connection_t *sql_connection, long serial_number)
114  | {
115  | char *sql_str;
116  | char str_id[STR_S];
117  | int atlast=-1;
118  | 
119  | 
120  |   sprintf(str_id, "%ld", serial_number);
121  |   sql_str= get_field_str(sql_connection, "atlast", "serials", "serial_id", str_id, NULL);
122  |   if(sql_str) {
123  |        	  atlast = atoi(sql_str);
124  |        	  free(sql_str);
125  |   }
126  |   
127  |   return(atlast);
128  | 
129  | }
130  | 
131  | 
132  | /************************************************************
133  | * int getop(long serial_number)
134  | * -1 - sql error
135  | *
136  | * **********************************************************/
137  | 
138  | static int getop(SQ_connection_t *sql_connection, long serial_number)
139  | {
140  | char *sql_str;
141  | char str_id[STR_S];
142  | int op=-1;
143  | 
144  | 
145  |   sprintf(str_id, "%ld", serial_number);
146  |   sql_str= get_field_str(sql_connection, "operation", "serials", "serial_id", str_id, NULL);
147  |   if(sql_str) {
148  |        	  op = atoi(sql_str);
149  |        	  free(sql_str);
150  |   }
151  |   
152  |   return(op);
153  | 
154  | }
155  | 
156  | 
157  | /************************************************************
158  | * char *PM_get_serial_object()                                 *
159  | *                                                           *
160  | * Returns text block corresponding to the requested serial  *
161  | *                                                           *
162  | * Returns:                                                  *
163  | *  operation (ADD/DEL) and text object                      *
164  | *  NULL in case of an error                                 *
165  | *                                                           *
166  | * Note:                                                     *
167  | *  returned string should be freed by the caller            *
168  | *                                                           *
169  | *************************************************************/
170  | char *PM_get_serial_object(SQ_connection_t *sql_connection, long serial_number, int *operation)
171  | {
172  | char *table;
173  | SQ_result_set_t * sql_result;
174  | SQ_row_t *sql_row;
175  | char *sql_str;
176  | char query[STR_M];
177  | int sql_err;
178  | int location;
179  | 
180  |   switch(location=atlast(sql_connection, serial_number)){
181  |   
182  |    case 0: table="history";
183  |            break;
184  |    case 1: table="last";   
185  |            break;
186  |    case 2: table="failed_transaction";
187  |            break;	   
188  |    default: return(NULL);   
189  |       
190  |   }
191  | 
192  |   if(location == 2) 
193  |      sprintf(query, "SELECT object FROM %s "
194  |                     "WHERE serial_id=%ld ",
195  | 		    table, serial_number);
196  |   else	  
197  |      sprintf(query, "SELECT %s.object FROM %s, serials "
198  |                     "WHERE serials.serial_id=%ld "
199  |                     "AND serials.object_id=%s.object_id "
200  |                     "AND serials.sequence_id=%s.sequence_id ", table, table, serial_number, table, table);
201  |                  
202  | 
203  |  sql_err = SQ_execute_query(sql_connection, query, &sql_result);
204  |  
205  |  if(sql_err) {
206  |     ER_perror(FAC_PM, PM_NOSQLC,"%s[%s]", SQ_error(sql_connection), query);
207  |     die;
208  |  }
209  |         
210  | 	 
211  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
212  | 	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
213  | 
214  |      /* We must process all the rows of the result,*/
215  |      /* otherwise we'll have them as part of the next qry */
216  | 	while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
217  | 	  ER_perror(FAC_PM, PM_NOSQLC,"duplicate PK [%s]", query);
218  | 	  if(sql_str)free(sql_str); sql_str=NULL;
219  | 	}
220  |  }
221  |  else sql_str=NULL;
222  |  
223  |  if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
224  |  
225  |  *operation=getop(sql_connection, serial_number);
226  |  
227  |  return(sql_str);
228  |  
229  | }
230  | 
231  | /************************************************************
232  | * void pm_get_source_info()                                 *
233  | *                                                           *
234  | * Fills supplied buffer with information about the source   *
235  | *                                                           *
236  | * Returns text block corresponding to the requested source  *
237  | * Format:                                                   *
238  | * <source>:<can_mirror>:min_serial-max_serial               *
239  | * source - name of the source (e.g. RIPE, RADB, etc.)       *
240  | * can_mirror                                                * 
241  | *    'Y' if the client is allowed to mirror the source      *
242  | *    'N' if not                                             *
243  | *    'N' if there is no serials (then the range starts at 0)*    
244  | *                                                           * 
245  | *                                                           *
246  | *************************************************************/
247  | void pm_get_source_info(GString *gbuff, ip_addr_t *client_address, char *source, ca_dbSource_t *source_hdl)
248  | {
249  | 
250  | char *db_host = ca_get_srcdbmachine(source_hdl);
251  | int   db_port = ca_get_srcdbport(source_hdl);
252  | char *db_name = ca_get_srcdbname(source_hdl);
253  | char *db_user = ca_get_srcdbuser(source_hdl);
254  | char *db_passwd = ca_get_srcdbpassword(source_hdl);
255  | int version = ca_get_srcnrtmprotocolvers(source_hdl);
256  | SQ_connection_t *db_connection;
257  | long min_serial, max_serial;
258  | char can_mirror;
259  |   
260  |       /* Connect to the database */
261  |        db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
262  |        min_serial=PM_get_oldest_serial(db_connection);
263  |        max_serial=PM_get_current_serial(db_connection);
264  |        
265  |        /* If it cannot be morrored at all - N, but range starts with 0 */
266  |        /* If the client is allowed to mirror - Y         */
267  |        /* Otherwise - N                                  */
268  |        if(min_serial>max_serial) {
269  | 	       can_mirror='N';
270  | 	       min_serial=0;
271  |        }
272  |        else {
273  | 	       if(AA_can_mirror(client_address, source )) can_mirror='Y';
274  |                else can_mirror='N';
275  |        }	
276  |        g_string_sprintfa(gbuff, "%s:%d:%c:%lu-%lu\n", source, version, can_mirror, min_serial, max_serial);
277  |        
278  |        free(db_host);
279  |        free(db_name);
280  |        free(db_user);
281  |        free(db_passwd);
282  |        SQ_close_connection(db_connection);
283  | }
284  | 
285  | /************************************************************
286  | * GString *PM_get_nrtm_sources()                            *
287  | *                                                           *
288  | * Fills supplied buffer with information about the sources  *
289  | *                                                           *
290  | *                                                           * 
291  | * Note:                                                     *
292  | *  returned GString should be freed by the caller           *
293  | *                                                           *
294  | *************************************************************/
295  | GString *PM_get_nrtm_sources(ip_addr_t *client_address, char *source)
296  | {
297  | GString *gbuff=g_string_sized_new(STR_L);
298  | int nsource;
299  | ca_dbSource_t *source_hdl;
300  | 
301  |    if(source){
302  |       source_hdl = ca_get_SourceHandleByName(source);
303  |       if (source_hdl)pm_get_source_info(gbuff, client_address, source, source_hdl);
304  |    } else 
305  |       for(nsource=0; (source_hdl = ca_get_SourceHandleByPosition(nsource))!=NULL ; nsource++){
306  |        source=ca_get_srcname(source_hdl);
307  |        pm_get_source_info(gbuff, client_address, source, source_hdl);
308  |        free(source);
309  |    }
310  |    
311  |    g_string_sprintfa(gbuff, "\n\n");
312  |    return(gbuff);
313  | }