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

Last change on this file since 1602 was 1573, checked in by stoecker, 16 years ago

added connection end

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