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

Last change on this file since 1883 was 1883, checked in by stoecker, 15 years ago

removed beta warning

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