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

Last change on this file since 9402 was 9402, checked in by stuerze, 15 months ago

minor changes

  • Property svn:keywords set to Id Revision Date
File size: 76.1 KB
Line 
1/*
2 * $Id: ntripserver.c 9402 2021-04-12 19:59:00Z stuerze $
3 *
4 * Copyright (c) 2003...2019
5 * German Federal Agency for Cartography and Geodesy (BKG)
6 * Dirk Stöcker (Alberding GmbH)
7 *
8 * Developed for Networked Transport of RTCM via Internet Protocol (NTRIP)
9 * for streaming GNSS data over the Internet.
10 *
11 * Designed by Informatik Centrum Dortmund http://www.icd.de
12 *
13 * The BKG disclaims any liability nor responsibility to any person or
14 * entity with respect to any loss or damage caused, or alleged to be
15 * caused, directly or indirectly by the use and application of the NTRIP
16 * technology.
17 *
18 * For latest information and updates, access:
19 * https://igs.bkg.bund.de/ntrip/index
20 *
21 * BKG, Frankfurt, Germany, August 2019
22 * E-mail: euref-ip@bkg.bund.de
23 *
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * as published by the Free Software Foundation; either version 2
27 * of the License, or (at your option) any later version.
28 *
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
33 *
34 * You should have received a copy of the GNU General Public License along
35 * with this program; if not, write to the Free Software Foundation, Inc.,
36 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 */
38
39/* SVN revision and version */
40static char revisionstr[] = "$Revision: 9402 $";
41static char datestr[] = "$Date: 2021-04-12 19:59:00 +0000 (Mon, 12 Apr 2021) $";
42
43#include <ctype.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <getopt.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <sys/time.h>
51#include <sys/types.h>
52#include <time.h>
53#include <signal.h>
54#include <unistd.h>
55
56#ifdef WINDOWSVERSION
57 #include <winsock2.h>
58 #include <io.h>
59 #include <sys/stat.h>
60 #include <windows.h>
61 typedef SOCKET sockettype;
62 typedef u_long in_addr_t;
63 typedef size_t socklen_t;
64 typedef u_short uint16_t;
65#else
66typedef int sockettype;
67#include <arpa/inet.h>
68#include <sys/socket.h>
69#include <netinet/in.h>
70#include <netdb.h>
71#include <sys/termios.h>
72#define closesocket(sock) close(sock)
73#define INVALID_HANDLE_VALUE -1
74#define INVALID_SOCKET -1
75#endif
76
77#ifndef COMPILEDATE
78#define COMPILEDATE " built " __DATE__
79#endif
80
81#define ALARMTIME (2*60)
82
83#ifndef MSG_DONTWAIT
84#define MSG_DONTWAIT 0 /* prevent compiler errors */
85#endif
86#ifndef O_EXLOCK
87#define O_EXLOCK 0 /* prevent compiler errors */
88#endif
89
90enum MODE {
91 SERIAL = 1,
92 TCPSOCKET = 2,
93 INFILE = 3,
94 SISNET = 4,
95 UDPSOCKET = 5,
96 NTRIP1_IN = 6,
97 NTRIP2_HTTP_IN = 7, // HTTP only
98 LAST
99};
100
101enum OUTMODE {
102 HTTP = 1,
103 RTSP = 2,
104 NTRIP1 = 3,
105 UDP = 4,
106 TDC = 5,
107 END
108};
109
110#define AGENTSTRING "NTRIP NtripServerPOSIX"
111#define BUFSZ 10240
112#define SZ 64
113
114/* default socket source */
115#define SERV_HOST_ADDR "localhost"
116#define SERV_TCP_PORT 2101
117
118/* default destination */
119#define NTRIP_CASTER "www.euref-ip.net"
120#define NTRIP_PORT 2101
121
122#define DABPLUS_SERVER "62.225.182.198"
123#define DABPLUS_PORT 10000
124
125#define SISNET_SERVER "131.176.49.142"
126#define SISNET_PORT 7777
127
128#define RTP_VERSION 2
129#define TIME_RESOLUTION 125
130
131static int ttybaud = 19200;
132#ifndef WINDOWSVERSION
133static const char *ttyport = "/dev/gps";
134#else
135 static const char *ttyport = "COM1";
136#endif
137static const char *filepath = "/dev/stdin";
138static enum MODE inputmode = INFILE;
139static int sisnet = 31;
140static int gps_file = -1;
141static sockettype gps_socket = INVALID_SOCKET;
142static sockettype socket_tcp = INVALID_SOCKET;
143static sockettype socket_udp = INVALID_SOCKET;
144#ifndef WINDOWSVERSION
145static int gps_serial = INVALID_HANDLE_VALUE;
146static int sigpipe_received = 0;
147#else
148 HANDLE gps_serial = INVALID_HANDLE_VALUE;
149#endif
150static int sigalarm_received = 0;
151static int sigint_received = 0;
152static int reconnect_sec = 1;
153static const char *casterouthost = NTRIP_CASTER;
154static char rtsp_extension[SZ] = "";
155static const char *mountpoint = NULL;
156static int udp_cseq = 1;
157static int udp_tim, udp_seq, udp_init;
158
159/* Forward references */
160static void send_receive_loop(sockettype sock, int outmode,
161 struct sockaddr *pcasterRTP, socklen_t length, unsigned int rtpssrc,
162 int chnunkymode);
163static void usage(int, char*);
164static int encode(char *buf, int size, const char *user, const char *pwd);
165static int send_to_caster(char *input, sockettype socket, int input_size);
166static void close_session(const char *caster_addr, const char *mountpoint,
167 int session, char *rtsp_ext, int fallback);
168static int reconnect(int rec_sec, int rec_sec_max);
169static void handle_sigint(int sig);
170static void setup_signal_handler(int sig, void (*handler)(int));
171#ifndef WINDOWSVERSION
172static int openserial(const char *tty, int blocksz, int baud);
173static void handle_sigpipe(int sig);
174static void handle_alarm(int sig);
175#else
176 static HANDLE openserial(const char * tty, int baud);
177#endif
178
179/*
180 * main
181 *
182 * Main entry point for the program. Processes command-line arguments and
183 * prepares for action.
184 *
185 * Parameters:
186 * argc : integer : Number of command-line arguments.
187 * argv : array of char : Command-line arguments as an array of
188 * zero-terminated pointers to strings.
189 *
190 * Return Value:
191 * The function does not return a value (although its return type is int).
192 *
193 * Remarks:
194 *
195 */
196int main(int argc, char **argv) {
197 int c;
198 int size = 2048; /* for setting send buffer size */
199 struct sockaddr_in caster;
200 const char *proxyhost = "";
201 unsigned int proxyport = 0;
202
203 /*** INPUT ***/
204 const char *casterinhost = 0;
205 unsigned int casterinport = 0;
206 const char *inhost = 0;
207 unsigned int inport = 0;
208 int chunkymode = 0;
209 char get_extension[SZ] = "";
210
211 struct hostent *he;
212
213 const char *sisnetpassword = "";
214 const char *sisnetuser = "";
215
216 const char *stream_name = 0;
217 const char *stream_user = 0;
218 const char *stream_password = 0;
219
220 const char *recvrid = 0;
221 const char *recvrpwd = 0;
222
223 const char *initfile = NULL;
224
225 int bindmode = 0;
226
227 /*** OUTPUT ***/
228 unsigned int casteroutport = NTRIP_PORT;
229 const char *outhost = 0;
230 unsigned int outport = 0;
231 char post_extension[SZ] = "";
232
233 const char *ntrip_str = "";
234
235 const char *user = "";
236 const char *password = "";
237
238 int outputmode = NTRIP1;
239
240 struct sockaddr_in casterRTP;
241 struct sockaddr_in local;
242 int client_port = 0;
243 int server_port = 0;
244 unsigned int session = 0;
245 socklen_t len = 0;
246 int i = 0;
247
248 char szSendBuffer[BUFSZ];
249 char authorization[SZ];
250 int nBufferBytes = 0;
251 char *dlim = " \r\n=";
252 char *token;
253 char *tok_buf[BUFSZ];
254
255 int reconnect_sec_max = 0;
256
257 setbuf(stdout, 0);
258 setbuf(stdin, 0);
259 setbuf(stderr, 0);
260
261 {
262 char *a;
263 int i = 2;
264 strcpy(revisionstr, "1.");
265 for (a = revisionstr + 11; *a && *a != ' '; ++a)
266 revisionstr[i++] = *a;
267 revisionstr[i] = 0;
268 i = 0;
269 for (a = datestr + 7; *a && *a != ' '; ++a)
270 datestr[i++] = *a;
271 datestr[i] = 0;
272 }
273
274 /* setup signal handler for CTRL+C */
275 setup_signal_handler(SIGINT, handle_sigint);
276#ifndef WINDOWSVERSION
277 /* setup signal handler for boken pipe */
278 setup_signal_handler(SIGPIPE, handle_sigpipe);
279 /* setup signal handler for timeout */
280 setup_signal_handler(SIGALRM, handle_alarm);
281 alarm(ALARMTIME);
282#else
283 /* winsock initialization */
284 WSADATA wsaData;
285 if (WSAStartup(MAKEWORD(1,1), &wsaData))
286 {
287 fprintf(stderr, "Could not init network access.\n");
288 return 20;
289 }
290#endif
291
292 /* get and check program arguments */
293 if (argc <= 1) {
294 usage(2, argv[0]);
295 exit(1);
296 }
297 while ((c = getopt(argc, argv,
298 "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) {
299 switch (c) {
300 case 'M': /*** InputMode ***/
301 if (!strcmp(optarg, "serial"))
302 inputmode = SERIAL;
303 else if (!strcmp(optarg, "tcpsocket"))
304 inputmode = TCPSOCKET;
305 else if (!strcmp(optarg, "file"))
306 inputmode = INFILE;
307 else if (!strcmp(optarg, "sisnet"))
308 inputmode = SISNET;
309 else if (!strcmp(optarg, "udpsocket"))
310 inputmode = UDPSOCKET;
311 else if (!strcmp(optarg, "ntrip1"))
312 inputmode = NTRIP1_IN;
313 else if (!strcmp(optarg, "ntrip2http"))
314 inputmode = NTRIP2_HTTP_IN;
315 else
316 inputmode = atoi(optarg);
317 if ((inputmode == 0) || (inputmode >= LAST)) {
318 fprintf(stderr, "ERROR: can't convert <%s> to a valid InputMode\n",
319 optarg);
320 usage(-1, argv[0]);
321 }
322 break;
323 case 'i': /* serial input device */
324 ttyport = optarg;
325 break;
326 case 'B': /* bind to incoming UDP stream */
327 bindmode = 1;
328 break;
329 case 'V': /* Sisnet data server version number */
330 if (!strcmp("3.0", optarg))
331 sisnet = 30;
332 else if (!strcmp("3.1", optarg))
333 sisnet = 31;
334 else if (!strcmp("2.1", optarg))
335 sisnet = 21;
336 else {
337 fprintf(stderr, "ERROR: unknown SISNeT version <%s>\n", optarg);
338 usage(-2, argv[0]);
339 }
340 break;
341 case 'b': /* serial input baud rate */
342 ttybaud = atoi(optarg);
343 if (ttybaud <= 1) {
344 fprintf(stderr,
345 "ERROR: can't convert <%s> to valid serial baud rate\n", optarg);
346 usage(1, argv[0]);
347 }
348 break;
349 case 'a': /* Destination caster address */
350 casterouthost = optarg;
351 break;
352 case 'p': /* Destination caster port */
353 casteroutport = atoi(optarg);
354 if (casteroutport <= 1 || casteroutport > 65535) {
355 fprintf(stderr,
356 "ERROR: can't convert <%s> to a valid HTTP server port\n",
357 optarg);
358 usage(1, argv[0]);
359 }
360 break;
361 case 'm': /* Destination caster mountpoint for stream upload */
362 mountpoint = optarg;
363 break;
364 case 's': /* File name for input data simulation from file */
365 filepath = optarg;
366 break;
367 case 'f': /* name of an initialization file */
368 initfile = optarg;
369 break;
370 case 'x': /* user ID to access incoming stream */
371 recvrid = optarg;
372 break;
373 case 'y': /* password to access incoming stream */
374 recvrpwd = optarg;
375 break;
376 case 'u': /* Sisnet data server user ID */
377 sisnetuser = optarg;
378 break;
379 case 'l': /* Sisnet data server password */
380 sisnetpassword = optarg;
381 break;
382 case 'c': /* DestinationCaster password for stream upload to mountpoint */
383 password = optarg;
384 break;
385 case 'H': /* Input host address*/
386 casterinhost = optarg;
387 break;
388 case 'P': /* Input port */
389 casterinport = atoi(optarg);
390 if (casterinport <= 1 || casterinport > 65535) {
391 fprintf(stderr, "ERROR: can't convert <%s> to a valid port number\n",
392 optarg);
393 usage(1, argv[0]);
394 }
395 break;
396 case 'D': /* Source caster mountpoint for stream input */
397 stream_name = optarg;
398 break;
399 case 'U': /* Source caster user ID for input stream access */
400 stream_user = optarg;
401 break;
402 case 'W': /* Source caster password for input stream access */
403 stream_password = optarg;
404 break;
405 case 'E': /* Proxy Server */
406 proxyhost = optarg;
407 break;
408 case 'F': /* Proxy port */
409 proxyport = atoi(optarg);
410 break;
411 case 'R': /* maximum delay between reconnect attempts in seconds */
412 reconnect_sec_max = atoi(optarg);
413 break;
414 case 'O': /* OutputMode */
415 outputmode = 0;
416 if (!strcmp(optarg, "n") || !strcmp(optarg, "ntrip1"))
417 outputmode = NTRIP1;
418 else if (!strcmp(optarg, "h") || !strcmp(optarg, "http"))
419 outputmode = HTTP;
420 else if (!strcmp(optarg, "r") || !strcmp(optarg, "rtsp"))
421 outputmode = RTSP;
422 else if (!strcmp(optarg, "u") || !strcmp(optarg, "udp"))
423 outputmode = UDP;
424 else if (!strcmp(optarg, "t") || !strcmp(optarg, "tdc"))
425 outputmode = TDC;
426 else
427 outputmode = atoi(optarg);
428 if ((outputmode == 0) || (outputmode >= END)) {
429 fprintf(stderr, "ERROR: can't convert <%s> to a valid OutputMode\n",
430 optarg);
431 usage(-1, argv[0]);
432 }
433 break;
434 case 'n': /* Destination caster user ID for stream upload to mountpoint */
435 user = optarg;
436 break;
437 case 'N': /* Ntrip-STR, optional for Ntrip Version 2.0 */
438 ntrip_str = optarg;
439 break;
440 case 'h': /* print help screen */
441 case '?':
442 usage(0, argv[0]);
443 break;
444 default:
445 usage(2, argv[0]);
446 break;
447 }
448 }
449
450 argc -= optind;
451 argv += optind;
452
453 /*** argument analysis ***/
454 if (argc > 0) {
455 fprintf(stderr, "ERROR: Extra args on command line: ");
456 for (; argc > 0; argc--) {
457 fprintf(stderr, " %s", *argv++);
458 }
459 fprintf(stderr, "\n");
460 usage(1, argv[0]); /* never returns */
461 }
462
463 if ((reconnect_sec_max > 0) && (reconnect_sec_max < 256)) {
464 fprintf(stderr,
465 "WARNING: maximum delay between reconnect attempts changed from %d to 256 seconds\n",
466 reconnect_sec_max);
467 reconnect_sec_max = 256;
468 }
469
470 if (!mountpoint && outputmode != TDC) {
471 fprintf(stderr, "ERROR: Missing mountpoint argument for stream upload\n");
472 exit(1);
473 }
474
475 if (outputmode == TDC) {
476 mountpoint = NULL;
477 if (!strcmp(casterouthost, NTRIP_CASTER)) {
478 casterouthost = DABPLUS_SERVER;
479 }
480 if (casteroutport == NTRIP_PORT) {
481 casteroutport = DABPLUS_PORT;
482 }
483 }
484
485 if (!password[0]) {
486 if (outputmode != TDC)
487 fprintf(stderr,
488 "WARNING: Missing password argument for stream upload - are you really sure?\n");
489 } else {
490 nBufferBytes += encode(authorization, sizeof(authorization), user,
491 password);
492 if (nBufferBytes > (int) sizeof(authorization)) {
493 fprintf(stderr, "ERROR: user ID and/or password too long: %d (%d)\n"
494 " user ID: %s \npassword: <%s>\n", nBufferBytes,
495 (int) sizeof(authorization), user, password);
496 exit(1);
497 }
498 }
499
500 if (stream_name && stream_user && !stream_password) {
501 fprintf(stderr,
502 "WARNING: Missing password argument for stream download - are you really sure?\n");
503 }
504
505 /*** proxy server handling ***/
506 if (*proxyhost) {
507 outhost = inhost = proxyhost;
508 outport = inport = proxyport;
509 i = snprintf(szSendBuffer, sizeof(szSendBuffer), "http://%s:%d", casterouthost, casteroutport);
510 if ((i > SZ) || (i < 0)) {
511 fprintf(stderr,
512 "ERROR: Destination caster name/port to long - length = %d (max: %d)\n",
513 i, SZ);
514 exit(0);
515 } else {
516 strncpy(post_extension, szSendBuffer, (size_t) i);
517 strcpy(szSendBuffer, "");
518 i = snprintf(szSendBuffer, sizeof(szSendBuffer), ":%d", casteroutport);
519 strncpy(rtsp_extension, szSendBuffer, SZ);
520 strcpy(szSendBuffer, ""); i = 0;
521 }
522 i = snprintf(szSendBuffer, sizeof(szSendBuffer), "http://%s:%d", casterinhost, casterinport);
523 if ((i > SZ) || (i < 0)) {
524 fprintf(stderr,
525 "ERROR: Destination caster name/port to long - length = %d (max: %d)\n",
526 i, SZ);
527 exit(0);
528 } else {
529 strncpy(get_extension, szSendBuffer, (size_t) i);
530 strcpy(szSendBuffer, "");
531 i = 0;
532 fprintf(stdout, "%s",get_extension);
533 }
534 } else {
535 outhost = casterouthost;
536 outport = casteroutport;
537 inhost = casterinhost;
538 inport = casterinport;
539 }
540
541 while (inputmode != LAST) {
542 int input_init = 1;
543 if (sigint_received)
544 break;
545 /*** InputMode handling ***/
546 switch (inputmode) {
547 case INFILE: {
548 if ((gps_file = open(filepath, O_RDONLY)) < 0) {
549 perror("ERROR: opening input file");
550 exit(1);
551 }
552#ifndef WINDOWSVERSION
553 /* set blocking inputmode in case it was not set
554 (seems to be sometimes for fifo's) */
555 fcntl(gps_file, F_SETFL, 0);
556#endif
557 printf("file input: file = %s\n", filepath);
558 }
559 break;
560 case SERIAL: /* open serial port */ {
561#ifndef WINDOWSVERSION
562 gps_serial = openserial(ttyport, 1, ttybaud);
563#else
564 gps_serial = openserial(ttyport, ttybaud);
565#endif
566 if (gps_serial == INVALID_HANDLE_VALUE)
567 exit(1);
568 printf("serial input: device = %s, speed = %d\n", ttyport, ttybaud);
569
570 if (initfile) {
571 char buffer[1024];
572 FILE *fh;
573 int i;
574
575 if ((fh = fopen(initfile, "r"))) {
576 while ((i = fread(buffer, 1, sizeof(buffer), fh)) > 0) {
577#ifndef WINDOWSVERSION
578 if ((write(gps_serial, buffer, i)) != i) {
579 perror("WARNING: sending init file");
580 input_init = 0;
581 break;
582 }
583#else
584 DWORD nWrite = -1;
585 if(!WriteFile(gps_serial, buffer, sizeof(buffer), &nWrite, NULL)) {
586 fprintf(stderr,"ERROR: sending init file \n");
587 input_init = 0;
588 break;
589 }
590 i = (int)nWrite;
591#endif
592 }
593 if (i < 0) {
594 perror("ERROR: reading init file");
595 reconnect_sec_max = 0;
596 input_init = 0;
597 break;
598 }
599 fclose(fh);
600 } else {
601 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
602 reconnect_sec_max = 0;
603 input_init = 0;
604 break;
605 }
606 }
607 }
608 break;
609 case TCPSOCKET:
610 case UDPSOCKET:
611 case SISNET:
612 case NTRIP1_IN:
613 case NTRIP2_HTTP_IN: {
614 if (inputmode == SISNET) {
615 if (!inhost)
616 inhost = SISNET_SERVER;
617 if (!inport)
618 inport = SISNET_PORT;
619 } else if (inputmode == NTRIP1_IN || inputmode == NTRIP2_HTTP_IN) {
620 if (!inport)
621 inport = NTRIP_PORT;
622 if (!inhost)
623 inhost = NTRIP_CASTER;
624 } else if ((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET)) {
625 if (!inport)
626 inport = SERV_TCP_PORT;
627 if (!inhost)
628 inhost = SERV_HOST_ADDR;
629 }
630
631 if (!(he = gethostbyname(inhost))) {
632 fprintf(stderr, "ERROR: Input host <%s> unknown\n", inhost);
633 usage(-2, argv[0]);
634 }
635
636 if ((gps_socket = socket(AF_INET, inputmode == UDPSOCKET ? SOCK_DGRAM : SOCK_STREAM, 0)) == INVALID_SOCKET) {
637 fprintf(stderr,
638 "ERROR: can't create socket for incoming data stream\n");
639 exit(1);
640 }
641
642 memset((char*) &caster, 0x00, sizeof(caster));
643 if (!bindmode)
644 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
645 caster.sin_family = AF_INET;
646 caster.sin_port = htons(inport);
647
648 fprintf(stderr, "%s input: host = %s, port = %d, %s%s%s%s%s\n",
649 inputmode == NTRIP1_IN ? "ntrip1" :
650 inputmode == NTRIP2_HTTP_IN ? "ntrip2" :
651 inputmode == SISNET ? "sisnet" :
652 inputmode == TCPSOCKET ? "tcp socket" : "udp socket",
653 bindmode ? "127.0.0.1" : inet_ntoa(caster.sin_addr), inport,
654 stream_name ? "stream = " : "", stream_name ? stream_name : "",
655 initfile ? ", initfile = " : "", initfile ? initfile : "",
656 bindmode ? "binding mode" : "");
657
658 if (bindmode) {
659 if (bind(gps_socket, (struct sockaddr*) &caster, sizeof(caster))
660 < 0) {
661 fprintf(stderr, "ERROR: can't bind input to port %d\n", inport);
662 reconnect_sec_max = 0;
663 input_init = 0;
664 break;
665 }
666 } /* connect to input-caster or proxy server*/
667 else if (connect(gps_socket, (struct sockaddr*) &caster, sizeof(caster))
668 < 0) {
669 fprintf(stderr, "WARNING: can't connect input to %s at port %d\n",
670 inet_ntoa(caster.sin_addr), inport);
671 input_init = 0;
672 break;
673 }
674
675 /* input from NTRIP caster */
676 int init = 0;
677 /* set socket buffer size */
678 setsockopt(gps_socket, SOL_SOCKET, SO_SNDBUF, (const char*) &size, sizeof(const char*));
679 /* input from Ntrip caster*/
680 nBufferBytes=snprintf(szSendBuffer, sizeof(szSendBuffer) - 40,/* leave some space for login */
681 "GET %s/%s HTTP/1.1\r\n"
682 "Host: %s\r\n"
683 "%s"
684 "User-Agent: %s/%s\r\n"
685 //"%s%s%s" // nmea
686 "Connection: close%s",
687 get_extension,
688 stream_name ? stream_name : "",
689 casterinhost,
690 inputmode == NTRIP1_IN ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
691 AGENTSTRING, revisionstr,
692 //args.nmea ? "Ntrip-GGA: " : "", args.nmea ? args.nmea : "", args.nmea ? "\r\n" : "", // TODO: add argument
693 (*stream_user || *stream_password) ? "\r\nAuthorization: Basic " : "");
694 /* second check for old glibc */
695 if (nBufferBytes > (int) sizeof(szSendBuffer) - 40 || nBufferBytes < 0) {
696 fprintf(stderr, "ERROR: Source caster request too long\n");
697 input_init = 0;
698 reconnect_sec_max = 0;
699 break;
700 }
701 nBufferBytes += encode(szSendBuffer + nBufferBytes, sizeof(szSendBuffer) - nBufferBytes - 4,
702 stream_user, stream_password);
703 if (nBufferBytes > (int) sizeof(szSendBuffer) - 4) {
704 fprintf(stderr, "ERROR: Source caster user ID and/or password too long\n");
705 input_init = 0;
706 reconnect_sec_max = 0;
707 break;
708 }
709 szSendBuffer[nBufferBytes++] = '\r';
710 szSendBuffer[nBufferBytes++] = '\n';
711 szSendBuffer[nBufferBytes++] = '\r';
712 szSendBuffer[nBufferBytes++] = '\n';
713fprintf(stdout, "%s", szSendBuffer);
714 if ((send(gps_socket, szSendBuffer, (size_t) nBufferBytes, 0)) != nBufferBytes) {
715 fprintf(stderr, "WARNING: could not send Source caster request\n");
716 input_init = 0;
717 break;
718 }
719 nBufferBytes = 0;
720 /* check Source caster's response */
721 while (!init && nBufferBytes < (int) sizeof(szSendBuffer) &&
722 (nBufferBytes += recv(gps_socket, szSendBuffer, sizeof(szSendBuffer) - nBufferBytes, 0)) > 0) {
723 if( nBufferBytes > 17 && !strstr(szSendBuffer, "ICY 200 OK") && /* case 'proxy & ntrip 1.0 caster' */
724 (!strncmp(szSendBuffer, "HTTP/1.1 200 OK\r\n", 17) ||
725 !strncmp(szSendBuffer, "HTTP/1.0 200 OK\r\n", 17)) ) {
726 const char *datacheck = "Content-Type: gnss/data\r\n";
727 const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
728 int l = strlen(datacheck)-1;
729 int j=0;
730 for(i = 0; j != l && i < nBufferBytes-l; ++i) {
731 for(j = 0; j < l && szSendBuffer[i+j] == datacheck[j]; ++j)
732 ;
733 }
734 if(i == nBufferBytes-l) {
735 fprintf(stderr, "No 'Content-Type: gnss/data' found\n");
736 input_init = 0;
737 }
738 l = strlen(chunkycheck)-1;
739 j=0;
740 for(i = 0; j != l && i < nBufferBytes-l; ++i) {
741 for(j = 0; j < l && szSendBuffer[i+j] == chunkycheck[j]; ++j)
742 ;
743 }
744 if(i < nBufferBytes-l)
745 chunkymode = 1;
746 init = 1;
747 }
748 else if (strstr(szSendBuffer, "\r\n")) {
749 if (!strstr(szSendBuffer, "ICY 200 OK")) {
750 int k;
751 fprintf(stderr, "ERROR: could not get requested data from Source caster: ");
752 for (k = 0; k < nBufferBytes && szSendBuffer[k] != '\n' && szSendBuffer[k] != '\r'; ++k) {
753 fprintf(stderr, "%c", isprint(szSendBuffer[k]) ? szSendBuffer[k] : '.');
754 }
755 fprintf(stderr, "\n");
756 if (!strstr(szSendBuffer, "SOURCETABLE 200 OK")) {
757 reconnect_sec_max = 0;
758 }
759 input_init = 0;
760 break;
761 } else {// eventuell auskommentieren!
762 init = 1;
763 }
764 }
765
766 }
767 /* end input from NTRIP caster */
768
769 if (initfile && inputmode != SISNET) {
770 char buffer[1024];
771 FILE *fh;
772 int i;
773
774 if ((fh = fopen(initfile, "r"))) {
775 while ((i = fread(buffer, 1, sizeof(buffer), fh)) > 0) {
776 if ((send(gps_socket, buffer, (size_t) i, 0)) != i) {
777 perror("WARNING: sending init file");
778 input_init = 0;
779 break;
780 }
781 }
782 if (i < 0) {
783 perror("ERROR: reading init file");
784 reconnect_sec_max = 0;
785 input_init = 0;
786 break;
787 }
788 fclose(fh);
789 } else {
790 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
791 reconnect_sec_max = 0;
792 input_init = 0;
793 break;
794 }
795 }
796 }
797 if (inputmode == SISNET) {
798 int i, j;
799 char buffer[1024];
800
801 i = snprintf(buffer, sizeof(buffer),
802 sisnet >= 30 ? "AUTH,%s,%s\r\n" : "AUTH,%s,%s", sisnetuser,
803 sisnetpassword);
804 if ((send(gps_socket, buffer, (size_t) i, 0)) != i) {
805 perror("WARNING: sending authentication for SISNeT data server");
806 input_init = 0;
807 break;
808 }
809 i = sisnet >= 30 ? 7 : 5;
810 if ((j = recv(gps_socket, buffer, i, 0)) != i
811 && strncmp("*AUTH", buffer, 5)) {
812 fprintf(stderr, "WARNING: SISNeT connect failed:");
813 for (i = 0; i < j; ++i) {
814 if (buffer[i] != '\r' && buffer[i] != '\n') {
815 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
816 }
817 }
818 fprintf(stderr, "\n");
819 input_init = 0;
820 break;
821 }
822 if (sisnet >= 31) {
823 if ((send(gps_socket, "START\r\n", 7, 0)) != i) {
824 perror("WARNING: sending Sisnet start command");
825 input_init = 0;
826 break;
827 }
828 }
829 }
830 /*** receiver authentication ***/
831 if (recvrid && recvrpwd
832 && ((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET))) {
833 if (strlen(recvrid) > (BUFSZ - 3)) {
834 fprintf(stderr, "ERROR: Receiver ID too long\n");
835 reconnect_sec_max = 0;
836 input_init = 0;
837 break;
838 } else {
839 fprintf(stderr, "Sending user ID for receiver...\n");
840 nBufferBytes = recv(gps_socket, szSendBuffer, BUFSZ, 0);
841 strcpy(szSendBuffer, recvrid);
842 strcat(szSendBuffer, "\r\n");
843 if (send(gps_socket, szSendBuffer, strlen(szSendBuffer),
844 MSG_DONTWAIT) < 0) {
845 perror("WARNING: sending user ID for receiver");
846 input_init = 0;
847 break;
848 }
849 }
850
851 if (strlen(recvrpwd) > (BUFSZ - 3)) {
852 fprintf(stderr, "ERROR: Receiver password too long\n");
853 reconnect_sec_max = 0;
854 input_init = 0;
855 break;
856 } else {
857 fprintf(stderr, "Sending user password for receiver...\n");
858 nBufferBytes = recv(gps_socket, szSendBuffer, BUFSZ, 0);
859 strcpy(szSendBuffer, recvrpwd);
860 strcat(szSendBuffer, "\r\n");
861 if (send(gps_socket, szSendBuffer, strlen(szSendBuffer),
862 MSG_DONTWAIT) < 0) {
863 perror("WARNING: sending user password for receiver");
864 input_init = 0;
865 break;
866 }
867 }
868 }
869 break;
870 default:
871 usage(-1, argv[0]);
872 break;
873 }
874
875 /* ----- main part ----- */
876 int output_init = 1, fallback = 0;
877
878 while ((input_init) && (output_init)) {
879#ifndef WINDOWSVERSION
880 if ((sigalarm_received) || (sigint_received) || (sigpipe_received))
881 break;
882#else
883 if((sigalarm_received) || (sigint_received)) break;
884#endif
885 if (!(he = gethostbyname(outhost))) {
886 fprintf(stderr,
887 "ERROR: Destination caster, server or proxy host <%s> unknown\n",
888 outhost);
889 close_session(casterouthost, mountpoint, session, rtsp_extension, 0);
890 usage(-2, argv[0]);
891 }
892
893 /* create socket */
894 if ((socket_tcp = socket(AF_INET, (outputmode == UDP ? SOCK_DGRAM : SOCK_STREAM), 0)) == INVALID_SOCKET) {
895 perror("ERROR: tcp socket");
896 reconnect_sec_max = 0;
897 break;
898 }
899
900 memset((char*) &caster, 0x00, sizeof(caster));
901 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
902 caster.sin_family = AF_INET;
903 caster.sin_port = htons(outport);
904
905 /* connect to Destination caster, server or proxy host */
906 fprintf(stderr, "caster output: host = %s, port = %d, mountpoint = %s"
907 ", mode = %s\n\n", inet_ntoa(caster.sin_addr), outport, mountpoint,
908 outputmode == NTRIP1 ? "ntrip1" : outputmode == HTTP ? "http" :
909 outputmode == UDP ? "udp" : "rtsp");
910
911 if (connect(socket_tcp, (struct sockaddr*) &caster, sizeof(caster)) < 0) {
912 fprintf(stderr, "WARNING: can't connect output to %s at port %d\n",
913 inet_ntoa(caster.sin_addr), outport);
914 break;
915 }
916
917 /*** OutputMode handling ***/
918 switch (outputmode) {
919 case UDP: {
920 unsigned int session;
921 char rtpbuf[1526];
922 int i = 12, j;
923
924 udp_init = time(0);
925 srand(udp_init);
926 session = rand();
927 udp_tim = rand();
928 udp_seq = rand();
929
930 rtpbuf[0] = (2 << 6);
931 /* padding, extension, csrc are empty */
932 rtpbuf[1] = 97;
933 /* marker is empty */
934 rtpbuf[2] = (udp_seq >> 8) & 0xFF;
935 rtpbuf[3] = (udp_seq) & 0xFF;
936 rtpbuf[4] = (udp_tim >> 24) & 0xFF;
937 rtpbuf[5] = (udp_tim >> 16) & 0xFF;
938 rtpbuf[6] = (udp_tim >> 8) & 0xFF;
939 rtpbuf[7] = (udp_tim) & 0xFF;
940 /* sequence and timestamp are empty */
941 rtpbuf[8] = (session >> 24) & 0xFF;
942 rtpbuf[9] = (session >> 16) & 0xFF;
943 rtpbuf[10] = (session >> 8) & 0xFF;
944 rtpbuf[11] = (session) & 0xFF;
945 ++udp_seq;
946
947 j = snprintf(rtpbuf + i, sizeof(rtpbuf) - i - 40, /* leave some space for login */
948 "POST /%s HTTP/1.1\r\n"
949 "Host: %s\r\n"
950 "Ntrip-Version: Ntrip/2.0\r\n"
951 "User-Agent: %s/%s\r\n"
952 "Authorization: Basic %s%s%s\r\n"
953 "Connection: close\r\n"
954 "Transfer-Encoding: chunked\r\n\r\n", mountpoint, casterouthost,
955 AGENTSTRING, revisionstr, authorization,
956 ntrip_str ?
957 (outputmode == NTRIP1 ? "\r\nSTR: " : "\r\nNtrip-STR: ") : "",
958 ntrip_str);
959 i += j;
960 if (i > (int) sizeof(rtpbuf) - 40 || j < 0) /* second check for old glibc */
961 {
962 fprintf(stderr, "Requested data too long\n");
963 reconnect_sec_max = 0;
964 output_init = 0;
965 break;
966 } else {
967 rtpbuf[i++] = '\r';
968 rtpbuf[i++] = '\n';
969 rtpbuf[i++] = '\r';
970 rtpbuf[i++] = '\n';
971
972 if (send(socket_tcp, rtpbuf, i, 0) != i) {
973 perror("Could not send UDP packet");
974 reconnect_sec_max = 0;
975 output_init = 0;
976 break;
977 } else {
978 int stop = 0;
979 int numbytes;
980 if ((numbytes = recv(socket_tcp, rtpbuf, sizeof(rtpbuf) - 1, 0))
981 > 0) {
982 /* we don't expect message longer than 1513, so we cut the last
983 byte for security reasons to prevent buffer overrun */
984 rtpbuf[numbytes] = 0;
985 if (numbytes > 17 + 12
986 && (!strncmp(rtpbuf + 12, "HTTP/1.1 200 OK\r\n", 17)
987 || !strncmp(rtpbuf + 12, "HTTP/1.0 200 OK\r\n", 17))) {
988 const char *sessioncheck = "session: ";
989 int l = strlen(sessioncheck) - 1;
990 int j = 0;
991 for (i = 12; j != l && i < numbytes - l; ++i) {
992 for (j = 0;
993 j < l && tolower(rtpbuf[i + j]) == sessioncheck[j]; ++j)
994 ;
995 }
996 if (i != numbytes - l) /* found a session number */
997 {
998 i += l;
999 session = 0;
1000 while (i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9')
1001 session = session * 10 + rtpbuf[i++] - '0';
1002 if (rtpbuf[i] != '\r') {
1003 fprintf(stderr, "Could not extract session number\n");
1004 stop = 1;
1005 }
1006 }
1007 } else {
1008 int k;
1009 fprintf(stderr, "Could not access mountpoint: ");
1010 for (k = 12;
1011 k < numbytes && rtpbuf[k] != '\n' && rtpbuf[k] != '\r';
1012 ++k) {
1013 fprintf(stderr, "%c", isprint(rtpbuf[k]) ? rtpbuf[k] : '.');
1014 }
1015 fprintf(stderr, "\n");
1016 stop = 1;
1017 }
1018 }
1019 if (!stop) {
1020 send_receive_loop(socket_tcp, outputmode, NULL, 0, session, chunkymode);
1021 input_init = output_init = 0;
1022 /* send connection close always to allow nice session closing */
1023 udp_tim += (time(0) - udp_init) * 1000000 / TIME_RESOLUTION;
1024 rtpbuf[0] = (2 << 6);
1025 /* padding, extension, csrc are empty */
1026 rtpbuf[1] = 98;
1027 /* marker is empty */
1028 rtpbuf[2] = (udp_seq >> 8) & 0xFF;
1029 rtpbuf[3] = (udp_seq) & 0xFF;
1030 rtpbuf[4] = (udp_tim >> 24) & 0xFF;
1031 rtpbuf[5] = (udp_tim >> 16) & 0xFF;
1032 rtpbuf[6] = (udp_tim >> 8) & 0xFF;
1033 rtpbuf[7] = (udp_tim) & 0xFF;
1034 /* sequence and timestamp are empty */
1035 rtpbuf[8] = (session >> 24) & 0xFF;
1036 rtpbuf[9] = (session >> 16) & 0xFF;
1037 rtpbuf[10] = (session >> 8) & 0xFF;
1038 rtpbuf[11] = (session) & 0xFF;
1039
1040 send(socket_tcp, rtpbuf, 12, 0); /* cleanup */
1041 } else {
1042 reconnect_sec_max = 600;
1043 output_init = 0;
1044 }
1045 }
1046 }
1047 }
1048 break;
1049 case NTRIP1: /*** OutputMode Ntrip Version 1.0 ***/
1050 fallback = 0;
1051 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1052 "SOURCE %s %s/%s\r\n"
1053 "Source-Agent: %s/%s\r\n\r\n", password, post_extension,
1054 mountpoint, AGENTSTRING, revisionstr);
1055 if ((nBufferBytes > (int) sizeof(szSendBuffer))
1056 || (nBufferBytes < 0)) {
1057 fprintf(stderr, "ERROR: Destination caster request to long\n");
1058 reconnect_sec_max = 0;
1059 output_init = 0;
1060 break;
1061 }
1062 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
1063 output_init = 0;
1064 break;
1065 }
1066 /* check Destination caster's response */
1067 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer),
1068 0);
1069 szSendBuffer[nBufferBytes] = '\0';
1070 if (!strstr(szSendBuffer, "OK")) {
1071 char *a;
1072 fprintf(stderr,
1073 "ERROR: Destination caster's or Proxy's reply is not OK: ");
1074 for (a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a) {
1075 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
1076 }
1077 fprintf(stderr, "\n");
1078 if ((strstr(szSendBuffer, "ERROR - Bad Password"))
1079 || (strstr(szSendBuffer, "400 Bad Request")))
1080 reconnect_sec_max = 0;
1081 output_init = 0;
1082 break;
1083 }
1084#ifndef NDEBUG
1085 else {
1086 fprintf(stderr, "Destination caster response:\n%s\n", szSendBuffer);
1087 }
1088#endif
1089 send_receive_loop(socket_tcp, outputmode, NULL, 0, 0, chunkymode);
1090 input_init = output_init = 0;
1091 break;
1092 case HTTP: /*** Ntrip-Version 2.0 HTTP/1.1 ***/
1093 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1094 "POST %s/%s HTTP/1.1\r\n"
1095 "Host: %s\r\n"
1096 "Ntrip-Version: Ntrip/2.0\r\n"
1097 "User-Agent: %s/%s\r\n"
1098 "Authorization: Basic %s%s%s\r\n"
1099 "Connection: close\r\n"
1100 "Transfer-Encoding: chunked\r\n\r\n", post_extension,
1101 mountpoint, casterouthost, AGENTSTRING, revisionstr,
1102 authorization, ntrip_str ? "\r\nNtrip-STR: " : "", ntrip_str);
1103 if ((nBufferBytes > (int) sizeof(szSendBuffer))
1104 || (nBufferBytes < 0)) {
1105 fprintf(stderr, "ERROR: Destination caster request to long\n");
1106 reconnect_sec_max = 0;
1107 output_init = 0;
1108 break;
1109 }
1110 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
1111 output_init = 0;
1112 break;
1113 }
1114 /* check Destination caster's response */
1115 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
1116 szSendBuffer[nBufferBytes] = '\0';
1117 if (!strstr(szSendBuffer, "HTTP/1.1 200 OK")) {
1118 char *a;
1119 fprintf(stderr, "ERROR: Destination caster's%s reply is not OK: ",
1120 *proxyhost ? " or Proxy's" : "");
1121 for (a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a) {
1122 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
1123 }
1124 fprintf(stderr, "\n");
1125 /* fallback if necessary */
1126 if (!strstr(szSendBuffer, "Ntrip-Version: Ntrip/2.0\r\n")) {
1127 fprintf(stderr,
1128 " Ntrip Version 2.0 not implemented at Destination caster"
1129 " <%s>%s%s%s\n%s\n"
1130 "ntripserver falls back to Ntrip Version 1.0\n\n",
1131 casterouthost, *proxyhost ? " or Proxy <" : "", proxyhost,
1132 *proxyhost ? ">" : "",
1133 *proxyhost ?
1134 " or HTTP/1.1 not implemented at Proxy\n" : "");
1135 close_session(casterouthost, mountpoint, session, rtsp_extension, 1);
1136 outputmode = NTRIP1;
1137 break;
1138 } else if ((strstr(szSendBuffer, "HTTP/1.1 401 Unauthorized"))
1139 || (strstr(szSendBuffer, "501 Not Implemented"))) {
1140 reconnect_sec_max = 0;
1141 }
1142 output_init = 0;
1143 break;
1144 }
1145#ifndef NDEBUG
1146 else {
1147 fprintf(stderr, "Destination caster response:\n%s\n", szSendBuffer);
1148 }
1149#endif
1150 send_receive_loop(socket_tcp, outputmode, NULL, 0, 0, chunkymode);
1151 input_init = output_init = 0;
1152 break;
1153 case RTSP: /*** Ntrip-Version 2.0 RTSP / RTP ***/
1154 if ((socket_udp = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
1155 perror("ERROR: udp socket");
1156 exit(4);
1157 }
1158 /* fill structure with local address information for UDP */
1159 memset(&local, 0, sizeof(local));
1160 local.sin_family = AF_INET;
1161 local.sin_port = htons(0);
1162 local.sin_addr.s_addr = htonl(INADDR_ANY);
1163 len = (socklen_t) sizeof(local);
1164 /* bind() in order to get a random RTP client_port */
1165 if ((bind(socket_udp, (struct sockaddr*) &local, len)) < 0) {
1166 perror("ERROR: udp bind");
1167 reconnect_sec_max = 0;
1168 output_init = 0;
1169 break;
1170 }
1171 if ((getsockname(socket_udp, (struct sockaddr*) &local, &len))
1172 != -1) {
1173 client_port = (unsigned int) ntohs(local.sin_port);
1174 } else {
1175 perror("ERROR: getsockname(localhost)");
1176 reconnect_sec_max = 0;
1177 output_init = 0;
1178 break;
1179 }
1180 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1181 "SETUP rtsp://%s%s/%s RTSP/1.0\r\n"
1182 "CSeq: %d\r\n"
1183 "Ntrip-Version: Ntrip/2.0\r\n"
1184 "Ntrip-Component: Ntripserver\r\n"
1185 "User-Agent: %s/%s\r\n"
1186 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
1187 "Authorization: Basic %s%s%s\r\n\r\n", casterouthost,
1188 rtsp_extension, mountpoint, udp_cseq++, AGENTSTRING, revisionstr,
1189 client_port, authorization, ntrip_str ? "\r\nNtrip-STR: " : "",
1190 ntrip_str);
1191 if ((nBufferBytes > (int) sizeof(szSendBuffer))
1192 || (nBufferBytes < 0)) {
1193 fprintf(stderr, "ERROR: Destination caster request to long\n");
1194 reconnect_sec_max = 0;
1195 output_init = 0;
1196 break;
1197 }
1198 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
1199 output_init = 0;
1200 break;
1201 }
1202 while ((nBufferBytes = recv(socket_tcp, szSendBuffer,
1203 sizeof(szSendBuffer), 0)) > 0) {
1204 /* check Destination caster's response */
1205 szSendBuffer[nBufferBytes] = '\0';
1206 if (!strstr(szSendBuffer, "RTSP/1.0 200 OK")) {
1207 char *a;
1208 fprintf(stderr, "ERROR: Destination caster's%s reply is not OK: ",
1209 *proxyhost ? " or Proxy's" : "");
1210 for (a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a) {
1211 fprintf(stderr, "%c", isprint(*a) ? *a : '.');
1212 }
1213 fprintf(stderr, "\n");
1214 /* fallback if necessary */
1215 if (strncmp(szSendBuffer, "RTSP", 4) != 0) {
1216 if (strstr(szSendBuffer, "Ntrip-Version: Ntrip/2.0\r\n")) {
1217 fprintf(stderr,
1218 " RTSP not implemented at Destination caster <%s>%s%s%s\n\n"
1219 "ntripserver falls back to Ntrip Version 2.0 in TCP/IP"
1220 " mode\n\n", casterouthost,
1221 *proxyhost ? " or Proxy <" : "", proxyhost,
1222 *proxyhost ? ">" : "");
1223 close_session(casterouthost, mountpoint, session,
1224 rtsp_extension, 1);
1225 outputmode = HTTP;
1226 fallback = 1;
1227 break;
1228 } else {
1229 fprintf(stderr,
1230 " Ntrip-Version 2.0 not implemented at Destination caster"
1231 "<%s>%s%s%s\n%s"
1232 " or RTSP/1.0 not implemented at Destination caster%s\n\n"
1233 "ntripserver falls back to Ntrip Version 1.0\n\n",
1234 casterouthost, *proxyhost ? " or Proxy <" : "", proxyhost,
1235 *proxyhost ? ">" : "",
1236 *proxyhost ?
1237 " or HTTP/1.1 not implemented at Proxy\n" : "",
1238 *proxyhost ? " or Proxy" : "");
1239 close_session(casterouthost, mountpoint, session,
1240 rtsp_extension, 1);
1241 outputmode = NTRIP1;
1242 fallback = 1;
1243 break;
1244 }
1245 } else if ((strstr(szSendBuffer, "RTSP/1.0 401 Unauthorized"))
1246 || (strstr(szSendBuffer, "RTSP/1.0 501 Not Implemented"))) {
1247 reconnect_sec_max = 0;
1248 }
1249 output_init = 0;
1250 break;
1251 }
1252#ifndef NDEBUG
1253 else {
1254 fprintf(stderr, "Destination caster response:\n%s\n", szSendBuffer);
1255 }
1256#endif
1257 if ((strstr(szSendBuffer, "RTSP/1.0 200 OK\r\n"))
1258 && (strstr(szSendBuffer, "CSeq: 1\r\n"))) {
1259 for (token = strtok(szSendBuffer, dlim); token != NULL; token =
1260 strtok(NULL, dlim)) {
1261 tok_buf[i] = token;
1262 i++;
1263 }
1264 session = atoi(tok_buf[6]);
1265 server_port = atoi(tok_buf[10]);
1266 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1267 "RECORD rtsp://%s%s/%s RTSP/1.0\r\n"
1268 "CSeq: %d\r\n"
1269 "Session: %u\r\n"
1270 "\r\n", casterouthost, rtsp_extension, mountpoint,
1271 udp_cseq++, session);
1272 if ((nBufferBytes >= (int) sizeof(szSendBuffer))
1273 || (nBufferBytes < 0)) {
1274 fprintf(stderr, "ERROR: Destination caster request to long\n");
1275 reconnect_sec_max = 0;
1276 output_init = 0;
1277 break;
1278 }
1279 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
1280 output_init = 0;
1281 break;
1282 }
1283 } else if ((strstr(szSendBuffer, "RTSP/1.0 200 OK\r\n"))
1284 && (strstr(szSendBuffer, "CSeq: 2\r\n"))) {
1285 /* fill structure with caster address information for UDP */
1286 memset(&casterRTP, 0, sizeof(casterRTP));
1287 casterRTP.sin_family = AF_INET;
1288 casterRTP.sin_port = htons(((uint16_t) server_port));
1289 if ((he = gethostbyname(outhost)) == NULL) {
1290 fprintf(stderr, "ERROR: Destination caster unknown\n");
1291 reconnect_sec_max = 0;
1292 output_init = 0;
1293 break;
1294 } else {
1295 memcpy((char*) &casterRTP.sin_addr.s_addr, he->h_addr_list[0],
1296 (size_t) he->h_length);
1297 }
1298 len = (socklen_t) sizeof(casterRTP);
1299 send_receive_loop(socket_udp, outputmode,
1300 (struct sockaddr*) &casterRTP, (socklen_t) len, session, chunkymode);
1301 break;
1302 } else {
1303 break;
1304 }
1305 }
1306 input_init = output_init = 0;
1307 break;
1308 case TDC:
1309 break;
1310 }
1311 }
1312 close_session(casterouthost, mountpoint, session, rtsp_extension, 0);
1313 if ((reconnect_sec_max || fallback) && !sigint_received)
1314 reconnect_sec = reconnect(reconnect_sec, reconnect_sec_max);
1315 else
1316 inputmode = LAST;
1317 }
1318 return 0;
1319}
1320
1321static void send_receive_loop(sockettype sock, int outmode,
1322 struct sockaddr *pcasterRTP, socklen_t length, unsigned int rtpssrc,
1323 int chunkymode) {
1324 int nodata = 0;
1325 char buffer[BUFSZ] = { 0 };
1326 char sisnetbackbuffer[200];
1327 char szSendBuffer[BUFSZ] = "";
1328 int nBufferBytes = 0;
1329 int remainChunk = 0;
1330
1331 /* RTSP / RTP Mode */
1332 int isfirstpacket = 1;
1333 struct timeval now;
1334 struct timeval last = { 0, 0 };
1335 long int sendtimediff;
1336 int rtpseq = 0;
1337 int rtptime = 0;
1338 time_t laststate = time(0);
1339
1340 if (outmode == UDP) {
1341 rtptime = time(0);
1342#ifdef WINDOWSVERSION
1343 u_long blockmode = 1;
1344 if(ioctlsocket(socket_tcp, FIONBIO, &blockmode))
1345#else /* WINDOWSVERSION */
1346 if (fcntl(socket_tcp, F_SETFL, O_NONBLOCK) < 0)
1347#endif /* WINDOWSVERSION */
1348 {
1349 fprintf(stderr, "Could not set nonblocking mode\n");
1350 return;
1351 }
1352 } else if (outmode == RTSP) {
1353#ifdef WINDOWSVERSION
1354 u_long blockmode = 1;
1355 if(ioctlsocket(socket_tcp, FIONBIO, &blockmode))
1356#else /* WINDOWSVERSION */
1357 if (fcntl(socket_tcp, F_SETFL, O_NONBLOCK) < 0)
1358#endif /* WINDOWSVERSION */
1359 {
1360 fprintf(stderr, "Could not set nonblocking mode\n");
1361 return;
1362 }
1363 }
1364
1365 /* data transmission */
1366 fprintf(stderr, "transfering data ...\n");
1367 int send_recv_success = 0;
1368#ifdef WINDOWSVERSION
1369 time_t nodata_begin = 0, nodata_current = 0;
1370#endif
1371 while (1) {
1372 if (send_recv_success < 3)
1373 send_recv_success++;
1374 if (!nodata) {
1375#ifndef WINDOWSVERSION
1376 alarm(ALARMTIME);
1377#else
1378 time(&nodata_begin);
1379#endif
1380 } else {
1381 nodata = 0;
1382#ifdef WINDOWSVERSION
1383 time(&nodata_current);
1384 if(difftime(nodata_current, nodata_begin) >= ALARMTIME) {
1385 sigalarm_received = 1;
1386 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
1387 }
1388#endif
1389 }
1390 /* signal handling*/
1391#ifdef WINDOWSVERSION
1392 if((sigalarm_received) || (sigint_received)) break;
1393#else
1394 if ((sigalarm_received) || (sigint_received) || (sigpipe_received))
1395 break;
1396#endif
1397 if (!nBufferBytes) {
1398 if (inputmode == SISNET && sisnet <= 30) {
1399 int i;
1400 /* a somewhat higher rate than 1 second to get really each block */
1401 /* means we need to skip double blocks sometimes */
1402 struct timeval tv = { 0, 700000 };
1403 select(0, 0, 0, 0, &tv);
1404 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
1405 i = (sisnet >= 30 ? 5 : 3);
1406 if ((send(gps_socket, "MSG\r\n", i, 0)) != i) {
1407 perror("WARNING: sending SISNeT data request failed");
1408 return;
1409 }
1410 }
1411 /*** receiving data ****/
1412 if (inputmode == INFILE)
1413 nBufferBytes = read(gps_file, buffer, sizeof(buffer));
1414 else if (inputmode == SERIAL) {
1415#ifndef WINDOWSVERSION
1416 nBufferBytes = read(gps_serial, buffer, sizeof(buffer));
1417#else
1418 DWORD nRead = 0;
1419 if(!ReadFile(gps_serial, buffer, sizeof(buffer), &nRead, NULL))
1420 {
1421 fprintf(stderr,"ERROR: reading serial input failed\n");
1422 return;
1423 }
1424 nBufferBytes = (int)nRead;
1425#endif
1426 }
1427 else
1428#ifdef WINDOWSVERSION
1429 nBufferBytes = recv(gps_socket, buffer, sizeof(buffer), 0);
1430#else
1431 nBufferBytes = read(gps_socket, buffer, sizeof(buffer));
1432#endif
1433 if (!nBufferBytes) {
1434 fprintf(stderr, "WARNING: no data received from input\n");
1435 nodata = 1;
1436#ifndef WINDOWSVERSION
1437 sleep(3);
1438#else
1439 Sleep(3*1000);
1440#endif
1441 continue;
1442 } else if ((nBufferBytes < 0) && (!sigint_received)) {
1443 perror("WARNING: reading input failed");
1444 return;
1445 }
1446 /* we can compare the whole buffer, as the additional bytes
1447 remain unchanged */
1448 if (inputmode == SISNET && sisnet <= 30
1449 && !memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer))) {
1450 nBufferBytes = 0;
1451 }
1452 }
1453 if (nBufferBytes < 0)
1454 return;
1455
1456 if (chunkymode) {
1457 int cstop = 0;
1458 int pos = 0;
1459 int chunksize = 0;
1460 int totalbytes = 0;
1461 int nChunkBytes = 0;
1462 char chunkBytes[BUFSZ];
1463
1464 long i;
1465 while (!sigint_received && !cstop && pos < nBufferBytes) {
1466 switch (chunkymode) {
1467 case 1: /* reading number starts */
1468 chunksize = 0;
1469 ++chunkymode; /* no break */
1470 break;
1471 case 2: /* during reading number */
1472 i = buffer[pos++];
1473 if (i >= '0' && i <= '9')
1474 chunksize = chunksize * 16 + i - '0';
1475 else if (i >= 'a' && i <= 'f')
1476 chunksize = chunksize * 16 + i - 'a' + 10;
1477 else if (i >= 'A' && i <= 'F')
1478 chunksize = chunksize * 16 + i - 'A' + 10;
1479 else if (i == '\r')
1480 ++chunkymode;
1481 else if (i == ';')
1482 chunkymode = 5;
1483 else
1484 cstop = 1;
1485 break;
1486 case 3: /* scanning for return */
1487 if (buffer[pos++] == '\n')
1488 chunkymode = chunksize ? 4 : 1;
1489 else
1490 cstop = 1;
1491 break;
1492 case 4: /* output data */
1493 i = nBufferBytes - pos;
1494 if (i > chunksize) {
1495 i = chunksize;
1496 }
1497 if (nChunkBytes <= nBufferBytes) {
1498 memcpy(chunkBytes + nChunkBytes, buffer + pos, (size_t) i);
1499 nChunkBytes += i;
1500 }
1501 totalbytes += i;
1502 chunksize -= i;
1503 pos += i;
1504 if (!chunksize)
1505 chunkymode = 1;
1506 break;
1507 case 5:
1508 if (i == '\r')
1509 chunkymode = 3;
1510 break;
1511 }
1512 }
1513 if (cstop) {
1514 fprintf(stderr, "Error in chunky transfer encoding\n");
1515 return;
1516 }
1517 else {
1518 if (nChunkBytes <= nBufferBytes) {
1519 strcpy(buffer, "");
1520 memcpy(buffer, chunkBytes, (size_t) nChunkBytes);
1521 nBufferBytes = nChunkBytes;
1522 }
1523 }
1524 }
1525 /** send data ***/
1526 if ((nBufferBytes) && (outmode == NTRIP1)) /*** Ntrip-Version 1.0 ***/
1527 {
1528 int i;
1529 if ((i = send(sock, buffer, (size_t) nBufferBytes, MSG_DONTWAIT)) != nBufferBytes) {
1530 if (i < 0) {
1531 if (errno != EAGAIN) {
1532 perror("WARNING: could not send data to Destination caster");
1533 return;
1534 }
1535 } else if (i) {
1536 memmove(buffer, buffer + i, (size_t) (nBufferBytes - i));
1537 nBufferBytes -= i;
1538 }
1539 } else {
1540 nBufferBytes = 0;
1541 }
1542 } else if ((nBufferBytes) && (outmode == UDP)) {
1543 char rtpbuf[1592];
1544 int i;
1545 int ct = time(0);
1546 udp_tim += (ct - udp_init) * 1000000 / TIME_RESOLUTION;
1547 udp_init = ct;
1548 rtpbuf[0] = (2 << 6);
1549 rtpbuf[1] = 96;
1550 rtpbuf[2] = (udp_seq >> 8) & 0xFF;
1551 rtpbuf[3] = (udp_seq) & 0xFF;
1552 rtpbuf[4] = (udp_tim >> 24) & 0xFF;
1553 rtpbuf[5] = (udp_tim >> 16) & 0xFF;
1554 rtpbuf[6] = (udp_tim >> 8) & 0xFF;
1555 rtpbuf[7] = (udp_tim) & 0xFF;
1556 rtpbuf[8] = (rtpssrc >> 24) & 0xFF;
1557 rtpbuf[9] = (rtpssrc >> 16) & 0xFF;
1558 rtpbuf[10] = (rtpssrc >> 8) & 0xFF;
1559 rtpbuf[11] = (rtpssrc) & 0xFF;
1560 ++udp_seq;
1561 memcpy(rtpbuf + 12, buffer, nBufferBytes);
1562 if ((i = send(socket_tcp, rtpbuf, (size_t) nBufferBytes + 12, MSG_DONTWAIT)) != nBufferBytes + 12) {
1563 if (errno != EAGAIN) {
1564 perror("WARNING: could not send data to Destination caster");
1565 return;
1566 }
1567 } else
1568 nBufferBytes = 0;
1569 i = recv(socket_tcp, rtpbuf, sizeof(rtpbuf), 0);
1570 if (i >= 12 && (unsigned char) rtpbuf[0] == (2 << 6)
1571 && rtpssrc
1572 == (unsigned int) (((unsigned char) rtpbuf[8] << 24)
1573 + ((unsigned char) rtpbuf[9] << 16)
1574 + ((unsigned char) rtpbuf[10] << 8)
1575 + (unsigned char) rtpbuf[11])) {
1576 if (rtpbuf[1] == 96)
1577 rtptime = time(0);
1578 else if (rtpbuf[1] == 98) {
1579 fprintf(stderr, "Connection end\n");
1580 return;
1581 }
1582 } else if (time(0) > rtptime + 60) {
1583 fprintf(stderr, "Timeout\n");
1584 return;
1585 }
1586 }
1587 /*** Ntrip-Version 2.0 HTTP/1.1 ***/
1588 else if ((nBufferBytes) && (outmode == HTTP)) {
1589 if (!remainChunk) {
1590 int nChunkBytes = snprintf(szSendBuffer, sizeof(szSendBuffer), "%x\r\n", nBufferBytes);
1591 send(sock, szSendBuffer, nChunkBytes, 0);
1592 remainChunk = nBufferBytes;
1593 }
1594 int i = send(sock, buffer, (size_t) remainChunk, MSG_DONTWAIT);
1595 if (i < 0) {
1596 if (errno != EAGAIN) {
1597 perror("WARNING: could not send data to Destination caster");
1598 return;
1599 }
1600 } else if (i) {
1601 memmove(buffer, buffer + i, (size_t) (nBufferBytes - i));
1602 nBufferBytes -= i;
1603 remainChunk -= i;
1604 } else {
1605 nBufferBytes = 0;
1606 remainChunk = 0;
1607 }
1608 if (!remainChunk)
1609 send(sock, "\r\n", strlen("\r\n"), 0);
1610 }
1611 /*** Ntrip-Version 2.0 RTSP(TCP) / RTP(UDP) ***/
1612 else if ((nBufferBytes) && (outmode == RTSP)) {
1613 time_t ct;
1614 int r;
1615 char rtpbuffer[BUFSZ + 12];
1616 int i, j;
1617 gettimeofday(&now, NULL);
1618 /* RTP data packet generation*/
1619 if (isfirstpacket) {
1620 rtpseq = rand();
1621 rtptime = rand();
1622 last = now;
1623 isfirstpacket = 0;
1624 } else {
1625 ++rtpseq;
1626 sendtimediff = (((now.tv_sec - last.tv_sec) * 1000000)
1627 + (now.tv_usec - last.tv_usec));
1628 rtptime += sendtimediff / TIME_RESOLUTION;
1629 }
1630 rtpbuffer[0] = (RTP_VERSION << 6);
1631 /* padding, extension, csrc are empty */
1632 rtpbuffer[1] = 96;
1633 /* marker is empty */
1634 rtpbuffer[2] = rtpseq >> 8;
1635 rtpbuffer[3] = rtpseq;
1636 rtpbuffer[4] = rtptime >> 24;
1637 rtpbuffer[5] = rtptime >> 16;
1638 rtpbuffer[6] = rtptime >> 8;
1639 rtpbuffer[7] = rtptime;
1640 rtpbuffer[8] = rtpssrc >> 24;
1641 rtpbuffer[9] = rtpssrc >> 16;
1642 rtpbuffer[10] = rtpssrc >> 8;
1643 rtpbuffer[11] = rtpssrc;
1644 for (j = 0; j < nBufferBytes; j++) {
1645 rtpbuffer[12 + j] = buffer[j];
1646 }
1647 last.tv_sec = now.tv_sec;
1648 last.tv_usec = now.tv_usec;
1649 if ((i = sendto(sock, rtpbuffer, 12 + nBufferBytes, 0, pcasterRTP, length))
1650 != (nBufferBytes + 12)) {
1651 if (i < 0) {
1652 if (errno != EAGAIN) {
1653 perror("WARNING: could not send data to Destination caster");
1654 return;
1655 }
1656 } else if (i) {
1657 memmove(buffer, buffer + (i - 12),
1658 (size_t) (nBufferBytes - (i - 12)));
1659 nBufferBytes -= i - 12;
1660 }
1661 } else {
1662 nBufferBytes = 0;
1663 }
1664 ct = time(0);
1665 if (ct - laststate > 15) {
1666 i = snprintf(buffer, sizeof(buffer),
1667 "GET_PARAMETER rtsp://%s%s/%s RTSP/1.0\r\n"
1668 "CSeq: %d\r\n"
1669 "Session: %u\r\n"
1670 "\r\n", casterouthost, rtsp_extension, mountpoint, udp_cseq++,
1671 rtpssrc);
1672 if (i > (int) sizeof(buffer) || i < 0) {
1673 fprintf(stderr, "Requested data too long\n");
1674 return;
1675 } else if (send(socket_tcp, buffer, (size_t) i, 0) != i) {
1676 perror("send");
1677 return;
1678 }
1679 laststate = ct;
1680 }
1681 /* ignore RTSP server replies */
1682 if ((r = recv(socket_tcp, buffer, sizeof(buffer), 0)) < 0) {
1683#ifdef WINDOWSVERSION
1684 if(WSAGetLastError() != WSAEWOULDBLOCK)
1685#else /* WINDOWSVERSION */
1686 if (errno != EAGAIN)
1687#endif /* WINDOWSVERSION */
1688 {
1689 fprintf(stderr, "Control connection closed\n");
1690 return;
1691 }
1692 } else if (!r) {
1693 fprintf(stderr, "Control connection read error\n");
1694 return;
1695 }
1696 }
1697 if (send_recv_success == 3)
1698 reconnect_sec = 1;
1699 }
1700 return;
1701}
1702
1703/********************************************************************
1704 * openserial
1705 *
1706 * Open the serial port with the given device name and configure it for
1707 * reading NMEA data from a GPS receiver.
1708 *
1709 * Parameters:
1710 * tty : pointer to : A zero-terminated string containing the device
1711 * unsigned char name of the appropriate serial port.
1712 * blocksz : integer : Block size for port I/O (ifndef WINDOWSVERSION)
1713 * baud : integer : Baud rate for port I/O
1714 *
1715 * Return Value:
1716 * The function returns a file descriptor for the opened port if successful.
1717 * The function returns -1 / INVALID_HANDLE_VALUE in the event of an error.
1718 *
1719 * Remarks:
1720 *
1721 ********************************************************************/
1722#ifndef WINDOWSVERSION
1723static int openserial(const char *tty, int blocksz, int baud) {
1724 struct termios termios;
1725
1726 /*** opening the serial port ***/
1727 gps_serial = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
1728 if (gps_serial < 0) {
1729 perror("ERROR: opening serial connection");
1730 return (-1);
1731 }
1732
1733 /*** configuring the serial port ***/
1734 if (tcgetattr(gps_serial, &termios) < 0) {
1735 perror("ERROR: get serial attributes");
1736 return (-1);
1737 }
1738 termios.c_iflag = 0;
1739 termios.c_oflag = 0; /* (ONLRET) */
1740 termios.c_cflag = CS8 | CLOCAL | CREAD;
1741 termios.c_lflag = 0;
1742 {
1743 int cnt;
1744 for (cnt = 0; cnt < NCCS; cnt++)
1745 termios.c_cc[cnt] = -1;
1746 }
1747 termios.c_cc[VMIN] = blocksz;
1748 termios.c_cc[VTIME] = 2;
1749
1750#if (B4800 != 4800)
1751 /* Not every system has speed settings equal to absolute speed value. */
1752 switch (baud) {
1753 case 300:
1754 baud = B300;
1755 break;
1756 case 1200:
1757 baud = B1200;
1758 break;
1759 case 2400:
1760 baud = B2400;
1761 break;
1762 case 4800:
1763 baud = B4800;
1764 break;
1765 case 9600:
1766 baud = B9600;
1767 break;
1768 case 19200:
1769 baud = B19200;
1770 break;
1771 case 38400:
1772 baud = B38400;
1773 break;
1774#ifdef B57600
1775 case 57600:
1776 baud = B57600;
1777 break;
1778#endif
1779#ifdef B115200
1780 case 115200:
1781 baud = B115200;
1782 break;
1783#endif
1784#ifdef B230400
1785 case 230400:
1786 baud = B230400;
1787 break;
1788#endif
1789 default:
1790 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
1791 baud = B19200;
1792 break;
1793 }
1794#endif
1795
1796 if (cfsetispeed(&termios, baud) != 0) {
1797 perror("ERROR: setting serial speed with cfsetispeed");
1798 return (-1);
1799 }
1800 if (cfsetospeed(&termios, baud) != 0) {
1801 perror("ERROR: setting serial speed with cfsetospeed");
1802 return (-1);
1803 }
1804 if (tcsetattr(gps_serial, TCSANOW, &termios) < 0) {
1805 perror("ERROR: setting serial attributes");
1806 return (-1);
1807 }
1808 if (fcntl(gps_serial, F_SETFL, 0) == -1) {
1809 perror("WARNING: setting blocking inputmode failed");
1810 }
1811 return (gps_serial);
1812}
1813#else
1814static HANDLE openserial(const char * tty, int baud) {
1815 char compath[15] = "";
1816
1817 snprintf(compath, sizeof(compath), "\\\\.\\%s", tty);
1818 if((gps_serial = CreateFile(compath, GENERIC_WRITE|GENERIC_READ
1819 , 0, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
1820 fprintf(stderr, "ERROR: opening serial connection\n");
1821 return (INVALID_HANDLE_VALUE);
1822 }
1823
1824 DCB dcb;
1825 memset(&dcb, 0, sizeof(dcb));
1826 char str[100];
1827 snprintf(str,sizeof(str),
1828 "baud=%d parity=N data=8 stop=1 xon=off octs=off rts=off",
1829 baud);
1830
1831 COMMTIMEOUTS ct = {1000, 1, 0, 0, 0};
1832
1833 if(!BuildCommDCB(str, &dcb)) {
1834 fprintf(stderr, "ERROR: get serial attributes\n");
1835 return (INVALID_HANDLE_VALUE);
1836 }
1837 else if(!SetCommState(gps_serial, &dcb)) {
1838 fprintf(stderr, "ERROR: set serial attributes\n");
1839 return (INVALID_HANDLE_VALUE);
1840 }
1841 else if(!SetCommTimeouts(gps_serial, &ct)) {
1842 fprintf(stderr, "ERROR: set serial timeouts\n");
1843 return (INVALID_HANDLE_VALUE);
1844 }
1845
1846 return (gps_serial);
1847}
1848#endif
1849
1850/********************************************************************
1851 * usage
1852 *
1853 * Send a usage message to standard error and quit the program.
1854 *
1855 * Parameters:
1856 * None.
1857 *
1858 * Return Value:
1859 * The function does not return a value.
1860 *
1861 * Remarks:
1862 *
1863 *********************************************************************/
1864#ifdef __GNUC__
1865__attribute__ ((noreturn))
1866#endif /* __GNUC__ */
1867void usage(int rc, char *name) {
1868 fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s [OPTIONS]\n",
1869 revisionstr, datestr, name);
1870 fprintf(stderr, "PURPOSE\n");
1871 fprintf(stderr,
1872 " The purpose of this program is to pick up a GNSS data stream (Input, Source)\n");
1873 fprintf(stderr, " from either\n\n");
1874 fprintf(stderr, " 1. a Serial port, or\n");
1875 fprintf(stderr, " 2. an IP server, or\n");
1876 fprintf(stderr, " 3. a File, or\n");
1877 fprintf(stderr, " 4. a SISNeT Data Server, or\n");
1878 fprintf(stderr, " 5. a UDP server, or\n");
1879 fprintf(stderr, " 6. an NTRIP Version 1.0 Caster\n");
1880 fprintf(stderr, " 7. an NTRIP Version 2.0 Caster in HTTP mode \n\n");
1881 fprintf(stderr,
1882 " and forward that incoming stream (Output, Destination) to either\n\n");
1883 fprintf(stderr, " - an NTRIP Version 1.0 Caster, or\n");
1884 fprintf(stderr,
1885 " - an NTRIP Version 2.0 Caster via TCP/IP or RTSP/RTP, or \n");
1886 fprintf(stderr, " - an DABPLUS Content Server via TCP/IP and TDC \n\n\n");
1887 fprintf(stderr, "OPTIONS\n");
1888 fprintf(stderr, " -h|? print this help screen\n\n");
1889 fprintf(stderr,
1890 " -E <ProxyHost> Proxy server host name or address, required i.e. when\n");
1891 fprintf(stderr,
1892 " running the program in a proxy server protected LAN,\n");
1893 fprintf(stderr, " optional\n");
1894 fprintf(stderr,
1895 " -F <ProxyPort> Proxy server IP port, required i.e. when running\n");
1896 fprintf(stderr,
1897 " the program in a proxy server protected LAN, optional\n");
1898 fprintf(stderr,
1899 " -R <maxDelay> Reconnect mechanism with maximum delay between reconnect\n");
1900 fprintf(stderr,
1901 " attemts in seconds, default: no reconnect activated,\n");
1902 fprintf(stderr, " optional\n\n");
1903 fprintf(stderr,
1904 " -M <InputMode> Sets the input mode (1 = Serial Port, 2 = IP server,\n");
1905 fprintf(stderr,
1906 " 3 = File, 4 = SISNeT Data Server, 5 = UDP server, 6 = NTRIP1 Caster, 7 = NTRIP2 Caster in HTTP mode),\n");
1907 fprintf(stderr, " mandatory\n\n");
1908 fprintf(stderr, " <InputMode> = 1 (Serial Port):\n");
1909 fprintf(stderr,
1910 " -i <Device> Serial input device, default: %s, mandatory if\n",
1911 ttyport);
1912 fprintf(stderr, " <InputMode>=1\n");
1913 fprintf(stderr,
1914 " -b <BaudRate> Serial input baud rate, default: 19200 bps, mandatory\n");
1915 fprintf(stderr, " if <InputMode>=1\n");
1916 fprintf(stderr,
1917 " -f <InitFile> Name of initialization file to be send to input device,\n");
1918 fprintf(stderr, " optional\n\n");
1919 fprintf(stderr, " <InputMode> = 2|5 (IP port | UDP port):\n");
1920 fprintf(stderr,
1921 " -H <ServerHost> Input host name or address, default: 127.0.0.1,\n");
1922 fprintf(stderr, " mandatory if <InputMode> = 2|5\n");
1923 fprintf(stderr,
1924 " -P <ServerPort> Input port, default: 1025, mandatory if <InputMode>= 2|5\n");
1925 fprintf(stderr,
1926 " -f <ServerFile> Name of initialization file to be send to server,\n");
1927 fprintf(stderr, " optional\n");
1928 fprintf(stderr,
1929 " -x <ServerUser> User ID to access incoming stream, optional\n");
1930 fprintf(stderr,
1931 " -y <ServerPass> Password, to access incoming stream, optional\n");
1932 fprintf(stderr,
1933 " -B Bind to incoming UDP stream, optional for <InputMode> = 5\n\n");
1934 fprintf(stderr, " <InputMode> = 3 (File):\n");
1935 fprintf(stderr,
1936 " -s <File> File name to simulate stream by reading data from (log)\n");
1937 fprintf(stderr,
1938 " file, default is %s, mandatory for <InputMode> = 3\n\n",
1939 filepath);
1940 fprintf(stderr, " <InputMode> = 4 (SISNeT Data Server):\n");
1941 fprintf(stderr,
1942 " -H <SisnetHost> SISNeT Data Server name or address,\n");
1943 fprintf(stderr,
1944 " default: 131.176.49.142, mandatory if <InputMode> = 4\n");
1945 fprintf(stderr,
1946 " -P <SisnetPort> SISNeT Data Server port, default: 7777, mandatory if\n");
1947 fprintf(stderr, " <InputMode> = 4\n");
1948 fprintf(stderr,
1949 " -u <SisnetUser> SISNeT Data Server user ID, mandatory if <InputMode> = 4\n");
1950 fprintf(stderr,
1951 " -l <SisnetPass> SISNeT Data Server password, mandatory if <InputMode> = 4\n");
1952 fprintf(stderr,
1953 " -V <SisnetVers> SISNeT Data Server Version number, options are 2.1, 3.0\n");
1954 fprintf(stderr,
1955 " or 3.1, default: 3.1, mandatory if <InputMode> = 4\n\n");
1956 fprintf(stderr, " <InputMode> = 6 (NTRIP Version 1.0 Caster):\n");
1957 fprintf(stderr,
1958 " -H <SourceHost> Source caster name or address, default: 127.0.0.1,\n");
1959 fprintf(stderr, " mandatory if <InputMode> = 6\n");
1960 fprintf(stderr,
1961 " -P <SourcePort> Source caster port, default: 2101, mandatory if\n");
1962 fprintf(stderr, " <InputMode> = 6\n");
1963 fprintf(stderr,
1964 " -D <SourceMount> Source caster mountpoint for stream input, mandatory if\n");
1965 fprintf(stderr, " <InputMode> = 6|7\n");
1966 fprintf(stderr,
1967 " -U <SourceUser> Source caster user Id for input stream access, mandatory\n");
1968 fprintf(stderr,
1969 " for protected streams if <InputMode> = 6|7\n");
1970 fprintf(stderr,
1971 " -W <SourcePass> Source caster password for input stream access, mandatory\n");
1972 fprintf(stderr,
1973 " for protected streams if <InputMode> = 6|7\n\n");
1974 fprintf(stderr,
1975 " -O <OutputMode> Sets output mode for communication with destination caster / server\n");
1976 fprintf(stderr,
1977 " 1 = http: NTRIP Version 2.0 Caster in TCP/IP mode\n");
1978 fprintf(stderr,
1979 " 2 = rtsp: NTRIP Version 2.0 Caster in RTSP/RTP mode\n");
1980 fprintf(stderr, " 3 = ntrip1: NTRIP Version 1.0 Caster\n");
1981 fprintf(stderr,
1982 " 4 = udp: NTRIP Version 2.0 Caster in Plain UDP mode\n");
1983 fprintf(stderr,
1984 " 5 = tdc: DABPLUS Content Server in TDC mode\n\n\n");
1985 fprintf(stderr,
1986 " Defaults to NTRIP1.0, but will change to 2.0 in future versions\n");
1987 fprintf(stderr,
1988 " Note that the program automatically falls back from mode rtsp to mode http and\n");
1989 fprintf(stderr, " further to mode ntrip1 if necessary.\n\n");
1990 fprintf(stderr,
1991 " -a <DestHost> Destination caster name or address, default: 127.0.0.1,\n");
1992 fprintf(stderr, " mandatory\n");
1993 fprintf(stderr,
1994 " -p <DestPort> Destination caster port, default: 2101,\n");
1995 fprintf(stderr, " mandatory\n");
1996 fprintf(stderr,
1997 " -m <DestMount> Destination caster mountpoint for stream upload,\n");
1998 fprintf(stderr,
1999 " only for NTRIP destination casters, mandatory\n");
2000 fprintf(stderr,
2001 " -n <DestUser> Destination caster user ID for stream upload to mountpoint,\n");
2002 fprintf(stderr,
2003 " only for NTRIP Version 2.0 destination casters, mandatory\n");
2004 fprintf(stderr,
2005 " -c <DestPass> Destination caster password for stream upload to mountpoint,\n");
2006 fprintf(stderr,
2007 " only for NTRIP destination casters, mandatory\n");
2008 fprintf(stderr, " -N <STR-record> Sourcetable STR-record\n");
2009 fprintf(stderr,
2010 " optional for NTRIP Version 2.0 in RTSP/RTP and TCP/IP mode\n\n");
2011 exit(rc);
2012} /* usage */
2013
2014/********************************************************************/
2015/* signal handling */
2016/********************************************************************/
2017#ifdef __GNUC__
2018static void handle_sigint(int sig __attribute__((__unused__)))
2019#else /* __GNUC__ */
2020static void handle_sigint(int sig)
2021#endif /* __GNUC__ */
2022{
2023 sigint_received = 1;
2024 fprintf(stderr, "WARNING: SIGINT received - ntripserver terminates\n");
2025}
2026
2027#ifndef WINDOWSVERSION
2028#ifdef __GNUC__
2029static void handle_alarm(int sig __attribute__((__unused__)))
2030#else /* __GNUC__ */
2031static void handle_alarm(int sig)
2032#endif /* __GNUC__ */
2033{
2034 sigalarm_received = 1;
2035 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
2036}
2037
2038#ifdef __GNUC__
2039static void handle_sigpipe(int sig __attribute__((__unused__)))
2040#else /* __GNUC__ */
2041static void handle_sigpipe(int sig)
2042#endif /* __GNUC__ */
2043{
2044 sigpipe_received = 1;
2045}
2046#endif /* WINDOWSVERSION */
2047
2048static void setup_signal_handler(int sig, void (*handler)(int)) {
2049#if _POSIX_VERSION > 198800L
2050 struct sigaction action;
2051
2052 action.sa_handler = handler;
2053 sigemptyset(&(action.sa_mask));
2054 sigaddset(&(action.sa_mask), sig);
2055 action.sa_flags = 0;
2056 sigaction(sig, &action, 0);
2057#else
2058 signal(sig, handler);
2059#endif
2060 return;
2061} /* setupsignal_handler */
2062
2063/********************************************************************
2064 * base64-encoding *
2065 *******************************************************************/
2066static const char encodingTable[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2067 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2068 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
2069 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
2070 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
2071
2072/* does not buffer overrun, but breaks directly after an error */
2073/* returns the number of required bytes */
2074static int encode(char *buf, int size, const char *user, const char *pwd) {
2075 unsigned char inbuf[3];
2076 char *out = buf;
2077 int i, sep = 0, fill = 0, bytes = 0;
2078
2079 while (*user || *pwd) {
2080 i = 0;
2081 while (i < 3 && *user)
2082 inbuf[i++] = *(user++);
2083 if (i < 3 && !sep) {
2084 inbuf[i++] = ':';
2085 ++sep;
2086 }
2087 while (i < 3 && *pwd)
2088 inbuf[i++] = *(pwd++);
2089 while (i < 3) {
2090 inbuf[i++] = 0;
2091 ++fill;
2092 }
2093 if (out - buf < size - 1)
2094 *(out++) = encodingTable[(inbuf[0] & 0xFC) >> 2];
2095 if (out - buf < size - 1)
2096 *(out++) = encodingTable[((inbuf[0] & 0x03) << 4)
2097 | ((inbuf[1] & 0xF0) >> 4)];
2098 if (out - buf < size - 1) {
2099 if (fill == 2)
2100 *(out++) = '=';
2101 else
2102 *(out++) = encodingTable[((inbuf[1] & 0x0F) << 2)
2103 | ((inbuf[2] & 0xC0) >> 6)];
2104 }
2105 if (out - buf < size - 1) {
2106 if (fill >= 1)
2107 *(out++) = '=';
2108 else
2109 *(out++) = encodingTable[inbuf[2] & 0x3F];
2110 }
2111 bytes += 4;
2112 }
2113 if (out - buf < size)
2114 *out = 0;
2115 return bytes;
2116}/* base64 Encoding */
2117
2118/********************************************************************
2119 * send message to caster *
2120 *********************************************************************/
2121static int send_to_caster(char *input, sockettype socket, int input_size) {
2122 int send_error = 1;
2123
2124 if ((send(socket, input, (size_t) input_size, 0)) != input_size) {
2125 fprintf(stderr,
2126 "WARNING: could not send full header to Destination caster\n");
2127 send_error = 0;
2128 }
2129#ifndef NDEBUG
2130 else {
2131 fprintf(stderr, "\nDestination caster request:\n");
2132 fprintf(stderr, "%s", input);
2133 }
2134#endif
2135 return send_error;
2136}/* send_to_caster */
2137
2138/********************************************************************
2139 * reconnect *
2140 *********************************************************************/
2141int reconnect(int rec_sec, int rec_sec_max) {
2142 fprintf(stderr, "reconnect in <%d> seconds\n\n", rec_sec);
2143 rec_sec *= 2;
2144 if (rec_sec > rec_sec_max)
2145 rec_sec = rec_sec_max;
2146#ifndef WINDOWSVERSION
2147 sleep(rec_sec);
2148 sigpipe_received = 0;
2149#else
2150 Sleep(rec_sec*1000);
2151#endif
2152 sigalarm_received = 0;
2153 return rec_sec;
2154} /* reconnect */
2155
2156/********************************************************************
2157 * close session *
2158 *********************************************************************/
2159static void close_session(const char *caster_addr, const char *mountpoint,
2160 int session, char *rtsp_ext, int fallback) {
2161 int size_send_buf;
2162 char send_buf[BUFSZ];
2163
2164 if (!fallback) {
2165 if ((gps_socket != INVALID_SOCKET)
2166 && ((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET)
2167 || (inputmode == NTRIP1_IN) || (inputmode == NTRIP2_HTTP_IN)
2168 || (inputmode == SISNET))) {
2169 if (closesocket(gps_socket) == -1) {
2170 perror("ERROR: close input device ");
2171 exit(0);
2172 } else {
2173 gps_socket = -1;
2174#ifndef NDEBUG
2175 fprintf(stderr, "close input device: successful\n");
2176#endif
2177 }
2178 } else if ((gps_serial != INVALID_HANDLE_VALUE) && (inputmode == SERIAL)) {
2179#ifndef WINDOWSVERSION
2180 if (close(gps_serial) == INVALID_HANDLE_VALUE) {
2181 perror("ERROR: close input device ");
2182 exit(0);
2183 }
2184#else
2185 if(!CloseHandle(gps_serial))
2186 {
2187 fprintf(stderr, "ERROR: close input device ");
2188 exit(0);
2189 }
2190#endif
2191 else {
2192 gps_serial = INVALID_HANDLE_VALUE;
2193#ifndef NDEBUG
2194 fprintf(stderr, "close input device: successful\n");
2195#endif
2196 }
2197 } else if ((gps_file != -1) && (inputmode == INFILE)) {
2198 if (close(gps_file) == -1) {
2199 perror("ERROR: close input device ");
2200 exit(0);
2201 } else {
2202 gps_file = -1;
2203#ifndef NDEBUG
2204 fprintf(stderr, "close input device: successful\n");
2205#endif
2206 }
2207 }
2208 }
2209
2210 if (socket_udp != INVALID_SOCKET) {
2211 if (udp_cseq > 2) {
2212 size_send_buf = snprintf(send_buf, sizeof(send_buf),
2213 "TEARDOWN rtsp://%s%s/%s RTSP/1.0\r\n"
2214 "CSeq: %d\r\n"
2215 "Session: %u\r\n"
2216 "\r\n", caster_addr, rtsp_ext, mountpoint, udp_cseq++, session);
2217 if ((size_send_buf >= (int) sizeof(send_buf)) || (size_send_buf < 0)) {
2218 fprintf(stderr, "ERROR: Destination caster request to long\n");
2219 exit(0);
2220 }
2221 send_to_caster(send_buf, socket_tcp, size_send_buf);
2222 strcpy(send_buf, "");
2223 size_send_buf = recv(socket_tcp, send_buf, sizeof(send_buf), 0);
2224 send_buf[size_send_buf] = '\0';
2225#ifndef NDEBUG
2226 fprintf(stderr, "Destination caster response:\n%s", send_buf);
2227#endif
2228 }
2229 if (closesocket(socket_udp) == -1) {
2230 perror("ERROR: close udp socket");
2231 exit(0);
2232 } else {
2233 socket_udp = -1;
2234#ifndef NDEBUG
2235 fprintf(stderr, "close udp socket: successful\n");
2236#endif
2237 }
2238 }
2239
2240 if (socket_tcp != INVALID_SOCKET) {
2241 if (closesocket(socket_tcp) == -1) {
2242 perror("ERROR: close tcp socket");
2243 exit(0);
2244 } else {
2245 socket_tcp = -1;
2246#ifndef NDEBUG
2247 fprintf(stderr, "close tcp socket: successful\n");
2248#endif
2249 }
2250 }
2251} /* close_session */
Note: See TracBrowser for help on using the repository browser.