source: ntrip/trunk/BNC/RTCM3/rtcm3torinex.cpp@ 284

Last change on this file since 284 was 284, checked in by mervart, 17 years ago

* empty log message *

File size: 26.9 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.cpp,v 1.9 2006/11/08 16:08:32 mervart Exp $
4 Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@euronik.eu>
5
6 This software is a complete NTRIP-RTCM3 to RINEX converter as well as
7 a module of the BNC tool for multiformat conversion. Contact Dirk
8 Stöcker for suggestions and bug reports related to the RTCM3 to RINEX
9 conversion problems and the author of BNC for all the other problems.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 or read http://www.gnu.org/licenses/gpl.txt
25*/
26
27#include <ctype.h>
28#include <errno.h>
29#include <math.h>
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/types.h>
35#include <time.h>
36#include <unistd.h>
37
38#ifndef NO_RTCM3_MAIN
39#include <getopt.h>
40#include <netdb.h>
41#include <netinet/in.h>
42#include <sys/socket.h>
43#endif
44
45#ifndef sparc
46#include <stdint.h>
47#endif
48
49#include "rtcm3torinex.h"
50
51/* CVS revision and version */
52static char revisionstr[] = "$Revision: 1.9 $";
53
54static uint32_t CRC24(long size, const unsigned char *buf)
55{
56 uint32_t crc = 0;
57 int i;
58
59 while(size--)
60 {
61 crc ^= (*buf++) << (16);
62 for(i = 0; i < 8; i++)
63 {
64 crc <<= 1;
65 if(crc & 0x1000000)
66 crc ^= 0x01864cfb;
67 }
68 }
69 return crc;
70}
71
72static int GetMessage(struct RTCM3ParserData *handle)
73{
74 unsigned char *m, *e;
75 int i;
76
77 m = handle->Message+handle->SkipBytes;
78 e = handle->Message+handle->MessageSize;
79 handle->NeedBytes = handle->SkipBytes = 0;
80 while(e-m >= 3)
81 {
82 if(m[0] == 0xD3)
83 {
84 handle->size = ((m[1]&3)<<8)|m[2];
85 if(e-m >= handle->size+6)
86 {
87 if((uint32_t)((m[3+handle->size]<<16)|(m[3+handle->size+1]<<8)
88 |(m[3+handle->size+2])) == CRC24(handle->size+3, m))
89 {
90 handle->SkipBytes = handle->size;
91 break;
92 }
93 else
94 ++m;
95 }
96 else
97 {
98 handle->NeedBytes = handle->size+6;
99 break;
100 }
101 }
102 else
103 ++m;
104 }
105 if(e-m < 3)
106 handle->NeedBytes = 3;
107
108 /* copy buffer to front */
109 i = m - handle->Message;
110 if(i && m < e)
111 memmove(handle->Message, m, handle->MessageSize-i);
112 handle->MessageSize -= i;
113
114 return !handle->NeedBytes;
115}
116
117#define LOADBITS(a) \
118{ \
119 while((a) > numbits) \
120 { \
121 if(!size--) break; \
122 bitfield = (bitfield<<8)|*(data++); \
123 numbits += 8; \
124 } \
125}
126
127/* extract bits from data stream
128 b = variable to store result, a = number of bits */
129#define GETBITS(b, a) \
130{ \
131 LOADBITS(a) \
132 b = (bitfield<<(64-numbits))>>(64-(a)); \
133 numbits -= (a); \
134}
135
136/* extract bits from data stream
137 b = variable to store result, a = number of bits */
138#define GETBITSSIGN(b, a) \
139{ \
140 LOADBITS(a) \
141 b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
142 numbits -= (a); \
143}
144
145#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
146
147int RTCM3Parser(struct RTCM3ParserData *handle)
148{
149 int ret=0;
150
151 while(!ret && GetMessage(handle))
152 {
153 /* using 64 bit integer types, as it is much easier than handling
154 the long datatypes in 32 bit */
155 uint64_t numbits = 0, bitfield = 0;
156 int size = handle->size, type;
157 unsigned char *data = handle->Message+3;
158
159 GETBITS(type,12)
160 switch(type)
161 {
162 case 1001: case 1002: case 1003: case 1004:
163 if(handle->GPSWeek)
164 {
165 int lastlockl1[64];
166 int lastlockl2[64];
167 struct gnssdata *gnss;
168 int i, num, wasamb=0;
169
170 for(i = 0; i < 64; ++i)
171 lastlockl1[i] = lastlockl2[i] = 0;
172
173 gnss = &handle->Data;
174 memset(gnss, 0, sizeof(*gnss));
175
176 SKIPBITS(12) /* id */
177 GETBITS(i,30)
178 if(i/1000 < (int)handle->GPSTOW - 86400)
179 ++handle->GPSWeek;
180 handle->GPSTOW = i/1000;
181 gnss->timeofweek = i;
182 gnss->week = handle->GPSWeek;
183
184 SKIPBITS(1) /* sync */
185 GETBITS(i,5)
186 gnss->numsats = i;
187 SKIPBITS(4) /* smind, smint */
188
189 for(num = 0; num < gnss->numsats; ++num)
190 {
191 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
192
193 GETBITS(sv, 6);
194 gnss->satellites[num] = (sv < 40 ? sv : sv+80);
195 /* L1 */
196 GETBITS(code, 1);
197 if(code)
198 {
199 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
200 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
201 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
202 }
203 else
204 {
205 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
206 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
207 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
208 }
209 GETBITS(l1range, 24);
210 if(l1range != 0x80000)
211 {
212 gnss->dataflags[num] |= c;
213 gnss->measdata[num][ce] = l1range*0.02;
214 }
215 GETBITSSIGN(i, 20);
216 if(i != 0x80000)
217 {
218 gnss->dataflags[num] |= l;
219 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
220 }
221 GETBITS(i, 7);
222 lastlockl1[sv] = i;
223 if(handle->lastlockl1[sv] > i)
224 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
225 if(type == 1002 || type == 1004)
226 {
227 GETBITS(amb,8);
228 if(amb && (gnss->dataflags[num] & c))
229 {
230 gnss->measdata[num][ce] += amb*299792.458;
231 gnss->measdata[num][le] += amb*299792.458;
232 ++wasamb;
233 }
234 GETBITS(i, 8);
235 if(i)
236 {
237 gnss->dataflags[num] |= s;
238 gnss->measdata[num][se] = i*0.25;
239 i /= 4*4;
240 if(i > 9) i = 9;
241 else if(i < 1) i = 1;
242 gnss->snrL1[num] = i;
243 }
244 }
245 gnss->measdata[num][le] /= GPS_WAVELENGTH_L1;
246 if(type == 1003 || type == 1004)
247 {
248 /* L2 */
249 GETBITS(code,2);
250 if(code)
251 {
252 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
253 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
254 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
255 }
256 else
257 {
258 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
259 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
260 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
261 }
262 GETBITSSIGN(i,14);
263 if(i != 0x2000)
264 {
265 gnss->dataflags[num] |= c;
266 gnss->measdata[num][ce] = l1range*0.02+i*0.02
267 +amb*299792.458;
268 }
269 GETBITSSIGN(i,20);
270 if(i != 0x80000)
271 {
272 gnss->dataflags[num] |= l;
273 gnss->measdata[num][le] = l1range*0.02+i*0.0005
274 +amb*299792.458;
275 }
276 GETBITS(i,7);
277 lastlockl2[sv] = i;
278 if(handle->lastlockl2[sv] > i)
279 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
280 if(type == 1004)
281 {
282 GETBITS(i, 8);
283 if(i)
284 {
285 gnss->dataflags[num] |= s;
286 gnss->measdata[num][se] = i*0.25;
287 i /= 4*4;
288 if(i > 9) i = 9;
289 else if(i < 1) i = 1;
290 gnss->snrL2[num] = i;
291 }
292 }
293 gnss->measdata[num][le] /= GPS_WAVELENGTH_L2;
294 }
295 }
296 for(i = 0; i < 64; ++i)
297 {
298 handle->lastlockl1[i] = lastlockl1[i];
299 handle->lastlockl2[i] = lastlockl2[i];
300 }
301 if(wasamb) /* not RINEX compatible without */
302 ret = 1;
303 else
304 ret = 2;
305 }
306 break;
307 }
308 }
309 return ret;
310}
311
312static int longyear(int year, int month)
313{
314 if(!(year % 4) && (!(year % 400) || (year % 100)))
315 {
316 if(!month || month == 2)
317 return 1;
318 }
319 return 0;
320}
321
322void converttime(struct converttimeinfo *c, int week, int tow)
323{
324 /* static variables */
325 static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
326
327 int i, k, doy, j; /* temporary variables */
328 j = week*(7*24*60*60) + tow + 5*24*60*60;
329 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
330 j -= k;
331 c->year = i;
332 doy = 1+ (j / (24*60*60));
333 j %= (24*60*60);
334 c->hour = j / (60*60);
335 j %= (60*60);
336 c->minute = j / 60;
337 c->second = j % 60;
338 j = 0;
339 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
340 j += k;
341 c->month = i;
342 c->day = doy - j;
343}
344
345struct Header
346{
347 const char *version;
348 const char *pgm;
349 const char *marker;
350 const char *observer;
351 const char *receiver;
352 const char *antenna;
353 const char *position;
354 const char *antennaposition;
355 const char *wavelength;
356 const char *typesofobs; /* should not be modified outside */
357 const char *timeoffirstobs; /* should not be modified outside */
358};
359
360#define MAXHEADERLINES 50
361#define MAXHEADERBUFFERSIZE 4096
362struct HeaderData
363{
364 union
365 {
366 struct Header named;
367 const char *unnamed[MAXHEADERLINES];
368 } data;
369 int numheaders;
370};
371
372void HandleHeader(struct RTCM3ParserData *Parser)
373{
374 struct HeaderData hdata;
375 char thebuffer[MAXHEADERBUFFERSIZE];
376 char *buffer = thebuffer;
377 int buffersize = sizeof(thebuffer);
378 int i;
379
380 hdata.data.named.version =
381 " 2.11 OBSERVATION DATA M (Mixed)"
382 " RINEX VERSION / TYPE";
383
384 {
385 const char *str;
386 time_t t;
387 struct tm * t2;
388
389#ifdef NO_RTCM3_MAIN
390 if(revisionstr[0] == '$')
391 {
392 char *a;
393 int i=0;
394 for(a = revisionstr+11; *a && *a != ' '; ++a)
395 revisionstr[i++] = *a;
396 revisionstr[i] = 0;
397 }
398#endif
399
400 str = getenv("USER");
401 if(!str) str = "";
402 t = time(&t);
403 t2 = gmtime(&t);
404 hdata.data.named.pgm = buffer;
405 i = 1+snprintf(buffer, buffersize,
406 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
407 "PGM / RUN BY / DATE",
408 revisionstr, str, 1900+t2->tm_year, t2->tm_mon+1, t2->tm_mday, t2->tm_hour,
409 t2->tm_min);
410 buffer += i; buffersize -= i;
411
412 hdata.data.named.observer = buffer;
413 i = 1+snprintf(buffer, buffersize,
414 "%-20.20s "
415 "OBSERVER / AGENCY", str);
416 buffer += i; buffersize -= i;
417 }
418
419 hdata.data.named.marker =
420 "RTCM3TORINEX "
421 "MARKER NAME";
422
423 hdata.data.named.receiver =
424 " "
425 "REC # / TYPE / VERS";
426
427 hdata.data.named.antenna =
428 " "
429 "ANT # / TYPE";
430
431 hdata.data.named.position =
432 " .0000 .0000 .0000 "
433 "APPROX POSITION XYZ";
434
435 hdata.data.named.antennaposition =
436 " .0000 .0000 .0000 "
437 "ANTENNA: DELTA H/E/N";
438
439 hdata.data.named.wavelength =
440 " 1 1 "
441 "WAVELENGTH FACT L1/2";
442
443 {
444#define CHECKFLAGS(a, b) \
445 if(flags & GNSSDF_##a##DATA \
446 && !data[RINEXENTRY_##b##DATA]) \
447 { \
448 Parser->dataflag[Parser->numdatatypes] = GNSSDF_##a##DATA; \
449 Parser->datapos[Parser->numdatatypes++] = data[RINEXENTRY_##b##DATA] \
450 = GNSSENTRY_##a##DATA; \
451 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
452 tbufferpos += 6; \
453 }
454
455 int flags = 0;
456 int data[RINEXENTRY_NUMBER];
457 char tbuffer[6*RINEXENTRY_NUMBER+1];
458 int tbufferpos = 0;
459 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
460 data[i] = 0;
461 for(i = 0; i < Parser->Data.numsats; ++i)
462 flags |= Parser->Data.dataflags[i];
463
464 CHECKFLAGS(C1,C1)
465 CHECKFLAGS(C2,C2)
466 CHECKFLAGS(P1,P1)
467 CHECKFLAGS(P2,P2)
468 CHECKFLAGS(L1C,L1)
469 CHECKFLAGS(L1P,L1)
470 CHECKFLAGS(L2C,L2)
471 CHECKFLAGS(L2P,L2)
472 CHECKFLAGS(D1C,D1)
473 CHECKFLAGS(D1P,D1)
474 CHECKFLAGS(D2C,D2)
475 CHECKFLAGS(D2P,D2)
476 CHECKFLAGS(S1C,S1)
477 CHECKFLAGS(S1P,S1)
478 CHECKFLAGS(S2C,S2)
479 CHECKFLAGS(S2P,S2)
480
481 hdata.data.named.typesofobs = buffer;
482 i = 1+snprintf(buffer, buffersize,
483 "%6i%-54.54s# / TYPES OF OBSERV", Parser->numdatatypes, tbuffer);
484 if(Parser->numdatatypes>9)
485 {
486 i += snprintf(buffer+i-1, buffersize,
487 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
488 }
489 buffer += i; buffersize -= i;
490 }
491
492 {
493 struct converttimeinfo cti;
494 converttime(&cti, Parser->Data.week,
495 (int)floor(Parser->Data.timeofweek/1000.0));
496 hdata.data.named.timeoffirstobs = buffer;
497 i = 1+snprintf(buffer, buffersize,
498 " %4d %2d %2d %2d %2d %10.7f GPS "
499 "TIME OF FIRST OBS", cti.year%100, cti.month, cti.day, cti.hour,
500 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
501
502 buffer += i; buffersize -= i;
503 }
504
505 hdata.numheaders = 11;
506
507 if(Parser->headerfile)
508 {
509 FILE *fh;
510 if((fh = fopen(Parser->headerfile, "r")))
511 {
512 int siz;
513 char *lastblockstart;
514 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
515 {
516 buffer[siz] = '\n';
517 if(siz == buffersize)
518 {
519 fprintf(stderr, "Header file is too large. Only %d bytes read.",
520 siz);
521 }
522 /* scan the file line by line and enter the entries in the list */
523 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
524 /* overwrites entries, except for comments */
525 lastblockstart = buffer;
526 for(i = 0; i < siz; ++i)
527 {
528 if(buffer[i] == '\n')
529 { /* we found a line */
530 char *end;
531 while(buffer[i+1] == '\r')
532 ++i; /* skip \r in case there are any */
533 end = buffer+i;
534 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
535 *(end--) = 0;
536 if(end-lastblockstart < 60+5) /* short line */
537 fprintf(stderr, "Short Header line '%s' ignored.\n", lastblockstart);
538 else
539 {
540 int pos;
541 if(!strcmp("COMMENT", lastblockstart+60))
542 pos = hdata.numheaders;
543 else
544 {
545 for(pos = 0; pos < hdata.numheaders; ++pos)
546 {
547 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
548 break;
549 }
550 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
551 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
552 {
553 fprintf(stderr, "Overwriting header '%s' is dangerous.\n",
554 lastblockstart+60);
555 }
556 }
557 if(pos >= MAXHEADERLINES)
558 {
559 fprintf(stderr,
560 "Maximum number of header lines of %d reached.\n",
561 MAXHEADERLINES);
562 }
563 else if(!strcmp("END OF HEADER", lastblockstart+60))
564 {
565 fprintf(stderr, "End of header ignored.\n");
566 }
567 else
568 {
569 hdata.data.unnamed[pos] = lastblockstart;
570 if(pos == hdata.numheaders)
571 ++hdata.numheaders;
572 }
573 }
574 lastblockstart = buffer+i+1;
575 }
576 }
577 }
578 else
579 {
580 fprintf(stderr, "Could not read data from headerfile '%s'.\n",
581 Parser->headerfile);
582 }
583 fclose(fh);
584 }
585 else
586 {
587 fprintf(stderr, "Could not open header datafile '%s'.\n",
588 Parser->headerfile);
589 }
590 }
591
592#ifndef NO_RTCM3_MAIN
593 for(i = 0; i < hdata.numheaders; ++i)
594 printf("%s\n", hdata.data.unnamed[i]);
595 printf(" "
596 "END OF HEADER\n");
597#endif
598}
599
600void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
601{
602 Parser->Message[Parser->MessageSize++] = byte;
603 if(Parser->MessageSize >= Parser->NeedBytes)
604 {
605 int r;
606 while((r = RTCM3Parser(Parser)))
607 {
608 int i, j, o;
609 struct converttimeinfo cti;
610
611 if(!Parser->init)
612 {
613 HandleHeader(Parser);
614 Parser->init = 1;
615 }
616 if(r == 2 && !Parser->validwarning)
617 {
618 printf("No valid RINEX! All values are modulo 299792.458!"
619 " COMMENT\n");
620 Parser->validwarning = 1;
621 }
622
623 converttime(&cti, Parser->Data.week,
624 (int)floor(Parser->Data.timeofweek/1000.0));
625 printf(" %02d %2d %2d %2d %2d %10.7f 0%3d",
626 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
627 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
628 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
629 {
630 if(Parser->Data.satellites[i] <= PRN_GPS_END)
631 printf("G%02d", Parser->Data.satellites[i]);
632 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
633 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
634 printf("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
635 else
636 printf("%3d", Parser->Data.satellites[i]);
637 }
638 printf("\n");
639 o = 12;
640 j = Parser->Data.numsats - 12;
641 while(j > 0)
642 {
643 printf(" ");
644 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
645 {
646 if(Parser->Data.satellites[i] <= PRN_GPS_END)
647 printf("G%02d", Parser->Data.satellites[i]);
648 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
649 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
650 printf("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
651 else
652 printf("%3d", Parser->Data.satellites[i]);
653 }
654 printf("\n");
655 j -= 12;
656 o += 12;
657 }
658 for(i = 0; i < Parser->Data.numsats; ++i)
659 {
660 for(j = 0; j < Parser->numdatatypes; ++j)
661 {
662 if(!(Parser->Data.dataflags[i] & Parser->dataflag[j])
663 || isnan(Parser->Data.measdata[i][Parser->datapos[j]])
664 || isinf(Parser->Data.measdata[i][Parser->datapos[j]]))
665 { /* no or illegal data */
666 printf(" ");
667 }
668 else
669 {
670 char lli = ' ';
671 char snr = ' ';
672 if(Parser->dataflag[j] & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
673 {
674 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
675 lli = '1';
676 snr = '0'+Parser->Data.snrL1[i];
677 }
678 if(Parser->dataflag[j] & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
679 {
680 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
681 lli = '1';
682 snr = '0'+Parser->Data.snrL2[i];
683 }
684 printf("%14.3f%c%c",
685 Parser->Data.measdata[i][Parser->datapos[j]],lli,snr);
686 }
687 if(j%5 == 4 || j == Parser->numdatatypes-1)
688 printf("\n");
689 }
690 }
691 }
692 }
693}
694
695#ifndef NO_RTCM3_MAIN
696static char datestr[] = "$Date: 2006/11/08 16:08:32 $";
697
698/* The string, which is send as agent in HTTP request */
699#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
700
701#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
702
703static const char encodingTable [64] = {
704 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
705 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
706 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
707 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
708};
709
710/* does not buffer overrun, but breaks directly after an error */
711/* returns the number of required bytes */
712static int encode(char *buf, int size, const char *user, const char *pwd)
713{
714 unsigned char inbuf[3];
715 char *out = buf;
716 int i, sep = 0, fill = 0, bytes = 0;
717
718 while(*user || *pwd)
719 {
720 i = 0;
721 while(i < 3 && *user) inbuf[i++] = *(user++);
722 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
723 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
724 while(i < 3) {inbuf[i++] = 0; ++fill; }
725 if(out-buf < size-1)
726 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
727 if(out-buf < size-1)
728 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
729 | ((inbuf [1] & 0xF0) >> 4)];
730 if(out-buf < size-1)
731 {
732 if(fill == 2)
733 *(out++) = '=';
734 else
735 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
736 | ((inbuf [2] & 0xC0) >> 6)];
737 }
738 if(out-buf < size-1)
739 {
740 if(fill >= 1)
741 *(out++) = '=';
742 else
743 *(out++) = encodingTable[inbuf [2] & 0x3F];
744 }
745 bytes += 4;
746 }
747 if(out-buf < size)
748 *out = 0;
749 return bytes;
750}
751
752static int stop = 0;
753
754struct Args
755{
756 const char *server;
757 int port;
758 const char *user;
759 const char *password;
760 const char *data;
761 const char *headerfile;
762};
763
764/* option parsing */
765#ifdef NO_LONG_OPTS
766#define LONG_OPT(a)
767#else
768#define LONG_OPT(a) a
769static struct option opts[] = {
770{ "data", required_argument, 0, 'd'},
771{ "server", required_argument, 0, 's'},
772{ "password", required_argument, 0, 'p'},
773{ "port", required_argument, 0, 'r'},
774{ "header", required_argument, 0, 'f'},
775{ "user", required_argument, 0, 'u'},
776{ "help", no_argument, 0, 'h'},
777{0,0,0,0}};
778#endif
779#define ARGOPT "d:hp:r:s:u:f:"
780
781static int getargs(int argc, char **argv, struct Args *args)
782{
783 int res = 1;
784 int getoptr;
785 int help = 0;
786 char *t;
787
788 args->server = "www.euref-ip.net";
789 args->port = 80;
790 args->user = "";
791 args->password = "";
792 args->data = 0;
793 args->headerfile = 0;
794 help = 0;
795
796 do
797 {
798#ifdef NO_LONG_OPTS
799 switch((getoptr = getopt(argc, argv, ARGOPT)))
800#else
801 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
802#endif
803 {
804 case 's': args->server = optarg; break;
805 case 'u': args->user = optarg; break;
806 case 'p': args->password = optarg; break;
807 case 'd': args->data = optarg; break;
808 case 'f': args->headerfile = optarg; break;
809 case 'h': help=1; break;
810 case 'r':
811 args->port = strtoul(optarg, &t, 10);
812 if((t && *t) || args->port < 1 || args->port > 65535)
813 res = 0;
814 break;
815 case -1: break;
816 }
817 } while(getoptr != -1 || !res);
818
819 datestr[0] = datestr[7];
820 datestr[1] = datestr[8];
821 datestr[2] = datestr[9];
822 datestr[3] = datestr[10];
823 datestr[5] = datestr[12];
824 datestr[6] = datestr[13];
825 datestr[8] = datestr[15];
826 datestr[9] = datestr[16];
827 datestr[4] = datestr[7] = '-';
828 datestr[10] = 0;
829
830 if(!res || help)
831 {
832 fprintf(stderr, "Version %s (%s) GPL\nUsage: %s -s server -u user ...\n"
833 " -d " LONG_OPT("--data ") "the requested data set\n"
834 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
835 " -s " LONG_OPT("--server ") "the server name or address\n"
836 " -p " LONG_OPT("--password ") "the login password\n"
837 " -r " LONG_OPT("--port ") "the server port number (default 80)\n"
838 " -u " LONG_OPT("--user ") "the user name\n"
839 , revisionstr, datestr, argv[0]);
840 exit(1);
841 }
842 return res;
843}
844
845/* let the output complete a block if necessary */
846static void signalhandler(int sig)
847{
848 if(!stop)
849 {
850 fprintf(stderr, "Stop signal number %d received. "
851 "Trying to terminate gentle.\n", sig);
852 stop = 1;
853 alarm(1);
854 }
855}
856
857/* for some reason we had to abort hard (maybe waiting for data */
858#ifdef __GNUC__
859static __attribute__ ((noreturn)) void signalhandler_alarm(
860int sig __attribute__((__unused__)))
861#else /* __GNUC__ */
862static void signalhandler_alarm(int sig)
863#endif /* __GNUC__ */
864{
865 fprintf(stderr, "Programm forcefully terminated.\n");
866 exit(1);
867}
868
869int main(int argc, char **argv)
870{
871 struct Args args;
872 struct RTCM3ParserData Parser;
873
874 setbuf(stdout, 0);
875 setbuf(stdin, 0);
876 setbuf(stderr, 0);
877
878 {
879 char *a;
880 int i=0;
881 for(a = revisionstr+11; *a && *a != ' '; ++a)
882 revisionstr[i++] = *a;
883 revisionstr[i] = 0;
884 }
885
886 signal(SIGINT, signalhandler);
887 signal(SIGALRM,signalhandler_alarm);
888 signal(SIGQUIT,signalhandler);
889 signal(SIGTERM,signalhandler);
890 signal(SIGPIPE,signalhandler);
891 memset(&Parser, 0, sizeof(Parser));
892 {
893 time_t tim;
894 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
895 Parser.GPSWeek = tim/(7*24*60*60);
896 Parser.GPSTOW = tim%(7*24*60*60);
897 }
898
899 if(getargs(argc, argv, &args))
900 {
901 int i, sockfd, numbytes;
902 char buf[MAXDATASIZE];
903 struct hostent *he;
904 struct sockaddr_in their_addr; /* connector's address information */
905
906 Parser.headerfile = args.headerfile;
907
908 if(!(he=gethostbyname(args.server)))
909 {
910 perror("gethostbyname");
911 exit(1);
912 }
913 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
914 {
915 perror("socket");
916 exit(1);
917 }
918 their_addr.sin_family = AF_INET; /* host byte order */
919 their_addr.sin_port = htons(args.port); /* short, network byte order */
920 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
921 memset(&(their_addr.sin_zero), '\0', 8);
922 if(connect(sockfd, (struct sockaddr *)&their_addr,
923 sizeof(struct sockaddr)) == -1)
924 {
925 perror("connect");
926 exit(1);
927 }
928
929 if(!args.data)
930 {
931 i = snprintf(buf, MAXDATASIZE,
932 "GET / HTTP/1.0\r\n"
933 "User-Agent: %s/%s\r\n"
934#ifdef UNUSED
935 "Accept: */*\r\n"
936 "Connection: close\r\n"
937#endif
938 "\r\n"
939 , AGENTSTRING, revisionstr);
940 }
941 else
942 {
943 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
944 "GET /%s HTTP/1.0\r\n"
945 "User-Agent: %s/%s\r\n"
946#ifdef UNUSED
947 "Accept: */*\r\n"
948 "Connection: close\r\n"
949#endif
950 "Authorization: Basic "
951 , args.data, AGENTSTRING, revisionstr);
952 if(i > MAXDATASIZE-40 && i < 0) /* second check for old glibc */
953 {
954 fprintf(stderr, "Requested data too long\n");
955 exit(1);
956 }
957 i += encode(buf+i, MAXDATASIZE-i-5, args.user, args.password);
958 if(i > MAXDATASIZE-5)
959 {
960 fprintf(stderr, "Username and/or password too long\n");
961 exit(1);
962 }
963 snprintf(buf+i, 5, "\r\n\r\n");
964 i += 5;
965 }
966 if(send(sockfd, buf, (size_t)i, 0) != i)
967 {
968 perror("send");
969 exit(1);
970 }
971 if(args.data)
972 {
973 int k = 0;
974 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
975 {
976 if(!k)
977 {
978 if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
979 {
980 fprintf(stderr, "Could not get the requested data: ");
981 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
982 {
983 fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
984 }
985 fprintf(stderr, "\n");
986 exit(1);
987 }
988 ++k;
989 }
990 else
991 {
992 int z;
993 for(z = 0; z < numbytes && !stop; ++z)
994 HandleByte(&Parser, buf[z]);
995 }
996 }
997 }
998 else
999 {
1000 while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1001 {
1002 fwrite(buf, (size_t)numbytes, 1, stdout);
1003 }
1004 }
1005
1006 close(sockfd);
1007 }
1008 return 0;
1009}
1010#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.