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

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

fixed debug stuff

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