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

Last change on this file since 1196 was 1183, checked in by stoecker, 16 years ago

fixed illegal argument parsing

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