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

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

C++ comment removed

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