Changeset 494 in ntrip for trunk/ntripclient/ntripclient.c


Ignore:
Timestamp:
Sep 18, 2007, 9:09:07 AM (17 years ago)
Author:
stoecker
Message:

added NTRIP V2 modes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ntripclient/ntripclient.c

    r484 r494  
    11/*
    22  Easy example NTRIP client for POSIX.
    3   $Id: ntripclient.c,v 1.29 2007/08/30 07:35:13 stoecker Exp $
     3  $Id: ntripclient.c,v 1.30 2007/08/30 07:38:24 stoecker Exp $
    44  Copyright (C) 2003-2005 by Dirk Stoecker <soft@dstoecker.de>
    55   
     
    4545
    4646/* CVS revision and version */
    47 static char revisionstr[] = "$Revision: 1.29 $";
    48 static char datestr[]     = "$Date: 2007/08/30 07:35:13 $";
     47static char revisionstr[] = "$Revision: 1.30 $";
     48static char datestr[]     = "$Date: 2007/08/30 07:38:24 $";
     49
     50enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
    4951
    5052struct Args
    5153{
    5254  const char *server;
    53   int         port;
     55  const char *port;
    5456  const char *user;
     57  const char *proxyhost;
     58  const char *proxyport;
    5559  const char *password;
    5660  const char *nmea;
    5761  const char *data;
    5862  int         bitrate;
     63  int         mode;
    5964};
     65
     66
    6067
    6168/* option parsing */
     
    7077{ "password",   required_argument, 0, 'p'},
    7178{ "port",       required_argument, 0, 'r'},
     79{ "proxyport",  required_argument, 0, 'R'},
     80{ "proxyhost",  required_argument, 0, 'S'},
    7281{ "user",       required_argument, 0, 'u'},
    7382{ "nmea",       required_argument, 0, 'n'},
     
    7584{0,0,0,0}};
    7685#endif
    77 #define ARGOPT "-d:bhp:r:s:u:n:"
     86#define ARGOPT "-d:bhp:r:s:u:n:S:R:M:"
    7887
    7988#ifdef __GNUC__
     
    8695  fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
    8796  exit(1);
     97}
     98
     99int stop = 0;
     100#ifdef __GNUC__
     101static void sighandler_int(int sig __attribute__((__unused__)))
     102#else /* __GNUC__ */
     103static void sighandler_alarm(int sig)
     104#endif /* __GNUC__ */
     105{
     106  alarm(2);
     107  stop = 1;
    88108}
    89109
     
    138158  {
    139159    ++url;
    140     args->server = Buffer;
    141     while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
    142       *(Buffer++) = *(url++);
    143     if(Buffer == args->server)
    144       return "Servername cannot be empty.";
    145     else if(Buffer >= Bufend-1)
    146       return "Parsing buffer too short.";
    147     *(Buffer++) = 0;
     160    if(*url != '@' && *url != ':')
     161    {
     162      args->server = Buffer;
     163      while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
     164        *(Buffer++) = *(url++);
     165      if(Buffer == args->server)
     166        return "Servername cannot be empty.";
     167      else if(Buffer >= Bufend-1)
     168        return "Parsing buffer too short.";
     169      *(Buffer++) = 0;
     170    }
    148171
    149172    if(*url == ':')
    150173    {
    151       char *s2 = 0;
    152       args->port = strtol(++url, &s2, 10);
    153       if((*s2 && *s2 != ';') || args->port <= 0 || args->port > 0xFFFF)
    154         return "Illegal port number.";
    155       url = s2;
     174      ++url;
     175      args->port = Buffer;
     176      while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
     177        *(Buffer++) = *(url++);
     178      if(Buffer == args->port)
     179        return "Port cannot be empty.";
     180      else if(Buffer >= Bufend-1)
     181        return "Parsing buffer too short.";
     182      *(Buffer++) = 0;
     183    }
     184
     185    if(*url == '@') /* proxy */
     186    {
     187      ++url;
     188      args->proxyhost = Buffer;
     189      while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
     190        *(Buffer++) = *(url++);
     191      if(Buffer == args->proxyhost)
     192        return "Proxy servername cannot be empty.";
     193      else if(Buffer >= Bufend-1)
     194        return "Parsing buffer too short.";
     195      *(Buffer++) = 0;
     196
     197      if(*url == ':')
     198      {
     199        ++url;
     200        args->proxyport = Buffer;
     201        while(*url && *url != ';' && Buffer != Bufend)
     202          *(Buffer++) = *(url++);
     203        if(Buffer == args->proxyport)
     204          return "Proxy port cannot be empty.";
     205        else if(Buffer >= Bufend-1)
     206          return "Parsing buffer too short.";
     207        *(Buffer++) = 0;
     208      }
    156209    }
    157210  }
     
    172225  char *a;
    173226  int i = 0, help = 0;
    174   char *t;
    175227
    176228  args->server = "www.euref-ip.net";
    177   args->port = 2101;
     229  args->port = "2101";
    178230  args->user = "";
    179231  args->password = "";
     
    181233  args->data = 0;
    182234  args->bitrate = 0;
     235  args->proxyhost = 0;
     236  args->proxyport = "2101";
     237  args->mode = AUTO;
    183238  help = 0;
    184239
     
    198253    case 'b': args->bitrate = 1; break;
    199254    case 'h': help=1; break;
     255    case 'r': args->port = optarg; break;
     256    case 'S': args->proxyhost = optarg; break;
     257    case 'R': args->proxyport = optarg; break;
     258    case 'M':
     259      args->mode = 0;
     260      if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
     261        args->mode = NTRIP1;
     262      else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
     263        args->mode = HTTP;
     264      else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
     265        args->mode = RTSP;
     266      else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
     267        args->mode = AUTO;
     268      else args->mode = atoi(optarg);
     269      if((args->mode == 0) || (args->mode >= END))
     270      {
     271        fprintf(stderr, "Mode %s unknown\n", optarg);
     272        res = 0;
     273      }
     274      break;
    200275    case 1:
    201276      {
     
    207282        }
    208283      }
    209       break;
    210     case 'r':
    211       args->port = strtoul(optarg, &t, 10);
    212       if((t && *t) || args->port < 1 || args->port > 65535)
    213         res = 0;
    214284      break;
    215285    case -1: break;
     
    234304  {
    235305    fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s -s server -u user ...\n"
    236     " -d " LONG_OPT("--data     ") "the requested data set\n"
    237     " -s " LONG_OPT("--server   ") "the server name or address\n"
    238     " -p " LONG_OPT("--password ") "the login password\n"
    239     " -r " LONG_OPT("--port     ") "the server port number (default 2101)\n"
    240     " -u " LONG_OPT("--user     ") "the user name\n"
    241     " -n " LONG_OPT("--nmea     ") "NMEA string for sending to server\n"
    242     " -b " LONG_OPT("--bitrate  ") "output bitrate\n"
    243     "or using an URL:\n%s ntrip:mountpoint[/username[:password]][@server[:port]][;nmea]\n"
     306    " -d " LONG_OPT("--data      ") "the requested data set\n"
     307    " -s " LONG_OPT("--server    ") "the server name or address\n"
     308    " -p " LONG_OPT("--password  ") "the login password\n"
     309    " -r " LONG_OPT("--port      ") "the server port number (default 2101)\n"
     310    " -u " LONG_OPT("--user      ") "the user name\n"
     311    " -n " LONG_OPT("--nmea      ") "NMEA string for sending to server\n"
     312    " -b " LONG_OPT("--bitrate   ") "output bitrate\n"
     313    " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
     314    " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
     315    " -M " LONG_OPT("--mode      ") "mode for data request\n"
     316    "     Valid modes are:\n"
     317    "     1, h, http     NTRIP Version 2.0 Caster in TCP/IP mode\n"
     318    "     2, r, rtsp     NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
     319    "     3, n, ntrip1   NTRIP Version 1.0 Caster\n"
     320    "     4, a, auto     automatic detection (default)\n"
     321    "or using an URL:\n%s ntrip:mountpoint[/username[:password]][@[server][:port][@proxy[:port]]][;nmea]\n"
    244322    , revisionstr, datestr, argv[0], argv[0]);
    245323    exit(1);
     
    305383  setbuf(stderr, 0);
    306384  signal(SIGALRM,sighandler_alarm);
     385  signal(SIGINT,sighandler_int);
    307386  alarm(ALARMTIME);
    308387
    309388  if(getargs(argc, argv, &args))
    310389  {
    311     int i, sockfd, numbytes; 
    312     char buf[MAXDATASIZE];
    313     struct hostent *he;
    314     struct sockaddr_in their_addr; /* connector's address information */
    315 
    316     if(!(he=gethostbyname(args.server)))
     390    int sleeptime = 0;
     391
     392    do
    317393    {
    318       fprintf(stderr, "Server name lookup failed for '%s'.\n", args.server);
    319       exit(1);
    320     }
    321     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    322     {
    323       perror("socket");
    324       exit(1);
    325     }
    326     their_addr.sin_family = AF_INET;    /* host byte order */
    327     their_addr.sin_port = htons(args.port);  /* short, network byte order */
    328     their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    329     memset(&(their_addr.sin_zero), '\0', 8);
    330     if(connect(sockfd, (struct sockaddr *)&their_addr,
    331     sizeof(struct sockaddr)) == -1)
    332     {
    333       perror("connect");
    334       exit(1);
    335     }
    336 
    337     if(!args.data)
    338     {
    339       i = snprintf(buf, MAXDATASIZE,
    340       "GET / HTTP/1.0\r\n"
    341       "User-Agent: %s/%s\r\n"
    342 #ifdef UNUSED
    343       "Accept: */*\r\n"
    344       "Connection: close\r\n"
    345 #endif
    346       "\r\n"
    347       , AGENTSTRING, revisionstr);
    348     }
    349     else
    350     {
    351       i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
    352       "GET /%s HTTP/1.0\r\n"
    353       "User-Agent: %s/%s\r\n"
    354 #ifdef UNUSED
    355       "Accept: */*\r\n"
    356       "Connection: close\r\n"
    357 #endif
    358       "Authorization: Basic "
    359       , args.data, AGENTSTRING, revisionstr);
    360       if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
    361       {
    362         fprintf(stderr, "Requested data too long\n");
     394      int sockfd, numbytes; 
     395      char buf[MAXDATASIZE];
     396      struct sockaddr_in their_addr; /* connector's address information */
     397      struct hostent *he;
     398      struct servent *se;
     399      const char *server, *port, *proxyserver = 0;
     400      char proxyport[6];
     401      char *b;
     402      long i;
     403      if(sleeptime)
     404      {
     405        sleep(sleeptime);
     406        sleeptime += 2;
     407      }
     408      else
     409      {
     410        sleeptime = 1;
     411      }
     412      alarm(ALARMTIME);
     413      if(args.proxyhost)
     414      {
     415        int p;
     416        if((i = strtol(args.port, &b, 10)) && (!b || !*b))
     417          p = i;
     418        else if(!(se = getservbyname(args.port, 0)))
     419        {
     420          fprintf(stderr, "Can't resolve port %s.", args.port);
     421          exit(1);
     422        }
     423        else
     424        {
     425          p = ntohs(se->s_port);
     426        }
     427        snprintf(proxyport, sizeof(proxyport), "%d", p);
     428        port = args.proxyport;
     429        proxyserver = args.server;
     430        server = args.proxyhost;
     431      }
     432      else
     433      {
     434        server = args.server;
     435        port = args.port;
     436      }
     437
     438      memset(&their_addr, 0, sizeof(struct sockaddr_in));
     439      if((i = strtol(port, &b, 10)) && (!b || !*b))
     440        their_addr.sin_port = htons(i);
     441      else if(!(se = getservbyname(port, 0)))
     442      {
     443        fprintf(stderr, "Can't resolve port %s.", port);
    363444        exit(1);
    364445      }
    365       i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
    366       if(i > MAXDATASIZE-4)
    367       {
    368         fprintf(stderr, "Username and/or password too long\n");
     446      else
     447      {
     448        their_addr.sin_port = se->s_port;
     449      }
     450      if(!(he=gethostbyname(server)))
     451      {
     452        fprintf(stderr, "Server name lookup failed for '%s'.\n", server);
    369453        exit(1);
    370454      }
    371       buf[i++] = '\r';
    372       buf[i++] = '\n';
    373       buf[i++] = '\r';
    374       buf[i++] = '\n';
    375       if(args.nmea)
    376       {
    377         int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
    378         if(j >= 0 && j < MAXDATASIZE-i)
    379           i += j;
     455      if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
     456      {
     457        perror("socket");
     458        exit(1);
     459      }
     460      their_addr.sin_family = AF_INET;
     461      their_addr.sin_addr = *((struct in_addr *)he->h_addr);
     462
     463      if(args.data && args.mode == RTSP)
     464      {
     465        struct sockaddr_in local;
     466        int sockudp, localport;
     467        int cseq = 1;
     468        socklen_t len;
     469
     470        if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
     471        {
     472          perror("socket");
     473          exit(1);
     474        }
     475        /* fill structure with local address information for UDP */
     476        memset(&local, 0, sizeof(local));
     477        local.sin_family = AF_INET;     
     478        local.sin_port = htons(0);
     479        local.sin_addr.s_addr = htonl(INADDR_ANY);
     480        len = sizeof(local);
     481        /* bind() in order to get a random RTP client_port */
     482        if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
     483        {
     484          perror("bind");
     485          exit(1);
     486        }
     487        if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
     488        {
     489          localport = ntohs(local.sin_port);
     490        }
    380491        else
    381492        {
    382           fprintf(stderr, "NMEA string too long\n");
    383           exit(1);
    384         }
    385       }
    386     }
    387     if(send(sockfd, buf, (size_t)i, 0) != i)
    388     {
    389       perror("send");
    390       exit(1);
    391     }
    392     if(args.data)
    393     {
    394       int k = 0;
    395       int starttime = time(0);
    396       int lastout = starttime;
    397       int totalbytes = 0;
    398 
    399       while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
    400       {
    401         alarm(ALARMTIME);
    402         if(!k)
    403         {
    404           if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
     493          perror("local access failed");
     494          exit(1);
     495        }
     496        if(connect(sockfd, (struct sockaddr *)&their_addr,
     497        sizeof(struct sockaddr)) == -1)
     498        {
     499          perror("connect");
     500          exit(1);
     501        }
     502        i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
     503        "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"           
     504        "CSeq: %d\r\n"         
     505        "Ntrip-Version: Ntrip/2.0\r\n"
     506        "Ntrip-Component: Ntripclient\r\n"
     507        "User-Agent: %s/%s\r\n"
     508        "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
     509        "Authorization: Basic ",
     510        args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
     511        args.data, cseq++, AGENTSTRING, revisionstr, localport);
     512        if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
     513        {
     514          fprintf(stderr, "Requested data too long\n");
     515          exit(1);
     516        }
     517        i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
     518        if(i > MAXDATASIZE-4)
     519        {
     520          fprintf(stderr, "Username and/or password too long\n");
     521          exit(1);
     522        }
     523        buf[i++] = '\r';
     524        buf[i++] = '\n';
     525        buf[i++] = '\r';
     526        buf[i++] = '\n';
     527        if(args.nmea)
     528        {
     529          int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
     530          if(j >= 0 && j < MAXDATASIZE-i)
     531            i += j;
     532          else
    405533          {
    406             fprintf(stderr, "Could not get the requested data: ");
    407             for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
    408             {
    409               fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
    410             }
    411             fprintf(stderr, "\n");
     534            fprintf(stderr, "NMEA string too long\n");
    412535            exit(1);
    413536          }
    414           ++k;
     537        }
     538        if(send(sockfd, buf, (size_t)i, 0) != i)
     539        {
     540          perror("send");
     541          exit(1);
     542        }
     543        if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
     544        {
     545          if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
     546          {
     547            int serverport = 0, session = 0;
     548            const char *portcheck = "server_port=";
     549            const char *sessioncheck = "session: ";
     550            int l = strlen(portcheck)-1;
     551            int j=0;
     552            for(i = 0; j != l && i < numbytes-l; ++i)
     553            {
     554              for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
     555                ;
     556            }
     557            if(i == numbytes-l)
     558            {
     559              fprintf(stderr, "No server port number found\n");
     560              exit(1);
     561            }
     562            else
     563            {
     564              i+=l;
     565              while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
     566                serverport = serverport * 10 + buf[i++]-'0';
     567              if(buf[i] != '\r' && buf[i] != ';')
     568              {
     569                fprintf(stderr, "Could not extract server port\n");
     570                exit(1);
     571              }
     572            }
     573            l = strlen(sessioncheck)-1;
     574            j=0;
     575            for(i = 0; j != l && i < numbytes-l; ++i)
     576            {
     577              for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
     578                ;
     579            }
     580            if(i == numbytes-l)
     581            {
     582              fprintf(stderr, "No session number found\n");
     583              exit(1);
     584            }
     585            else
     586            {
     587              i+=l;
     588              while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
     589                session = session * 10 + buf[i++]-'0';
     590              if(buf[i] != '\r')
     591              {
     592                fprintf(stderr, "Could not extract session number\n");
     593                exit(1);
     594              }
     595            }
     596
     597            i = snprintf(buf, MAXDATASIZE,
     598            "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"               
     599            "CSeq: %d\r\n"
     600            "Session: %d\r\n"
     601            "\r\n",
     602            args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
     603            args.data, cseq++, session);
     604
     605            if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
     606            {
     607              fprintf(stderr, "Requested data too long\n");
     608              exit(1);
     609            }
     610            if(send(sockfd, buf, (size_t)i, 0) != i)
     611            {
     612              perror("send");
     613              exit(1);
     614            }
     615            if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
     616            {
     617              if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
     618              {
     619                struct sockaddr_in addrRTP;
     620                /* fill structure with caster address information for UDP */
     621                memset(&addrRTP, 0, sizeof(addrRTP));
     622                addrRTP.sin_family = AF_INET; 
     623                addrRTP.sin_port   = htons(serverport);
     624                their_addr.sin_addr = *((struct in_addr *)he->h_addr);
     625                len = sizeof(addrRTP);
     626                int ts = 0;
     627                int sn = 0;
     628                int ssrc = 0;
     629                int init = 0;
     630                int u, v, w;
     631                while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
     632                (struct sockaddr*) &addrRTP, &len)) > 0)
     633                {
     634                  alarm(ALARMTIME);
     635                  if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
     636                  {
     637                    u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
     638                    v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
     639                    +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
     640                    w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
     641                    +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
     642
     643                    if(init)
     644                    {
     645                      if(u < -30000 && sn > 30000) sn -= 0xFFFF;
     646                      if(ssrc != w || ts > v)
     647                      {
     648                        fprintf(stderr, "Illegal UDP data received.\n");
     649                        exit(1);
     650                      }
     651                      if(u > sn) /* don't show out-of-order packets */
     652                        fwrite(buf+12, (size_t)i-12, 1, stdout);
     653                    }
     654                    sn = u; ts = v; ssrc = w; init = 1;
     655                  }
     656                  else
     657                  {
     658                    fprintf(stderr, "Illegal UDP header.\n");
     659                    exit(1);
     660                  }
     661                }
     662              }
     663              i = snprintf(buf, MAXDATASIZE,
     664              "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"         
     665              "CSeq: %d\r\n"
     666              "Session: %d\r\n"
     667              "\r\n",
     668              args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
     669              args.data, cseq++, session);
     670
     671              if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
     672              {
     673                fprintf(stderr, "Requested data too long\n");
     674                exit(1);
     675              }
     676              if(send(sockfd, buf, (size_t)i, 0) != i)
     677              {
     678                perror("send");
     679                exit(1);
     680              }
     681            }
     682            else
     683            {
     684              fprintf(stderr, "Could not start data stream.\n");
     685              exit(1);
     686            }
     687          }
     688          else
     689          {
     690            fprintf(stderr, "Could not setup initial control connection.\n");
     691            exit(1);
     692          }
    415693        }
    416694        else
    417695        {
    418           totalbytes += numbytes;
    419           if(totalbytes < 0) /* overflow */
     696          perror("recv");
     697          exit(1);
     698        }
     699      }
     700      else
     701      {
     702        if(connect(sockfd, (struct sockaddr *)&their_addr,
     703        sizeof(struct sockaddr)) == -1)
     704        {
     705          perror("connect");
     706          exit(1);
     707        }
     708        if(!args.data)
     709        {
     710          i = snprintf(buf, MAXDATASIZE,
     711          "GET %s%s%s%s/ HTTP/1.0\r\n"
     712          "Host: %s\r\n%s"
     713          "User-Agent: %s/%s\r\n"
     714          "\r\n"
     715          , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
     716          proxyserver ? ":" : "", proxyserver ? proxyport : "",
     717          args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
     718          AGENTSTRING, revisionstr);
     719        }
     720        else
     721        {
     722          i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
     723          "GET %s%s%s%s/%s HTTP/1.0\r\n"
     724          "Host: %s\r\n%s"
     725          "User-Agent: %s/%s\r\n"
     726          "Authorization: Basic "
     727          , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
     728          proxyserver ? ":" : "", proxyserver ? proxyport : "",
     729          args.data, args.server,
     730          args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
     731          AGENTSTRING, revisionstr);
     732          if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
    420733          {
    421             totalbytes = 0;
    422             starttime = time(0);
    423             lastout = starttime;
     734            fprintf(stderr, "Requested data too long\n");
     735            exit(1);
    424736          }
    425           fwrite(buf, (size_t)numbytes, 1, stdout);
    426           fflush(stdout);
    427           if(args.bitrate)
     737          i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
     738          if(i > MAXDATASIZE-4)
    428739          {
    429             int t = time(0);
    430             if(t > lastout + 60)
    431             {
    432               lastout = t;
    433               fprintf(stderr, "Bitrate is %dbyte/s (%d seconds accumulated).\n",
    434               totalbytes/(t-starttime), t-starttime);
    435             }
     740            fprintf(stderr, "Username and/or password too long\n");
     741            exit(1);
    436742          }
    437         }
    438       }
    439     }
    440     else
    441     {
    442       while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
    443       {
    444         fwrite(buf, (size_t)numbytes, 1, stdout);
    445       }
    446     }
    447 
    448     close(sockfd);
     743          buf[i++] = '\r';
     744          buf[i++] = '\n';
     745          buf[i++] = '\r';
     746          buf[i++] = '\n';
     747          if(args.nmea)
     748          {
     749            int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
     750            if(j >= 0 && j < MAXDATASIZE-i)
     751              i += j;
     752            else
     753            {
     754              fprintf(stderr, "NMEA string too long\n");
     755              exit(1);
     756            }
     757          }
     758        }
     759        if(send(sockfd, buf, (size_t)i, 0) != i)
     760        {
     761          perror("send");
     762          exit(1);
     763        }
     764        if(args.data)
     765        {
     766          int k = 0;
     767          int chunkymode = 0;
     768          int starttime = time(0);
     769          int lastout = starttime;
     770          int totalbytes = 0;
     771          int chunksize = 0;
     772
     773          while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
     774          {
     775            alarm(ALARMTIME);
     776            if(!k)
     777            {
     778              if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
     779              || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
     780              {
     781                const char *datacheck = "Content-Type: gnss/data\r\n";
     782                const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
     783                int l = strlen(datacheck)-1;
     784                int j=0;
     785                for(i = 0; j != l && i < numbytes-l; ++i)
     786                {
     787                  for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
     788                    ;
     789                }
     790                if(i == numbytes-l)
     791                {
     792                  fprintf(stderr, "No 'Content-Type: gnss/data' found\n");
     793                  exit(1);
     794                }
     795                l = strlen(chunkycheck)-1;
     796                j=0;
     797                for(i = 0; j != l && i < numbytes-l; ++i)
     798                {
     799                  for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
     800                    ;
     801                }
     802                if(i < numbytes-l)
     803                  chunkymode = 1;
     804              }
     805              else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
     806              {
     807                fprintf(stderr, "Could not get the requested data: ");
     808                for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
     809                {
     810                  fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
     811                }
     812                fprintf(stderr, "\n");
     813                exit(1);
     814              }
     815              else if(args.mode != NTRIP1)
     816              {
     817                fprintf(stderr, "NTRIP version 2 HTTP connection failed%s.\n",
     818                args.mode == AUTO ? ", falling back to NTRIP1" : "");
     819                if(args.mode == HTTP)
     820                  exit(1);
     821              }
     822              ++k;
     823            }
     824            else
     825            {
     826              sleeptime = 0;
     827              if(chunkymode)
     828              {
     829                int stop = 0;
     830                int pos = 0;
     831                while(!stop && pos < numbytes)
     832                {
     833                  switch(chunkymode)
     834                  {
     835                  case 1: /* reading number starts */
     836                    chunksize = 0;
     837                    ++chunkymode; /* no break */
     838                  case 2: /* during reading number */
     839                    i = buf[pos++];
     840                    if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
     841                    else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
     842                    else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
     843                    else if(i == '\r') ++chunkymode;
     844                    else stop = 1;
     845                    break;
     846                  case 3: /* scanning for return */
     847                    if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
     848                    else stop = 1;
     849                    break;
     850                  case 4: /* output data */
     851                    i = numbytes-pos;
     852                    if(i > chunksize) i = chunksize;
     853                    fwrite(buf+pos, (size_t)i, 1, stdout);
     854                    totalbytes += i;
     855                    chunksize -= i;
     856                    pos += i;
     857                    if(!chunksize)
     858                      chunkymode = 1;
     859                    break;
     860                  }
     861                }
     862                if(stop)
     863                {
     864                  fprintf(stderr, "Error in chunky transfer encoding\n");
     865                  break;
     866                }
     867              }
     868              else
     869              {
     870                totalbytes += numbytes;
     871                fwrite(buf, (size_t)numbytes, 1, stdout);
     872              }
     873              fflush(stdout);
     874              if(totalbytes < 0) /* overflow */
     875              {
     876                totalbytes = 0;
     877                starttime = time(0);
     878                lastout = starttime;
     879              }
     880              if(args.bitrate)
     881              {
     882                int t = time(0);
     883                if(t > lastout + 60)
     884                {
     885                  lastout = t;
     886                  fprintf(stderr, "Bitrate is %dbyte/s (%d seconds accumulated).\n",
     887                  totalbytes/(t-starttime), t-starttime);
     888                }
     889              }
     890            }
     891          }
     892        }
     893        else
     894        {
     895          sleeptime = 0;
     896          while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
     897          {
     898            alarm(ALARMTIME);
     899            fwrite(buf, (size_t)numbytes, 1, stdout);
     900          }
     901        }
     902        close(sockfd);
     903      }
     904    } while(args.data && !stop);
    449905  }
    450906  return 0;
Note: See TracChangeset for help on using the changeset viewer.