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

Last change on this file since 9455 was 9455, checked in by stuerze, 7 weeks ago

minor changes

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