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

Last change on this file since 10792 was 10685, checked in by stuerze, 5 months ago

minor changes

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