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

Last change on this file since 550 was 550, checked in by stuerze, 16 years ago

argument renaming

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