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

Last change on this file since 2273 was 2273, checked in by stoecker, 14 years ago

fixed serial access problem

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