source: ntrip/trunk/ntripclient/ntripclient.c @ 834

Last change on this file since 834 was 834, checked in by stoecker, 13 years ago

added support for serial output

File size: 37.8 KB
Line 
1/*
2  NTRIP client for POSIX.
3  $Id: ntripclient.c,v 1.42 2008/04/07 11:49:13 stoecker Exp $
4  Copyright (C) 2003-2008 by Dirk Stöcker <soft@dstoecker.de>
5
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  or read http://www.gnu.org/licenses/gpl.txt
20*/
21
22#include <ctype.h>
23#include <getopt.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <string.h>
28#include <time.h>
29
30#include "serial.c"
31
32#ifdef WINDOWSVERSION
33  #include <winsock.h>
34  typedef SOCKET sockettype;
35  typedef u_long in_addr_t;
36  typedef size_t socklen_t;
37#else
38  typedef int sockettype;
39  #include <signal.h>
40  #include <fcntl.h>
41  #include <unistd.h>
42  #include <arpa/inet.h>
43  #include <sys/socket.h>
44  #include <netinet/in.h>
45  #include <netdb.h>
46
47  #define closesocket(sock)       close(sock)
48  #define ALARMTIME   (2*60)
49#endif
50
51#ifndef COMPILEDATE
52#define COMPILEDATE " built " __DATE__
53#endif
54
55/* The string, which is send as agent in HTTP request */
56#define AGENTSTRING "NTRIP NtripClientPOSIX"
57
58#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
59
60/* CVS revision and version */
61static char revisionstr[] = "$Revision: 1.42 $";
62static char datestr[]     = "$Date: 2008/04/07 11:49:13 $";
63
64enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
65
66struct Args
67{
68  const char *server;
69  const char *port;
70  const char *user;
71  const char *proxyhost;
72  const char *proxyport;
73  const char *password;
74  const char *nmea;
75  const char *data;
76  int         bitrate;
77  int         mode;
78
79  int         udpport;
80  int         initudp;
81  enum SerialBaud baud;
82  enum SerialDatabits databits;
83  enum SerialStopbits stopbits;
84  enum SerialParity parity;
85  enum SerialProtocol protocol;
86  const char *serdevice;
87};
88
89/* option parsing */
90#ifdef NO_LONG_OPTS
91#define LONG_OPT(a)
92#else
93#define LONG_OPT(a) a
94static struct option opts[] = {
95{ "bitrate",    no_argument,       0, 'b'},
96{ "data",       required_argument, 0, 'd'}, /* compatibility */
97{ "mountpoint", required_argument, 0, 'm'},
98{ "initudp",    no_argument,       0, 'I'},
99{ "udpport",    required_argument, 0, 'P'},
100{ "server",     required_argument, 0, 's'},
101{ "password",   required_argument, 0, 'p'},
102{ "port",       required_argument, 0, 'r'},
103{ "proxyport",  required_argument, 0, 'R'},
104{ "proxyhost",  required_argument, 0, 'S'},
105{ "user",       required_argument, 0, 'u'},
106{ "nmea",       required_argument, 0, 'n'},
107{ "mode",       required_argument, 0, 'M'},
108{ "serdevice",  required_argument, 0, 'D'},
109{ "baud",       required_argument, 0, 'B'},
110{ "stopbits",   required_argument, 0, 'T'},
111{ "protocol",   required_argument, 0, 'C'},
112{ "parity",     required_argument, 0, 'Y'},
113{ "databits",   required_argument, 0, 'A'},
114{ "help",       no_argument,       0, 'h'},
115{0,0,0,0}};
116#endif
117#define ARGOPT "-d:m:bhp:r:s:u:n:S:R:M:IP:D:B:T:C:Y:A:"
118
119int stop = 0;
120#ifndef WINDOWSVERSION
121#ifdef __GNUC__
122static __attribute__ ((noreturn)) void sighandler_alarm(
123int sig __attribute__((__unused__)))
124#else /* __GNUC__ */
125static void sighandler_alarm(int sig)
126#endif /* __GNUC__ */
127{
128  fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
129  exit(1);
130}
131
132#ifdef __GNUC__
133static void sighandler_int(int sig __attribute__((__unused__)))
134#else /* __GNUC__ */
135static void sighandler_alarm(int sig)
136#endif /* __GNUC__ */
137{
138  alarm(2);
139  stop = 1;
140}
141#endif /* WINDOWSVERSION */
142
143static const char *encodeurl(const char *req)
144{
145  char *h = "0123456789abcdef";
146  static char buf[128];
147  char *urlenc = buf;
148  char *bufend = buf + sizeof(buf) - 3;
149
150  while(*req && urlenc < bufend)
151  {
152    if(isalnum(*req) 
153    || *req == '-' || *req == '_' || *req == '.')
154      *urlenc++ = *req++;
155    else
156    {
157      *urlenc++ = '%';
158      *urlenc++ = h[*req >> 4];
159      *urlenc++ = h[*req & 0x0f];
160      req++;
161    }
162  }
163  *urlenc = 0;
164  return buf;
165}
166
167static const char *geturl(const char *url, struct Args *args)
168{
169  static char buf[1000];
170  static char *Buffer = buf;
171  static char *Bufend = buf+sizeof(buf);
172  char *h = "0123456789abcdef";
173
174  if(strncmp("ntrip:", url, 6))
175    return "URL must start with 'ntrip:'.";
176  url += 6; /* skip ntrip: */
177
178  if(*url != '@' && *url != '/')
179  {
180    /* scan for mountpoint */
181    args->data = Buffer;
182    if(*url != '?')
183    {
184       while(*url && *url != '@' &&  *url != ';' && *url != '/' && Buffer != Bufend)
185         *(Buffer++) = *(url++);
186    }
187    else
188    {
189       while(*url && *url != '@' &&  *url != '/' && Buffer != Bufend) 
190       {
191          if(isalnum(*url) || *url == '-' || *url == '_' || *url == '.')
192            *Buffer++ = *url++;
193          else
194          {
195            *Buffer++ = '%';
196            *Buffer++ = h[*url >> 4];
197            *Buffer++ = h[*url & 0x0f];
198            url++;
199          }
200       }
201    }
202    if(Buffer == args->data)
203      return "Mountpoint required.";
204    else if(Buffer >= Bufend-1)
205      return "Parsing buffer too short.";
206    *(Buffer++) = 0;
207  }
208
209  if(*url == '/') /* username and password */
210  {
211    ++url;
212    args->user = Buffer;
213    while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
214      *(Buffer++) = *(url++);
215    if(Buffer == args->user)
216      return "Username cannot be empty.";
217    else if(Buffer >= Bufend-1)
218      return "Parsing buffer too short.";
219    *(Buffer++) = 0;
220
221    if(*url == ':') ++url;
222
223    args->password = Buffer;
224    while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
225      *(Buffer++) = *(url++);
226    if(Buffer == args->password)
227      return "Password cannot be empty.";
228    else if(Buffer >= Bufend-1)
229      return "Parsing buffer too short.";
230    *(Buffer++) = 0;
231  }
232
233  if(*url == '@') /* server */
234  {
235    ++url;
236    if(*url != '@' && *url != ':')
237    {
238      args->server = Buffer;
239      while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
240        *(Buffer++) = *(url++);
241      if(Buffer == args->server)
242        return "Servername cannot be empty.";
243      else if(Buffer >= Bufend-1)
244        return "Parsing buffer too short.";
245      *(Buffer++) = 0;
246    }
247
248    if(*url == ':')
249    {
250      ++url;
251      args->port = Buffer;
252      while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
253        *(Buffer++) = *(url++);
254      if(Buffer == args->port)
255        return "Port cannot be empty.";
256      else if(Buffer >= Bufend-1)
257        return "Parsing buffer too short.";
258      *(Buffer++) = 0;
259    }
260
261    if(*url == '@') /* proxy */
262    {
263      ++url;
264      args->proxyhost = Buffer;
265      while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
266        *(Buffer++) = *(url++);
267      if(Buffer == args->proxyhost)
268        return "Proxy servername cannot be empty.";
269      else if(Buffer >= Bufend-1)
270        return "Parsing buffer too short.";
271      *(Buffer++) = 0;
272
273      if(*url == ':')
274      {
275        ++url;
276        args->proxyport = Buffer;
277        while(*url && *url != ';' && Buffer != Bufend)
278          *(Buffer++) = *(url++);
279        if(Buffer == args->proxyport)
280          return "Proxy port cannot be empty.";
281        else if(Buffer >= Bufend-1)
282          return "Parsing buffer too short.";
283        *(Buffer++) = 0;
284      }
285    }
286  }
287  if(*url == ';') /* NMEA */
288  {
289    args->nmea = ++url;
290    while(*url)
291      ++url;
292  }
293
294  return *url ? "Garbage at end of server string." : 0;
295}
296
297static int getargs(int argc, char **argv, struct Args *args)
298{
299  int res = 1;
300  int getoptr;
301  char *a;
302  int i = 0, help = 0;
303
304  args->server = "www.euref-ip.net";
305  args->port = "2101";
306  args->user = "";
307  args->password = "";
308  args->nmea = 0;
309  args->data = 0;
310  args->bitrate = 0;
311  args->proxyhost = 0;
312  args->proxyport = "2101";
313  args->mode = AUTO;
314  args->initudp = 0;
315  args->udpport = 0;
316  args->protocol = SPAPROTOCOL_NONE;
317  args->parity = SPAPARITY_NONE;
318  args->stopbits = SPASTOPBITS_1;
319  args->databits = SPADATABITS_8;
320  args->baud = SPABAUD_9600;
321  args->serdevice = 0;
322  help = 0;
323
324  do
325  {
326#ifdef NO_LONG_OPTS
327    switch((getoptr = getopt(argc, argv, ARGOPT)))
328#else
329    switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
330#endif
331    {
332    case 's': args->server = optarg; break;
333    case 'u': args->user = optarg; break;
334    case 'p': args->password = optarg; break;
335    case 'd':
336    case 'm':
337      if(optarg && *optarg == '?') 
338        args->data = encodeurl(optarg);
339      else 
340        args->data = optarg; 
341      break;
342    case 'B':
343      {
344        int i = strtol(optarg, 0, 10);
345
346        switch(i)
347        {
348        case 50: args->baud = SPABAUD_50; break;
349        case 110: args->baud = SPABAUD_110; break;
350        case 300: args->baud = SPABAUD_300; break;
351        case 600: args->baud = SPABAUD_600; break;
352        case 1200: args->baud = SPABAUD_1200; break;
353        case 2400: args->baud = SPABAUD_2400; break;
354        case 4800: args->baud = SPABAUD_4800; break;
355        case 9600: args->baud = SPABAUD_9600; break;
356        case 19200: args->baud = SPABAUD_19200; break;
357        case 38400: args->baud = SPABAUD_38400; break;
358        case 57600: args->baud = SPABAUD_57600; break;
359        case 115200: args->baud = SPABAUD_115200; break;
360        default:
361          fprintf(stderr, "Baudrate '%s' unknown\n", optarg);
362          res = 0;
363          break;
364        }
365      }
366      break;
367    case 'T':
368      if(!strcmp(optarg, "1")) args->stopbits = SPASTOPBITS_1;
369      else if(!strcmp(optarg, "2")) args->stopbits = SPASTOPBITS_2;
370      else
371      {
372        fprintf(stderr, "Stopbits '%s' unknown\n", optarg);
373        res = 0;
374      }
375      break;
376    case 'A':
377      if(!strcmp(optarg, "5")) args->databits = SPADATABITS_5;
378      else if(!strcmp(optarg, "6")) args->databits = SPADATABITS_6;
379      else if(!strcmp(optarg, "7")) args->databits = SPADATABITS_7;
380      else if(!strcmp(optarg, "8")) args->databits = SPADATABITS_8;
381      else
382      {
383        fprintf(stderr, "Databits '%s' unknown\n", optarg);
384        res = 0;
385      }
386      break;
387    case 'C':
388      {
389        int i = 0;
390        args->protocol = SerialGetProtocol(optarg, &i);
391        if(i)
392        {
393          fprintf(stderr, "Protocol '%s' unknown\n", optarg);
394          res = 0;
395        }
396      }
397      break;
398    case 'Y':
399      {
400        int i = 0;
401        args->parity = SerialGetParity(optarg, &i);
402        if(i)
403        {
404          fprintf(stderr, "Parity '%s' unknown\n", optarg);
405          res = 0;
406        }
407      }
408      break;
409    case 'D': args->serdevice = optarg; break;
410    case 'I': args->initudp = 1; break;
411    case 'P': args->udpport = strtol(optarg, 0, 10); break;
412    case 'n': args->nmea = optarg; break;
413    case 'b': args->bitrate = 1; break;
414    case 'h': help=1; break;
415    case 'r': args->port = optarg; break;
416    case 'S': args->proxyhost = optarg; break;
417    case 'R': args->proxyport = optarg; break;
418    case 'M':
419      args->mode = 0;
420      if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
421        args->mode = NTRIP1;
422      else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
423        args->mode = HTTP;
424      else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
425        args->mode = RTSP;
426      else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
427        args->mode = AUTO;
428      else args->mode = atoi(optarg);
429      if((args->mode == 0) || (args->mode >= END))
430      {
431        fprintf(stderr, "Mode %s unknown\n", optarg);
432        res = 0;
433      }
434      break;
435    case 1:
436      {
437        const char *err;
438        if((err = geturl(optarg, args)))
439        {
440          fprintf(stderr, "%s\n\n", err);
441          res = 0;
442        }
443      }
444      break;
445    case -1: break;
446    }
447  } while(getoptr != -1 && res);
448
449  for(a = revisionstr+11; *a && *a != ' '; ++a)
450    revisionstr[i++] = *a;
451  revisionstr[i] = 0;
452  datestr[0] = datestr[7];
453  datestr[1] = datestr[8];
454  datestr[2] = datestr[9];
455  datestr[3] = datestr[10];
456  datestr[5] = datestr[12];
457  datestr[6] = datestr[13];
458  datestr[8] = datestr[15];
459  datestr[9] = datestr[16];
460  datestr[4] = datestr[7] = '-';
461  datestr[10] = 0;
462
463  if(!res || help)
464  {
465    fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s -s server -u user ...\n"
466    " -m " LONG_OPT("--mountpoint ") "the requested data set or sourcetable filtering criteria\n"
467    " -s " LONG_OPT("--server     ") "the server name or address\n"
468    " -p " LONG_OPT("--password   ") "the login password\n"
469    " -r " LONG_OPT("--port       ") "the server port number (default 2101)\n"
470    " -u " LONG_OPT("--user       ") "the user name\n"
471    " -n " LONG_OPT("--nmea       ") "NMEA string for sending to server\n"
472    " -b " LONG_OPT("--bitrate    ") "output bitrate\n"
473    " -I " LONG_OPT("--initudp    ") "send initial UDP packet for firewall handling\n"
474    " -P " LONG_OPT("--udpport    ") "set the local UDP port\n"
475    " -S " LONG_OPT("--proxyhost  ") "proxy name or address\n"
476    " -R " LONG_OPT("--proxyport  ") "proxy port, optional (default 2101)\n"
477    " -D " LONG_OPT("--serdevice  ") "serial device for output\n"
478    " -B " LONG_OPT("--baud       ") "baudrate for serial device\n"
479    " -T " LONG_OPT("--stopbits   ") "stopbits for serial device\n"
480    " -C " LONG_OPT("--protocol   ") "protocol for serial device\n"
481    " -Y " LONG_OPT("--parity     ") "parity for serial device\n"
482    " -A " LONG_OPT("--databits   ") "databits for serial device\n"
483    " -M " LONG_OPT("--mode       ") "mode for data request\n"
484    "     Valid modes are:\n"
485    "     1, h, http     NTRIP Version 2.0 Caster in TCP/IP mode\n"
486    "     2, r, rtsp     NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
487    "     3, n, ntrip1   NTRIP Version 1.0 Caster\n"
488    "     4, a, auto     automatic detection (default)\n"
489    "or using an URL:\n%s ntrip:mountpoint[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
490    , revisionstr, datestr, argv[0], argv[0]);
491    exit(1);
492  }
493  return res;
494}
495
496static const char encodingTable [64] = {
497  'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
498  'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
499  'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
500  'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
501};
502
503/* does not buffer overrun, but breaks directly after an error */
504/* returns the number of required bytes */
505static int encode(char *buf, int size, const char *user, const char *pwd)
506{
507  unsigned char inbuf[3];
508  char *out = buf;
509  int i, sep = 0, fill = 0, bytes = 0;
510
511  while(*user || *pwd)
512  {
513    i = 0;
514    while(i < 3 && *user) inbuf[i++] = *(user++);
515    if(i < 3 && !sep)    {inbuf[i++] = ':'; ++sep; }
516    while(i < 3 && *pwd)  inbuf[i++] = *(pwd++);
517    while(i < 3)         {inbuf[i++] = 0; ++fill; }
518    if(out-buf < size-1)
519      *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
520    if(out-buf < size-1)
521      *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
522               | ((inbuf [1] & 0xF0) >> 4)];
523    if(out-buf < size-1)
524    {
525      if(fill == 2)
526        *(out++) = '=';
527      else
528        *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
529                 | ((inbuf [2] & 0xC0) >> 6)];
530    }
531    if(out-buf < size-1)
532    {
533      if(fill >= 1)
534        *(out++) = '=';
535      else
536        *(out++) = encodingTable[inbuf [2] & 0x3F];
537    }
538    bytes += 4;
539  }
540  if(out-buf < size)
541    *out = 0;
542  return bytes;
543}
544
545int main(int argc, char **argv)
546{
547  struct Args args;
548
549  setbuf(stdout, 0);
550  setbuf(stdin, 0);
551  setbuf(stderr, 0);
552#ifndef WINDOWSVERSION
553  signal(SIGALRM,sighandler_alarm);
554  signal(SIGINT,sighandler_int);
555  alarm(ALARMTIME);
556#else
557  WSADATA wsaData;
558  if(WSAStartup(MAKEWORD(1,1),&wsaData))
559  {
560    fprintf(stderr, "Could not init network access.\n");
561    return 20;
562  }
563#endif
564
565  if(getargs(argc, argv, &args))
566  {
567    struct serial sx;
568    char nmeabuffer[200] = "$GPGGA,"; /* our start string */
569    size_t nmeabufpos = 0;
570    size_t nmeastarpos = 0;
571    int sleeptime = 0;
572    if(args.serdevice)
573    {
574      const char *e = SerialInit(&sx, args.serdevice, args.baud,
575      args.stopbits, args.protocol, args.parity, args.databits, 1);
576      if(e)
577      {
578        fprintf(stderr, "%s\n", e);
579        return 20;
580      }
581    }
582    do
583    {
584      sockettype sockfd;
585      int numbytes; 
586      char buf[MAXDATASIZE];
587      struct sockaddr_in their_addr; /* connector's address information */
588      struct hostent *he;
589      struct servent *se;
590      const char *server, *port, *proxyserver = 0;
591      char proxyport[6];
592      char *b;
593      long i;
594      if(sleeptime)
595      {
596#ifdef WINDOWSVERSION
597        Sleep(sleeptime*1000);
598#else
599        sleep(sleeptime);
600#endif
601        sleeptime += 2;
602      }
603      else
604      {
605        sleeptime = 1;
606      }
607#ifndef WINDOWSVERSION
608      alarm(ALARMTIME);
609#endif
610      if(args.proxyhost)
611      {
612        int p;
613        if((i = strtol(args.port, &b, 10)) && (!b || !*b))
614          p = i;
615        else if(!(se = getservbyname(args.port, 0)))
616        {
617          fprintf(stderr, "Can't resolve port %s.", args.port);
618          exit(1);
619        }
620        else
621        {
622          p = ntohs(se->s_port);
623        }
624        snprintf(proxyport, sizeof(proxyport), "%d", p);
625        port = args.proxyport;
626        proxyserver = args.server;
627        server = args.proxyhost;
628      }
629      else
630      {
631        server = args.server;
632        port = args.port;
633      }
634      memset(&their_addr, 0, sizeof(struct sockaddr_in));
635      if((i = strtol(port, &b, 10)) && (!b || !*b))
636        their_addr.sin_port = htons(i);
637      else if(!(se = getservbyname(port, 0)))
638      {
639        fprintf(stderr, "Can't resolve port %s.", port);
640        exit(1);
641      }
642      else
643      {
644        their_addr.sin_port = se->s_port;
645      }
646      if(!(he=gethostbyname(server)))
647      {
648        fprintf(stderr, "Server name lookup failed for '%s'.\n", server);
649        exit(1);
650      }
651      if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
652      {
653        perror("socket");
654        exit(1);
655      }
656      their_addr.sin_family = AF_INET;
657      their_addr.sin_addr = *((struct in_addr *)he->h_addr);
658
659      if(args.data && *args.data != '%' && args.mode == RTSP)
660      {
661        struct sockaddr_in local;
662        int sockudp, localport;
663        int cseq = 1;
664        socklen_t len;
665
666        if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
667        {
668          perror("socket");
669          exit(1);
670        }
671        /* fill structure with local address information for UDP */
672        memset(&local, 0, sizeof(local));
673        local.sin_family = AF_INET;
674        local.sin_port = htons(args.udpport);
675        local.sin_addr.s_addr = htonl(INADDR_ANY); 
676        len = sizeof(local);
677        /* bind() in order to get a random RTP client_port */ 
678        if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
679        {
680          perror("bind");
681          exit(1);
682        }
683        if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1) 
684        {
685          localport = ntohs(local.sin_port); 
686        }
687        else
688        {
689          perror("local access failed"); 
690          exit(1);
691        }
692        if(connect(sockfd, (struct sockaddr *)&their_addr,
693        sizeof(struct sockaddr)) == -1)
694        {
695          perror("connect");
696          exit(1);
697        }
698        i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
699        "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"           
700        "CSeq: %d\r\n"         
701        "Ntrip-Version: Ntrip/2.0\r\n"
702        "Ntrip-Component: Ntripclient\r\n"
703        "User-Agent: %s/%s\r\n"
704        "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
705        "Authorization: Basic ",
706        args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
707        args.data, cseq++, AGENTSTRING, revisionstr, localport);
708        if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
709        {
710          fprintf(stderr, "Requested data too long\n");
711          exit(1);
712        }
713        i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
714        if(i > MAXDATASIZE-4)
715        {
716          fprintf(stderr, "Username and/or password too long\n");
717          exit(1);
718        }
719        buf[i++] = '\r';
720        buf[i++] = '\n';
721        buf[i++] = '\r';
722        buf[i++] = '\n';
723        if(args.nmea)
724        {
725          int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
726          if(j >= 0 && j < MAXDATASIZE-i)
727            i += j;
728          else
729          {
730            fprintf(stderr, "NMEA string too long\n");
731            exit(1);
732          }
733        }
734        if(send(sockfd, buf, (size_t)i, 0) != i)
735        {
736          perror("send");
737          exit(1);
738        }
739        if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
740        {
741          if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
742          {
743            int serverport = 0, session = 0;
744            const char *portcheck = "server_port=";
745            const char *sessioncheck = "session: ";
746            int l = strlen(portcheck)-1;
747            int j=0;
748            for(i = 0; j != l && i < numbytes-l; ++i)
749            {
750              for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
751                ;
752            }
753            if(i == numbytes-l)
754            {
755              fprintf(stderr, "No server port number found\n");
756              exit(1);
757            }
758            else
759            {
760              i+=l;
761              while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
762                serverport = serverport * 10 + buf[i++]-'0';
763              if(buf[i] != '\r' && buf[i] != ';')
764              {
765                fprintf(stderr, "Could not extract server port\n");
766                exit(1);
767              }
768            }
769            l = strlen(sessioncheck)-1;
770            j=0;
771            for(i = 0; j != l && i < numbytes-l; ++i)
772            {
773              for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
774                ;
775            }
776            if(i == numbytes-l)
777            {
778              fprintf(stderr, "No session number found\n");
779              exit(1);
780            }
781            else
782            {
783              i+=l;
784              while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
785                session = session * 10 + buf[i++]-'0';
786              if(buf[i] != '\r')
787              {
788                fprintf(stderr, "Could not extract session number\n");
789                exit(1);
790              }
791            }
792            if(args.initudp)
793            {
794              printf("Sending initial UDP packet\n");
795              struct sockaddr_in casterRTP;
796              char rtpbuffer[12];
797              int i;
798              rtpbuffer[0] = (2<<6);
799              /* padding, extension, csrc are empty */
800              rtpbuffer[1] = 96;
801              /* marker is empty */
802              rtpbuffer[2] = 0;
803              rtpbuffer[3] = 0;
804              rtpbuffer[4] = 0;
805              rtpbuffer[5] = 0;
806              rtpbuffer[6] = 0;
807              rtpbuffer[7] = 0;
808              /* sequence and timestamp are empty */
809              rtpbuffer[8] = (session>>24)&0xFF;
810              rtpbuffer[9] = (session>>16)&0xFF;
811              rtpbuffer[10] = (session>>8)&0xFF;
812              rtpbuffer[11] = (session)&0xFF;
813              /* fill structure with caster address information for UDP */
814              memset(&casterRTP, 0, sizeof(casterRTP));
815              casterRTP.sin_family = AF_INET;
816              casterRTP.sin_port   = htons(serverport);
817              casterRTP.sin_addr   = *((struct in_addr *)he->h_addr);
818
819              if((i = sendto(sockudp, rtpbuffer, 12, 0,
820              (struct sockaddr *) &casterRTP, sizeof(casterRTP))) != 12)
821                perror("WARNING: could not send initial UDP packet");
822            }
823
824            i = snprintf(buf, MAXDATASIZE,
825            "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"               
826            "CSeq: %d\r\n"
827            "Session: %d\r\n"
828            "\r\n", 
829            args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
830            args.data, cseq++, session);
831
832            if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
833            {
834              fprintf(stderr, "Requested data too long\n");
835              exit(1);
836            }
837            if(send(sockfd, buf, (size_t)i, 0) != i)
838            {
839              perror("send");
840              exit(1);
841            }
842            if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
843            {
844              if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
845              {
846                struct sockaddr_in addrRTP;
847                /* fill structure with caster address information for UDP */
848                memset(&addrRTP, 0, sizeof(addrRTP));
849                addrRTP.sin_family = AF_INET; 
850                addrRTP.sin_port   = htons(serverport);
851                their_addr.sin_addr = *((struct in_addr *)he->h_addr);
852                len = sizeof(addrRTP);
853                int ts = 0;
854                int sn = 0;
855                int ssrc = 0;
856                int init = 0;
857                int u, v, w;
858                while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
859                (struct sockaddr*) &addrRTP, &len)) > 0)
860                {
861#ifndef WINDOWSVERSION
862                  alarm(ALARMTIME);
863#endif
864                  if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
865                  {
866                    u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
867                    v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
868                    +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
869                    w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
870                    +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
871
872                    if(init)
873                    {
874                      if(u < -30000 && sn > 30000) sn -= 0xFFFF;
875                      if(ssrc != w || ts > v)
876                      {
877                        fprintf(stderr, "Illegal UDP data received.\n");
878                        exit(1);
879                      }
880                      if(u > sn) /* don't show out-of-order packets */
881                        fwrite(buf+12, (size_t)i-12, 1, stdout);
882                    }
883                    sn = u; ts = v; ssrc = w; init = 1;
884                  }
885                  else
886                  {
887                    fprintf(stderr, "Illegal UDP header.\n");
888                    exit(1);
889                  }
890                }
891              }
892              i = snprintf(buf, MAXDATASIZE,
893              "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"         
894              "CSeq: %d\r\n"
895              "Session: %d\r\n"
896              "\r\n", 
897              args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
898              args.data, cseq++, session);
899
900              if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
901              {
902                fprintf(stderr, "Requested data too long\n");
903                exit(1);
904              }
905              if(send(sockfd, buf, (size_t)i, 0) != i)
906              {
907                perror("send");
908                exit(1);
909              }
910            }
911            else
912            {
913              fprintf(stderr, "Could not start data stream.\n");
914              exit(1);
915            }
916          }
917          else
918          {
919            fprintf(stderr, "Could not setup initial control connection.\n");
920            exit(1);
921          }
922        }
923        else
924        {
925          perror("recv");
926          exit(1);
927        }
928      }
929      else
930      {
931        if(connect(sockfd, (struct sockaddr *)&their_addr,
932        sizeof(struct sockaddr)) == -1)
933        {
934          perror("connect");
935          exit(1);
936        }
937        if(!args.data)
938        {
939          i = snprintf(buf, MAXDATASIZE,
940          "GET %s%s%s%s/ HTTP/1.0\r\n"
941          "Host: %s\r\n%s"
942          "User-Agent: %s/%s\r\n"
943          "Connection: close\r\n"
944          "\r\n"
945          , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
946          proxyserver ? ":" : "", proxyserver ? proxyport : "",
947          args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
948          AGENTSTRING, revisionstr);
949        }
950        else
951        {
952          i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
953          "GET %s%s%s%s/%s HTTP/1.0\r\n"
954          "Host: %s\r\n%s"
955          "User-Agent: %s/%s\r\n"
956          "Connection: close\r\n"
957          "Authorization: Basic "
958          , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
959          proxyserver ? ":" : "", proxyserver ? proxyport : "",
960          args.data, args.server,
961          args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
962          AGENTSTRING, revisionstr);
963          if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
964          {
965            fprintf(stderr, "Requested data too long\n");
966            exit(1);
967          }
968          i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
969          if(i > MAXDATASIZE-4)
970          {
971            fprintf(stderr, "Username and/or password too long\n");
972            exit(1);
973          }
974          buf[i++] = '\r';
975          buf[i++] = '\n';
976          buf[i++] = '\r';
977          buf[i++] = '\n';
978          if(args.nmea)
979          {
980            int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
981            if(j >= 0 && j < MAXDATASIZE-i)
982              i += j;
983            else
984            {
985              fprintf(stderr, "NMEA string too long\n");
986              exit(1);
987            }
988          }
989        }
990        if(send(sockfd, buf, (size_t)i, 0) != i)
991        {
992          perror("send");
993          exit(1);
994        }
995        if(args.data && *args.data != '%')
996        {
997          int k = 0;
998          int chunkymode = 0;
999          int starttime = time(0);
1000          int lastout = starttime;
1001          int totalbytes = 0;
1002          int chunksize = 0;
1003
1004          while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1005          {
1006#ifndef WINDOWSVERSION
1007            alarm(ALARMTIME);
1008#endif
1009            if(!k)
1010            {
1011              if( numbytes > 17 && 
1012                 !strstr(buf, "ICY 200 OK")  &&  /* case 'proxy & ntrip 1.0 caster' */
1013                 (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) || 
1014                  !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)) )
1015              {
1016                const char *datacheck = "Content-Type: gnss/data\r\n";
1017                const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
1018                int l = strlen(datacheck)-1;
1019                int j=0;
1020                for(i = 0; j != l && i < numbytes-l; ++i)
1021                {
1022                  for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
1023                    ;
1024                }
1025                if(i == numbytes-l)
1026                {
1027                  fprintf(stderr, "No 'Content-Type: gnss/data' found\n");
1028                  exit(1);
1029                }
1030                l = strlen(chunkycheck)-1;
1031                j=0;
1032                for(i = 0; j != l && i < numbytes-l; ++i)
1033                {
1034                  for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
1035                    ;
1036                }
1037                if(i < numbytes-l)
1038                  chunkymode = 1;
1039              }
1040              else if(!strstr(buf, "ICY 200 OK"))
1041              {
1042                fprintf(stderr, "Could not get the requested data: ");
1043                for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
1044                {
1045                  fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
1046                }
1047                fprintf(stderr, "\n");
1048                exit(1);
1049              }
1050              else if(args.mode != NTRIP1)
1051              {
1052                fprintf(stderr, "NTRIP version 2 HTTP connection failed%s.\n",
1053                args.mode == AUTO ? ", falling back to NTRIP1" : "");
1054                if(args.mode == HTTP)
1055                  exit(1);
1056              }
1057              ++k;
1058            }
1059            else
1060            {
1061              sleeptime = 0;
1062              if(chunkymode)
1063              {
1064                int stop = 0;
1065                int pos = 0;
1066                while(!stop && pos < numbytes)
1067                {
1068                  switch(chunkymode)
1069                  {
1070                  case 1: /* reading number starts */
1071                    chunksize = 0;
1072                    ++chunkymode; /* no break */
1073                  case 2: /* during reading number */
1074                    i = buf[pos++];
1075                    if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
1076                    else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
1077                    else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
1078                    else if(i == '\r') ++chunkymode;
1079                    else if(i == ';') chunkymode = 5;
1080                    else stop = 1;
1081                    break;
1082                  case 3: /* scanning for return */
1083                    if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
1084                    else stop = 1;
1085                    break;
1086                  case 4: /* output data */
1087                    i = numbytes-pos;
1088                    if(i > chunksize) i = chunksize;
1089                    if(args.serdevice)
1090                    {
1091                      int ofs = 0;
1092                      while(i > ofs && !stop)
1093                      {
1094                        int j = SerialWrite(&sx, buf+pos+ofs, i-ofs);
1095                        if(j < 0)
1096                        {
1097                          fprintf(stderr, "Could not access serial device\n");
1098                          stop = 1;
1099                        }
1100                        else
1101                          ofs += j;
1102                      }
1103                    }
1104                    else
1105                      fwrite(buf+pos, (size_t)i, 1, stdout);
1106                    totalbytes += i;
1107                    chunksize -= i;
1108                    pos += i;
1109                    if(!chunksize)
1110                      chunkymode = 1;
1111                    break;
1112                  case 5:
1113                    if(i == '\r') chunkymode = 3;
1114                    break;
1115                  }
1116                }
1117                if(stop)
1118                {
1119                  fprintf(stderr, "Error in chunky transfer encoding\n");
1120                  break;
1121                }
1122              }
1123              else
1124              {
1125                totalbytes += numbytes;
1126                if(args.serdevice)
1127                {
1128                  int ofs = 0;
1129                  while(numbytes > ofs && !stop)
1130                  {
1131                    int i = SerialWrite(&sx, buf+ofs, numbytes-ofs);
1132                    if(i < 0)
1133                    {
1134                      fprintf(stderr, "Could not access serial device\n");
1135                      stop = 1;
1136                    }
1137                    else
1138                      ofs += i;
1139                  }
1140                }
1141                else
1142                  fwrite(buf, (size_t)numbytes, 1, stdout);
1143              }
1144              fflush(stdout);
1145              if(totalbytes < 0) /* overflow */
1146              {
1147                totalbytes = 0;
1148                starttime = time(0);
1149                lastout = starttime;
1150              }
1151              if(args.serdevice && !stop)
1152              {
1153                int doloop = 1;
1154                while(doloop && !stop)
1155                {
1156                  int i = SerialRead(&sx, buf, 200);
1157                  if(i < 0)
1158                  {
1159                    fprintf(stderr, "Could not access serial device\n");
1160                    stop = 1;
1161                  }
1162                  else
1163                  {
1164                    int j = 0;
1165                    if(i < 200) doloop = 0;
1166                    fwrite(buf, i, 1, stdout);
1167                    while(j < i)
1168                    {
1169                      if(nmeabufpos < 6)
1170                      {
1171                        if(nmeabuffer[nmeabufpos] != buf[j])
1172                        {
1173                          if(nmeabufpos) nmeabufpos = 0;
1174                          else ++j;
1175                        }
1176                        else
1177                        {
1178                          nmeastarpos = 0;
1179                          ++j; ++nmeabufpos;
1180                        }
1181                      }
1182                      else if((nmeastarpos && nmeabufpos == nmeastarpos + 3)
1183                      || buf[j] == '\r' || buf[j] == '\n')
1184                      {
1185                        doloop = 0;
1186                        nmeabuffer[nmeabufpos++] = '\r';
1187                        nmeabuffer[nmeabufpos++] = '\n';
1188                        if(send(sockfd, nmeabuffer, nmeabufpos, 0)
1189                        != (int)nmeabufpos)
1190                        {
1191                          fprintf(stderr, "Could not send NMEA\n");
1192                          stop = 1;
1193                        }
1194                        nmeabufpos = 0;
1195                      }
1196                      else if(nmeabufpos > sizeof(nmeabuffer)-10 ||
1197                      buf[j] == '$')
1198                        nmeabufpos = 0;
1199                      else
1200                      {
1201                        if(buf[j] == '*') nmeastarpos = nmeabufpos;
1202                        nmeabuffer[nmeabufpos++] = buf[j++];
1203                      }
1204                    }
1205                  }
1206                }
1207              }
1208              if(args.bitrate)
1209              {
1210                int t = time(0);
1211                if(t > lastout + 60)
1212                {
1213                  lastout = t;
1214                  fprintf(stderr, "Bitrate is %dbyte/s (%d seconds accumulated).\n",
1215                  totalbytes/(t-starttime), t-starttime);
1216                }
1217              }
1218            }
1219          }
1220        }
1221        else
1222        {
1223          sleeptime = 0;
1224          while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1225          {
1226#ifndef WINDOWSVERSION
1227            alarm(ALARMTIME);
1228#endif
1229            fwrite(buf, (size_t)numbytes, 1, stdout);
1230          }
1231        }
1232        closesocket(sockfd);
1233      }
1234    } while(args.data && *args.data != '%' && !stop);
1235    if(args.serdevice)
1236    {
1237      SerialFree(&sx);
1238    }
1239  }
1240  return 0;
1241}
Note: See TracBrowser for help on using the repository browser.