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

Last change on this file since 9467 was 9467, checked in by stuerze, 3 years ago

minor changes

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