1 | /***************************************
2 | $Revision: 1.19 $
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 "ud.h"
40 | #include "ud_int.h"
41 | #include "constants.h"
42 |
43 | #include "server.h"
44 | #include "protocol_mirror.h"
45 | #include "ta.h"
46 |
47 | /* here we store sockets for update threads */
48 | /* they are from SV module */
49 | extern int SV_update_sock[];
50 |
51 | /* Response time to swtching updates on and off */
52 | #define TIMEOUT 60
53 | /* Maximum number of objects(serials) we can consume at a time */
54 | #define SBUNCH 1000
55 |
56 | /************************************************************
57 | * int get_NRTM_fd() *
58 | * *
59 | * Gets the NRTM stream *
60 | * *
61 | * First tries to request the serials from the NRTM server *
62 | * If the name of the server appears to be not a network name*
63 | * it tries to open the file with this name *
64 | * *
65 | * nrtm - pointer to _nrtm structure *
66 | * upto_last - if==1 then requests to download serials using *
67 | * LAST keyword *
68 | * *
69 | * Returns: *
70 | * A file descriptor for a data stream *
71 | * -1 - error *
72 | * *
73 | ************************************************************/
74 | int get_NRTM_fd(struct _nrtm *nrtm, int upto_last, char *source)
75 | {
76 | int sockfd;
77 | struct hostent *hptr;
78 | struct sockaddr_in serv_addr;
79 | struct in_addr *paddr;
80 | char line_buff[STR_XXL];
81 | int fd;
82 | int nwrite;
83 | struct hostent result;
84 | int error;
85 | int network;
86 |
87 |
88 | fprintf(stderr, "Making connection to NRTM server ...\n");
89 | if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){
90 | perror("socket");
91 | return(-1);
92 | }
93 | /* hptr=gethostbyname(nrtm->server);*/
94 | hptr=gethostbyname_r(nrtm->server, &result, line_buff, sizeof(line_buff), &error);
95 |
96 | /* Check if it is a network stream or a file */
97 | if (hptr) { /* this is a network stream*/
98 | paddr=(struct in_addr *)hptr->h_addr;
99 | bzero(&serv_addr, sizeof(serv_addr));
100 | serv_addr.sin_family=AF_INET;
101 | serv_addr.sin_port=nrtm->port;
102 | memcpy(&serv_addr.sin_addr, paddr, sizeof(struct in_addr));
103 | fprintf(stderr,"Trying %s port %d\n", inet_ntoa(serv_addr.sin_addr), nrtm->port);
104 | if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))==-1) {
105 | perror("connect");
106 | return(-1);
107 | }
108 | fprintf(stderr, "Sending Invitation\n");
109 |
110 | /* Request all available serials (upto LAST), or SBUNCH of them */
111 | if(upto_last)
112 | sprintf(line_buff, "-g %s:%d:%ld-LAST\n", source, nrtm->version, nrtm->current_serial+1);
113 | else
114 | sprintf(line_buff, "-g %s:%d:%ld-%ld\n", source, nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH);
115 | nwrite=SK_write(sockfd, line_buff, strlen(line_buff) );
116 | if(nwrite != strlen(line_buff)) { perror("write"); return(-1); }
117 | fd=sockfd;
118 | network=1;
119 | fprintf(stderr, "Returning stream pointer\n");
120 | }
121 | else { /* this is a file stream*/
122 | network=0;
123 | close(sockfd);
124 | fprintf(stderr, "Trying file ...\n");
125 | if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) {
126 | perror("open");
127 | return(-1);
128 | }
129 | }
130 | return(fd);
131 | }
132 |
133 | /************************************************************
134 | * void UD_do_nrtm() *
135 | * *
136 | * Processes NRTM stream *
137 | * *
138 | * It cycles requesting objects from the NRTM server, *
139 | * processing them and then sleeping a specified amount of *
140 | * time. *
141 | * *
142 | * It starts by requesting SBUNCH number of serials and does *
143 | * so untill no serials are received (actually a warning *
144 | * is received saying that the requested range is invalid) *
145 | * This approach avoids excessive load on the NRTM server *
146 | * *
147 | * After that it requests serials using LAST keyward keeping *
148 | * almost in sync with the server *
149 | * *
150 | ************************************************************/
151 |
152 | void UD_do_nrtm(void *arg)
153 | {
154 | int source = (int)arg;
155 | UD_stream_t ud_stream;
156 | struct _nrtm *nrtm;
157 | int delay;
158 | int do_update=1;
159 | int do_server;
160 | char *logfilename;
161 | FILE *file;
162 | int nrtm_fd;
163 | int num_ok;
164 | int upto_last;
165 | char ta_activity[STR_M];
166 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source);
167 | char *db_host, *db_name, *db_user, *db_passwd;
168 | int db_port;
169 | char *source_name;
170 |
171 |
172 |
173 | nrtm=calloc(1, sizeof(struct _nrtm));
174 | if(nrtm==NULL) {
175 | printf("Cannot allocate memory\n");
176 | die;
177 | }
178 | /* get mode of operation: protected/unprotected (dummy) */
179 | ud_stream.source_hdl=source_hdl;
180 | ud_stream.ud_mode=ca_get_srcmode(source_hdl);
181 |
182 | fprintf(stderr, "Mode of operation:\n");
183 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n");
184 | else fprintf(stderr, "* dummy not allowed\n");
185 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n");
186 | else fprintf(stderr, "* NRTM\n");
187 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n");
188 | else fprintf(stderr, "* running as a server\n");
189 |
190 | /* get mirror server */
191 | nrtm->server=ca_get_srcnrtmhost(source_hdl);
192 |
193 |
194 | /* get mirror port */
195 | nrtm->port = htons(ca_get_srcnrtmport(source_hdl));
196 | printf("XXX nrtm_port=%d\n", ntohs(nrtm->port));
197 |
198 | /*
199 | if(nrtm->port == -1) {
200 | printf("Invalid service/port: %d\n", nrtm->port);
201 | return;
202 | }
203 | */
204 |
205 | /* get mirror version */
206 | nrtm->version=ca_get_srcnrtmprotocolvers(source_hdl);
207 |
208 | /* get source we are going to mirror */
209 | source_name = ca_get_srcname(source_hdl);
210 |
211 |
212 | /* get error log facility */
213 | logfilename=ca_get_srcnrtmlog(source_hdl);
214 |
215 | db_host = ca_get_srcdbmachine(source_hdl);
216 | db_port = ca_get_srcdbport(source_hdl);
217 | db_name = ca_get_srcdbname(source_hdl);
218 | db_user = ca_get_srcdbuser(source_hdl);
219 | db_passwd = ca_get_srcdbpassword(source_hdl);
220 |
221 | /* Connect to the database */
222 | fprintf(stderr, "D: Making SQL connection to %s@%s ...", db_name, db_host);
223 | ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
224 |
225 |
226 | if(! ud_stream.db_connection) {
227 | fprintf(stderr, "D: ERROR: no SQL connection\n");
228 | die;
229 | }
230 |
231 | fprintf(stderr, "OK\n");
232 |
233 | ud_stream.num_skip=0;
234 | ud_stream.load_pass=0;
235 | ud_stream.nrtm=nrtm;
236 | ud_stream.log.logfile = fopen(logfilename, "a+");
237 | if(!ud_stream.log.logfile){
238 | fprintf(stderr, "D: ERROR: cannot open log file %s\n", logfilename);
239 | die;
240 | }
241 |
242 | free(logfilename);
243 |
244 |
245 | upto_last=0; /* let's start gradually if the backlog is > SBUNCH (1000) serials*/
246 |
247 | /*+++ main cycle +++*/
248 |
249 | do {
250 | do_update=CO_get_do_update();
251 | if(do_update) {
252 |
253 | /* Check connection to the database and try to reconnect */
254 | if(mysql_ping(ud_stream.db_connection)) {
255 | fprintf(stderr, "D: ERROR: SQL connection time out - reestablishing\n");
256 | }
257 |
258 | /* get current serial */
259 | nrtm->current_serial=PM_get_current_serial(ud_stream.db_connection);
260 |
261 | if(nrtm->current_serial == -1) {
262 | fprintf(stderr, "D: ERROR: Error obtaining current serial: %ld\n", nrtm->current_serial);
263 | die;
264 | }
265 |
266 | fprintf(stderr, "current_serial:\t%ld\n", nrtm->current_serial);
267 | fprintf(stderr, "conecting to server...\n");
268 |
269 | /* Get file descriptor of the data stream (RPSL format, use mirror reflector to convert if needed)*/
270 | nrtm_fd=get_NRTM_fd(nrtm, upto_last, source_name);
271 |
272 | /* make a record for thread accounting */
273 | TA_add(nrtm_fd, "nrtm_clnt");
274 | sprintf(ta_activity,"[%s]%ld->", source_name, nrtm->current_serial);
275 | TA_setactivity(ta_activity);
276 | file=fdopen(nrtm_fd, "r+");
277 |
278 |
279 | fprintf(stderr, "OK\n");
280 | printf("OK\n");
281 |
282 |
283 | if (file==NULL) {
284 | fprintf(stderr, "Cannot open data stream. Trying...\n");
285 | sleep(100);
286 | continue;
287 | }
288 |
289 |
290 | ud_stream.stream=file;
291 | ud_stream.log.num_ok=0;
292 | ud_stream.log.num_failed=0;
293 |
294 |
295 | fprintf(stderr, "starting processing stream\n");
296 |
297 | num_ok=UD_process_stream(&ud_stream);
298 |
299 |
300 | /*Check for errors */
301 | if(num_ok<0) {
302 | fprintf(stderr, "processing stream failed\n");
303 | do_server=0;
304 | break;
305 | }
306 | else fprintf(stderr, "processing stream finished\n");
307 |
308 | /* Now we can process serials in normal way (upto LAST)*/
309 | if(num_ok==0) upto_last=1;
310 |
311 | fprintf(ud_stream.log.logfile, "forwarded to serial:\t%ld\n", (nrtm->current_serial+num_ok));
312 | fflush(ud_stream.log.logfile);
313 | fprintf(stderr, "forwarded to serial:\t%ld\n", (nrtm->current_serial+num_ok));
314 | printf("Objects received: %d\n-----------\n", num_ok);
315 |
316 | /* set activity for thread record */
317 | sprintf(ta_activity,"[%s]->%ld", source_name, (nrtm->current_serial+num_ok));
318 | TA_setactivity(ta_activity);
319 |
320 |
321 | /* get delay */
322 | delay=ca_get_srcnrtmdelay(source_hdl);
323 | SV_sleep(LOCK_SHTDOWN, delay);
324 | } /* if do_updates */
325 | else SV_sleep(LOCK_SHTDOWN, TIMEOUT);
326 |
327 | do_server=CO_get_do_server();
328 | TA_delete();
329 |
330 | } while(do_server); /* main cycle */
331 |
332 | fclose(ud_stream.log.logfile);
333 | free(source_name);
334 | /* free data associated with nrtm structure */
335 | if(nrtm) {
336 | free(nrtm->server);
337 | free(nrtm);
338 | }
339 |
340 | /* That's all. Close connection to the DB */
341 | SQ_close_connection(ud_stream.db_connection);
342 | free(db_host);
343 | free(db_name);
344 | free(db_user);
345 | free(db_passwd);
346 |
347 | fprintf(stderr, "NRTM stopped\n");
348 |
349 | } /* UD_do_nrtm() */
350 |
351 | /************************************************************
352 | * void UD_do_updates() *
353 | * *
354 | * Processes updates *
355 | * *
356 | * It cycles accepting connections and processing them *
357 | * (interactive server). This assures that there is only *
358 | * one write thread per database/source. *
359 | * *
360 | ************************************************************/
361 |
362 | void UD_do_updates(void *arg)
363 | {
364 | int source = (int)arg;
365 | int listening_socket = SV_update_sock[source];
366 | int connected_socket;
367 | UD_stream_t ud_stream;
368 | int do_update=1;
369 | int do_server;
370 | char *logfilename;
371 | FILE *file, *file_ack;
372 | int num_ok;
373 | ca_dbSource_t *source_hdl = ca_get_SourceHandleByPosition(source);
374 | char *db_host, *db_name, *db_user, *db_passwd;
375 | int db_port;
376 |
377 |
378 |
379 | /* get mode of operation: protected/unprotected (dummy) */
380 | /* ud_stream.ud_mode=CO_get_update_mode(); */
381 | ud_stream.source_hdl=source_hdl;
382 | ud_stream.ud_mode=ca_get_srcmode(source_hdl);
383 |
384 | fprintf(stderr, "Mode of operation:\n");
385 | if(IS_DUMMY_ALLOWED(ud_stream.ud_mode))fprintf(stderr, "* dummy allowed\n");
386 | else fprintf(stderr, "* dummy not allowed\n");
387 | if(IS_UPDATE(ud_stream.ud_mode))fprintf(stderr, "* DBupdate\n");
388 | else fprintf(stderr, "* NRTM\n");
389 | if(IS_STANDALONE(ud_stream.ud_mode))fprintf(stderr, "* running standalone\n");
390 | else fprintf(stderr, "* running as a server\n");
391 |
392 |
393 | /* get error log facility */
394 | logfilename=ca_get_srcnrtmlog(source_hdl);
395 | db_host = ca_get_srcdbmachine(source_hdl);
396 | db_port = ca_get_srcdbport(source_hdl);
397 | db_name = ca_get_srcdbname(source_hdl);
398 | db_user = ca_get_srcdbuser(source_hdl);
399 | db_passwd = ca_get_srcdbpassword(source_hdl);
400 |
401 | /* Connect to the database */
402 | fprintf(stderr, "D: Making SQL connection to %s@%s ...", db_name, db_host);
403 |
404 | /* ud_stream.db_connection=SQ_get_connection2(); */
405 | ud_stream.db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
406 |
407 | if(! ud_stream.db_connection) {
408 | fprintf(stderr, "D: ERROR: no SQL connection\n");
409 | die;
410 | }
411 |
412 | fprintf(stderr, "OK\n");
413 |
414 | ud_stream.num_skip=0;
415 | ud_stream.load_pass=0;
416 | ud_stream.nrtm=NULL;
417 | ud_stream.log.logfile = fopen(logfilename, "a+");
418 | if(!ud_stream.log.logfile){
419 | fprintf(stderr, "D: ERROR: cannot open log file %s\n", logfilename);
420 | die;
421 | }
422 |
423 | free(logfilename);
424 |
425 |
426 | /*+++ main cycle +++*/
427 |
428 | do { /* be alive while do_server is 1. do_server is turned off by SIGINT */
429 |
430 | /* make a record for thread accounting */
431 | TA_add(listening_socket, "update");
432 | TA_setactivity("waiting");
433 |
434 |
435 | /* accept connection */
436 | connected_socket = SK_accept_connection(listening_socket);
437 | if(connected_socket==-1) break;
438 |
439 |
440 | /* make a record for thread accounting */
441 | TA_delete(); /* Delete 'waiting' record */
442 | TA_add(connected_socket, "update");
443 |
444 | file=fdopen(connected_socket, "r");
445 | file_ack=fdopen(connected_socket, "w");
446 |
447 | do_update=CO_get_do_update();
448 | if(do_update) {
449 |
450 | TA_setactivity("suspended");
451 |
452 | fprintf(stderr, "Connection accepted...\n");
453 |
454 | if ((file==NULL) || (file_ack==NULL)) {
455 | fprintf(stderr, "Cannot open data stream. Closing connction\n");
456 | return;
457 | }
458 | fprintf(stderr, "Connection accepted...\n");
459 |
460 | ud_stream.stream=file;
461 | ud_stream.log.num_ok=0;
462 | ud_stream.log.num_failed=0;
463 |
464 | /* Check connection to the database and try to reconnect*/
465 | if(mysql_ping(ud_stream.db_connection)) {
466 | fprintf(stderr, "D: ERROR: SQL connection time out - reestablishing\n");
467 | }
468 |
469 | fprintf(stderr, "starting processing object\n");
470 |
471 | num_ok=UD_process_stream(&ud_stream);
472 |
473 | fprintf(stderr, "processing object finished\n");
474 |
475 | if(num_ok==1) {
476 | fprintf(file_ack, "%%ERROR 0\n");
477 | fprintf(stderr, "%%ERROR 0\n");
478 | }
479 | else {
480 | num_ok=(-1)*num_ok;
481 | fprintf(file_ack, "%%ERROR %d\n",num_ok);
482 | fprintf(stderr, "%%ERROR %d\n",num_ok);
483 | fprintf(file_ack, "Transaction had the following problems:\n");
484 | if(num_ok & ERROR_U_MEM) fprintf(file_ack, "Memory allocation error\n");
485 | /* if(num_ok & ERROR_U_DBS) fprintf(file_ack, "Database (SQL) error\n");*/
486 | /* if(num_ok & ERROR_U_OBJ) fprintf(file_ack, "Object (RF) error\n");*/
487 | /* if(num_ok & ERROR_U_AUT) fprintf(file_ack, "Object authentication error\n");*/
488 | if(num_ok & ERROR_U_BADOP) fprintf(file_ack, "Bad operation\n");
489 | if(num_ok & ERROR_U_COP) fprintf(file_ack, "Conflicting operation\n");
490 | if(num_ok & ERROR_U_NSUP) fprintf(file_ack, "Object of this type is not supported\n");
491 | if(num_ok & ERROR_U_BUG) fprintf(file_ack, "Software bug - report to <ripe-dbm@ripe.net>\n");
492 | }
493 | if(ud_stream.error_script)fprintf(file_ack, "%s\n", ud_stream.error_script);
494 |
495 | if(ud_stream.error_script) free(ud_stream.error_script);
496 |
497 | fflush(file_ack); fclose(file_ack);
498 | fclose(file);
499 | } /* if do_update*/
500 | else { /* Otherwise print a message*/
501 | /* To display with 'show threads' */
502 | TA_setactivity("suspended");
503 |
504 | fprintf(file_ack, "%%ERROR 1000\n%%Updates are suspended\n");
505 | fflush(file_ack); fclose(file_ack);
506 | fclose(file);
507 | }
508 | /* make a record for thread accounting */
509 | TA_delete();
510 |
511 | do_server=CO_get_do_server();
512 |
513 | } while (do_server); /* main cycle */
514 |
515 | fclose(ud_stream.log.logfile);
516 | /* That's all. Close connection to the DB */
517 | SQ_close_connection(ud_stream.db_connection);
518 | free(db_host);
519 | free(db_name);
520 | free(db_user);
521 | free(db_passwd);
522 |
523 |
524 | fprintf(stderr, "server stopped\n");
525 |
526 | } /* UD_do_update() */
527 |
528 |
529 |
530 |