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

Last change on this file since 8784 was 8784, checked in by stoecker, 5 years ago

fix chunked transfer in case of buffer full situations

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