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

Last change on this file since 10675 was 10675, checked in by stuerze, 5 days ago

minor changes

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