source: ntrip/trunk/rtcm3torinex/rtcm3torinex.c@ 269

Last change on this file since 269 was 269, checked in by stoecker, 17 years ago

minor fixes

File size: 26.9 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c,v 1.6 2006/11/02 13:34:00 stoecker 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.6 $";
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 for(i = 0; i < hdata.numheaders; ++i)
593 printf("%s\n", hdata.data.unnamed[i]);
594 printf(" "
595 "END OF HEADER\n");
596}
597
598void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
599{
600 Parser->Message[Parser->MessageSize++] = byte;
601 if(Parser->MessageSize >= Parser->NeedBytes)
602 {
603 int r;
604 while((r = RTCM3Parser(Parser)))
605 {
606 int i, j, o;
607 struct converttimeinfo cti;
608
609 if(!Parser->init)
610 {
611 HandleHeader(Parser);
612 Parser->init = 1;
613 }
614 if(r == 2 && !Parser->validwarning)
615 {
616 printf("No valid RINEX! All values are modulo 299792.458!"
617 " COMMENT\n");
618 Parser->validwarning = 1;
619 }
620
621 converttime(&cti, Parser->Data.week,
622 (int)floor(Parser->Data.timeofweek/1000.0));
623 printf(" %02d %2d %2d %2d %2d %10.7f 0%3d",
624 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
625 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
626 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
627 {
628 if(Parser->Data.satellites[i] <= PRN_GPS_END)
629 printf("G%02d", Parser->Data.satellites[i]);
630 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
631 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
632 printf("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
633 else
634 printf("%3d", Parser->Data.satellites[i]);
635 }
636 printf("\n");
637 o = 12;
638 j = Parser->Data.numsats - 12;
639 while(j > 0)
640 {
641 printf(" ");
642 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
643 {
644 if(Parser->Data.satellites[i] <= PRN_GPS_END)
645 printf("G%02d", Parser->Data.satellites[i]);
646 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
647 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
648 printf("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
649 else
650 printf("%3d", Parser->Data.satellites[i]);
651 }
652 printf("\n");
653 j -= 12;
654 o += 12;
655 }
656 for(i = 0; i < Parser->Data.numsats; ++i)
657 {
658 for(j = 0; j < Parser->numdatatypes; ++j)
659 {
660 if(!(Parser->Data.dataflags[i] & Parser->dataflag[j])
661 || isnan(Parser->Data.measdata[i][Parser->datapos[j]])
662 || isinf(Parser->Data.measdata[i][Parser->datapos[j]]))
663 { /* no or illegal data */
664 printf(" ");
665 }
666 else
667 {
668 char lli = ' ';
669 char snr = ' ';
670 if(Parser->dataflag[j] & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
671 {
672 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
673 lli = '1';
674 snr = '0'+Parser->Data.snrL1[i];
675 }
676 if(Parser->dataflag[j] & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
677 {
678 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
679 lli = '1';
680 snr = '0'+Parser->Data.snrL2[i];
681 }
682 printf("%14.3f%c%c",
683 Parser->Data.measdata[i][Parser->datapos[j]],lli,snr);
684 }
685 if(j%5 == 4 || j == Parser->numdatatypes-1)
686 printf("\n");
687 }
688 }
689 }
690 }
691}
692
693#ifndef NO_RTCM3_MAIN
694static char datestr[] = "$Date: 2006/11/02 13:34:00 $";
695
696/* The string, which is send as agent in HTTP request */
697#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
698
699#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
700
701static const char encodingTable [64] = {
702 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
703 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
704 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
705 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
706};
707
708/* does not buffer overrun, but breaks directly after an error */
709/* returns the number of required bytes */
710static int encode(char *buf, int size, const char *user, const char *pwd)
711{
712 unsigned char inbuf[3];
713 char *out = buf;
714 int i, sep = 0, fill = 0, bytes = 0;
715
716 while(*user || *pwd)
717 {
718 i = 0;
719 while(i < 3 && *user) inbuf[i++] = *(user++);
720 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
721 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
722 while(i < 3) {inbuf[i++] = 0; ++fill; }
723 if(out-buf < size-1)
724 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
725 if(out-buf < size-1)
726 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
727 | ((inbuf [1] & 0xF0) >> 4)];
728 if(out-buf < size-1)
729 {
730 if(fill == 2)
731 *(out++) = '=';
732 else
733 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
734 | ((inbuf [2] & 0xC0) >> 6)];
735 }
736 if(out-buf < size-1)
737 {
738 if(fill >= 1)
739 *(out++) = '=';
740 else
741 *(out++) = encodingTable[inbuf [2] & 0x3F];
742 }
743 bytes += 4;
744 }
745 if(out-buf < size)
746 *out = 0;
747 return bytes;
748}
749
750static int stop = 0;
751
752struct Args
753{
754 const char *server;
755 int port;
756 const char *user;
757 const char *password;
758 const char *data;
759 const char *headerfile;
760};
761
762/* option parsing */
763#ifdef NO_LONG_OPTS
764#define LONG_OPT(a)
765#else
766#define LONG_OPT(a) a
767static struct option opts[] = {
768{ "data", required_argument, 0, 'd'},
769{ "server", required_argument, 0, 's'},
770{ "password", required_argument, 0, 'p'},
771{ "port", required_argument, 0, 'r'},
772{ "header", required_argument, 0, 'f'},
773{ "user", required_argument, 0, 'u'},
774{ "help", no_argument, 0, 'h'},
775{0,0,0,0}};
776#endif
777#define ARGOPT "d:hp:r:s:u:f:"
778
779static int getargs(int argc, char **argv, struct Args *args)
780{
781 int res = 1;
782 int getoptr;
783 int help = 0;
784 char *t;
785
786 args->server = "www.euref-ip.net";
787 args->port = 80;
788 args->user = "";
789 args->password = "";
790 args->data = 0;
791 args->headerfile = 0;
792 help = 0;
793
794 do
795 {
796#ifdef NO_LONG_OPTS
797 switch((getoptr = getopt(argc, argv, ARGOPT)))
798#else
799 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
800#endif
801 {
802 case 's': args->server = optarg; break;
803 case 'u': args->user = optarg; break;
804 case 'p': args->password = optarg; break;
805 case 'd': args->data = optarg; break;
806 case 'f': args->headerfile = optarg; break;
807 case 'h': help=1; break;
808 case 'r':
809 args->port = strtoul(optarg, &t, 10);
810 if((t && *t) || args->port < 1 || args->port > 65535)
811 res = 0;
812 break;
813 case -1: break;
814 }
815 } while(getoptr != -1 || !res);
816
817 datestr[0] = datestr[7];
818 datestr[1] = datestr[8];
819 datestr[2] = datestr[9];
820 datestr[3] = datestr[10];
821 datestr[5] = datestr[12];
822 datestr[6] = datestr[13];
823 datestr[8] = datestr[15];
824 datestr[9] = datestr[16];
825 datestr[4] = datestr[7] = '-';
826 datestr[10] = 0;
827
828 if(!res || help)
829 {
830 fprintf(stderr, "Version %s (%s) GPL\nUsage: %s -s server -u user ...\n"
831 " -d " LONG_OPT("--data ") "the requested data set\n"
832 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
833 " -s " LONG_OPT("--server ") "the server name or address\n"
834 " -p " LONG_OPT("--password ") "the login password\n"
835 " -r " LONG_OPT("--port ") "the server port number (default 80)\n"
836 " -u " LONG_OPT("--user ") "the user name\n"
837 , revisionstr, datestr, argv[0]);
838 exit(1);
839 }
840 return res;
841}
842
843/* let the output complete a block if necessary */
844static void signalhandler(int sig)
845{
846 if(!stop)
847 {
848 fprintf(stderr, "Stop signal number %d received. "
849 "Trying to terminate gentle.\n", sig);
850 stop = 1;
851 alarm(1);
852 }
853}
854
855/* for some reason we had to abort hard (maybe waiting for data */
856#ifdef __GNUC__
857static __attribute__ ((noreturn)) void signalhandler_alarm(
858int sig __attribute__((__unused__)))
859#else /* __GNUC__ */
860static void signalhandler_alarm(int sig)
861#endif /* __GNUC__ */
862{
863 fprintf(stderr, "Programm forcefully terminated.\n");
864 exit(1);
865}
866
867int main(int argc, char **argv)
868{
869 struct Args args;
870 struct RTCM3ParserData Parser;
871
872 setbuf(stdout, 0);
873 setbuf(stdin, 0);
874 setbuf(stderr, 0);
875
876 {
877 char *a;
878 int i=0;
879 for(a = revisionstr+11; *a && *a != ' '; ++a)
880 revisionstr[i++] = *a;
881 revisionstr[i] = 0;
882 }
883
884 signal(SIGINT, signalhandler);
885 signal(SIGALRM,signalhandler_alarm);
886 signal(SIGQUIT,signalhandler);
887 signal(SIGTERM,signalhandler);
888 signal(SIGPIPE,signalhandler);
889 memset(&Parser, 0, sizeof(Parser));
890 {
891 time_t tim;
892 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
893 Parser.GPSWeek = tim/(7*24*60*60);
894 Parser.GPSTOW = tim%(7*24*60*60);
895 }
896
897 if(getargs(argc, argv, &args))
898 {
899 int i, sockfd, numbytes;
900 char buf[MAXDATASIZE];
901 struct hostent *he;
902 struct sockaddr_in their_addr; /* connector's address information */
903
904 Parser.headerfile = args.headerfile;
905
906 if(!(he=gethostbyname(args.server)))
907 {
908 perror("gethostbyname");
909 exit(1);
910 }
911 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
912 {
913 perror("socket");
914 exit(1);
915 }
916 their_addr.sin_family = AF_INET; /* host byte order */
917 their_addr.sin_port = htons(args.port); /* short, network byte order */
918 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
919 memset(&(their_addr.sin_zero), '\0', 8);
920 if(connect(sockfd, (struct sockaddr *)&their_addr,
921 sizeof(struct sockaddr)) == -1)
922 {
923 perror("connect");
924 exit(1);
925 }
926
927 if(!args.data)
928 {
929 i = snprintf(buf, MAXDATASIZE,
930 "GET / HTTP/1.0\r\n"
931 "User-Agent: %s/%s\r\n"
932#ifdef UNUSED
933 "Accept: */*\r\n"
934 "Connection: close\r\n"
935#endif
936 "\r\n"
937 , AGENTSTRING, revisionstr);
938 }
939 else
940 {
941 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
942 "GET /%s HTTP/1.0\r\n"
943 "User-Agent: %s/%s\r\n"
944#ifdef UNUSED
945 "Accept: */*\r\n"
946 "Connection: close\r\n"
947#endif
948 "Authorization: Basic "
949 , args.data, AGENTSTRING, revisionstr);
950 if(i > MAXDATASIZE-40 && i < 0) /* second check for old glibc */
951 {
952 fprintf(stderr, "Requested data too long\n");
953 exit(1);
954 }
955 i += encode(buf+i, MAXDATASIZE-i-5, args.user, args.password);
956 if(i > MAXDATASIZE-5)
957 {
958 fprintf(stderr, "Username and/or password too long\n");
959 exit(1);
960 }
961 snprintf(buf+i, 5, "\r\n\r\n");
962 i += 5;
963 }
964 if(send(sockfd, buf, (size_t)i, 0) != i)
965 {
966 perror("send");
967 exit(1);
968 }
969 if(args.data)
970 {
971 int k = 0;
972 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
973 {
974 if(!k)
975 {
976 if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
977 {
978 fprintf(stderr, "Could not get the requested data: ");
979 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
980 {
981 fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
982 }
983 fprintf(stderr, "\n");
984 exit(1);
985 }
986 ++k;
987 }
988 else
989 {
990 int z;
991 for(z = 0; z < numbytes && !stop; ++z)
992 HandleByte(&Parser, buf[z]);
993 }
994 }
995 }
996 else
997 {
998 while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
999 {
1000 fwrite(buf, (size_t)numbytes, 1, stdout);
1001 }
1002 }
1003
1004 close(sockfd);
1005 }
1006 return 0;
1007}
1008#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.