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

Last change on this file since 486 was 485, checked in by stoecker, 17 years ago

renamed from NtripLinuxServer.c

File size: 52.6 KB
Line 
1/*
2 * $Id: NtripLinuxServer.c,v 1.32 2007/06/07 07:47:24 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.32 $";
40static char datestr[] = "$Date: 2007/06/07 07:47:24 $";
41
42#include <ctype.h>
43#include <errno.h>
44#include <fcntl.h>
45#include <getopt.h>
46#include <netdb.h>
47#include <signal.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52#include <arpa/inet.h>
53#include <netinet/in.h>
54#include <sys/socket.h>
55#include <sys/termios.h>
56#include <sys/types.h>
57#include <sys/time.h>
58
59#ifndef COMPILEDATE
60#define COMPILEDATE " built " __DATE__
61#endif
62
63#ifndef MSG_DONTWAIT
64#define MSG_DONTWAIT 0 /* prevent compiler errors */
65#endif
66#ifndef O_EXLOCK
67#define O_EXLOCK 0 /* prevent compiler errors */
68#endif
69
70enum MODE { SERIAL = 1, TCPSOCKET = 2, INFILE = 3, SISNET = 4, UDPSOCKET = 5,
71CASTER = 6, LAST };
72
73enum OUTMODE { HTTP = 1, RTSP = 2, NTRIPV1 = 3, END };
74
75#define AGENTSTRING "NTRIP NtripLinuxServer"
76#define BUFSZ 1024
77#define SZ 64
78
79/* default socket source */
80#define SERV_HOST_ADDR "localhost"
81#define SERV_TCP_PORT 2101
82
83/* default destination */
84#define NTRIP_CASTER "www.euref-ip.net"
85#define NTRIP_PORT 2101
86
87/* default sisnet source */
88#define SISNET_SERVER "131.176.49.142"
89#define SISNET_PORT 7777
90
91#define ALARMTIME 60
92
93#define RTP_VERSION 2
94#define TIME_RESOLUTION 125
95
96static int ttybaud = 19200;
97static const char *ttyport = "/dev/gps";
98static const char *filepath = "/dev/stdin";
99static enum MODE inputmode = INFILE;
100static int sisnet = 31;
101static int gpsfd = -1;
102static int sigint_received = 0;
103
104/* Forward references */
105static int openserial(const char * tty, int blocksz, int baud);
106static void send_receive_loop(int sock, int fd, int outmode,
107 struct sockaddr * pcasterRTP, socklen_t length);
108static void usage(int, char *);
109static int encode(char *buf, int size, const char *user, const char *pwd);
110static int send_to_caster(char *input, int socket, int input_size);
111static void close_session(int sock_udp, int sock_tcp,
112 const char *caster_addr, const char *mountpoint, int cseq,
113 int session, char *rtsp_ext, int in_fd);
114
115/* Signal Handling */
116static void handle_sigint(int sig);
117static void setup_signal_handler(int sig, void (*handler)(int));
118static int signal_was_caught(void);
119
120#ifdef __GNUC__
121static __attribute__ ((noreturn)) void sighandler_alarm(
122int sig __attribute__((__unused__)))
123#else /* __GNUC__ */
124static void sighandler_alarm(int sig)
125#endif /* __GNUC__ */
126{
127 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
128 exit(1);
129}
130
131/*
132* main
133*
134* Main entry point for the program. Processes command-line arguments and
135* prepares for action.
136*
137* Parameters:
138* argc : integer : Number of command-line arguments.
139* argv : array of char : Command-line arguments as an array of
140* zero-terminated pointers to strings.
141*
142* Return Value:
143* The function does not return a value (although its return type is int).
144*
145* Remarks:
146*
147*/
148
149int main(int argc, char **argv)
150{
151 int c;
152 int size = 2048; /* for setting send buffer size */
153 struct sockaddr_in caster;
154 const char * proxyhost = "";
155 unsigned int proxyport = 0;
156 /*** INPUT ***/
157 const char * casterinhost = 0;
158 unsigned int casterinport = 0;
159 const char * inhost = 0;
160 unsigned int inport = 0;
161
162 char get_extension[SZ] = "";
163
164 struct hostent * he;
165 const char * mountpoint = NULL;
166
167 const char * sisnetpassword = "";
168 const char * sisnetuser = "";
169
170 const char * stream_name = 0;
171 const char * stream_user = 0;
172 const char * stream_password = 0;
173
174 const char * recvrid= 0;
175 const char * recvrpwd = 0;
176
177 const char * initfile = NULL;
178
179 int bindmode = 0;
180
181 /*** OUTPUT ***/
182 const char * casterouthost = NTRIP_CASTER;
183 unsigned int casteroutport = NTRIP_PORT;
184 const char * outhost = 0;
185 unsigned int outport = 0;
186 char post_extension[SZ] = "";
187 char rtsp_extension[SZ] = "";
188
189 const char * ntrip_str = "";
190
191 const char * user = "";
192 const char * password = "";
193
194 int socket_tcp = 0;
195 int outputmode = NTRIPV1;
196
197 struct sockaddr_in casterRTP;
198 struct sockaddr_in local;
199 int socket_udp = 0;
200 int client_port = 0;
201 int server_port = 0;
202 int session = 0;
203 int cseq = 0;
204 socklen_t len = 0;
205 int i = 0;
206
207 char szSendBuffer[BUFSZ];
208 char authorization[SZ];
209 int nBufferBytes = 0;
210 char * dlim = " \r\n=";
211 char * token;
212 char * tok_buf[BUFSZ];
213
214 setbuf(stdout, 0);
215 setbuf(stdin, 0);
216 setbuf(stderr, 0);
217
218 {
219 char *a;
220 int i = 0;
221 for(a = revisionstr+11; *a && *a != ' '; ++a)
222 revisionstr[i++] = *a;
223 revisionstr[i] = 0;
224 datestr[0] = datestr[7];
225 datestr[1] = datestr[8];
226 datestr[2] = datestr[9];
227 datestr[3] = datestr[10];
228 datestr[5] = datestr[12];
229 datestr[6] = datestr[13];
230 datestr[8] = datestr[15];
231 datestr[9] = datestr[16];
232 datestr[4] = datestr[7] = '-';
233 datestr[10] = 0;
234 }
235
236 /* setup signal handler for timeout */
237 signal(SIGALRM,sighandler_alarm);
238 alarm(ALARMTIME);
239
240 /* get and check program arguments */
241 if(argc <= 1)
242 {
243 usage(2, argv[0]);
244 exit(1);
245 }
246 while((c = getopt(argc, argv,
247 "M:i:h:b:p:s:a:m:c:H:P:f:x:y:l:u:V:D:U:W:B:O:E:F:N:n:")) != EOF)
248 {
249 switch (c)
250 {
251 case 'M': /*** InputMode ***/
252 if(!strcmp(optarg, "serial")) inputmode = SERIAL;
253 else if(!strcmp(optarg, "tcpsocket")) inputmode = TCPSOCKET;
254 else if(!strcmp(optarg, "file")) inputmode = INFILE;
255 else if(!strcmp(optarg, "sisnet")) inputmode = SISNET;
256 else if(!strcmp(optarg, "udpsocket")) inputmode = UDPSOCKET;
257 else if(!strcmp(optarg, "caster")) inputmode = CASTER;
258 else inputmode = atoi(optarg);
259 if((inputmode == 0) || (inputmode >= LAST))
260 {
261 fprintf(stderr, "ERROR: can't convert <%s> to a valid InputMode\n",
262 optarg);
263 usage(-1, argv[0]);
264 }
265 break;
266 case 'i': /* serial input device */
267 ttyport = optarg;
268 break;
269 case 'B': /* bind to incoming UDP stream */
270 bindmode = 1;
271 break;
272 case 'V': /* Sisnet data server version number */
273 if(!strcmp("3.0", optarg)) sisnet = 30;
274 else if(!strcmp("3.1", optarg)) sisnet = 31;
275 else if(!strcmp("2.1", optarg)) sisnet = 21;
276 else
277 {
278 fprintf(stderr, "ERROR: unknown SISNeT version <%s>\n", optarg);
279 usage(-2, argv[0]);
280 }
281 break;
282 case 'b': /* serial input baud rate */
283 ttybaud = atoi(optarg);
284 if(ttybaud <= 1)
285 {
286 fprintf(stderr, "ERROR: can't convert <%s> to valid serial baud rate\n",
287 optarg);
288 usage(1, argv[0]);
289 }
290 break;
291 case 'a': /* Destination caster address */
292 casterouthost = optarg;
293 break;
294 case 'p': /* Destination caster port */
295 casteroutport = atoi(optarg);
296 if(casteroutport <= 1 || casteroutport > 65535)
297 {
298 fprintf(stderr,
299 "ERROR: can't convert <%s> to a valid HTTP server port\n", optarg);
300 usage(1, argv[0]);
301 }
302 break;
303 case 'm': /* Destination caster mountpoint for stream upload */
304 mountpoint = optarg;
305 break;
306 case 's': /* File name for input data simulation from file */
307 filepath = optarg;
308 break;
309 case 'f': /* name of an initialization file */
310 initfile = optarg;
311 break;
312 case 'x': /* user ID to access incoming stream */
313 recvrid = optarg;
314 break;
315 case 'y': /* password to access incoming stream */
316 recvrpwd = optarg;
317 break;
318 case 'u': /* Sisnet data server user ID */
319 sisnetuser = optarg;
320 break;
321 case 'l': /* Sisnet data server password */
322 sisnetpassword = optarg;
323 break;
324 case 'c': /* DestinationCaster password for stream upload to mountpoint */
325 password = optarg;
326 break;
327 case 'H': /* Input host address*/
328 casterinhost = optarg;
329 break;
330 case 'P': /* Input port */
331 casterinport = atoi(optarg);
332 if(casterinport <= 1 || casterinport > 65535)
333 {
334 fprintf(stderr, "ERROR: can't convert <%s> to a valid port number\n",
335 optarg);
336 usage(1, argv[0]);
337 }
338 break;
339 case 'D': /* Source caster mountpoint for stream input */
340 stream_name = optarg;
341 break;
342 case 'U': /* Source caster user ID for input stream access */
343 stream_user = optarg;
344 break;
345 case 'W': /* Source caster password for input stream access */
346 stream_password = optarg;
347 break;
348 case 'E': /* Proxy Server */
349 proxyhost = optarg;
350 break;
351 case 'F': /* Proxy port */
352 proxyport = atoi(optarg);
353 break;
354 case 'O': /* OutputMode */
355 outputmode = 0;
356 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
357 outputmode = NTRIPV1;
358 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
359 outputmode = HTTP;
360 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
361 outputmode = RTSP;
362 else outputmode = atoi(optarg);
363 if((outputmode == 0) || (outputmode >= END))
364 {
365 fprintf(stderr, "ERROR: can't convert <%s> to a valid OutputMode\n",
366 optarg);
367 usage(-1, argv[0]);
368 }
369 break;
370 case 'n': /* Destination caster user ID for stream upload to mountpoint */
371 user = optarg;
372 break;
373 case 'N': /* Ntrip-STR, optional for Ntrip Version 2.0 */
374 ntrip_str = optarg;
375 break;
376 case 'h': /* print help screen */
377 case '?':
378 usage(0, argv[0]);
379 break;
380 default:
381 usage(2, argv[0]);
382 break;
383 }
384 }
385
386 argc -= optind;
387 argv += optind;
388
389 /*** argument analysis ***/
390 if(argc > 0)
391 {
392 fprintf(stderr, "ERROR: Extra args on command line: ");
393 for(; argc > 0; argc--)
394 {
395 fprintf(stderr, " %s", *argv++);
396 }
397 fprintf(stderr, "\n");
398 usage(1, argv[0]); /* never returns */
399 }
400
401 if(*ntrip_str && (outputmode == NTRIPV1))
402 {
403 fprintf(stderr, "WARNING: OutputMode is Ntrip version 1.0"
404 " - Ntrip-STR will not be considered\n");
405 }
406
407 if(!mountpoint)
408 {
409 fprintf(stderr, "ERROR: Missing mountpoint argument for stream upload\n");
410 exit(1);
411 }
412
413 if(!password[0])
414 {
415 fprintf(stderr, "WARNING: Missing password argument for stream upload - "
416 "are you really sure?\n");
417 }
418 else
419 {
420 nBufferBytes += encode(authorization, sizeof(authorization), user,
421 password);
422 if(nBufferBytes > (int)sizeof(authorization))
423 {
424 fprintf(stderr, "ERROR: user ID and/or password too long: %d (%d)\n"
425 " user ID: %s \npassword: <%s>\n",
426 nBufferBytes, (int)sizeof(authorization), user, password);
427 exit(1);
428 }
429 }
430
431 if(stream_name && stream_user && !stream_password)
432 {
433 fprintf(stderr, "WARNING: Missing password argument for stream download"
434 " - are you really sure?\n");
435 }
436
437 /*** proxy server handling ***/
438 if(*proxyhost)
439 {
440 outhost = inhost = proxyhost;
441 outport = inport = proxyport;
442 i = snprintf(szSendBuffer, sizeof(szSendBuffer),"http://%s:%d",
443 casterouthost, casteroutport);
444 if((i > SZ) || (i < 0))
445 {
446 fprintf(stderr, "ERROR: Destination caster name/port to long - "
447 "length = %d (max: %d)\n", i, SZ);
448 exit(0);
449 }
450 else
451 {
452 strncpy(post_extension, szSendBuffer, (size_t)i);
453 strcpy(szSendBuffer, "");
454 i = snprintf(szSendBuffer, sizeof(szSendBuffer),":%d", casteroutport);
455 strncpy(rtsp_extension, szSendBuffer, SZ);
456 strcpy(szSendBuffer,""); i = 0;
457 }
458 i = snprintf(szSendBuffer, sizeof(szSendBuffer),"http://%s:%d", casterinhost, casterinport);
459 if((i > SZ) || (i < 0))
460 {
461 fprintf(stderr, "ERROR: Destination caster name/port to long - length = %d (max: %d)\n", i, SZ);
462 exit(0);
463 }
464 else
465 {
466 strncpy(get_extension, szSendBuffer, (size_t)i);
467 strcpy(szSendBuffer, "");
468 i = 0;
469 }
470 }
471 else
472 {
473 outhost = casterouthost; outport = casteroutport;
474 inhost = casterinhost; inport = casterinport;
475 }
476
477 /*** InputMode handling ***/
478 switch(inputmode)
479 {
480 case INFILE:
481 {
482 if((gpsfd = open(filepath, O_RDONLY)) < 0)
483 {
484 perror("ERROR: opening input file");
485 exit(1);
486 }
487 /* set blocking inputmode in case it was not set
488 (seems to be sometimes for fifo's) */
489 fcntl(gpsfd, F_SETFL, 0);
490 printf("file input: file = %s\n", filepath);
491 }
492 break;
493 case SERIAL: /* open serial port */
494 {
495 gpsfd = openserial(ttyport, 1, ttybaud);
496 if(gpsfd < 0)
497 {
498 exit(1);
499 }
500 printf("serial input: device = %s, speed = %d\n", ttyport, ttybaud);
501 }
502 break;
503 case TCPSOCKET: case UDPSOCKET: case SISNET: case CASTER:
504 {
505 if(inputmode == SISNET)
506 {
507 if(!inhost) inhost = SISNET_SERVER;
508 if(!inport) inport = SISNET_PORT;
509 }
510 else if(inputmode == CASTER)
511 {
512 if(!inport) inport = NTRIP_PORT;
513 if(!inhost) inhost = NTRIP_CASTER;
514 }
515 else if((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET))
516 {
517 if(!inport) inport = SERV_TCP_PORT;
518 if(!inhost) inhost = SERV_HOST_ADDR;
519 }
520
521 if(!(he = gethostbyname(inhost)))
522 {
523 fprintf(stderr, "ERROR: Input host <%s> unknown\n", inhost);
524 usage(-2, argv[0]);
525 }
526
527 if((gpsfd = socket(AF_INET, inputmode == UDPSOCKET
528 ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
529 {
530 fprintf(stderr,
531 "ERROR: can't create socket for incoming data stream\n");
532 exit(1);
533 }
534
535 memset((char *) &caster, 0x00, sizeof(caster));
536 if(!bindmode)
537 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
538 caster.sin_family = AF_INET;
539 caster.sin_port = htons(inport);
540
541 fprintf(stderr, "%s input: host = %s, port = %d, %s%s%s%s%s\n",
542 inputmode == CASTER ? "caster" : inputmode == SISNET ? "sisnet" :
543 inputmode == TCPSOCKET ? "tcp socket" : "udp socket",
544 bindmode ? "127.0.0.1" : inet_ntoa(caster.sin_addr),
545 inport, stream_name ? "stream = " : "", stream_name ? stream_name : "",
546 initfile ? ", initfile = " : "", initfile ? initfile : "",
547 bindmode ? "binding mode" : "");
548
549 if(bindmode)
550 {
551 if(bind(gpsfd, (struct sockaddr *) &caster, sizeof(caster)) < 0)
552 {
553 fprintf(stderr, "ERROR: can't bind input to port %d\n", inport);
554 exit(1);
555 }
556 } /* connect to input-caster or proxy server*/
557 else if(connect(gpsfd, (struct sockaddr *)&caster, sizeof(caster)) < 0)
558 {
559 fprintf(stderr, "ERROR: can't connect input to %s at port %d\n",
560 inet_ntoa(caster.sin_addr), inport);
561 exit(1);
562 }
563
564 if(stream_name) /* input from Ntrip Version 1.0 caster*/
565 {
566 int init = 0;
567
568 /* set socket buffer size */
569 setsockopt(gpsfd, SOL_SOCKET, SO_SNDBUF, (const char *) &size,
570 sizeof(const char *));
571 if(stream_user && stream_password)
572 {
573 /* leave some space for login */
574 nBufferBytes=snprintf(szSendBuffer, sizeof(szSendBuffer)-40,
575 "GET %s/%s HTTP/1.0\r\n"
576 "User-Agent: %s/%s\r\n"
577 "Authorization: Basic ", get_extension, stream_name,
578 AGENTSTRING, revisionstr);
579 /* second check for old glibc */
580 if(nBufferBytes > (int)sizeof(szSendBuffer)-40 || nBufferBytes < 0)
581 {
582 fprintf(stderr, "ERROR: Source caster request too long\n");
583 exit(1);
584 }
585 nBufferBytes += encode(szSendBuffer+nBufferBytes,
586 sizeof(szSendBuffer)-nBufferBytes-4, stream_user, stream_password);
587 if(nBufferBytes > (int)sizeof(szSendBuffer)-4)
588 {
589 fprintf(stderr,
590 "ERROR: Source caster user ID and/or password too long\n");
591 exit(1);
592 }
593 szSendBuffer[nBufferBytes++] = '\r';
594 szSendBuffer[nBufferBytes++] = '\n';
595 szSendBuffer[nBufferBytes++] = '\r';
596 szSendBuffer[nBufferBytes++] = '\n';
597 }
598 else
599 {
600 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
601 "GET %s/%s HTTP/1.0\r\n"
602 "User-Agent: %s/%s\r\n"
603 "\r\n", get_extension, stream_name, AGENTSTRING, revisionstr);
604 }
605 if((send(gpsfd, szSendBuffer, (size_t)nBufferBytes, 0))
606 != nBufferBytes)
607 {
608 fprintf(stderr, "ERROR: could not send Source caster request\n");
609 exit(1);
610 }
611 nBufferBytes = 0;
612 /* check Source caster's response */
613 while(!init && nBufferBytes < (int)sizeof(szSendBuffer)
614 && (nBufferBytes += recv(gpsfd, szSendBuffer,
615 sizeof(szSendBuffer)-nBufferBytes, 0)) > 0)
616 {
617 if(strstr(szSendBuffer, "\r\n"))
618 {
619 if(!strncmp(szSendBuffer, "ICY 200 OK\r\n", 10))
620 init = 1;
621 else
622 {
623 int k;
624 fprintf(stderr,
625 "ERROR: could not get requested data from Source caster: ");
626 for(k = 0; k < nBufferBytes && szSendBuffer[k] != '\n'
627 && szSendBuffer[k] != '\r'; ++k)
628 {
629 fprintf(stderr, "%c", isprint(szSendBuffer[k])
630 ? szSendBuffer[k] : '.');
631 }
632 fprintf(stderr, "\n");
633 exit(1);
634 }
635 }
636 }
637 if(!init)
638 {
639 fprintf(stderr, "ERROR: could not init Source caster download\n");
640 exit(1);
641 }
642 } /* end input from Ntrip Version 1.0 caster */
643
644 if(initfile && inputmode != SISNET)
645 {
646 char buffer[1024];
647 FILE *fh;
648 int i;
649
650 if((fh = fopen(initfile, "r")))
651 {
652 while((i = fread(buffer, 1, sizeof(buffer), fh)) > 0)
653 {
654 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
655 {
656 perror("ERROR: sending init file");
657 exit(1);
658 }
659 }
660 if(i < 0)
661 {
662 perror("ERROR: reading init file");
663 exit(1);
664 }
665 fclose(fh);
666 }
667 else
668 {
669 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
670 exit(1);
671 }
672 }
673 }
674 if(inputmode == SISNET)
675 {
676 int i, j;
677 char buffer[1024];
678
679 i = snprintf(buffer, sizeof(buffer), sisnet >= 30 ? "AUTH,%s,%s\r\n"
680 : "AUTH,%s,%s", sisnetuser, sisnetpassword);
681 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
682 {
683 perror("ERROR: sending authentication for SISNeT data server");
684 exit(1);
685 }
686 i = sisnet >= 30 ? 7 : 5;
687 if((j = recv(gpsfd, buffer, i, 0)) != i && strncmp("*AUTH", buffer, 5))
688 {
689 fprintf(stderr, "ERROR: SISNeT connect failed:");
690 for(i = 0; i < j; ++i)
691 {
692 if(buffer[i] != '\r' && buffer[i] != '\n')
693 {
694 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
695 }
696 }
697 fprintf(stderr, "\n");
698 exit(1);
699 }
700 if(sisnet >= 31)
701 {
702 if((send(gpsfd, "START\r\n", 7, 0)) != i)
703 {
704 perror("ERROR: sending Sisnet start command");
705 exit(1);
706 }
707 }
708 }
709 /*** receiver authentication ***/
710 if (recvrid && recvrpwd && ((inputmode == TCPSOCKET)
711 || (inputmode == UDPSOCKET)))
712 {
713 if (strlen(recvrid) > (BUFSZ-3))
714 {
715 fprintf(stderr, "ERROR: Receiver ID too long\n");
716 exit(0);
717 }
718 else
719 {
720 fprintf(stderr, "Sending user ID for receiver...\n");
721 nBufferBytes = read(gpsfd, szSendBuffer, BUFSZ);
722 strcpy(szSendBuffer, recvrid);
723 strcat(szSendBuffer,"\r\n");
724 send(gpsfd,szSendBuffer, strlen(szSendBuffer), MSG_DONTWAIT);
725 }
726
727 if (strlen(recvrpwd) > (BUFSZ-3))
728 {
729 fprintf(stderr, "ERROR: Receiver password too long\n");
730 exit(0);
731 }
732 else
733 {
734 fprintf(stderr, "Sending user password for receiver...\n");
735 nBufferBytes = read(gpsfd, szSendBuffer, BUFSZ);
736 strcpy(szSendBuffer, recvrpwd);
737 strcat(szSendBuffer,"\r\n");
738 send(gpsfd, szSendBuffer, strlen(szSendBuffer), MSG_DONTWAIT);
739 }
740 }
741 break;
742 default:
743 usage(-1, argv[0]);
744 break;
745 }
746
747 /* ----- main part ----- */
748 /* setup signal handler for CTRL+C */
749 setup_signal_handler(SIGINT, handle_sigint);
750
751 while(outputmode != END)
752 {
753 if(signal_was_caught())
754 {
755 fprintf(stderr, "NtripLinuxServer terminates\n");
756 break;
757 }
758
759 if(!(he = gethostbyname(outhost)))
760 {
761 fprintf(stderr, "ERROR: Destination caster or proxy host <%s> unknown\n",
762 outhost);
763 usage(-2, argv[0]);
764 }
765
766 /* create socket */
767 if((socket_tcp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
768 {
769 perror("ERROR: tcp socket");
770 exit(2);
771 }
772
773 memset((char *) &caster, 0x00, sizeof(caster));
774 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
775 caster.sin_family = AF_INET;
776 caster.sin_port = htons(outport);
777
778 /* connect to Destination caster or Proxy server*/
779 fprintf(stderr, "caster output: host = %s, port = %d, mountpoint = %s"
780 ", mode = %s\n", inet_ntoa(caster.sin_addr), outport, mountpoint,
781 outputmode == NTRIPV1 ? "ntrip1" : outputmode == HTTP ? "http" : "rtsp");
782
783 if(connect(socket_tcp, (struct sockaddr *) &caster, sizeof(caster)) < 0)
784 {
785 fprintf(stderr, "ERROR: can't connect output to %s at port %d\n",
786 inet_ntoa(caster.sin_addr), outport);
787 if(close(socket_tcp)==-1) perror("ERROR: close tcp socket");
788 exit(3);
789 }
790
791 /*** OutputMode handling ***/
792 switch(outputmode){
793 case NTRIPV1: /*** OutputMode Ntrip Version 1.0 ***/
794 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
795 "SOURCE %s %s/%s\r\n"
796 "Source-Agent: %s\r\n\r\n",
797 password, post_extension, mountpoint, AGENTSTRING);
798 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
799 {
800 fprintf(stderr, "ERROR: Destination caster request to long\n");
801 outputmode = END;
802 break;
803 }
804 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
805 {
806 outputmode = END;
807 break;
808 }
809 /* check Destination caster's response */
810 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
811 szSendBuffer[nBufferBytes] = '\0';
812 if(!strstr(szSendBuffer, "OK"))
813 {
814 char *a;
815 fprintf(stderr,
816 "ERROR: Destination caster's or Proxy's reply is not OK: ");
817 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
818 {
819 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
820 }
821 fprintf(stderr, "\n");
822 outputmode = END;
823 break;
824 }
825#ifndef NDEBUG
826 else
827 {
828 fprintf(stderr,
829 "Destination caster response:\n%s\nconnection successfull\n",
830 szSendBuffer);
831 }
832#endif
833 send_receive_loop(socket_tcp, gpsfd, outputmode, NULL, 0);
834 break;
835 case HTTP: /*** Ntrip-Version 2.0 HTTP/1.1 ***/
836 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
837 "POST %s/%s HTTP/1.1\r\n"
838 "Host: %s\r\n"
839 "Ntrip-Version: Ntrip/2.0\r\n"
840 "User-Agent: %s/%s\r\n"
841 "Authorization: Basic %s\r\n"
842 "Ntrip-STR: %s\r\n"
843 "Transfer-Encoding: chunked\r\n\r\n",
844 post_extension, mountpoint, casterouthost, AGENTSTRING,
845 revisionstr, authorization, ntrip_str);
846 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
847 {
848 fprintf(stderr, "ERROR: Destination caster request to long\n");
849 outputmode = END;
850 break;
851 }
852 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
853 {
854 outputmode = END;
855 break;
856 }
857 /* check Destination caster's response */
858 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
859 szSendBuffer[nBufferBytes] = '\0';
860 if(!strstr(szSendBuffer, "HTTP/1.1 200 OK"))
861 {
862 char *a;
863 fprintf(stderr,
864 "ERROR: Destination caster's%s reply is not OK: ",
865 *proxyhost ? " or Proxy's" : "");
866 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
867 {
868 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
869 }
870 fprintf(stderr, "\n");
871 /* fallback if necessary */
872 if(!strstr(szSendBuffer,"Ntrip-Version: Ntrip/2.0\r\n"))
873 {
874 fprintf(stderr,
875 " Ntrip Version 2.0 not implemented at Destination caster"
876 " <%s>%s%s%s\n%s\n"
877 "caster fallback: Fallback to Ntrip Version 1.0\n",
878 casterouthost,
879 *proxyhost ? " or Proxy <" : "", proxyhost, *proxyhost ? ">" : "",
880 *proxyhost ? " or HTTP/1.1 not implemented at Proxy\n" : "");
881 outputmode = NTRIPV1;
882 break;
883 }
884 outputmode = END;
885 break;
886 }
887#ifndef NDEBUG
888 else
889 {
890 fprintf(stderr, "Destination caster response:\n%s\n"
891 "connection successfull\n",szSendBuffer);
892 }
893#endif
894 send_receive_loop(socket_tcp, gpsfd, outputmode, NULL, 0);
895 break;
896 case RTSP: /*** Ntrip-Version 2.0 RTSP / RTP ***/
897 if((socket_udp = socket(AF_INET, SOCK_DGRAM,0)) < 0)
898 {
899 perror("ERROR: udp socket");
900 exit(4);
901 }
902 /* fill structure with local address information for UDP */
903 memset(&local, 0, sizeof(local));
904 local.sin_family = AF_INET;
905 local.sin_port = htons(0);
906 local.sin_addr.s_addr = htonl(INADDR_ANY);
907 len = (socklen_t)sizeof(local);
908 /* bind() in order to get a random RTP client_port */
909 if((bind(socket_udp,(struct sockaddr *)&local, len)) < 0)
910 {
911 perror("ERROR: udp bind");
912 if(close(socket_udp)==-1) perror("ERROR: close udp socket");
913 if(close(socket_tcp)==-1) perror("ERROR: close tcp socket");
914 exit(4);
915 }
916 if((getsockname(socket_udp, (struct sockaddr*)&local, &len)) != -1)
917 {
918 client_port = (unsigned int)ntohs(local.sin_port);
919 }else{
920 perror("ERROR: getsockname(localhost)");
921 if(close(socket_udp)==-1) perror("ERROR: close udp socket");
922 if(close(socket_tcp)==-1) perror("ERROR: close tcp socket");
923 exit(4);
924 }
925 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
926 "SETUP rtsp://%s%s/%s RTSP/1.0\r\n"
927 "CSeq: 1\r\n"
928 "Ntrip-Version: Ntrip/2.0\r\n"
929 "Ntrip-Component: Ntripserver\r\n"
930 "User-Agent: %s/%s\r\n"
931 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
932 "Authorization: Basic %s\r\n"
933 "Ntrip-STR: %s\r\n\r\n",
934 casterouthost, rtsp_extension, mountpoint, AGENTSTRING, revisionstr,
935 client_port, authorization, ntrip_str);
936 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
937 {
938 fprintf(stderr, "ERROR: Destination caster request to long\n");
939 outputmode = END;
940 break;
941 }
942 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
943 {
944 outputmode = END;
945 break;
946 }
947 while((nBufferBytes = recv(socket_tcp, szSendBuffer,
948 sizeof(szSendBuffer), 0)) > 0)
949 {
950 /* check Destination caster's response */
951 szSendBuffer[nBufferBytes] = '\0';
952 if(!strstr(szSendBuffer, "RTSP/1.0 200 OK"))
953 {
954 char *a;
955 fprintf(stderr,
956 "ERROR: Destination caster's%s reply is not OK: ",
957 *proxyhost ? " or Proxy's" : "");
958 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
959 {
960 fprintf(stderr, "%c", isprint(*a) ? *a : '.');
961 }
962 fprintf(stderr, "\n");
963 /* fallback if necessary */
964 if(strncmp(szSendBuffer, "RTSP",4) != 0)
965 {
966 if(strstr(szSendBuffer,"Ntrip-Version: Ntrip/2.0\r\n"))
967 {
968 fprintf(stderr,
969 " - RTSP not implemented at Destination caster <%s>%s%s%s\n\n"
970 "caster fallback: Fallback to Ntrip Version 2.0 in TCP/IP"
971 " mode\n\n", casterouthost,
972 *proxyhost ? " or Proxy <" :"", proxyhost, *proxyhost ? ">":"");
973 outputmode = HTTP;
974 break;
975 }
976 else
977 {
978 fprintf(stderr,
979 " Ntrip-Version 2.0 not implemented at Destination caster"
980 "<%s>%s%s%s\n%s"
981 " or RTSP/1.0 not implemented at Destination caster%s\n\n"
982 "caster fallback: Fallback to Ntrip Version 1.0\n",
983 casterouthost, *proxyhost ? " or Proxy <" :"", proxyhost,
984 *proxyhost ? ">":"",
985 *proxyhost ? " or HTTP/1.1 not implemented at Proxy\n" : "",
986 *proxyhost ? " or Proxy" :"");
987 outputmode = NTRIPV1;
988 break;
989 }
990 }
991 else
992 {
993 outputmode = END;
994 break;
995 }
996 }
997#ifndef NDEBUG
998 else
999 {
1000 fprintf(stderr, "Destination caster response:\n%s\n",szSendBuffer);
1001 }
1002#endif
1003 if((strstr(szSendBuffer,"RTSP/1.0 200 OK\r\n"))
1004 && (strstr(szSendBuffer,"CSeq: 1\r\n")))
1005 {
1006 for(token = strtok(szSendBuffer, dlim); token != NULL;
1007 token = strtok(NULL, dlim))
1008 {
1009 tok_buf[i] = token; i++;
1010 }
1011 session = atoi(tok_buf[6]);
1012 server_port = atoi(tok_buf[10]);
1013 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1014 "POST rtsp://%s%s/%s RTSP/1.0\r\n"
1015 "CSeq: 2\r\n"
1016 "Session: %d\r\n"
1017 "\r\n",
1018 casterouthost, rtsp_extension, mountpoint, session);
1019 if((nBufferBytes >= (int)sizeof(szSendBuffer))
1020 || (nBufferBytes < 0))
1021 {
1022 fprintf(stderr, "ERROR: Destination caster request to long\n");
1023 outputmode = END;
1024 break;
1025 }
1026 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
1027 {
1028 outputmode = END;
1029 break;
1030 }
1031 }else if((strstr(szSendBuffer,"RTSP/1.0 200 OK\r\n")) && (strstr(szSendBuffer,"CSeq: 2\r\n"))) {
1032 /* fill structure with caster address information for UDP */
1033 memset(&casterRTP, 0, sizeof(casterRTP));
1034 casterRTP.sin_family = AF_INET;
1035 casterRTP.sin_port = htons(((uint16_t)server_port));
1036 if((he = gethostbyname(outhost))== NULL) {
1037 fprintf(stderr, "ERROR: Destination caster unknown\n");
1038 if(close(socket_udp)==-1) perror("ERROR: close udp socket");
1039 if(close(socket_tcp)==-1) perror("ERROR: close tcp socket");
1040 exit(4);
1041 }else{
1042 memcpy((char *)&casterRTP.sin_addr.s_addr,
1043 he->h_addr_list[0], (size_t)he->h_length);
1044 }
1045 cseq = 2;
1046 len = (socklen_t)sizeof(casterRTP);
1047 send_receive_loop(socket_udp, gpsfd, outputmode, (struct sockaddr *)&casterRTP, (socklen_t)len);
1048 break;
1049 }else{break;}
1050 }
1051 break;
1052 }
1053 }
1054 close_session(socket_udp, socket_tcp, casterouthost, mountpoint, cseq, session, rtsp_extension, gpsfd);
1055 return 0;
1056}
1057
1058static void send_receive_loop(int sock, int fd, int outmode, struct sockaddr* pcasterRTP,
1059socklen_t length)
1060{
1061 int nodata = 0;
1062 char buffer[BUFSZ] = { 0 };
1063 char sisnetbackbuffer[200];
1064 char szSendBuffer[BUFSZ] = "";
1065 int nBufferBytes = 0;
1066
1067 /* RTSP / RTP Mode */
1068 int isfirstpacket = 1;
1069 struct timeval now;
1070 struct timeval last = {0,0};
1071 long int sendtimediff;
1072 int rtpseq = 0;
1073 int rtpssrc = 0;
1074 int rtptime = 0;
1075
1076 /* data transmission */
1077 fprintf(stderr,"transfering data ...\n");
1078
1079 while(1)
1080 {
1081 /* signal handling*/
1082 if(signal_was_caught())
1083 {
1084 fprintf(stderr, "NtripLinuxServer exits send-receive mode\n");
1085 break;
1086 }
1087 if(!nodata) alarm(ALARMTIME);
1088 else nodata = 0;
1089
1090 if(!nBufferBytes)
1091 {
1092 if(inputmode == SISNET && sisnet <= 30)
1093 {
1094 int i;
1095 /* a somewhat higher rate than 1 second to get really each block */
1096 /* means we need to skip double blocks sometimes */
1097 struct timeval tv = {0,700000};
1098 select(0, 0, 0, 0, &tv);
1099 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
1100 i = (sisnet >= 30 ? 5 : 3);
1101 if((send(gpsfd, "MSG\r\n", i, 0)) != i)
1102 {
1103 perror("ERROR: sending SISNeT data request");
1104 exit(1);
1105 }
1106 }
1107 /*** receiving data ****/
1108 nBufferBytes = read(fd, buffer, sizeof(buffer));
1109 if(!nBufferBytes)
1110 {
1111 printf("WARNING: no data received from input\n");
1112 sleep(3);
1113 nodata = 1;
1114 continue;
1115 }
1116 else if(nBufferBytes < 0)
1117 {
1118 perror("ERROR: reading input failed");
1119 exit(1);
1120 }
1121 /* we can compare the whole buffer, as the additional bytes
1122 remain unchanged */
1123 if(inputmode == SISNET && sisnet <= 30 &&
1124 !memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer)))
1125 {
1126 nBufferBytes = 0;
1127 }
1128 }
1129 /** send data ***/
1130 if((nBufferBytes) && (outmode == NTRIPV1)) /*** Ntrip-Version 1.0 ***/
1131 {
1132 int i;
1133 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
1134 != nBufferBytes)
1135 {
1136 if(i < 0)
1137 {
1138 if(errno != EAGAIN)
1139 {
1140 perror("WARNING: could not send data to Destination caster"
1141 " - retry connection");
1142 close(sock);
1143 sleep(5);
1144 return;
1145 }
1146 }
1147 else if(i)
1148 {
1149 memmove(buffer, buffer+i, (size_t)(nBufferBytes-i));
1150 nBufferBytes -= i;
1151 }
1152 }else
1153 {
1154 nBufferBytes = 0;
1155 }
1156 }
1157 /*** Ntrip-Version 2.0 HTTP/1.1 ***/
1158 else if((nBufferBytes) && (outmode == HTTP))
1159 {
1160 int i, nChunkBytes, j = 1;
1161 nChunkBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),"%x\r\n",
1162 nBufferBytes);
1163 send(sock, szSendBuffer, nChunkBytes, MSG_DONTWAIT);
1164 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
1165 != nBufferBytes)
1166 {
1167 if(i < 0)
1168 {
1169 if(errno != EAGAIN)
1170 {
1171 perror("WARNING: could not send data to Destination caster"
1172 " - retry connection");
1173 close(sock);
1174 sleep(5);
1175 return;
1176 }
1177 }
1178 else if(i)
1179 {
1180 while(j>0)
1181 {
1182 j = send(sock, buffer, (size_t)BUFSZ, MSG_DONTWAIT);
1183 }
1184 }
1185 }
1186 else
1187 {
1188 send(sock, "\r\n", strlen("\r\n"), MSG_DONTWAIT);
1189 nBufferBytes = 0;
1190 }
1191 }
1192 /*** Ntrip-Version 2.0 RTSP(TCP) / RTP(UDP) ***/
1193 else if((nBufferBytes) && (outmode == RTSP))
1194 {
1195 char rtpbuffer[BUFSZ+12];
1196 int i, j;
1197 /* Signal Handling */
1198 if(signal_was_caught())
1199 {
1200 fprintf(stderr, "NtripLinuxServer exits send-receive mode\n");
1201 break;
1202 }
1203 gettimeofday(&now, NULL);
1204 /* RTP data packet generation*/
1205 if(isfirstpacket){
1206 rtpseq = rand();
1207 rtptime = rand();
1208 rtpssrc = rand();
1209 last = now;
1210 isfirstpacket = 0;
1211 }
1212 else
1213 {
1214 ++rtpseq;
1215 sendtimediff = (((now.tv_sec - last.tv_sec)*1000000)
1216 + (now.tv_usec - last.tv_usec));
1217 rtptime += sendtimediff/TIME_RESOLUTION;
1218 }
1219 rtpbuffer[0] = (RTP_VERSION<<6);
1220 /* padding, extension, csrc are empty */
1221 rtpbuffer[1] = 96;
1222 /* marker is empty */
1223 rtpbuffer[2] = rtpseq>>8;
1224 rtpbuffer[3] = rtpseq;
1225 rtpbuffer[4] = rtptime>>24;
1226 rtpbuffer[5] = rtptime>>16;
1227 rtpbuffer[6] = rtptime>>8;
1228 rtpbuffer[7] = rtptime;
1229 rtpbuffer[8] = rtpssrc>>24;
1230 rtpbuffer[9] = rtpssrc>>16;
1231 rtpbuffer[10] = rtpssrc>>8;
1232 rtpbuffer[11] = rtpssrc;
1233 for(j=0; j<nBufferBytes; j++) {rtpbuffer[12+j] = buffer[j];}
1234 last.tv_sec = now.tv_sec;
1235 last.tv_usec = now.tv_usec;
1236
1237 if ((i = sendto(sock, rtpbuffer, 12 + nBufferBytes, 0, pcasterRTP,
1238 length)) != (nBufferBytes + 12))
1239 {
1240 if(i < 0)
1241 {
1242 if(errno != EAGAIN)
1243 {
1244 perror("WARNING: could not send data to Destination caster - retry connection");
1245 close(sock);
1246 sleep(5);
1247 return;
1248 }
1249 }
1250 else if(i)
1251 {
1252 memmove(buffer, buffer+(i-12), (size_t)(nBufferBytes-(i-12)));
1253 nBufferBytes -= i-12;
1254 }
1255 }
1256 else
1257 {
1258 nBufferBytes = 0;
1259 }
1260 }
1261 }
1262 return;
1263}
1264
1265
1266/********************************************************************
1267 * openserial
1268 *
1269 * Open the serial port with the given device name and configure it for
1270 * reading NMEA data from a GPS receiver.
1271 *
1272 * Parameters:
1273 * tty : pointer to : A zero-terminated string containing the device
1274 * unsigned char name of the appropriate serial port.
1275 * blocksz : integer : Block size for port I/O
1276 * baud : integer : Baud rate for port I/O
1277 *
1278 * Return Value:
1279 * The function returns a file descriptor for the opened port if successful.
1280 * The function returns -1 in the event of an error.
1281 *
1282 * Remarks:
1283 *
1284 ********************************************************************/
1285
1286static int openserial(const char * tty, int blocksz, int baud)
1287{
1288 int fd;
1289 struct termios termios;
1290
1291 fd = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
1292 if(fd < 0)
1293 {
1294 perror("ERROR: opening serial connection");
1295 return (-1);
1296 }
1297 if(tcgetattr(fd, &termios) < 0)
1298 {
1299 perror("ERROR: get serial attributes");
1300 return (-1);
1301 }
1302 termios.c_iflag = 0;
1303 termios.c_oflag = 0; /* (ONLRET) */
1304 termios.c_cflag = CS8 | CLOCAL | CREAD;
1305 termios.c_lflag = 0;
1306 {
1307 int cnt;
1308 for(cnt = 0; cnt < NCCS; cnt++)
1309 termios.c_cc[cnt] = -1;
1310 }
1311 termios.c_cc[VMIN] = blocksz;
1312 termios.c_cc[VTIME] = 2;
1313
1314#if (B4800 != 4800)
1315/* Not every system has speed settings equal to absolute speed value. */
1316
1317 switch (baud)
1318 {
1319 case 300:
1320 baud = B300;
1321 break;
1322 case 1200:
1323 baud = B1200;
1324 break;
1325 case 2400:
1326 baud = B2400;
1327 break;
1328 case 4800:
1329 baud = B4800;
1330 break;
1331 case 9600:
1332 baud = B9600;
1333 break;
1334 case 19200:
1335 baud = B19200;
1336 break;
1337 case 38400:
1338 baud = B38400;
1339 break;
1340#ifdef B57600
1341 case 57600:
1342 baud = B57600;
1343 break;
1344#endif
1345#ifdef B115200
1346 case 115200:
1347 baud = B115200;
1348 break;
1349#endif
1350#ifdef B230400
1351 case 230400:
1352 baud = B230400;
1353 break;
1354#endif
1355 default:
1356 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
1357 baud = B19200;
1358 break;
1359 }
1360#endif
1361
1362 if(cfsetispeed(&termios, baud) != 0)
1363 {
1364 perror("ERROR: setting serial speed with cfsetispeed");
1365 return (-1);
1366 }
1367 if(cfsetospeed(&termios, baud) != 0)
1368 {
1369 perror("ERROR: setting serial speed with cfsetospeed");
1370 return (-1);
1371 }
1372 if(tcsetattr(fd, TCSANOW, &termios) < 0)
1373 {
1374 perror("ERROR: setting serial attributes");
1375 return (-1);
1376 }
1377 if(fcntl(fd, F_SETFL, 0) == -1)
1378 {
1379 perror("WARNING: setting blocking inputmode failed");
1380 }
1381 return (fd);
1382} /* openserial */
1383
1384/********************************************************************
1385* usage
1386*
1387* Send a usage message to standard error and quit the program.
1388*
1389* Parameters:
1390* None.
1391*
1392* Return Value:
1393* The function does not return a value.
1394*
1395* Remarks:
1396*
1397*********************************************************************/
1398static
1399#ifdef __GNUC__
1400__attribute__ ((noreturn))
1401#endif /* __GNUC__ */
1402void usage(int rc, char *name)
1403{
1404 fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s [OPTIONS]\n",
1405 revisionstr, datestr, name);
1406 fprintf(stderr, "PURPOSE\n");
1407 fprintf(stderr, " The purpose of this program is to pick up a GNSS data stream (Input, Source)\n");
1408 fprintf(stderr, " from either\n\n");
1409 fprintf(stderr, " 1. a Serial port, or\n");
1410 fprintf(stderr, " 2. an IP server, or\n");
1411 fprintf(stderr, " 3. a File, or\n");
1412 fprintf(stderr, " 4. a SISNeT Data Server, or\n");
1413 fprintf(stderr, " 5. a UDP server, or\n");
1414 fprintf(stderr, " 6. an NTRIP Version 1.0 Caster\n\n");
1415 fprintf(stderr, " and forward that incoming stream (Output, Destination) to either\n\n");
1416 fprintf(stderr, " - an NTRIP Version 1.0 Caster, or\n");
1417 fprintf(stderr, " - an NTRIP Version 2.0 Caster via TCP/IP or RTSP/RTP.\n\n\n");
1418 fprintf(stderr, "OPTIONS\n");
1419 fprintf(stderr, " -h|? print this help screen\n\n");
1420 fprintf(stderr, " -E <ProxyHost> Proxy server host name or address, required i.e. when\n");
1421 fprintf(stderr, " running the program in a proxy server protected LAN,\n");
1422 fprintf(stderr, " optional\n");
1423 fprintf(stderr, " -F <ProxyPort> Proxy server IP port, required i.e. when running\n");
1424 fprintf(stderr, " the program in a proxy server protected LAN, optional\n\n");
1425 fprintf(stderr, " -M <InputMode> Sets the input mode (1 = Serial Port, 2 = IP server,\n");
1426 fprintf(stderr, " 3 = File, 4 = SISNeT Data Server, 5 = UDP server, 6 = NTRIP Caster),\n");
1427 fprintf(stderr, " mandatory\n\n");
1428 fprintf(stderr, " <InputMode> = 1 (Serial Port):\n");
1429 fprintf(stderr, " -i <Device> Serial input device, default: /dev/gps, mandatory if\n");
1430 fprintf(stderr, " <InputMode>=1\n");
1431 fprintf(stderr, " -b <BaudRate> Serial input baud rate, default: 19200 bps, mandatory\n");
1432 fprintf(stderr, " if <InputMode>=1\n\n");
1433 fprintf(stderr, " <InputMode> = 2|5 (IP port | UDP port):\n");
1434 fprintf(stderr, " -H <ServerHost> Input host name or address, default: 127.0.0.1,\n");
1435 fprintf(stderr, " mandatory if <InputMode> = 2|5\n");
1436 fprintf(stderr, " -P <ServerPort> Input port, default: 1025, mandatory if <InputMode>= 2|5\n");
1437 fprintf(stderr, " -f <ServerFile> Name of initialization file to be send to server,\n");
1438 fprintf(stderr, " optional\n");
1439 fprintf(stderr, " -x <ServerUser> User ID to access incoming stream, optional\n");
1440 fprintf(stderr, " -y <ServerPass> Password, to access incoming stream, optional\n");
1441 fprintf(stderr, " -B Bind to incoming UDP stream, optional for <InputMode> = 5\n\n");
1442 fprintf(stderr, " <InputMode> = 3 (File):\n");
1443 fprintf(stderr, " -s <File> File name to simulate stream by reading data from (log)\n");
1444 fprintf(stderr, " file, default is /dev/stdin, mandatory for <InputMode> = 3\n\n");
1445 fprintf(stderr, " <InputMode> = 4 (SISNeT Data Server):\n");
1446 fprintf(stderr, " -H <SisnetHost> SISNeT Data Server name or address,\n");
1447 fprintf(stderr, " default: 131.176.49.142, mandatory if <InputMode> = 4\n");
1448 fprintf(stderr, " -P <SisnetPort> SISNeT Data Server port, default: 7777, mandatory if\n");
1449 fprintf(stderr, " <InputMode> = 4\n");
1450 fprintf(stderr, " -u <SisnetUser> SISNeT Data Server user ID, mandatory if <InputMode> = 4\n");
1451 fprintf(stderr, " -l <SisnetPass> SISNeT Data Server password, mandatory if <InputMode> = 4\n");
1452 fprintf(stderr, " -V <SisnetVers> SISNeT Data Server Version number, options are 2.1, 3.0\n");
1453 fprintf(stderr, " or 3.1, default: 3.1, mandatory if <InputMode> = 4\n\n");
1454 fprintf(stderr, " <InputMode> = 6 (NTRIP Version 1.0 Caster):\n");
1455 fprintf(stderr, " -H <SourceHost> Source caster name or address, default: 127.0.0.1,\n");
1456 fprintf(stderr, " mandatory if <InputMode> = 6\n");
1457 fprintf(stderr, " -P <SourcePort> Source caster port, default: 2101, mandatory if\n");
1458 fprintf(stderr, " <InputMode> = 6\n");
1459 fprintf(stderr, " -D <SourceMount> Source caster mountpoint for stream input, mandatory if\n");
1460 fprintf(stderr, " <InputMode> = 6\n");
1461 fprintf(stderr, " -U <SourceUser> Source caster user Id for input stream access, mandatory\n");
1462 fprintf(stderr, " for protected streams if <InputMode> = 6\n");
1463 fprintf(stderr, " -W <SourcePass> Source caster password for input stream access, mandatory\n");
1464 fprintf(stderr, " for protected streams if <InputMode> = 6\n\n");
1465 fprintf(stderr, " -O <OutputMode> Sets output mode for communatation with destination caster\n");
1466 fprintf(stderr, " 0 = h = http: Ntrip Version 2.0 Caster in TCP/IP mode\n");
1467 fprintf(stderr, " 1 = r = rtsp: NTRIP Version 2.0 Caster in RTSP/RTP mode\n");
1468 fprintf(stderr, " 2 = n = ntrip1: NTRIP Version 1.0 Caster\n\n");
1469 fprintf(stderr, " Defaults to NTRIP1.0, but wil change to 2.0 in future versions\n");
1470 fprintf(stderr, " Note that the program automatically falls back from mode r to mode t and\n");
1471 fprintf(stderr, " further to mode f if necessary.\n\n");
1472 fprintf(stderr, " -a <DestHost> Destination caster name or address, default: 127.0.0.1,\n");
1473 fprintf(stderr, " mandatory\n");
1474 fprintf(stderr, " -p <DestPort> Destination caster port, default: 2101, mandatory\n");
1475 fprintf(stderr, " -m <DestMount> Destination caster mountpoint for stream upload,\n");
1476 fprintf(stderr, " mandatory\n");
1477 fprintf(stderr, " -n <DestUser> Destination caster user ID for stream upload to\n");
1478 fprintf(stderr, " mountpoint, only for NTRIP Version 2.0 destination\n");
1479 fprintf(stderr, " casters, mandatory\n");
1480 fprintf(stderr, " -c <DestPass> Destination caster password for stream upload to\n");
1481 fprintf(stderr, " mountpoint, mandatory\n");
1482 fprintf(stderr, " -N <STR-record> Sourcetable STR-record\n");
1483 fprintf(stderr, " optional for Ntrip Version 2.0 in RTSP/RTP and TCP/IP mode\n\n");
1484 exit(rc);
1485} /* usage */
1486
1487
1488/********************************************************************/
1489/* signal handling */
1490/********************************************************************/
1491#ifdef __GNUC__
1492static void handle_sigint(int sig __attribute__((__unused__)))
1493#else /* __GNUC__ */
1494static void handle_sigint(int sig)
1495#endif /* __GNUC__ */
1496{sigint_received = 1;}
1497
1498static void setup_signal_handler(int sig, void (*handler)(int))
1499{
1500#if _POSIX_VERSION > 198800L
1501 struct sigaction action;
1502
1503 action.sa_handler = handler;
1504 sigemptyset(&(action.sa_mask));
1505 sigaddset(&(action.sa_mask), sig);
1506 action.sa_flags = 0;
1507 sigaction(sig, &action, 0);
1508#else
1509 signal(sig, handler);
1510#endif
1511 return;
1512} /* setupsignal_handler */
1513
1514static int signal_was_caught(void)
1515{
1516 fflush(stdout);
1517 if(sigint_received)
1518 fprintf(stderr, "SIGINT received: ");
1519
1520 return (sigint_received);
1521} /* signal_was_caught */
1522
1523/********************************************************************
1524 * base64-encoding *
1525*******************************************************************/
1526static const char encodingTable [64] =
1527{
1528 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1529 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1530 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1531 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1532};
1533
1534/* does not buffer overrun, but breaks directly after an error */
1535/* returns the number of required bytes */
1536static int encode(char *buf, int size, const char *user, const char *pwd)
1537{
1538 unsigned char inbuf[3];
1539 char *out = buf;
1540 int i, sep = 0, fill = 0, bytes = 0;
1541
1542 while(*user || *pwd)
1543 {
1544 i = 0;
1545 while(i < 3 && *user) inbuf[i++] = *(user++);
1546 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1547 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1548 while(i < 3) {inbuf[i++] = 0; ++fill; }
1549 if(out-buf < size-1)
1550 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1551 if(out-buf < size-1)
1552 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1553 | ((inbuf [1] & 0xF0) >> 4)];
1554 if(out-buf < size-1)
1555 {
1556 if(fill == 2)
1557 *(out++) = '=';
1558 else
1559 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1560 | ((inbuf [2] & 0xC0) >> 6)];
1561 }
1562 if(out-buf < size-1)
1563 {
1564 if(fill >= 1)
1565 *(out++) = '=';
1566 else
1567 *(out++) = encodingTable[inbuf [2] & 0x3F];
1568 }
1569 bytes += 4;
1570 }
1571 if(out-buf < size)
1572 *out = 0;
1573 return bytes;
1574}/* base64 Encoding */
1575
1576
1577/********************************************************************
1578 * send message to caster *
1579*********************************************************************/
1580static int send_to_caster(char *input, int socket, int input_size)
1581{
1582 int send_error = 1;
1583
1584 if((send(socket, input, (size_t)input_size, 0)) != input_size)
1585 {
1586 fprintf(stderr, "ERROR: could not send full header to Destination caster\n");
1587 send_error = 0;
1588 }
1589#ifndef NDEBUG
1590 else
1591 {
1592 fprintf(stderr, "\nDestination caster request:\n");
1593 fprintf(stderr, "%s", input);
1594 }
1595#endif
1596 return send_error;
1597}/* send_to_caster */
1598
1599
1600/********************************************************************
1601 * close session *
1602*********************************************************************/
1603static void close_session(int sock_udp, int sock_tcp,
1604const char *caster_addr, const char *mountpoint, int cseq,
1605int session, char *rtsp_ext, int in_fd)
1606{
1607 int size_send_buf;
1608 char send_buf[BUFSZ];
1609
1610 if(in_fd)
1611 {
1612 if(close(in_fd)==-1)
1613 {
1614 perror("ERROR: close input device ");
1615 exit(0);
1616 }
1617#ifndef NDEBUG
1618 else
1619 {
1620 fprintf(stderr, "\nclose input device: successful\n");
1621 }
1622#endif
1623 }
1624
1625 if(sock_udp != 0)
1626 {
1627 if(cseq == 2)
1628 {
1629 size_send_buf = snprintf(send_buf, sizeof(send_buf),
1630 "TEARDOWN rtsp://%s%s/%s RTSP/1.0\r\n"
1631 "CSeq: 2\r\n"
1632 "Session: %d\r\n"
1633 "\r\n",
1634 caster_addr, rtsp_ext, mountpoint, session);
1635 if((size_send_buf >= (int)sizeof(send_buf)) || (size_send_buf < 0))
1636 {
1637 fprintf(stderr, "ERROR: Destination caster request to long\n");
1638 exit(0);
1639 }
1640 send_to_caster(send_buf, sock_tcp, size_send_buf); strcpy(send_buf,"");
1641 size_send_buf = recv(sock_tcp, send_buf, sizeof(send_buf), 0);
1642 send_buf[size_send_buf] = '\0';
1643#ifndef NDEBUG
1644 fprintf(stderr, "Destination caster response:\n%s", send_buf);
1645#endif
1646 }
1647 if(close(sock_udp)==-1)
1648 {
1649 perror("ERROR: close udp socket");
1650 exit(0);
1651 }
1652#ifndef NDEBUG
1653 else
1654 {
1655 fprintf(stderr, "close udp socket: successful\n");
1656 }
1657#endif
1658 }
1659
1660 if(close(sock_tcp)==-1)
1661 {
1662 perror("ERROR: close tcp socket");
1663 exit(0);
1664 }
1665#ifndef NDEBUG
1666 else
1667 {
1668 fprintf(stderr, "close tcp socket: successful\n\n");
1669 }
1670#endif
1671} /* close_session */
Note: See TracBrowser for help on using the repository browser.