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 | }