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

Last change on this file since 10679 was 10679, checked in by stuerze, 14 months ago

minor changes

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