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

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

added support for serial output

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