source: ntrip/trunk/ntripserver/ntripserver.c@ 598

Last change on this file since 598 was 598, checked in by stoecker, 16 years ago

added Connection: close

File size: 56.4 KB
Line 
1/*
2 * $Id: ntripserver.c,v 1.35 2007/08/30 16:40:51 stoecker Exp $
3 *
4 * Copyright (c) 2003...2007
5 * German Federal Agency for Cartography and Geodesy (BKG)
6 *
7 * Developed for Networked Transport of RTCM via Internet Protocol (NTRIP)
8 * for streaming GNSS data over the Internet.
9 *
10 * Designed by Informatik Centrum Dortmund http://www.icd.de
11 *
12 * The BKG disclaims any liability nor responsibility to any person or
13 * entity with respect to any loss or damage caused, or alleged to be
14 * caused, directly or indirectly by the use and application of the NTRIP
15 * technology.
16 *
17 * For latest information and updates, access:
18 * http://igs.bkg.bund.de/index_ntrip_down.htm
19 *
20 * BKG, Frankfurt, Germany, February 2007
21 * E-mail: euref-ip@bkg.bund.de
22 *
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 */
37
38/* CVS revision and version */
39static char revisionstr[] = "$Revision: 1.35 $";
40static char datestr[] = "$Date: 2007/08/30 16:40:51 $";
41
42#include <ctype.h>
43#include <errno.h>
44#include <fcntl.h>
45#include <getopt.h>
46#include <netdb.h>
47#include <signal.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52#include <arpa/inet.h>
53#include <netinet/in.h>
54#include <sys/socket.h>
55#include <sys/termios.h>
56#include <sys/types.h>
57#include <sys/time.h>
58
59#ifndef COMPILEDATE
60#define COMPILEDATE " built " __DATE__
61#endif
62
63#ifndef MSG_DONTWAIT
64#define MSG_DONTWAIT 0 /* prevent compiler errors */
65#endif
66#ifndef O_EXLOCK
67#define O_EXLOCK 0 /* prevent compiler errors */
68#endif
69
70enum MODE { SERIAL = 1, TCPSOCKET = 2, INFILE = 3, SISNET = 4, UDPSOCKET = 5,
71CASTER = 6, LAST };
72
73enum OUTMODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, END };
74
75#define AGENTSTRING "NTRIP NtripServerPOSIX"
76#define BUFSZ 1024
77#define SZ 64
78
79/* default socket source */
80#define SERV_HOST_ADDR "localhost"
81#define SERV_TCP_PORT 2101
82
83/* default destination */
84#define NTRIP_CASTER "www.euref-ip.net"
85#define NTRIP_PORT 2101
86
87/* default sisnet source */
88#define SISNET_SERVER "131.176.49.142"
89#define SISNET_PORT 7777
90
91#define ALARMTIME 60
92
93#define RTP_VERSION 2
94#define TIME_RESOLUTION 125
95
96static int ttybaud = 19200;
97static const char *ttyport = "/dev/gps";
98static const char *filepath = "/dev/stdin";
99static enum MODE inputmode = INFILE;
100static int sisnet = 31;
101static int gpsfd = -1;
102static int socket_tcp = -1;
103static int socket_udp = -1;
104static int sigint_received = 0;
105static int sigalarm_received = 0;
106static int sigpipe_received = 0;
107static int reconnect_sec = 1;
108
109
110/* Forward references */
111static int openserial(const char * tty, int blocksz, int baud);
112static void send_receive_loop(int sock, int fd, int outmode,
113 struct sockaddr * pcasterRTP, socklen_t length);
114static void usage(int, char *);
115static int encode(char *buf, int size, const char *user, const char *pwd);
116static int send_to_caster(char *input, int socket, int input_size);
117static void close_session(const char *caster_addr, const char *mountpoint,
118 int cseq, int session, char *rtsp_ext, int fallback);
119static int reconnect(int rec_sec, int rec_sec_max);
120
121/* Signal Handling */
122static void handle_sigint(int sig);
123static void handle_alarm(int sig);
124static void handle_sigpipe(int sig);
125static void setup_signal_handler(int sig, void (*handler)(int));
126
127/*
128* main
129*
130* Main entry point for the program. Processes command-line arguments and
131* prepares for action.
132*
133* Parameters:
134* argc : integer : Number of command-line arguments.
135* argv : array of char : Command-line arguments as an array of
136* zero-terminated pointers to strings.
137*
138* Return Value:
139* The function does not return a value (although its return type is int).
140*
141* Remarks:
142*
143*/
144
145int main(int argc, char **argv)
146{
147 int c;
148 int size = 2048; /* for setting send buffer size */
149 struct sockaddr_in caster;
150 const char * proxyhost = "";
151 unsigned int proxyport = 0;
152 /*** INPUT ***/
153 const char * casterinhost = 0;
154 unsigned int casterinport = 0;
155 const char * inhost = 0;
156 unsigned int inport = 0;
157
158 char get_extension[SZ] = "";
159
160 struct hostent * he;
161 const char * mountpoint = NULL;
162
163 const char * sisnetpassword = "";
164 const char * sisnetuser = "";
165
166 const char * stream_name = 0;
167 const char * stream_user = 0;
168 const char * stream_password = 0;
169
170 const char * recvrid= 0;
171 const char * recvrpwd = 0;
172
173 const char * initfile = NULL;
174
175 int bindmode = 0;
176
177 /*** OUTPUT ***/
178 const char * casterouthost = NTRIP_CASTER;
179 unsigned int casteroutport = NTRIP_PORT;
180 const char * outhost = 0;
181 unsigned int outport = 0;
182 char post_extension[SZ] = "";
183 char rtsp_extension[SZ] = "";
184
185 const char * ntrip_str = "";
186
187 const char * user = "";
188 const char * password = "";
189
190 int outputmode = NTRIP1;
191
192 struct sockaddr_in casterRTP;
193 struct sockaddr_in local;
194 int client_port = 0;
195 int server_port = 0;
196 int session = 0;
197 int cseq = 0;
198 socklen_t len = 0;
199 int i = 0;
200
201 char szSendBuffer[BUFSZ];
202 char authorization[SZ];
203 int nBufferBytes = 0;
204 char * dlim = " \r\n=";
205 char * token;
206 char * tok_buf[BUFSZ];
207
208 int reconnect_sec_max = 0;
209
210 setbuf(stdout, 0);
211 setbuf(stdin, 0);
212 setbuf(stderr, 0);
213
214 {
215 char *a;
216 int i = 0;
217 for(a = revisionstr+11; *a && *a != ' '; ++a)
218 revisionstr[i++] = *a;
219 revisionstr[i] = 0;
220 datestr[0] = datestr[7];
221 datestr[1] = datestr[8];
222 datestr[2] = datestr[9];
223 datestr[3] = datestr[10];
224 datestr[5] = datestr[12];
225 datestr[6] = datestr[13];
226 datestr[8] = datestr[15];
227 datestr[9] = datestr[16];
228 datestr[4] = datestr[7] = '-';
229 datestr[10] = 0;
230 }
231
232 /* setup signal handler for timeout */
233 setup_signal_handler(SIGALRM, handle_alarm);
234 alarm(ALARMTIME);
235
236 /* setup signal handler for CTRL+C */
237 setup_signal_handler(SIGINT, handle_sigint);
238
239/* setup signal handler for boken pipe */
240 setup_signal_handler(SIGPIPE, handle_sigpipe);
241
242 /* get and check program arguments */
243 if(argc <= 1)
244 {
245 usage(2, argv[0]);
246 exit(1);
247 }
248 while((c = getopt(argc, argv,
249 "M:i:h:b:p:s:a:m:c:H:P:f:x:y:l:u:V:D:U:W:O:E:F:R:N:n:B")) != EOF)
250 {
251 switch (c)
252 {
253 case 'M': /*** InputMode ***/
254 if(!strcmp(optarg, "serial")) inputmode = SERIAL;
255 else if(!strcmp(optarg, "tcpsocket")) inputmode = TCPSOCKET;
256 else if(!strcmp(optarg, "file")) inputmode = INFILE;
257 else if(!strcmp(optarg, "sisnet")) inputmode = SISNET;
258 else if(!strcmp(optarg, "udpsocket")) inputmode = UDPSOCKET;
259 else if(!strcmp(optarg, "caster")) inputmode = CASTER;
260 else inputmode = atoi(optarg);
261 if((inputmode == 0) || (inputmode >= LAST))
262 {
263 fprintf(stderr, "ERROR: can't convert <%s> to a valid InputMode\n",
264 optarg);
265 usage(-1, argv[0]);
266 }
267 break;
268 case 'i': /* serial input device */
269 ttyport = optarg;
270 break;
271 case 'B': /* bind to incoming UDP stream */
272 bindmode = 1;
273 break;
274 case 'V': /* Sisnet data server version number */
275 if(!strcmp("3.0", optarg)) sisnet = 30;
276 else if(!strcmp("3.1", optarg)) sisnet = 31;
277 else if(!strcmp("2.1", optarg)) sisnet = 21;
278 else
279 {
280 fprintf(stderr, "ERROR: unknown SISNeT version <%s>\n", optarg);
281 usage(-2, argv[0]);
282 }
283 break;
284 case 'b': /* serial input baud rate */
285 ttybaud = atoi(optarg);
286 if(ttybaud <= 1)
287 {
288 fprintf(stderr, "ERROR: can't convert <%s> to valid serial baud rate\n",
289 optarg);
290 usage(1, argv[0]);
291 }
292 break;
293 case 'a': /* Destination caster address */
294 casterouthost = optarg;
295 break;
296 case 'p': /* Destination caster port */
297 casteroutport = atoi(optarg);
298 if(casteroutport <= 1 || casteroutport > 65535)
299 {
300 fprintf(stderr,
301 "ERROR: can't convert <%s> to a valid HTTP server port\n", optarg);
302 usage(1, argv[0]);
303 }
304 break;
305 case 'm': /* Destination caster mountpoint for stream upload */
306 mountpoint = optarg;
307 break;
308 case 's': /* File name for input data simulation from file */
309 filepath = optarg;
310 break;
311 case 'f': /* name of an initialization file */
312 initfile = optarg;
313 break;
314 case 'x': /* user ID to access incoming stream */
315 recvrid = optarg;
316 break;
317 case 'y': /* password to access incoming stream */
318 recvrpwd = optarg;
319 break;
320 case 'u': /* Sisnet data server user ID */
321 sisnetuser = optarg;
322 break;
323 case 'l': /* Sisnet data server password */
324 sisnetpassword = optarg;
325 break;
326 case 'c': /* DestinationCaster password for stream upload to mountpoint */
327 password = optarg;
328 break;
329 case 'H': /* Input host address*/
330 casterinhost = optarg;
331 break;
332 case 'P': /* Input port */
333 casterinport = atoi(optarg);
334 if(casterinport <= 1 || casterinport > 65535)
335 {
336 fprintf(stderr, "ERROR: can't convert <%s> to a valid port number\n",
337 optarg);
338 usage(1, argv[0]);
339 }
340 break;
341 case 'D': /* Source caster mountpoint for stream input */
342 stream_name = optarg;
343 break;
344 case 'U': /* Source caster user ID for input stream access */
345 stream_user = optarg;
346 break;
347 case 'W': /* Source caster password for input stream access */
348 stream_password = optarg;
349 break;
350 case 'E': /* Proxy Server */
351 proxyhost = optarg;
352 break;
353 case 'F': /* Proxy port */
354 proxyport = atoi(optarg);
355 break;
356 case 'R': /* maximum delay between reconnect attempts in seconds */
357 reconnect_sec_max = atoi(optarg);
358 break;
359 case 'O': /* OutputMode */
360 outputmode = 0;
361 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
362 outputmode = NTRIP1;
363 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
364 outputmode = HTTP;
365 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
366 outputmode = RTSP;
367 else outputmode = atoi(optarg);
368 if((outputmode == 0) || (outputmode >= END))
369 {
370 fprintf(stderr, "ERROR: can't convert <%s> to a valid OutputMode\n",
371 optarg);
372 usage(-1, argv[0]);
373 }
374 break;
375 case 'n': /* Destination caster user ID for stream upload to mountpoint */
376 user = optarg;
377 break;
378 case 'N': /* Ntrip-STR, optional for Ntrip Version 2.0 */
379 ntrip_str = optarg;
380 break;
381 case 'h': /* print help screen */
382 case '?':
383 usage(0, argv[0]);
384 break;
385 default:
386 usage(2, argv[0]);
387 break;
388 }
389 }
390
391 argc -= optind;
392 argv += optind;
393
394 /*** argument analysis ***/
395 if(argc > 0)
396 {
397 fprintf(stderr, "ERROR: Extra args on command line: ");
398 for(; argc > 0; argc--)
399 {
400 fprintf(stderr, " %s", *argv++);
401 }
402 fprintf(stderr, "\n");
403 usage(1, argv[0]); /* never returns */
404 }
405
406 if(outputmode != NTRIP1)
407 {
408 fprintf(stderr, "\nWARNING: *** NTRIP VERSION 2 PROTOCOL IS STILL"
409 " BETA AND MAY BE CHANGED ***\n\n");
410 }
411
412 if(*ntrip_str && (outputmode == NTRIP1))
413 {
414 fprintf(stderr, "WARNING: OutputMode is Ntrip version 1.0"
415 " - Ntrip-STR will not be considered\n");
416 }
417
418 if((reconnect_sec_max > 0) && (reconnect_sec_max < 256))
419 {
420 fprintf(stderr,
421 "WARNING: maximum delay between reconnect attemts changed from %d to 256 seconds\n"
422 , reconnect_sec_max);
423 reconnect_sec_max = 256;
424 }
425
426 if(!mountpoint)
427 {
428 fprintf(stderr, "ERROR: Missing mountpoint argument for stream upload\n");
429 exit(1);
430 }
431
432 if(!password[0])
433 {
434 fprintf(stderr, "WARNING: Missing password argument for stream upload - "
435 "are you really sure?\n");
436 }
437 else
438 {
439 nBufferBytes += encode(authorization, sizeof(authorization), user,
440 password);
441 if(nBufferBytes > (int)sizeof(authorization))
442 {
443 fprintf(stderr, "ERROR: user ID and/or password too long: %d (%d)\n"
444 " user ID: %s \npassword: <%s>\n",
445 nBufferBytes, (int)sizeof(authorization), user, password);
446 exit(1);
447 }
448 }
449
450 if(stream_name && stream_user && !stream_password)
451 {
452 fprintf(stderr, "WARNING: Missing password argument for stream download"
453 " - are you really sure?\n");
454 }
455
456 /*** proxy server handling ***/
457 if(*proxyhost)
458 {
459 outhost = inhost = proxyhost;
460 outport = inport = proxyport;
461 i = snprintf(szSendBuffer, sizeof(szSendBuffer),"http://%s:%d",
462 casterouthost, casteroutport);
463 if((i > SZ) || (i < 0))
464 {
465 fprintf(stderr, "ERROR: Destination caster name/port to long - "
466 "length = %d (max: %d)\n", i, SZ);
467 exit(0);
468 }
469 else
470 {
471 strncpy(post_extension, szSendBuffer, (size_t)i);
472 strcpy(szSendBuffer, "");
473 i = snprintf(szSendBuffer, sizeof(szSendBuffer),":%d", casteroutport);
474 strncpy(rtsp_extension, szSendBuffer, SZ);
475 strcpy(szSendBuffer,""); i = 0;
476 }
477 i = snprintf(szSendBuffer, sizeof(szSendBuffer),"http://%s:%d", casterinhost, casterinport);
478 if((i > SZ) || (i < 0))
479 {
480 fprintf(stderr,"ERROR: Destination caster name/port to long - length = %d (max: %d)\n", i, SZ);
481 exit(0);
482 }
483 else
484 {
485 strncpy(get_extension, szSendBuffer, (size_t)i);
486 strcpy(szSendBuffer, "");
487 i = 0;
488 }
489 }
490 else
491 {
492 outhost = casterouthost; outport = casteroutport;
493 inhost = casterinhost; inport = casterinport;
494 }
495
496 while(inputmode != LAST)
497 {
498 int input_init = 1;
499 /*** InputMode handling ***/
500 switch(inputmode)
501 {
502 case INFILE:
503 {
504 if((gpsfd = open(filepath, O_RDONLY)) < 0)
505 {
506 perror("ERROR: opening input file");
507 exit(1);
508 }
509 /* set blocking inputmode in case it was not set
510 (seems to be sometimes for fifo's) */
511 fcntl(gpsfd, F_SETFL, 0);
512 printf("file input: file = %s\n", filepath);
513 }
514 break;
515 case SERIAL: /* open serial port */
516 {
517 gpsfd = openserial(ttyport, 1, ttybaud);
518 if(gpsfd < 0)
519 {
520 exit(1);
521 }
522 printf("serial input: device = %s, speed = %d\n", ttyport, ttybaud);
523 }
524 break;
525 case TCPSOCKET: case UDPSOCKET: case SISNET: case CASTER:
526 {
527 if(inputmode == SISNET)
528 {
529 if(!inhost) inhost = SISNET_SERVER;
530 if(!inport) inport = SISNET_PORT;
531 }
532 else if(inputmode == CASTER)
533 {
534 if(!inport) inport = NTRIP_PORT;
535 if(!inhost) inhost = NTRIP_CASTER;
536 }
537 else if((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET))
538 {
539 if(!inport) inport = SERV_TCP_PORT;
540 if(!inhost) inhost = SERV_HOST_ADDR;
541 }
542
543 if(!(he = gethostbyname(inhost)))
544 {
545 fprintf(stderr, "ERROR: Input host <%s> unknown\n", inhost);
546 usage(-2, argv[0]);
547 }
548
549 if((gpsfd = socket(AF_INET, inputmode == UDPSOCKET
550 ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
551 {
552 fprintf(stderr,
553 "ERROR: can't create socket for incoming data stream\n");
554 exit(1);
555 }
556
557 memset((char *) &caster, 0x00, sizeof(caster));
558 if(!bindmode)
559 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
560 caster.sin_family = AF_INET;
561 caster.sin_port = htons(inport);
562
563 fprintf(stderr, "%s input: host = %s, port = %d, %s%s%s%s%s\n",
564 inputmode == CASTER ? "caster" : inputmode == SISNET ? "sisnet" :
565 inputmode == TCPSOCKET ? "tcp socket" : "udp socket",
566 bindmode ? "127.0.0.1" : inet_ntoa(caster.sin_addr),
567 inport, stream_name ? "stream = " : "", stream_name ? stream_name : "",
568 initfile ? ", initfile = " : "", initfile ? initfile : "",
569 bindmode ? "binding mode" : "");
570
571 if(bindmode)
572 {
573 if(bind(gpsfd, (struct sockaddr *) &caster, sizeof(caster)) < 0)
574 {
575 fprintf(stderr, "ERROR: can't bind input to port %d\n", inport);
576 reconnect_sec_max = 0;
577 input_init = 0;
578 break;
579 }
580 } /* connect to input-caster or proxy server*/
581 else if(connect(gpsfd, (struct sockaddr *)&caster, sizeof(caster)) < 0)
582 {
583 fprintf(stderr, "WARNING: can't connect input to %s at port %d\n",
584 inet_ntoa(caster.sin_addr), inport);
585 input_init = 0;
586 break;
587 }
588
589 if(stream_name) /* input from Ntrip Version 1.0 caster*/
590 {
591 int init = 0;
592
593 /* set socket buffer size */
594 setsockopt(gpsfd, SOL_SOCKET, SO_SNDBUF, (const char *) &size,
595 sizeof(const char *));
596 if(stream_user && stream_password)
597 {
598 /* leave some space for login */
599 nBufferBytes=snprintf(szSendBuffer, sizeof(szSendBuffer)-40,
600 "GET %s/%s HTTP/1.0\r\n"
601 "User-Agent: %s/%s\r\n"
602 "Connection: close\r\n"
603 "Authorization: Basic ", get_extension, stream_name,
604 AGENTSTRING, revisionstr);
605 /* second check for old glibc */
606 if(nBufferBytes > (int)sizeof(szSendBuffer)-40 || nBufferBytes < 0)
607 {
608 fprintf(stderr, "ERROR: Source caster request too long\n");
609 input_init = 0;
610 reconnect_sec_max =0;
611 break;
612 }
613 nBufferBytes += encode(szSendBuffer+nBufferBytes,
614 sizeof(szSendBuffer)-nBufferBytes-4, stream_user, stream_password);
615 if(nBufferBytes > (int)sizeof(szSendBuffer)-4)
616 {
617 fprintf(stderr,
618 "ERROR: Source caster user ID and/or password too long\n");
619 input_init = 0;
620 reconnect_sec_max =0;
621 break;
622 }
623 szSendBuffer[nBufferBytes++] = '\r';
624 szSendBuffer[nBufferBytes++] = '\n';
625 szSendBuffer[nBufferBytes++] = '\r';
626 szSendBuffer[nBufferBytes++] = '\n';
627 }
628 else
629 {
630 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
631 "GET %s/%s HTTP/1.0\r\n"
632 "User-Agent: %s/%s\r\n"
633 "Connection: close\r\n"
634 "\r\n", get_extension, stream_name, AGENTSTRING, revisionstr);
635 }
636 if((send(gpsfd, szSendBuffer, (size_t)nBufferBytes, 0))
637 != nBufferBytes)
638 {
639 fprintf(stderr, "WARNING: could not send Source caster request\n");
640 input_init = 0;
641 break;
642 }
643 nBufferBytes = 0;
644 /* check Source caster's response */
645 while(!init && nBufferBytes < (int)sizeof(szSendBuffer)
646 && (nBufferBytes += recv(gpsfd, szSendBuffer,
647 sizeof(szSendBuffer)-nBufferBytes, 0)) > 0)
648 {
649 if(strstr(szSendBuffer, "\r\n"))
650 {
651 if(strncmp(szSendBuffer, "ICY 200 OK", 10))
652 {
653 int k;
654 fprintf(stderr,
655 "ERROR: could not get requested data from Source caster: ");
656 for(k = 0; k < nBufferBytes && szSendBuffer[k] != '\n'
657 && szSendBuffer[k] != '\r'; ++k)
658 {
659 fprintf(stderr, "%c", isprint(szSendBuffer[k])
660 ? szSendBuffer[k] : '.');
661 }
662 fprintf(stderr, "\n");
663 if(strncmp(szSendBuffer, "SOURCETABLE 200 OK",18))
664 {
665 reconnect_sec_max =0;
666 }
667 input_init = 0;
668 break;
669 }
670 else init = 1;
671 }
672 }
673 } /* end input from Ntrip Version 1.0 caster */
674
675 if(initfile && inputmode != SISNET)
676 {
677 char buffer[1024];
678 FILE *fh;
679 int i;
680
681 if((fh = fopen(initfile, "r")))
682 {
683 while((i = fread(buffer, 1, sizeof(buffer), fh)) > 0)
684 {
685 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
686 {
687 perror("WARNING: sending init file");
688 input_init = 0;
689 break;
690 }
691 }
692 if(i < 0)
693 {
694 perror("ERROR: reading init file");
695 reconnect_sec_max = 0;
696 input_init = 0;
697 break;
698 }
699 fclose(fh);
700 }
701 else
702 {
703 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
704 reconnect_sec_max = 0;
705 input_init = 0;
706 break;
707 }
708 }
709 }
710 if(inputmode == SISNET)
711 {
712 int i, j;
713 char buffer[1024];
714
715 i = snprintf(buffer, sizeof(buffer), sisnet >= 30 ? "AUTH,%s,%s\r\n"
716 : "AUTH,%s,%s", sisnetuser, sisnetpassword);
717 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
718 {
719 perror("WARNING: sending authentication for SISNeT data server");
720 input_init = 0;
721 break;
722 }
723 i = sisnet >= 30 ? 7 : 5;
724 if((j = recv(gpsfd, buffer, i, 0)) != i && strncmp("*AUTH", buffer, 5))
725 {
726 fprintf(stderr, "WARNING: SISNeT connect failed:");
727 for(i = 0; i < j; ++i)
728 {
729 if(buffer[i] != '\r' && buffer[i] != '\n')
730 {
731 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
732 }
733 }
734 fprintf(stderr, "\n");
735 input_init = 0;
736 break;
737 }
738 if(sisnet >= 31)
739 {
740 if((send(gpsfd, "START\r\n", 7, 0)) != i)
741 {
742 perror("WARNING: sending Sisnet start command");
743 input_init = 0;
744 break;
745 }
746 }
747 }
748 /*** receiver authentication ***/
749 if (recvrid && recvrpwd && ((inputmode == TCPSOCKET)
750 || (inputmode == UDPSOCKET)))
751 {
752 if (strlen(recvrid) > (BUFSZ-3))
753 {
754 fprintf(stderr, "ERROR: Receiver ID too long\n");
755 reconnect_sec_max = 0;
756 input_init = 0;
757 break;
758 }
759 else
760 {
761 fprintf(stderr, "Sending user ID for receiver...\n");
762 nBufferBytes = read(gpsfd, szSendBuffer, BUFSZ);
763 strcpy(szSendBuffer, recvrid);
764 strcat(szSendBuffer,"\r\n");
765 if(send(gpsfd,szSendBuffer, strlen(szSendBuffer), MSG_DONTWAIT) < 0)
766 {
767 perror("WARNING: sending user ID for receiver");
768 input_init = 0;
769 break;
770 }
771 }
772
773 if (strlen(recvrpwd) > (BUFSZ-3))
774 {
775 fprintf(stderr, "ERROR: Receiver password too long\n");
776 reconnect_sec_max = 0;
777 input_init = 0;
778 break;
779 }
780 else
781 {
782 fprintf(stderr, "Sending user password for receiver...\n");
783 nBufferBytes = read(gpsfd, szSendBuffer, BUFSZ);
784 strcpy(szSendBuffer, recvrpwd);
785 strcat(szSendBuffer,"\r\n");
786 if(send(gpsfd, szSendBuffer, strlen(szSendBuffer), MSG_DONTWAIT) < 0)
787 {
788 perror("WARNING: sending user password for receiver");
789 input_init = 0;
790 break;
791 }
792 }
793 }
794 break;
795 default:
796 usage(-1, argv[0]);
797 break;
798 }
799
800 /* ----- main part ----- */
801 int output_init = 1;
802
803 while((input_init) && (output_init))
804 {
805 if((sigint_received) || (sigalarm_received) || (sigpipe_received)) break;
806
807 if(!(he = gethostbyname(outhost)))
808 {
809 fprintf(stderr, "ERROR: Destination caster or proxy host <%s> unknown\n",
810 outhost);
811 close_session(casterouthost, mountpoint, cseq, session, rtsp_extension, 0);
812 usage(-2, argv[0]);
813 }
814
815 /* create socket */
816 if((socket_tcp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
817 {
818 perror("ERROR: tcp socket");
819 reconnect_sec_max = 0;
820 break;
821 }
822
823 memset((char *) &caster, 0x00, sizeof(caster));
824 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
825 caster.sin_family = AF_INET;
826 caster.sin_port = htons(outport);
827
828 /* connect to Destination caster or Proxy server*/
829 fprintf(stderr, "caster output: host = %s, port = %d, mountpoint = %s"
830 ", mode = %s\n\n", inet_ntoa(caster.sin_addr), outport, mountpoint,
831 outputmode == NTRIP1 ? "ntrip1" : outputmode == HTTP ? "http" : "rtsp");
832
833 if(connect(socket_tcp, (struct sockaddr *) &caster, sizeof(caster)) < 0)
834 {
835 fprintf(stderr, "WARNING: can't connect output to %s at port %d\n",
836 inet_ntoa(caster.sin_addr), outport);
837 break;
838 }
839
840 /*** OutputMode handling ***/
841 switch(outputmode)
842 {
843 case NTRIP1: /*** OutputMode Ntrip Version 1.0 ***/
844 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
845 "SOURCE %s %s/%s\r\n"
846 "Source-Agent: %s/%s\r\n\r\n",
847 password, post_extension, mountpoint, AGENTSTRING, revisionstr);
848 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
849 {
850 fprintf(stderr, "ERROR: Destination caster request to long\n");
851 reconnect_sec_max = 0;
852 output_init = 0;
853 break;
854 }
855 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
856 {
857 output_init = 0;
858 break;
859 }
860 /* check Destination caster's response */
861 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
862 szSendBuffer[nBufferBytes] = '\0';
863 if(!strstr(szSendBuffer, "OK"))
864 {
865 char *a;
866 fprintf(stderr,
867 "ERROR: Destination caster's or Proxy's reply is not OK: ");
868 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
869 {
870 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
871 }
872 fprintf(stderr, "\n");
873 if((strstr(szSendBuffer,"ERROR - Bad Password"))
874 || (strstr(szSendBuffer,"400 Bad Request")))
875 reconnect_sec_max = 0;
876 output_init = 0;
877 break;
878 }
879#ifndef NDEBUG
880 else
881 {
882 fprintf(stderr, "Destination caster response:\n%s\n",
883 szSendBuffer);
884 }
885#endif
886 send_receive_loop(socket_tcp, gpsfd, outputmode, NULL, 0);
887 break;
888 case HTTP: /*** Ntrip-Version 2.0 HTTP/1.1 ***/
889 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
890 "POST %s/%s HTTP/1.1\r\n"
891 "Host: %s\r\n"
892 "Ntrip-Version: Ntrip/2.0\r\n"
893 "User-Agent: %s/%s\r\n"
894 "Authorization: Basic %s\r\n"
895 "Ntrip-STR: %s\r\n"
896 "Connection: close\r\n"
897 "Transfer-Encoding: chunked\r\n\r\n",
898 post_extension, mountpoint, casterouthost, AGENTSTRING,
899 revisionstr, authorization, ntrip_str);
900 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
901 {
902 fprintf(stderr, "ERROR: Destination caster request to long\n");
903 reconnect_sec_max = 0;
904 output_init = 0;
905 break;
906 }
907 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
908 {
909 output_init = 0;
910 break;
911 }
912 /* check Destination caster's response */
913 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
914 szSendBuffer[nBufferBytes] = '\0';
915 if(!strstr(szSendBuffer, "HTTP/1.1 200 OK"))
916 {
917 char *a;
918 fprintf(stderr,
919 "ERROR: Destination caster's%s reply is not OK: ",
920 *proxyhost ? " or Proxy's" : "");
921 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
922 {
923 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
924 }
925 fprintf(stderr, "\n");
926 /* fallback if necessary */
927 if(!strstr(szSendBuffer,"Ntrip-Version: Ntrip/2.0\r\n"))
928 {
929 fprintf(stderr,
930 " Ntrip Version 2.0 not implemented at Destination caster"
931 " <%s>%s%s%s\n%s\n"
932 "ntripserver falls back to Ntrip Version 1.0\n\n",
933 casterouthost,
934 *proxyhost ? " or Proxy <" : "", proxyhost, *proxyhost ? ">" : "",
935 *proxyhost ? " or HTTP/1.1 not implemented at Proxy\n" : "");
936 close_session(casterouthost, mountpoint, cseq, session, rtsp_extension, 1);
937 outputmode = NTRIP1;
938 break;
939 }
940 else if((strstr(szSendBuffer,"HTTP/1.1 401 Unauthorized"))
941 || (strstr(szSendBuffer,"501 Not Implemented")))
942 {
943 reconnect_sec_max = 0;
944 }
945 output_init = 0;
946 break;
947 }
948#ifndef NDEBUG
949 else
950 {
951 fprintf(stderr, "Destination caster response:\n%s\n",szSendBuffer);
952 }
953#endif
954 send_receive_loop(socket_tcp, gpsfd, outputmode, NULL, 0);
955 break;
956 case RTSP: /*** Ntrip-Version 2.0 RTSP / RTP ***/
957 if((socket_udp = socket(AF_INET, SOCK_DGRAM,0)) < 0)
958 {
959 perror("ERROR: udp socket");
960 exit(4);
961 }
962 /* fill structure with local address information for UDP */
963 memset(&local, 0, sizeof(local));
964 local.sin_family = AF_INET;
965 local.sin_port = htons(0);
966 local.sin_addr.s_addr = htonl(INADDR_ANY);
967 len = (socklen_t)sizeof(local);
968 /* bind() in order to get a random RTP client_port */
969 if((bind(socket_udp,(struct sockaddr *)&local, len)) < 0)
970 {
971 perror("ERROR: udp bind");
972 reconnect_sec_max = 0;
973 output_init = 0;
974 break;
975 }
976 if((getsockname(socket_udp, (struct sockaddr*)&local, &len)) != -1)
977 {
978 client_port = (unsigned int)ntohs(local.sin_port);
979 }
980 else
981 {
982 perror("ERROR: getsockname(localhost)");
983 reconnect_sec_max = 0;
984 output_init = 0;
985 break;
986 }
987 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
988 "SETUP rtsp://%s%s/%s RTSP/1.0\r\n"
989 "CSeq: 1\r\n"
990 "Ntrip-Version: Ntrip/2.0\r\n"
991 "Ntrip-Component: Ntripserver\r\n"
992 "User-Agent: %s/%s\r\n"
993 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
994 "Authorization: Basic %s\r\n"
995 "Ntrip-STR: %s\r\n\r\n",
996 casterouthost, rtsp_extension, mountpoint, AGENTSTRING, revisionstr,
997 client_port, authorization, ntrip_str);
998 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
999 {
1000 fprintf(stderr, "ERROR: Destination caster request to long\n");
1001 reconnect_sec_max = 0;
1002 output_init = 0;
1003 break;
1004 }
1005 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
1006 {
1007 output_init = 0;
1008 break;
1009 }
1010 while((nBufferBytes = recv(socket_tcp, szSendBuffer,
1011 sizeof(szSendBuffer), 0)) > 0)
1012 {
1013 /* check Destination caster's response */
1014 szSendBuffer[nBufferBytes] = '\0';
1015 if(!strstr(szSendBuffer, "RTSP/1.0 200 OK"))
1016 {
1017 char *a;
1018 fprintf(stderr,
1019 "ERROR: Destination caster's%s reply is not OK: ",
1020 *proxyhost ? " or Proxy's" : "");
1021 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
1022 {
1023 fprintf(stderr, "%c", isprint(*a) ? *a : '.');
1024 }
1025 fprintf(stderr, "\n");
1026 /* fallback if necessary */
1027 if(strncmp(szSendBuffer, "RTSP",4) != 0)
1028 {
1029 if(strstr(szSendBuffer,"Ntrip-Version: Ntrip/2.0\r\n"))
1030 {
1031 fprintf(stderr,
1032 " RTSP not implemented at Destination caster <%s>%s%s%s\n\n"
1033 "ntripserver falls back to Ntrip Version 2.0 in TCP/IP"
1034 " mode\n\n", casterouthost,
1035 *proxyhost ? " or Proxy <" :"", proxyhost, *proxyhost ? ">":"");
1036 close_session(casterouthost, mountpoint, cseq, session, rtsp_extension, 1);
1037 outputmode = HTTP;
1038 break;
1039 }
1040 else
1041 {
1042 fprintf(stderr,
1043 " Ntrip-Version 2.0 not implemented at Destination caster"
1044 "<%s>%s%s%s\n%s"
1045 " or RTSP/1.0 not implemented at Destination caster%s\n\n"
1046 "ntripserver falls back to Ntrip Version 1.0\n\n",
1047 casterouthost, *proxyhost ? " or Proxy <" :"", proxyhost,
1048 *proxyhost ? ">":"",
1049 *proxyhost ? " or HTTP/1.1 not implemented at Proxy\n" : "",
1050 *proxyhost ? " or Proxy" :"");
1051 close_session(casterouthost, mountpoint, cseq, session, rtsp_extension, 1);
1052 outputmode = NTRIP1;
1053 break;
1054 }
1055 }
1056 else if((strstr(szSendBuffer, "RTSP/1.0 401 Unauthorized"))
1057 || (strstr(szSendBuffer, "RTSP/1.0 501 Not Implemented")))
1058 {
1059 reconnect_sec_max = 0;
1060 }
1061 output_init = 0;
1062 break;
1063 }
1064#ifndef NDEBUG
1065 else
1066 {
1067 fprintf(stderr, "Destination caster response:\n%s\n",szSendBuffer);
1068 }
1069#endif
1070 if((strstr(szSendBuffer,"RTSP/1.0 200 OK\r\n"))
1071 && (strstr(szSendBuffer,"CSeq: 1\r\n")))
1072 {
1073 for(token = strtok(szSendBuffer, dlim); token != NULL;
1074 token = strtok(NULL, dlim))
1075 {
1076 tok_buf[i] = token; i++;
1077 }
1078 session = atoi(tok_buf[6]);
1079 server_port = atoi(tok_buf[10]);
1080 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1081 "POST rtsp://%s%s/%s RTSP/1.0\r\n"
1082 "CSeq: 2\r\n"
1083 "Session: %d\r\n"
1084 "\r\n",
1085 casterouthost, rtsp_extension, mountpoint, session);
1086 if((nBufferBytes >= (int)sizeof(szSendBuffer))
1087 || (nBufferBytes < 0))
1088 {
1089 fprintf(stderr, "ERROR: Destination caster request to long\n");
1090 reconnect_sec_max = 0;
1091 output_init = 0;
1092 break;
1093 }
1094 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
1095 {
1096 output_init = 0;
1097 break;
1098 }
1099 }
1100 else if((strstr(szSendBuffer,"RTSP/1.0 200 OK\r\n")) && (strstr(szSendBuffer,
1101 "CSeq: 2\r\n")))
1102 {
1103 /* fill structure with caster address information for UDP */
1104 memset(&casterRTP, 0, sizeof(casterRTP));
1105 casterRTP.sin_family = AF_INET;
1106 casterRTP.sin_port = htons(((uint16_t)server_port));
1107 if((he = gethostbyname(outhost))== NULL)
1108 {
1109 fprintf(stderr, "ERROR: Destination caster unknown\n");
1110 reconnect_sec_max = 0;
1111 output_init = 0;
1112 break;
1113 }
1114 else
1115 {
1116 memcpy((char *)&casterRTP.sin_addr.s_addr,
1117 he->h_addr_list[0], (size_t)he->h_length);
1118 }
1119 cseq = 2;
1120 len = (socklen_t)sizeof(casterRTP);
1121 send_receive_loop(socket_udp, gpsfd, outputmode, (struct sockaddr *)&casterRTP,
1122 (socklen_t)len);
1123 break;
1124 }
1125 else{break;}
1126 }
1127 break;
1128 }
1129 }
1130 close_session(casterouthost, mountpoint, cseq, session, rtsp_extension, 0);
1131 if((!sigint_received) && (reconnect_sec_max))
1132 {
1133 reconnect_sec = reconnect(reconnect_sec, reconnect_sec_max);
1134 }
1135 else inputmode = LAST;
1136 }
1137 return 0;
1138}
1139
1140static void send_receive_loop(int sock, int fd, int outmode, struct sockaddr* pcasterRTP,
1141socklen_t length)
1142{
1143 int nodata = 0;
1144 char buffer[BUFSZ] = { 0 };
1145 char sisnetbackbuffer[200];
1146 char szSendBuffer[BUFSZ] = "";
1147 int nBufferBytes = 0;
1148
1149 /* RTSP / RTP Mode */
1150 int isfirstpacket = 1;
1151 struct timeval now;
1152 struct timeval last = {0,0};
1153 long int sendtimediff;
1154 int rtpseq = 0;
1155 int rtpssrc = 0;
1156 int rtptime = 0;
1157
1158 /* data transmission */
1159 fprintf(stderr,"transfering data ...\n");
1160 int send_recv_success = 0;
1161 while(1)
1162 {
1163 if(send_recv_success < 3) send_recv_success++;
1164 if(!nodata) alarm(ALARMTIME);
1165 else nodata = 0;
1166
1167 /* signal handling*/
1168 if((sigint_received) || (sigpipe_received) || (sigalarm_received)) break;
1169
1170 if(!nBufferBytes)
1171 {
1172 if(inputmode == SISNET && sisnet <= 30)
1173 {
1174 int i;
1175 /* a somewhat higher rate than 1 second to get really each block */
1176 /* means we need to skip double blocks sometimes */
1177 struct timeval tv = {0,700000};
1178 select(0, 0, 0, 0, &tv);
1179 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
1180 i = (sisnet >= 30 ? 5 : 3);
1181 if((send(gpsfd, "MSG\r\n", i, 0)) != i)
1182 {
1183 perror("WARNING: sending SISNeT data request failed");
1184 return;
1185 }
1186 }
1187 /*** receiving data ****/
1188 nBufferBytes = read(fd, buffer, sizeof(buffer));
1189 if(!nBufferBytes)
1190 {
1191 printf("WARNING: no data received from input\n");
1192 sleep(3);
1193 nodata = 1;
1194 continue;
1195 }
1196 else if((nBufferBytes < 0) && (!sigint_received))
1197 {
1198 perror("WARNING: reading input failed");
1199 return;
1200 }
1201 /* we can compare the whole buffer, as the additional bytes
1202 remain unchanged */
1203 if(inputmode == SISNET && sisnet <= 30 &&
1204 !memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer)))
1205 {
1206 nBufferBytes = 0;
1207 }
1208 }
1209 /** send data ***/
1210 if((nBufferBytes) && (outmode == NTRIP1)) /*** Ntrip-Version 1.0 ***/
1211 {
1212 int i;
1213 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
1214 != nBufferBytes)
1215 {
1216 if(i < 0)
1217 {
1218 if(errno != EAGAIN)
1219 {
1220 perror("WARNING: could not send data to Destination caster");
1221 return;
1222 }
1223 }
1224 else if(i)
1225 {
1226 memmove(buffer, buffer+i, (size_t)(nBufferBytes-i));
1227 nBufferBytes -= i;
1228 }
1229 }else
1230 {
1231 nBufferBytes = 0;
1232 }
1233 }
1234 /*** Ntrip-Version 2.0 HTTP/1.1 ***/
1235 else if((nBufferBytes) && (outmode == HTTP))
1236 {
1237 int i, nChunkBytes, j = 1;
1238 nChunkBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),"%x\r\n",
1239 nBufferBytes);
1240 send(sock, szSendBuffer, nChunkBytes, MSG_DONTWAIT);
1241 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
1242 != nBufferBytes)
1243 {
1244 if(i < 0)
1245 {
1246 if(errno != EAGAIN)
1247 {
1248 perror("WARNING: could not send data to Destination caster");
1249 return;
1250 }
1251 }
1252 else if(i)
1253 {
1254 while(j>0)
1255 {
1256 j = send(sock, buffer, (size_t)BUFSZ, MSG_DONTWAIT);
1257 }
1258 }
1259 }
1260 else
1261 {
1262 send(sock, "\r\n", strlen("\r\n"), MSG_DONTWAIT);
1263 nBufferBytes = 0;
1264 }
1265 }
1266 /*** Ntrip-Version 2.0 RTSP(TCP) / RTP(UDP) ***/
1267 else if((nBufferBytes) && (outmode == RTSP))
1268 {
1269 char rtpbuffer[BUFSZ+12];
1270 int i, j;
1271 gettimeofday(&now, NULL);
1272 /* RTP data packet generation*/
1273 if(isfirstpacket){
1274 rtpseq = rand();
1275 rtptime = rand();
1276 rtpssrc = rand();
1277 last = now;
1278 isfirstpacket = 0;
1279 }
1280 else
1281 {
1282 ++rtpseq;
1283 sendtimediff = (((now.tv_sec - last.tv_sec)*1000000)
1284 + (now.tv_usec - last.tv_usec));
1285 rtptime += sendtimediff/TIME_RESOLUTION;
1286 }
1287 rtpbuffer[0] = (RTP_VERSION<<6);
1288 /* padding, extension, csrc are empty */
1289 rtpbuffer[1] = 96;
1290 /* marker is empty */
1291 rtpbuffer[2] = rtpseq>>8;
1292 rtpbuffer[3] = rtpseq;
1293 rtpbuffer[4] = rtptime>>24;
1294 rtpbuffer[5] = rtptime>>16;
1295 rtpbuffer[6] = rtptime>>8;
1296 rtpbuffer[7] = rtptime;
1297 rtpbuffer[8] = rtpssrc>>24;
1298 rtpbuffer[9] = rtpssrc>>16;
1299 rtpbuffer[10] = rtpssrc>>8;
1300 rtpbuffer[11] = rtpssrc;
1301 for(j=0; j<nBufferBytes; j++) {rtpbuffer[12+j] = buffer[j];}
1302 last.tv_sec = now.tv_sec;
1303 last.tv_usec = now.tv_usec;
1304
1305 if ((i = sendto(sock, rtpbuffer, 12 + nBufferBytes, 0, pcasterRTP,
1306 length)) != (nBufferBytes + 12))
1307 {
1308 if(i < 0)
1309 {
1310 if(errno != EAGAIN)
1311 {
1312 perror("WARNING: could not send data to Destination caster");
1313 return;
1314 }
1315 }
1316 else if(i)
1317 {
1318 memmove(buffer, buffer+(i-12), (size_t)(nBufferBytes-(i-12)));
1319 nBufferBytes -= i-12;
1320 }
1321 }
1322 else
1323 {
1324 nBufferBytes = 0;
1325 }
1326 }
1327 if(send_recv_success == 3) reconnect_sec = 1;
1328 }
1329 return;
1330}
1331
1332
1333/********************************************************************
1334 * openserial
1335 *
1336 * Open the serial port with the given device name and configure it for
1337 * reading NMEA data from a GPS receiver.
1338 *
1339 * Parameters:
1340 * tty : pointer to : A zero-terminated string containing the device
1341 * unsigned char name of the appropriate serial port.
1342 * blocksz : integer : Block size for port I/O
1343 * baud : integer : Baud rate for port I/O
1344 *
1345 * Return Value:
1346 * The function returns a file descriptor for the opened port if successful.
1347 * The function returns -1 in the event of an error.
1348 *
1349 * Remarks:
1350 *
1351 ********************************************************************/
1352
1353static int openserial(const char * tty, int blocksz, int baud)
1354{
1355 int fd;
1356 struct termios termios;
1357
1358 fd = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
1359 if(fd < 0)
1360 {
1361 perror("ERROR: opening serial connection");
1362 return (-1);
1363 }
1364 if(tcgetattr(fd, &termios) < 0)
1365 {
1366 perror("ERROR: get serial attributes");
1367 return (-1);
1368 }
1369 termios.c_iflag = 0;
1370 termios.c_oflag = 0; /* (ONLRET) */
1371 termios.c_cflag = CS8 | CLOCAL | CREAD;
1372 termios.c_lflag = 0;
1373 {
1374 int cnt;
1375 for(cnt = 0; cnt < NCCS; cnt++)
1376 termios.c_cc[cnt] = -1;
1377 }
1378 termios.c_cc[VMIN] = blocksz;
1379 termios.c_cc[VTIME] = 2;
1380
1381#if (B4800 != 4800)
1382/* Not every system has speed settings equal to absolute speed value. */
1383
1384 switch (baud)
1385 {
1386 case 300:
1387 baud = B300;
1388 break;
1389 case 1200:
1390 baud = B1200;
1391 break;
1392 case 2400:
1393 baud = B2400;
1394 break;
1395 case 4800:
1396 baud = B4800;
1397 break;
1398 case 9600:
1399 baud = B9600;
1400 break;
1401 case 19200:
1402 baud = B19200;
1403 break;
1404 case 38400:
1405 baud = B38400;
1406 break;
1407#ifdef B57600
1408 case 57600:
1409 baud = B57600;
1410 break;
1411#endif
1412#ifdef B115200
1413 case 115200:
1414 baud = B115200;
1415 break;
1416#endif
1417#ifdef B230400
1418 case 230400:
1419 baud = B230400;
1420 break;
1421#endif
1422 default:
1423 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
1424 baud = B19200;
1425 break;
1426 }
1427#endif
1428
1429 if(cfsetispeed(&termios, baud) != 0)
1430 {
1431 perror("ERROR: setting serial speed with cfsetispeed");
1432 return (-1);
1433 }
1434 if(cfsetospeed(&termios, baud) != 0)
1435 {
1436 perror("ERROR: setting serial speed with cfsetospeed");
1437 return (-1);
1438 }
1439 if(tcsetattr(fd, TCSANOW, &termios) < 0)
1440 {
1441 perror("ERROR: setting serial attributes");
1442 return (-1);
1443 }
1444 if(fcntl(fd, F_SETFL, 0) == -1)
1445 {
1446 perror("WARNING: setting blocking inputmode failed");
1447 }
1448 return (fd);
1449} /* openserial */
1450
1451/********************************************************************
1452* usage
1453*
1454* Send a usage message to standard error and quit the program.
1455*
1456* Parameters:
1457* None.
1458*
1459* Return Value:
1460* The function does not return a value.
1461*
1462* Remarks:
1463*
1464*********************************************************************/
1465static
1466#ifdef __GNUC__
1467__attribute__ ((noreturn))
1468#endif /* __GNUC__ */
1469void usage(int rc, char *name)
1470{
1471 fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s [OPTIONS]\n",
1472 revisionstr, datestr, name);
1473 fprintf(stderr, "PURPOSE\n");
1474 fprintf(stderr, " The purpose of this program is to pick up a GNSS data stream (Input, Source)\n");
1475 fprintf(stderr, " from either\n\n");
1476 fprintf(stderr, " 1. a Serial port, or\n");
1477 fprintf(stderr, " 2. an IP server, or\n");
1478 fprintf(stderr, " 3. a File, or\n");
1479 fprintf(stderr, " 4. a SISNeT Data Server, or\n");
1480 fprintf(stderr, " 5. a UDP server, or\n");
1481 fprintf(stderr, " 6. an NTRIP Version 1.0 Caster\n\n");
1482 fprintf(stderr, " and forward that incoming stream (Output, Destination) to either\n\n");
1483 fprintf(stderr, " - an NTRIP Version 1.0 Caster, or\n");
1484 fprintf(stderr, " - an NTRIP Version 2.0 Caster via TCP/IP or RTSP/RTP.\n\n\n");
1485 fprintf(stderr, "OPTIONS\n");
1486 fprintf(stderr, " -h|? print this help screen\n\n");
1487 fprintf(stderr, " -E <ProxyHost> Proxy server host name or address, required i.e. when\n");
1488 fprintf(stderr, " running the program in a proxy server protected LAN,\n");
1489 fprintf(stderr, " optional\n");
1490 fprintf(stderr, " -F <ProxyPort> Proxy server IP port, required i.e. when running\n");
1491 fprintf(stderr, " the program in a proxy server protected LAN, optional\n");
1492 fprintf(stderr, " -R <maxDelay> Reconnect mechanism with maximum delay between reconnect\n");
1493 fprintf(stderr, " attemts in seconds, default: no reconnect activated,\n");
1494 fprintf(stderr, " optional\n\n");
1495 fprintf(stderr, " -M <InputMode> Sets the input mode (1 = Serial Port, 2 = IP server,\n");
1496 fprintf(stderr, " 3 = File, 4 = SISNeT Data Server, 5 = UDP server, 6 = NTRIP Caster),\n");
1497 fprintf(stderr, " mandatory\n\n");
1498 fprintf(stderr, " <InputMode> = 1 (Serial Port):\n");
1499 fprintf(stderr, " -i <Device> Serial input device, default: /dev/gps, mandatory if\n");
1500 fprintf(stderr, " <InputMode>=1\n");
1501 fprintf(stderr, " -b <BaudRate> Serial input baud rate, default: 19200 bps, mandatory\n");
1502 fprintf(stderr, " if <InputMode>=1\n\n");
1503 fprintf(stderr, " <InputMode> = 2|5 (IP port | UDP port):\n");
1504 fprintf(stderr, " -H <ServerHost> Input host name or address, default: 127.0.0.1,\n");
1505 fprintf(stderr, " mandatory if <InputMode> = 2|5\n");
1506 fprintf(stderr, " -P <ServerPort> Input port, default: 1025, mandatory if <InputMode>= 2|5\n");
1507 fprintf(stderr, " -f <ServerFile> Name of initialization file to be send to server,\n");
1508 fprintf(stderr, " optional\n");
1509 fprintf(stderr, " -x <ServerUser> User ID to access incoming stream, optional\n");
1510 fprintf(stderr, " -y <ServerPass> Password, to access incoming stream, optional\n");
1511 fprintf(stderr, " -B Bind to incoming UDP stream, optional for <InputMode> = 5\n\n");
1512 fprintf(stderr, " <InputMode> = 3 (File):\n");
1513 fprintf(stderr, " -s <File> File name to simulate stream by reading data from (log)\n");
1514 fprintf(stderr, " file, default is /dev/stdin, mandatory for <InputMode> = 3\n\n");
1515 fprintf(stderr, " <InputMode> = 4 (SISNeT Data Server):\n");
1516 fprintf(stderr, " -H <SisnetHost> SISNeT Data Server name or address,\n");
1517 fprintf(stderr, " default: 131.176.49.142, mandatory if <InputMode> = 4\n");
1518 fprintf(stderr, " -P <SisnetPort> SISNeT Data Server port, default: 7777, mandatory if\n");
1519 fprintf(stderr, " <InputMode> = 4\n");
1520 fprintf(stderr, " -u <SisnetUser> SISNeT Data Server user ID, mandatory if <InputMode> = 4\n");
1521 fprintf(stderr, " -l <SisnetPass> SISNeT Data Server password, mandatory if <InputMode> = 4\n");
1522 fprintf(stderr, " -V <SisnetVers> SISNeT Data Server Version number, options are 2.1, 3.0\n");
1523 fprintf(stderr, " or 3.1, default: 3.1, mandatory if <InputMode> = 4\n\n");
1524 fprintf(stderr, " <InputMode> = 6 (NTRIP Version 1.0 Caster):\n");
1525 fprintf(stderr, " -H <SourceHost> Source caster name or address, default: 127.0.0.1,\n");
1526 fprintf(stderr, " mandatory if <InputMode> = 6\n");
1527 fprintf(stderr, " -P <SourcePort> Source caster port, default: 2101, mandatory if\n");
1528 fprintf(stderr, " <InputMode> = 6\n");
1529 fprintf(stderr, " -D <SourceMount> Source caster mountpoint for stream input, mandatory if\n");
1530 fprintf(stderr, " <InputMode> = 6\n");
1531 fprintf(stderr, " -U <SourceUser> Source caster user Id for input stream access, mandatory\n");
1532 fprintf(stderr, " for protected streams if <InputMode> = 6\n");
1533 fprintf(stderr, " -W <SourcePass> Source caster password for input stream access, mandatory\n");
1534 fprintf(stderr, " for protected streams if <InputMode> = 6\n\n");
1535 fprintf(stderr, " -O <OutputMode> Sets output mode for communatation with destination caster\n");
1536 fprintf(stderr, " 1 = http: NTRIP Version 2.0 Caster in TCP/IP mode\n");
1537 fprintf(stderr, " 2 = rtsp: NTRIP Version 2.0 Caster in RTSP/RTP mode\n");
1538 fprintf(stderr, " 3 = ntrip1: NTRIP Version 1.0 Caster\n");
1539 fprintf(stderr, " optional\n\n");
1540 fprintf(stderr, " Defaults to NTRIP1.0, but will change to 2.0 in future versions\n");
1541 fprintf(stderr, " Note that the program automatically falls back from mode rtsp to mode http and\n");
1542 fprintf(stderr, " further to mode ntrip1 if necessary.\n\n");
1543 fprintf(stderr, " -a <DestHost> Destination caster name or address, default: 127.0.0.1,\n");
1544 fprintf(stderr, " mandatory\n");
1545 fprintf(stderr, " -p <DestPort> Destination caster port, default: 2101, mandatory\n");
1546 fprintf(stderr, " -m <DestMount> Destination caster mountpoint for stream upload,\n");
1547 fprintf(stderr, " mandatory\n");
1548 fprintf(stderr, " -n <DestUser> Destination caster user ID for stream upload to\n");
1549 fprintf(stderr, " mountpoint, only for NTRIP Version 2.0 destination\n");
1550 fprintf(stderr, " casters, mandatory\n");
1551 fprintf(stderr, " -c <DestPass> Destination caster password for stream upload to\n");
1552 fprintf(stderr, " mountpoint, mandatory\n");
1553 fprintf(stderr, " -N <STR-record> Sourcetable STR-record\n");
1554 fprintf(stderr, " optional for NTRIP Version 2.0 in RTSP/RTP and TCP/IP mode\n\n");
1555 exit(rc);
1556} /* usage */
1557
1558
1559/********************************************************************/
1560/* signal handling */
1561/********************************************************************/
1562#ifdef __GNUC__
1563static void handle_sigint(int sig __attribute__((__unused__)))
1564#else /* __GNUC__ */
1565static void handle_sigint(int sig)
1566#endif /* __GNUC__ */
1567{
1568 sigint_received = 1;
1569 fprintf(stderr, "WARNING: SIGINT received - ntripserver terminates\n");
1570}
1571
1572#ifdef __GNUC__
1573static void handle_alarm(int sig __attribute__((__unused__)))
1574#else /* __GNUC__ */
1575static void handle_alarm(int sig)
1576#endif /* __GNUC__ */
1577{
1578 sigalarm_received = 1;
1579 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
1580}
1581
1582#ifdef __GNUC__
1583static void handle_sigpipe(int sig __attribute__((__unused__)))
1584#else /* __GNUC__ */
1585static void handle_sigpipe(int sig)
1586#endif /* __GNUC__ */
1587{sigpipe_received = 1;}
1588
1589static void setup_signal_handler(int sig, void (*handler)(int))
1590{
1591#if _POSIX_VERSION > 198800L
1592 struct sigaction action;
1593
1594 action.sa_handler = handler;
1595 sigemptyset(&(action.sa_mask));
1596 sigaddset(&(action.sa_mask), sig);
1597 action.sa_flags = 0;
1598 sigaction(sig, &action, 0);
1599#else
1600 signal(sig, handler);
1601#endif
1602 return;
1603} /* setupsignal_handler */
1604
1605/********************************************************************
1606 * base64-encoding *
1607*******************************************************************/
1608static const char encodingTable [64] =
1609{
1610 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1611 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1612 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1613 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1614};
1615
1616/* does not buffer overrun, but breaks directly after an error */
1617/* returns the number of required bytes */
1618static int encode(char *buf, int size, const char *user, const char *pwd)
1619{
1620 unsigned char inbuf[3];
1621 char *out = buf;
1622 int i, sep = 0, fill = 0, bytes = 0;
1623
1624 while(*user || *pwd)
1625 {
1626 i = 0;
1627 while(i < 3 && *user) inbuf[i++] = *(user++);
1628 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1629 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1630 while(i < 3) {inbuf[i++] = 0; ++fill; }
1631 if(out-buf < size-1)
1632 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1633 if(out-buf < size-1)
1634 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1635 | ((inbuf [1] & 0xF0) >> 4)];
1636 if(out-buf < size-1)
1637 {
1638 if(fill == 2)
1639 *(out++) = '=';
1640 else
1641 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1642 | ((inbuf [2] & 0xC0) >> 6)];
1643 }
1644 if(out-buf < size-1)
1645 {
1646 if(fill >= 1)
1647 *(out++) = '=';
1648 else
1649 *(out++) = encodingTable[inbuf [2] & 0x3F];
1650 }
1651 bytes += 4;
1652 }
1653 if(out-buf < size)
1654 *out = 0;
1655 return bytes;
1656}/* base64 Encoding */
1657
1658
1659/********************************************************************
1660 * send message to caster *
1661*********************************************************************/
1662static int send_to_caster(char *input, int socket, int input_size)
1663{
1664 int send_error = 1;
1665
1666 if((send(socket, input, (size_t)input_size, 0)) != input_size)
1667 {
1668 fprintf(stderr, "WARNING: could not send full header to Destination caster\n");
1669 send_error = 0;
1670 }
1671#ifndef NDEBUG
1672 else
1673 {
1674 fprintf(stderr, "\nDestination caster request:\n");
1675 fprintf(stderr, "%s", input);
1676 }
1677#endif
1678 return send_error;
1679}/* send_to_caster */
1680
1681
1682/********************************************************************
1683 * reconnect *
1684*********************************************************************/
1685int reconnect(int rec_sec, int rec_sec_max)
1686{
1687 fprintf(stderr,"reconnect in <%d> seconds\n\n", rec_sec);
1688 rec_sec *= 2;
1689 if (rec_sec > rec_sec_max) rec_sec = rec_sec_max;
1690 sleep(rec_sec);
1691 sigalarm_received = 0;
1692 sigpipe_received = 0;
1693 return rec_sec;
1694} /* reconnect */
1695
1696
1697/********************************************************************
1698 * close session *
1699*********************************************************************/
1700static void close_session(const char *caster_addr, const char *mountpoint,
1701int cseq, int session, char *rtsp_ext, int fallback)
1702{
1703 int size_send_buf;
1704 char send_buf[BUFSZ];
1705
1706 if((gpsfd != -1) && (!fallback))
1707 {
1708 if(close(gpsfd) == -1)
1709 {
1710 perror("ERROR: close input device ");
1711 exit(0);
1712 }
1713 else
1714 {
1715 gpsfd = -1;
1716#ifndef NDEBUG
1717 fprintf(stderr, "close input device: successful\n");
1718#endif
1719 }
1720 }
1721
1722 if(socket_udp != -1)
1723 {
1724 if(cseq == 2)
1725 {
1726 size_send_buf = snprintf(send_buf, sizeof(send_buf),
1727 "TEARDOWN rtsp://%s%s/%s RTSP/1.0\r\n"
1728 "CSeq: 2\r\n"
1729 "Session: %d\r\n"
1730 "\r\n",
1731 caster_addr, rtsp_ext, mountpoint, session);
1732 if((size_send_buf >= (int)sizeof(send_buf)) || (size_send_buf < 0))
1733 {
1734 fprintf(stderr, "ERROR: Destination caster request to long\n");
1735 exit(0);
1736 }
1737 send_to_caster(send_buf, socket_tcp, size_send_buf); strcpy(send_buf,"");
1738 size_send_buf = recv(socket_tcp, send_buf, sizeof(send_buf), 0);
1739 send_buf[size_send_buf] = '\0';
1740#ifndef NDEBUG
1741 fprintf(stderr, "Destination caster response:\n%s", send_buf);
1742#endif
1743 }
1744 if(close(socket_udp)==-1)
1745 {
1746 perror("ERROR: close udp socket");
1747 exit(0);
1748 }
1749 else
1750 {
1751 socket_udp = -1;
1752#ifndef NDEBUG
1753 fprintf(stderr, "close udp socket: successful\n");
1754#endif
1755 }
1756 }
1757
1758 if(socket_tcp != -1)
1759 {
1760 if(close(socket_tcp) == -1)
1761 {
1762 perror("ERROR: close tcp socket");
1763 exit(0);
1764 }
1765 else
1766 {
1767 socket_tcp = -1;
1768#ifndef NDEBUG
1769 fprintf(stderr, "close tcp socket: successful\n");
1770#endif
1771 }
1772 }
1773} /* close_session */
Note: See TracBrowser for help on using the repository browser.