source: ntrip/trunk/ntripserver/NtripLinuxServer.c@ 467

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

updated to Version 2.0 (may not work yet)

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