1 | /***************************************
2 | $Revision: 1.22 $
3 |
4 | Wrapper for NRTM client
5 |
6 | Status: NOT REVUED, NOT TESTED
7 |
8 | Author(s): Andrei Robachevsky
9 |
10 | ******************/ /******************
11 | Modification History:
12 | andrei (17/01/2000) Created.
13 | ******************/ /******************
14 | Copyright (c) 2000 RIPE NCC
15 |
16 | All Rights Reserved
17 |
18 | Permission to use, copy, modify, and distribute this software and its
19 | documentation for any purpose and without fee is hereby granted,
20 | provided that the above copyright notice appear in all copies and that
21 | both that copyright notice and this permission notice appear in
22 | supporting documentation, and that the name of the author not be
23 | used in advertising or publicity pertaining to distribution of the
24 | software without specific, written prior permission.
25 |
26 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 | ***************************************/
33 | #include <sys/types.h>
34 | #include <sys/socket.h>
35 | #include <netinet/in.h>
36 | #include <arpa/inet.h>
37 | #include <fcntl.h>
38 | #include <signal.h>
39 | /*#include <stream.h>*/
40 |
41 |
42 | #include "ud.h"
43 | #include "ud_int.h"
44 |
45 | #include "constants.h"
46 |
47 | #include "er_macro.h"
48 | #include "er_paths.h"
49 |
50 | #include "server.h"
51 | #include "protocol_mirror.h"
52 | #include "ta.h"
53 |
54 | /* here we store sockets for update threads */
55 | /* they are from SV module */
56 | extern int SV_update_sock[];
57 |
58 | /* Response time to swtching updates on and off */
59 | #define TIMEOUT 60
60 | /* Maximum number of objects(serials) we can consume at a time */
61 | #define SBUNCH 1000
62 |
63 | /* Timeout in seconds when reading from DBupdate */
64 | #define STREAM_TIMEOUT 120
65 |
66 | /************************************************************
67 | * int get_NRTM_fd() *
68 | * *
69 | * Gets the NRTM stream *
70 | * *
71 | * First tries to request the serials from the NRTM server *
72 | * If the name of the server appears to be not a network name*
73 | * it tries to open the file with this name *
74 | * *
75 | * nrtm - pointer to _nrtm structure *
76 | * upto_last - if==1 then requests to download serials using *
77 | * LAST keyword *
78 | * *
79 | * Returns: *
80 | * A file descriptor for a data stream *
81 | * -1 - error *
82 | * *
83 | ************************************************************/
84 | int get_NRTM_fd(struct _nrtm *nrtm, int upto_last, char *source)
85 | {
86 | int sockfd;
87 | struct hostent *hptr;
88 | struct sockaddr_in serv_addr;
89 | struct in_addr *paddr;
90 | char line_buff[STR_XXL];
91 | int fd;
92 | int nwrite;
93 | struct hostent result;
94 | int error;
95 | int network;
96 |
97 |
98 | /* fprintf(stderr, "Making connection to NRTM server ...\n");*/
99 | if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){
100 | ER_perror(FAC_UD, UD_FS, "cannot create socket");
101 | perror("socket");
102 | return(-1);
103 | }
104 | #ifdef _LINUX
105 | if(gethostbyname_r(nrtm->server, &result, line_buff, sizeof(line_buff), &hptr, &error)<0) hptr=NULL;
106 | #else/* default is Solaris implementation */
107 | hptr=gethostbyname_r(nrtm->server, &result, line_buff, sizeof(line_buff), &error);
108 | #endif
109 |
110 | /* Check if it is a network stream or a file */
111 | if (hptr) { /* this is a network stream*/
112 | paddr=(struct in_addr *)hptr->h_addr;
113 | bzero(&serv_addr, sizeof(serv_addr));
114 | serv_addr.sin_family=AF_INET;
115 | serv_addr.sin_port=nrtm->port;
116 | memcpy(&serv_addr.sin_addr, paddr, sizeof(struct in_addr));
117 | /* fprintf(stderr,"Trying %s port %d\n", inet_ntoa(serv_addr.sin_addr), nrtm->port);*/
118 | if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))==-1) {
119 | ER_perror(FAC_UD, UD_FS, "cannot cannect");
120 | perror("connect");
121 | return(-1);
122 | }
123 | /* fprintf(stderr, "Sending Invitation\n"); */
124 |
125 | /* Request all available serials (upto LAST), or SBUNCH of them */
126 | if(upto_last)
127 | sprintf(line_buff, "-g %s:%d:%ld-LAST\n", source, nrtm->version, nrtm->current_serial+1);
128 | else
129 | sprintf(line_buff, "-g %s:%d:%ld-%ld\n", source, nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH);
130 | nwrite=SK_write(sockfd, line_buff, strlen(line_buff) );
131 | if(nwrite != strlen(line_buff)) {
132 | ER_perror(FAC_UD, UD_FS, "cannot write");
133 | perror("write"); return(-1);
134 | }
135 | fd=sockfd;
136 | network=1;
137 | /* fprintf(stderr, "Returning stream pointer\n"); */
138 | }
139 | else { /* this is a file stream*/
140 | network=0;
141 | close(sockfd);
142 | /* fprintf(stderr, "Trying file ...\n");*/
143 | if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) {
144 | ER_perror(FAC_UD, UD_FS, "cannot open");
145 | perror("open");
146 | return(-1);
147 | }
148 | }
149 | return(fd);
150 | }
151 |
152 |
153 |
154 | /************************************************************
155 | * void UD_do_nrtm() *
156 | * *
157 | * Processes NRTM stream *
158 | * *
159 | * It cycles requesting objects from the NRTM server, *
160 | * processing them and then sleeping a specified amount of *
161 | * time. *
162 | * *
163 | * It starts by requesting SBUNCH number of serials and does *
164 | * so untill no serials are received (actually a warning *
165 | * is received saying that the requested range is invalid) *
166 | * This approach avoids excessive load on the NRTM server *
167 | * *
168 | * After that it requests serials using LAST keyward keeping *
169 | * almost in sync with the server *
170 | * *
171 | ************************************************************/
172 |
173 | void UD_do_nrtm(void *arg)
174 | {
175 | int source = (int)arg;
176 | UD_stream_t ud_stream;
177 | struct _nrtm *nrtm;
178 | int delay;
179 | int do_update=1;
180 | int do_server;
181 | int nrtm_fd;
182 | int num_ok;
183 | int upto_last;
184 | char ta_activity[STR_M];
185 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source);
186 | char *db_host, *db_name, *db_user, *db_passwd;
187 | int db_port;
188 | /* get source we are going to mirror */
189 | char *source_name = ca_get_srcname(source_hdl);
190 |
191 | { /* set up the lohgging path */
192 | int res;
193 | char *er_ud_def = ca_get_er_ud_def; /* something like 'RIPUPDLOG basename' */
194 | char er_def[256];
195 | char *erret = NULL;
196 |
197 | sprintf(er_def, "%s %s", er_ud_def, source_name);
198 | fprintf(stderr, "[%s]\n", er_def);
199 | if( (res = ER_macro_spec(er_def, &erret)) != 0 ) {
200 | fputs(erret, stderr);
201 | die;
202 | /* or some other error handling */
203 | }
204 | free(erret); /* the response is allocated and must be freed */
205 | free(er_ud_def);
206 | }
207 |
208 | nrtm=calloc(1, sizeof(struct _nrtm));
209 | if(nrtm==NULL) {
210 | ER_perror(FAC_UD, UD_MEM, "cannot allocate memory");
211 | die;
212 | }
213 | /* get mode of operation: protected/unprotected (dummy) */
214 | memset(&ud_stream, 0, sizeof(ud_stream));
215 | ud_stream.source_hdl=source_hdl;
216 | ud_stream.ud_mode=ca_get_srcmode(source_hdl);
217 |
218 | fprintf(stderr, "Mode of operation:\n");
219 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n");
220 | else fprintf(stderr, "* dummy not allowed\n");
221 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n");
222 | else if(IS_NRTM_CLNT(ud_stream.ud_mode))fprintf(stderr, "* NRTM\n");
223 | else fprintf(stderr, "* STATIC\n");
224 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n");
225 | else fprintf(stderr, "* running as a server\n");
226 |
227 | /* get mirror server */
228 | nrtm->server=ca_get_srcnrtmhost(source_hdl);
229 |
230 |
231 | /* get mirror port */
232 | nrtm->port = htons(ca_get_srcnrtmport(source_hdl));
233 | printf("XXX nrtm_port=%d\n", ntohs(nrtm->port));
234 |
235 | /* get mirror version */
236 | nrtm->version=ca_get_srcnrtmprotocolvers(source_hdl);
237 |
238 |
239 | /* get error log facility */
240 | /* logfilename=ca_get_srcnrtmlog(source_hdl); */
241 |
242 | db_host = ca_get_srcdbmachine(source_hdl);
243 | db_port = ca_get_srcdbport(source_hdl);
244 | db_name = ca_get_srcdbname(source_hdl);
245 | db_user = ca_get_srcdbuser(source_hdl);
246 | db_passwd = ca_get_srcdbpassword(source_hdl);
247 |
248 | /* Connect to the database */
249 | ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s making SQL connection to %s@%s ...", UD_TAG, db_name, db_host);
250 | ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
251 |
252 |
253 | if(! ud_stream.db_connection) {
254 | ER_perror(FAC_UD, UD_SQL, "no connection to SQL server");
255 | die;
256 | }
257 |
258 | ud_stream.num_skip=0;
259 | ud_stream.load_pass=0;
260 | ud_stream.nrtm=nrtm;
261 |
262 | upto_last=0; /* let's start gradually if the backlog is > SBUNCH (1000) serials*/
263 |
264 | /*+++ main cycle +++*/
265 |
266 | do {
267 | do_update=CO_get_do_update();
268 | if(do_update) {
269 |
270 | /* Check connection to the database and try to reconnect */
271 | if(mysql_ping(ud_stream.db_connection)) {
272 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s connection to SQL server timed out - reistablishing", UD_TAG);
273 | }
274 |
275 | /* get current serial */
276 | nrtm->current_serial=PM_get_current_serial(ud_stream.db_connection);
277 |
278 | if(nrtm->current_serial == -1) {
279 | ER_perror(FAC_UD, UD_SQL, "cannot obtain current serial: %ld", nrtm->current_serial);
280 | die;
281 | }
282 |
283 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s connecting to NRTM server (current serial=%ld)", UD_TAG, nrtm->current_serial);
284 |
285 | /* Get file descriptor of the data stream (RPSL format, use mirror reflector to convert if needed)*/
286 | nrtm_fd=get_NRTM_fd(nrtm, upto_last, source_name);
287 | if (nrtm_fd==-1) {
288 | ER_inf_va(FAC_UD, ASP_UD_OBJ, "%s Cannot open data stream. Trying...", UD_TAG);
289 | SV_sleep(10);
290 | continue;
291 | }
292 |
293 |
294 | /* make a record for thread accounting */
295 | TA_add(nrtm_fd, "nrtm_clnt");
296 | sprintf(ta_activity,"[%s]%ld->", source_name, nrtm->current_serial);
297 | TA_setactivity(ta_activity);
298 |
299 |
300 | ud_stream.condat.sock = nrtm_fd;
301 | ud_stream.log.num_ok=0;
302 | ud_stream.log.num_failed=0;
303 |
304 |
305 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s starting processing stream", UD_TAG);
306 |
307 | /***************** process stream ****************/
308 |
309 | num_ok=UD_process_stream(&ud_stream);
310 |
311 | /***************** process stream ****************/
312 |
313 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s processing stream finished", UD_TAG);
314 |
315 | /* close the socket of the NRTM stream */
316 | close(ud_stream.condat.sock);
317 |
318 | /* Now we can process serials in normal way (upto LAST)*/
319 | if(num_ok==0) upto_last=1;
320 |
321 | ER_inf_va(FAC_UD, ASP_UD_OBJ, "%s forwarded to serial:%ld", UD_TAG, (nrtm->current_serial+num_ok));
322 |
323 | /* set activity for thread record */
324 | sprintf(ta_activity,"[%s]->%ld", source_name, (nrtm->current_serial+num_ok));
325 | TA_setactivity(ta_activity);
326 |
327 |
328 | /* get delay */
329 | delay=ca_get_srcnrtmdelay(source_hdl);
330 | /* sleep the delay seconds or untill the shutdown requested */
331 | SV_sleep(delay);
332 | } /* if do_updates */
333 | else SV_sleep(TIMEOUT);
334 |
335 |
336 | TA_delete();
337 |
338 | } while((do_server=CO_get_do_server())); /* main cycle */
339 |
340 | /* fclose(ud_stream.log.logfile);*/
341 | free(source_name);
342 | /* free data associated with nrtm structure */
343 | if(nrtm) {
344 | free(nrtm->server);
345 | free(nrtm);
346 | }
347 |
348 | /* That's all. Close connection to the DB */
349 | SQ_close_connection(ud_stream.db_connection);
350 | free(db_host);
351 | free(db_name);
352 | free(db_user);
353 | free(db_passwd);
354 |
355 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s NRTM client stopped", UD_TAG);
356 | } /* UD_do_nrtm() */
357 |
358 | /************************************************************
359 | * void UD_do_updates() *
360 | * *
361 | * Processes updates *
362 | * *
363 | * It cycles accepting connections and processing them *
364 | * (interactive server). This assures that there is only *
365 | * one write thread per database/source. *
366 | * *
367 | ************************************************************/
368 |
369 | void UD_do_updates(void *arg)
370 | {
371 | int source = (int)arg;
372 | int listening_socket = SV_update_sock[source];
373 | int connected_socket;
374 | UD_stream_t ud_stream;
375 | int do_update=1;
376 | int do_server;
377 | int num_ok;
378 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source);
379 | char *db_host, *db_name, *db_user, *db_passwd;
380 | int db_port;
381 |
382 | { /* set up the lohgging path */
383 | /* get source we are going to update */
384 | char *source_name = ca_get_srcname(source_hdl);
385 | int res;
386 | char *er_ud_def = ca_get_er_ud_def; /* something like 'RIPUPDLOG basename' */
387 | char er_def[256];
388 | char *erret = NULL;
389 |
390 | sprintf(er_def, "%s %s", er_ud_def, source_name);
391 | if( (res = ER_macro_spec(er_def, &erret)) != 0 ) {
392 | fputs(erret, stderr);
393 | die;
394 | /* or some other error handling */
395 | }
396 | free(erret); /* the response is allocated and must be freed */
397 | free(er_ud_def);
398 | free(source_name);
399 | }
400 |
401 | /* get mode of operation: protected/unprotected (dummy) */
402 | memset(&ud_stream, 0, sizeof(ud_stream));
403 | ud_stream.source_hdl=source_hdl;
404 | ud_stream.ud_mode=ca_get_srcmode(source_hdl);
405 |
406 | fprintf(stderr, "Mode of operation:\n");
407 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n");
408 | else fprintf(stderr, "* dummy not allowed\n");
409 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n");
410 | else fprintf(stderr, "* NRTM\n");
411 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n");
412 | else fprintf(stderr, "* running as a server\n");
413 |
414 |
415 | /* get error log facility */
416 | db_host = ca_get_srcdbmachine(source_hdl);
417 | db_port = ca_get_srcdbport(source_hdl);
418 | db_name = ca_get_srcdbname(source_hdl);
419 | db_user = ca_get_srcdbuser(source_hdl);
420 | db_passwd = ca_get_srcdbpassword(source_hdl);
421 |
422 | /* Connect to the database */
423 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s making SQL connection to %s@%s ...", UD_TAG, db_name, db_host);
424 | ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
425 |
426 | if(! ud_stream.db_connection) {
427 | ER_perror(FAC_UD, UD_SQL, "no connection to SQL server\n");
428 | die;
429 | }
430 |
431 |
432 | ud_stream.condat.rd_timeout.tv_sec=STREAM_TIMEOUT;
433 | ud_stream.num_skip=0;
434 | ud_stream.load_pass=0;
435 | ud_stream.nrtm=NULL;
436 |
437 | /*+++ main cycle +++*/
438 |
439 | do { /* be alive while do_server is 1. do_server is turned off by SIGINT */
440 |
441 | /* make a record for thread accounting */
442 | TA_add(listening_socket, "update");
443 | TA_setactivity("waiting");
444 |
445 |
446 | /* accept connection */
447 | connected_socket = SK_accept_connection(listening_socket);
448 | if(connected_socket==-1) break;
449 |
450 |
451 | /* make a record for thread accounting */
452 | TA_delete(); /* Delete 'waiting' record */
453 | TA_add(connected_socket, "update");
454 |
455 |
456 | ud_stream.condat.sock = connected_socket;
457 | ud_stream.condat.rtc = 0;
458 |
459 | do_update=CO_get_do_update();
460 | if(do_update) {
461 |
462 | TA_setactivity("suspended");
463 |
464 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s Connection accepted...", UD_TAG);
465 |
466 | ud_stream.log.num_ok=0;
467 | ud_stream.log.num_failed=0;
468 |
469 | /* Check connection to the database and try to reconnect*/
470 | if(mysql_ping(ud_stream.db_connection)) {
471 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s connection to SQL server timed out - reistablishing", UD_TAG);
472 | }
473 |
474 | ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s starting processing object", UD_TAG);
475 |
476 | /***************** process stream ****************/
477 |
478 | num_ok=UD_process_stream(&ud_stream);
479 |
480 | /***************** process stream ****************/
481 |
482 | ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s processing object finished", UD_TAG);
483 |
484 | /* close the socket of the NRTM stream */
485 | close(ud_stream.condat.sock);
486 |
487 | } /* if do_update*/
488 | else { /* Otherwise print a message*/
489 | /* To display with 'show threads' */
490 | TA_setactivity("suspended");
491 |
492 | }
493 | /* make a record for thread accounting */
494 | TA_delete();
495 |
496 | do_server=CO_get_do_server();
497 |
498 | } while (do_server); /* main cycle */
499 |
500 | /* fclose(ud_stream.log.logfile); */
501 | /* That's all. Close connection to the DB */
502 | SQ_close_connection(ud_stream.db_connection);
503 | free(db_host);
504 | free(db_name);
505 | free(db_user);
506 | free(db_passwd);
507 |
508 |
509 | ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "%s update server stopped", UD_TAG);
510 | } /* UD_do_update() */
511 |
512 |
513 |
514 |