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