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

Last change on this file since 500 was 500, checked in by stuerze, 17 years ago

sth. added for sourcetable filtering

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