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

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

data upload to localhost added

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