source: ntrip/trunk/ntripserver/NtripLinuxServer.c@ 32

Last change on this file since 32 was 32, checked in by stoecker, 18 years ago

added caster download

File size: 26.0 KB
Line 
1/*
2 * NtripServerLinux.c
3 *
4 * Copyright (c) 2003...2005
5 * German Federal Agency for Cartography and Geodesy (BKG)
6 *
7 * Developed for Networked Transport of RTCM via Internet Protocol (NTRIP)
8 * for streaming GNSS data over the Internet.
9 *
10 * Designed by Informatik Centrum Dortmund http://www.icd.de
11 *
12 * NTRIP is currently an experimental technology.
13 * The BKG disclaims any liability nor responsibility to any person or
14 * entity with respect to any loss or damage caused, or alleged to be
15 * caused, directly or indirectly by the use and application of the NTRIP
16 * technology.
17 *
18 * For latest information and updates, access:
19 * http://igs.ifag.de/index_ntrip.htm
20 *
21 * Georg Weber
22 * BKG, Frankfurt, Germany, June 2003-06-13
23 * E-mail: euref-ip@bkg.bund.de
24 *
25 * Based on the GNU General Public License published nmead
26 *
27 * This program is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU General Public License
29 * as published by the Free Software Foundation; either version 2
30 * of the License, or (at your option) any later version.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program; if not, write to the Free Software
39 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
40 * USA.
41 */
42
43/* $Id: NtripLinuxServer.c,v 1.12 2005/06/02 09:33:11 stoecker Exp $
44 * Changes - Version 0.7
45 * Sep 22 2003 Steffen Tschirpke <St.Tschirpke@actina.de>
46 * - socket support
47 * - command line option handling
48 * - error handling
49 * - help screen
50 *
51 * Changes - Version 0.9
52 * Feb 15 2005 Dirk Stoecker <soft@dstoecker.de>
53 * - some minor updates, fixed serial baudrate settings
54 *
55 * Changes - Version 0.10
56 * Apr 05 2005 Dirk Stoecker <soft@dstoecker.de>
57 * - some cleanup and miscellaneous fixes
58 * - replaced non-working simulate with file input (stdin)
59 * - TCP sending now somewhat more stable
60 * - cleanup of error handling
61 * - Modes may be symbolic and not only numeric
62 *
63 * Changes - Version 0.11
64 * Jun 02 2005 Dirk Stoecker <soft@dstoecker.de>
65 * - added SISNeT support
66 * - added UDP support
67 * - cleanup of host and port handling
68 * - added inactivity alarm of 60 seconds
69 *
70 * Changes - Version 0.12
71 * Jun 07 2005 Dirk Stoecker <soft@dstoecker.de>
72 * - added UDP bindmode
73 *
74 * Changes - Version 0.13
75 * Apr 25 2006 Andrea Stuerze <andrea.stuerze@bkg.bund.de>
76 * - added stream retrieval from caster
77 *
78 * Changes - Version 0.14
79 * Apr 27 2006 Dirk Stoecker <soft@dstoecker.de>
80 * - fixed some problems with caster download
81 *
82 */
83
84#include <ctype.h>
85#include <errno.h>
86#include <fcntl.h>
87#include <getopt.h>
88#include <netdb.h>
89#include <signal.h>
90#include <stdio.h>
91#include <stdlib.h>
92#include <string.h>
93#include <unistd.h>
94#include <arpa/inet.h>
95#include <netinet/in.h>
96#include <sys/socket.h>
97#include <sys/termios.h>
98#include <sys/types.h>
99
100#ifndef MSG_DONTWAIT
101#define MSG_DONTWAIT 0 /* prevent compiler errors */
102#endif
103#ifndef O_EXLOCK
104#define O_EXLOCK 0 /* prevent compiler errors */
105#endif
106
107enum MODE { SERIAL = 1, TCPSOCKET = 2, INFILE = 3, SISNET = 4, UDPSOCKET = 5,
108CASTER = 6};
109
110#define VERSION "NTRIP NtripServerLinux/0.13"
111#define BUFSZ 1024
112
113/* default socket source */
114#define SERV_HOST_ADDR "127.0.0.1"
115#define SERV_TCP_PORT 1025
116
117/* default destination */
118#define NTRIP_CASTER "www.euref-ip.net"
119#define NTRIP_PORT 80
120
121/* default sisnet source */
122#define SISNET_SERVER "131.176.49.142"
123#define SISNET_PORT 7777
124
125#define ALARMTIME 60
126
127static int ttybaud = 19200;
128static const char *ttyport = "/dev/gps";
129static const char *filepath = "/dev/stdin";
130static enum MODE mode = INFILE;
131static int sisnetv3 = 0;
132static int gpsfd = -1;
133
134/* Forward references */
135static int openserial(const char * tty, int blocksz, int baud);
136static void send_receive_loop(int sock, int fd, int sisnet);
137static void usage(int);
138static int encode(char *buf, int size, const char *user, const char *pwd);
139
140#ifdef __GNUC__
141static __attribute__ ((noreturn)) void sighandler_alarm(
142int sig __attribute__((__unused__)))
143#else /* __GNUC__ */
144static void sighandler_alarm(int sig)
145#endif /* __GNUC__ */
146{
147 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
148 exit(1);
149}
150
151/*
152* main
153*
154* Main entry point for the program. Processes command-line arguments and
155* prepares for action.
156*
157* Parameters:
158* argc : integer : Number of command-line arguments.
159* argv : array of char : Command-line arguments as an array of
160* zero-terminated pointers to strings.
161*
162* Return Value:
163* The function does not return a value (although its return type is int).
164*
165* Remarks:
166*
167*/
168
169int main(int argc, char **argv)
170{
171 int c;
172 int size = 2048; /* for setting send buffer size */
173
174 const char *inhost = 0;
175 const char *outhost = 0;
176 unsigned int outport = 0;
177 unsigned int inport = 0;
178 const char *mountpoint = NULL;
179 const char *password = "";
180 const char *sisnetpassword = "";
181 const char *sisnetuser = "";
182
183 const char *stream_name=0;
184 const char *stream_user=0;
185 const char *stream_password=0;
186
187 const char *initfile = NULL;
188 int bindmode = 0;
189 int sock_id;
190 char szSendBuffer[BUFSZ];
191 int nBufferBytes;
192 struct hostent *he;
193 struct sockaddr_in addr;
194
195 signal(SIGALRM,sighandler_alarm);
196 alarm(ALARMTIME);
197 /* get and check program arguments */
198 if(argc <= 1)
199 {
200 usage(2);
201 exit(1);
202 }
203 while((c = getopt(argc, argv, "M:i:h:b:p:s:a:m:c:H:P:f:l:u:V:D:U:W:B"))
204 != EOF)
205 {
206 switch (c)
207 {
208 case 'M':
209 if(!strcmp(optarg, "serial")) mode = 1;
210 else if(!strcmp(optarg, "tcpsocket")) mode = 2;
211 else if(!strcmp(optarg, "file")) mode = 3;
212 else if(!strcmp(optarg, "sisnet")) mode = 4;
213 else if(!strcmp(optarg, "udpsocket")) mode = 5;
214 else if(!strcmp(optarg, "caster")) mode = 6;
215 else mode = atoi(optarg);
216 if((mode == 0) || (mode > 6))
217 {
218 fprintf(stderr, "ERROR: can't convert %s to a valid mode\n", optarg);
219 usage(-1);
220 }
221 break;
222 case 'i': /* gps serial ttyport */
223 ttyport = optarg;
224 break;
225 case 'B':
226 bindmode = 1;
227 break;
228 case 'V':
229 if(!strcmp("3.0", optarg)) sisnetv3 = 1;
230 else if(strcmp("2.1", optarg))
231 {
232 fprintf(stderr, "ERROR: unknown SISNeT version %s\n", optarg);
233 usage(-2);
234 }
235 case 'b': /* serial ttyin speed */
236 ttybaud = atoi(optarg);
237 if(ttybaud <= 1)
238 {
239 fprintf(stderr, "ERROR: can't convert %s to valid serial speed\n",
240 optarg);
241 usage(1);
242 }
243 break;
244 case 'a': /* http server IP address A.B.C.D */
245 outhost = optarg;
246 break;
247 case 'p': /* http server port */
248 outport = atoi(optarg);
249 if(outport <= 1 || outport > 65535)
250 {
251 fprintf(stderr,
252 "ERROR: can't convert %s to a valid HTTP server port\n", optarg);
253 usage(1);
254 }
255 break;
256 case 'm': /* http server mountpoint */
257 mountpoint = optarg;
258 break;
259 case 's': /* datastream from file */
260 filepath = optarg;
261 break;
262 case 'f':
263 initfile = optarg;
264 break;
265 case 'u':
266 sisnetuser = optarg;
267 break;
268 case 'l':
269 sisnetpassword = optarg;
270 break;
271 case 'c': /* password */
272 password = optarg;
273 break;
274 case 'H': /* host */
275 inhost = optarg;
276 break;
277 case 'P': /* port */
278 inport = atoi(optarg);
279 if(inport <= 1 || inport > 65535)
280 {
281 fprintf(stderr, "ERROR: can't convert %s to a valid port number\n",
282 optarg);
283 usage(1);
284 }
285 break;
286 case 'D':
287 stream_name=optarg; /* desired stream from SourceCaster */
288 break;
289 case 'U':
290 stream_user=optarg; /* username for desired stream */
291 break;
292 case 'W':
293 stream_password=optarg; /* passwd for desired stream */
294 break;
295 case 'h': /* help */
296 case '?':
297 usage(0);
298 break;
299 default:
300 usage(2);
301 break;
302 }
303 }
304
305 argc -= optind;
306 argv += optind;
307
308 if(argc > 0)
309 {
310 fprintf(stderr, "ERROR: Extra args on command line: ");
311 for(; argc > 0; argc--)
312 {
313 fprintf(stderr, " %s", *argv++);
314 }
315 fprintf(stderr, "\n");
316 usage(1); /* never returns */
317 }
318
319 if(mountpoint == NULL)
320 {
321 fprintf(stderr, "ERROR: Missing mountpoint argument\n");
322 exit(1);
323 }
324 if(!password[0])
325 {
326 fprintf(stderr,
327 "WARNING: Missing password argument - are you really sure?\n");
328 }
329
330 if(stream_name && (!stream_user || stream_password))
331 {
332 fprintf(stderr, "WARNING: Missing password argument for download"
333 " - are you really sure?\n");
334 }
335
336 if(!outhost) outhost = NTRIP_CASTER;
337 if(!outport) outport = NTRIP_PORT;
338
339 switch(mode)
340 {
341 case INFILE:
342 {
343 gpsfd = open(filepath, O_RDONLY);
344 if(!gpsfd)
345 {
346 perror("ERROR: opening input file");
347 exit(1);
348 }
349 /* set blocking mode in case it was not set
350 (seems to be sometimes for fifo's) */
351 fcntl(gpsfd, F_SETFL, 0);
352 printf("file input: file = %s\n", filepath);
353 }
354 break;
355 case SERIAL: /* open serial port */
356 {
357 gpsfd = openserial(ttyport, 1, ttybaud);
358 if(gpsfd < 0)
359 {
360 exit(1);
361 }
362 printf("serial input: device = %s, speed = %d\n", ttyport, ttybaud);
363 }
364 break;
365 case TCPSOCKET: case UDPSOCKET: case SISNET: case CASTER:
366 {
367 if(mode == SISNET)
368 {
369 if(!inhost) inhost = SISNET_SERVER;
370 if(!inport) inport = SISNET_PORT;
371 }
372 else if(mode == CASTER)
373 {
374 if(!inport) inport = NTRIP_PORT;
375 if(!inhost) inhost = NTRIP_CASTER;
376 }
377 else if((mode == TCPSOCKET) || (mode == UDPSOCKET))
378 {
379 if(!inport) inport = SERV_TCP_PORT;
380 if(!inhost) inhost = "127.0.0.1";
381 }
382
383 if(!(he = gethostbyname(inhost)))
384 {
385 fprintf(stderr, "ERROR: host %s unknown\n", inhost);
386 usage(-2);
387 }
388
389 if((gpsfd = socket(AF_INET, mode == UDPSOCKET
390 ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
391 {
392 fprintf(stderr, "ERROR: can't create socket\n");
393 exit(1);
394 }
395
396 memset((char *) &addr, 0x00, sizeof(addr));
397 if(!bindmode)
398 memcpy(&addr.sin_addr, he->h_addr, (size_t)he->h_length);
399 addr.sin_family = AF_INET;
400 addr.sin_port = htons(inport);
401
402 printf("%s input: host = %s, port = %d, %s%s%s%s%s\n",
403 mode == CASTER ? "caster" : mode == SISNET ? "sisnet" :
404 mode == TCPSOCKET ? "tcp socket" : "udp socket",
405 bindmode ? "127.0.0.1" : inet_ntoa(addr.sin_addr),
406 inport, stream_name ? "stream = " : "", stream_name ? stream_name : "",
407 initfile ? ", initfile = " : "", initfile ? initfile : "",
408 bindmode ? " binding mode" : "");
409
410 if(bindmode)
411 {
412 if(bind(gpsfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
413 {
414 fprintf(stderr, "ERROR: can't bind input to port %d\n", inport);
415 exit(1);
416 }
417 }
418 else if(connect(gpsfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
419 {
420 fprintf(stderr, "ERROR: can't connect input to %s at port %d\n",
421 inet_ntoa(addr.sin_addr), inport);
422 exit(1);
423 }
424
425 if(stream_name) /* data stream from caster */
426 {
427 int init = 0;
428
429 /* set socket buffer size */
430 setsockopt(gpsfd, SOL_SOCKET, SO_SNDBUF, (const char *) &size,
431 sizeof(const char *));
432 if(stream_user && stream_password)
433 {
434 /* leave some space for login */
435 nBufferBytes=snprintf(szSendBuffer, sizeof(szSendBuffer)-40,
436 "GET /%s HTTP/1.0\r\n"
437 "User-Agent: %s\r\n"
438 "Authorization: Basic ", stream_name, VERSION);
439 /* second check for old glibc */
440 if(nBufferBytes > (int)sizeof(szSendBuffer)-40 || nBufferBytes < 0)
441 {
442 fprintf(stderr, "Requested data too long\n");
443 exit(1);
444 }
445 nBufferBytes += encode(szSendBuffer+nBufferBytes,
446 sizeof(szSendBuffer)-nBufferBytes-5, stream_user, stream_password);
447 if(nBufferBytes > (int)sizeof(szSendBuffer)-5)
448 {
449 fprintf(stderr, "Username and/or password too long\n");
450 exit(1);
451 }
452 snprintf(szSendBuffer+nBufferBytes, 5, "\r\n\r\n");
453 nBufferBytes += 5;
454 }
455 else
456 {
457 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
458 "GET /%s HTTP/1.0\r\n"
459 "User-Agent: %s\r\n"
460 "\r\n", stream_name, VERSION);
461 }
462 if((send(gpsfd, szSendBuffer, (size_t)nBufferBytes, 0))
463 != nBufferBytes)
464 {
465 fprintf(stderr, "ERROR: could not send to caster\n");
466 exit(1);
467 }
468 nBufferBytes = 0;
469 /* check caster's response */
470 while(!init && nBufferBytes < (int)sizeof(szSendBuffer)
471 && (nBufferBytes += recv(gpsfd, szSendBuffer,
472 sizeof(szSendBuffer)-nBufferBytes, 0)) > 0)
473 {
474 if(strstr(szSendBuffer, "\r\n"))
475 {
476 if(!strncmp(szSendBuffer, "ICY 200 OK\r\n", 10))
477 init = 1;
478 else
479 {
480 int k;
481 fprintf(stderr, "Could not get the requested data: ");
482 for(k = 0; k < nBufferBytes && szSendBuffer[k] != '\n'
483 && szSendBuffer[k] != '\r'; ++k)
484 {
485 fprintf(stderr, "%c", isprint(szSendBuffer[k])
486 ? szSendBuffer[k] : '.');
487 }
488 fprintf(stderr, "\n");
489 exit(1);
490 }
491 }
492 }
493 if(!init)
494 {
495 fprintf(stderr, "Could not init caster download.");
496 exit(1);
497 }
498 } /* end data stream from caster */
499
500 if(initfile && mode != SISNET)
501 {
502 char buffer[1024];
503 FILE *fh;
504 int i;
505
506 if((fh = fopen(initfile, "r")))
507 {
508 while((i = fread(buffer, 1, sizeof(buffer), fh)) > 0)
509 {
510 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
511 {
512 perror("ERROR: sending init file");
513 exit(1);
514 }
515 }
516 if(i < 0)
517 {
518 perror("ERROR: reading init file");
519 exit(1);
520 }
521 fclose(fh);
522 }
523 else
524 {
525 fprintf(stderr, "ERROR: can't read init file %s\n", initfile);
526 exit(1);
527 }
528 }
529 }
530 if(mode == SISNET)
531 {
532 int i, j;
533 char buffer[1024];
534
535 i = snprintf(buffer, sizeof(buffer), sisnetv3 ? "AUTH,%s,%s\r\n"
536 : "AUTH,%s,%s", sisnetuser, sisnetpassword);
537 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
538 {
539 perror("ERROR: sending authentication");
540 exit(1);
541 }
542 i = sisnetv3 ? 7 : 5;
543 if((j = recv(gpsfd, buffer, i, 0)) != i && strncmp("*AUTH", buffer, 5))
544 {
545 fprintf(stderr, "ERROR: SISNeT connect failed:");
546 for(i = 0; i < j; ++i)
547 {
548 if(buffer[i] != '\r' && buffer[i] != '\n')
549 {
550 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
551 }
552 }
553 fprintf(stderr, "\n");
554 exit(1);
555 }
556 }
557 break;
558 default:
559 usage(-1);
560 break;
561 }
562
563 /* ----- main part ----- */
564 while(1)
565 {
566 if(!(he = gethostbyname(outhost)))
567 {
568 fprintf(stderr, "ERROR: host %s unknown\n", outhost);
569 usage(-2);
570 }
571
572 /* create socket */
573 if((sock_id = socket(AF_INET, SOCK_STREAM, 0)) < 0)
574 {
575 fprintf(stderr, "ERROR: could not create socket\n");
576 exit(2);
577 }
578
579 memset((char *) &addr, 0x00, sizeof(addr));
580 memcpy(&addr.sin_addr, he->h_addr, (size_t)he->h_length);
581 addr.sin_family = AF_INET;
582 addr.sin_port = htons(outport);
583
584 /* connect to caster */
585 fprintf(stderr, "caster output: host = %s, port = %d, mountpoint = %s\n",
586 inet_ntoa(addr.sin_addr), outport, mountpoint);
587 if(connect(sock_id, (struct sockaddr *) &addr, sizeof(addr)) < 0)
588 {
589 fprintf(stderr, "ERROR: can't connect output to %s at port %d\n",
590 inet_ntoa(addr.sin_addr), outport);
591 close(sock_id);
592 exit(3);
593 }
594
595 /* set socket buffer size */
596 setsockopt(sock_id, SOL_SOCKET, SO_SNDBUF, (const char *) &size,
597 sizeof(const char *));
598 /* send message to caster */
599 szSendBuffer[0] = '\0';
600 sprintf(szSendBuffer, "SOURCE %s /%s\r\n", password, mountpoint);
601 strcat(szSendBuffer, "Source-Agent: ");
602 strcat(szSendBuffer, VERSION);
603 strcat(szSendBuffer, "\r\n");
604 strcat(szSendBuffer, "\r\n");
605 strcat(szSendBuffer, "\0");
606 nBufferBytes = strlen(szSendBuffer);
607 if((send(sock_id, szSendBuffer, (size_t)nBufferBytes, 0)) != nBufferBytes)
608 {
609 fprintf(stderr, "ERROR: could not send to caster\n");
610 close(sock_id);
611 sleep(5);
612 exit(0);
613 }
614 /* check caster's response */
615 nBufferBytes = recv(sock_id, szSendBuffer, sizeof(szSendBuffer), 0);
616 szSendBuffer[nBufferBytes] = '\0';
617 if(strcmp(szSendBuffer, "OK\r\n"))
618 {
619 char *a;
620 fprintf(stderr, "ERROR: caster's reply is not OK : ");
621 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
622 {
623 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
624 }
625 fprintf(stderr, "\n");
626 close(sock_id);
627 sleep(5);
628 exit(0);
629 }
630 printf("connection successfull\n");
631 send_receive_loop(sock_id, gpsfd, mode == SISNET);
632 }
633 exit(0);
634}
635
636static void send_receive_loop(int sock, int fd, int sisnet)
637{
638 char buffer[BUFSZ] = { 0 };
639 char sisnetbackbuffer[200];
640 int nBufferBytes = 0;
641 /* data transmission */
642 printf("transfering data ...\n");
643 while(1)
644 {
645 alarm(ALARMTIME);
646
647 if(!nBufferBytes)
648 {
649 if(sisnet)
650 {
651 int i;
652 /* a somewhat higher rate than 1 second to get really each block */
653 /* means we need to skip double blocks sometimes */
654 struct timeval tv = {0,700000};
655 select(0, 0, 0, 0, &tv);
656 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
657 i = (sisnetv3 ? 5 : 3);
658 if((send(gpsfd, "MSG\r\n", i, 0)) != i)
659 {
660 perror("ERROR: sending data request");
661 exit(1);
662 }
663 }
664 /* receiving data */
665 nBufferBytes = read(fd, buffer, sizeof(buffer));
666 if(!nBufferBytes)
667 {
668 printf("WARNING: no data received from input\n");
669 continue;
670 }
671 else if(nBufferBytes < 0)
672 {
673 perror("ERROR: reading input failed");
674 exit(1);
675 }
676 /* we can compare the whole buffer, as the additional bytes
677 remain unchanged */
678 if(sisnet && !memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer)))
679 {
680 nBufferBytes = 0;
681 }
682 }
683 if(nBufferBytes)
684 {
685 int i;
686 /* send data */
687 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
688 != nBufferBytes)
689 {
690 if(i < 0 && errno != EAGAIN)
691 {
692 perror("WARNING: could not send data - retry connection");
693 close(sock);
694 sleep(5);
695 return;
696 }
697 else if(i)
698 {
699 memmove(buffer, buffer+i, (size_t)(nBufferBytes-i));
700 nBufferBytes -= i;
701 }
702 }
703 else
704 {
705 nBufferBytes = 0;
706 }
707 }
708 }
709}
710
711/*
712 * openserial
713 *
714 * Open the serial port with the given device name and configure it for
715 * reading NMEA data from a GPS receiver.
716 *
717 * Parameters:
718 * tty : pointer to : A zero-terminated string containing the device
719 * unsigned char name of the appropriate serial port.
720 * blocksz : integer : Block size for port I/O
721 * baud : integer : Baud rate for port I/O
722 *
723 * Return Value:
724 * The function returns a file descriptor for the opened port if successful.
725 * The function returns -1 in the event of an error.
726 *
727 * Remarks:
728 *
729 */
730
731static int openserial(const char * tty, int blocksz, int baud)
732{
733 int fd;
734 struct termios termios;
735
736 fd = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
737 if(fd < 0)
738 {
739 perror("ERROR: opening serial connection");
740 return (-1);
741 }
742 if(tcgetattr(fd, &termios) < 0)
743 {
744 perror("ERROR: get serial attributes");
745 return (-1);
746 }
747 termios.c_iflag = 0;
748 termios.c_oflag = 0; /* (ONLRET) */
749 termios.c_cflag = CS8 | CLOCAL | CREAD;
750 termios.c_lflag = 0;
751 {
752 int cnt;
753 for(cnt = 0; cnt < NCCS; cnt++)
754 termios.c_cc[cnt] = -1;
755 }
756 termios.c_cc[VMIN] = blocksz;
757 termios.c_cc[VTIME] = 2;
758
759#if (B4800 != 4800)
760 /*
761 * Not every system has speed settings equal to absolute speed value.
762 */
763
764 switch (baud)
765 {
766 case 300:
767 baud = B300;
768 break;
769 case 1200:
770 baud = B1200;
771 break;
772 case 2400:
773 baud = B2400;
774 break;
775 case 4800:
776 baud = B4800;
777 break;
778 case 9600:
779 baud = B9600;
780 break;
781 case 19200:
782 baud = B19200;
783 break;
784 case 38400:
785 baud = B38400;
786 break;
787#ifdef B57600
788 case 57600:
789 baud = B57600;
790 break;
791#endif
792#ifdef B115200
793 case 115200:
794 baud = B115200;
795 break;
796#endif
797#ifdef B230400
798 case 230400:
799 baud = B230400;
800 break;
801#endif
802 default:
803 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
804 baud = B19200;
805 break;
806 }
807#endif
808
809 if(cfsetispeed(&termios, baud) != 0)
810 {
811 perror("ERROR: setting serial speed with cfsetispeed");
812 return (-1);
813 }
814 if(cfsetospeed(&termios, baud) != 0)
815 {
816 perror("ERROR: setting serial speed with cfsetospeed");
817 return (-1);
818 }
819 if(tcsetattr(fd, TCSANOW, &termios) < 0)
820 {
821 perror("ERROR: setting serial attributes");
822 return (-1);
823 }
824 if(fcntl(fd, F_SETFL, 0) == -1)
825 {
826 perror("WARNING: setting blocking mode failed");
827 }
828 return (fd);
829}
830
831/*
832 * usage
833 *
834 * Send a usage message to standard error and quit the program.
835 *
836 * Parameters:
837 * None.
838 *
839 * Return Value:
840 * The function does not return a value.
841 *
842 * Remarks:
843 *
844 */
845
846static
847#ifdef __GNUC__
848__attribute__ ((noreturn))
849#endif /* __GNUC__ */
850void usage(int rc)
851{
852 fprintf(stderr, "Usage: %s [OPTIONS]\n", VERSION);
853 fprintf(stderr, " Options are: [-] \n");
854 fprintf(stderr, " -a DestinationCaster name or address (default: %s)\n",
855 NTRIP_CASTER);
856 fprintf(stderr, " -p DestinationCaster port (default: %d)\n", NTRIP_PORT);
857 fprintf(stderr, " -m DestinationCaster mountpoint\n");
858 fprintf(stderr, " -c DestinationCaster password\n");
859 fprintf(stderr, " -h|? print this help screen\n");
860 fprintf(stderr, " -M <mode> sets the input mode\n");
861 fprintf(stderr, " (1=serial, 2=tcpsocket, 3=file, 4=sisnet"
862 ", 5=udpsocket, 6=caster)\n");
863 fprintf(stderr, " Mode = file:\n");
864 fprintf(stderr, " -s file, simulate data stream by reading log file\n");
865 fprintf(stderr, " default/current setting is %s\n", filepath);
866 fprintf(stderr, " Mode = serial:\n");
867 fprintf(stderr, " -b baud_rate, sets serial input baud rate\n");
868 fprintf(stderr, " default/current value is %d\n", ttybaud);
869 fprintf(stderr, " -i input_device, sets name of serial input device\n");
870 fprintf(stderr, " default/current value is %s\n", ttyport);
871 fprintf(stderr, " (normally a symbolic link to /dev/tty\?\?)\n");
872 fprintf(stderr, " Mode = tcpsocket or udpsocket:\n");
873 fprintf(stderr, " -P receiver port (default: %d)\n", SERV_TCP_PORT);
874 fprintf(stderr, " -H hostname of TCP server (default: %s)\n",
875 SERV_HOST_ADDR);
876 fprintf(stderr, " -f initfile send to server\n");
877 fprintf(stderr, " -B bindmode: bind to incoming UDP stream\n");
878 fprintf(stderr, " Mode = sisnet:\n");
879 fprintf(stderr, " -P receiver port (default: %d)\n", SISNET_PORT);
880 fprintf(stderr, " -H hostname of TCP server (default: %s)\n",
881 SISNET_SERVER);
882 fprintf(stderr, " -u username\n");
883 fprintf(stderr, " -l password\n");
884 fprintf(stderr, " -V version [2.1 or 3.0] (default: 2.1)\n");
885 fprintf(stderr, " Mode = caster:\n");
886 fprintf(stderr, " -P SourceCaster port (default: %d)\n", NTRIP_PORT);
887 fprintf(stderr, " -H SourceCaster hostname (default: %s)\n",
888 NTRIP_CASTER);
889 fprintf(stderr, " -D SourceCaster mountpoint\n");
890 fprintf(stderr, " -U SourceCaster mountpoint username\n");
891 fprintf(stderr, " -W SourceCaster mountpoint password\n");
892 fprintf(stderr, "\n");
893 exit(rc);
894}
895
896static const char encodingTable [64] = {
897 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
898 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
899 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
900 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
901};
902
903/* does not buffer overrun, but breaks directly after an error */
904/* returns the number of required bytes */
905static int encode(char *buf, int size, const char *user, const char *pwd)
906{
907 unsigned char inbuf[3];
908 char *out = buf;
909 int i, sep = 0, fill = 0, bytes = 0;
910
911 while(*user || *pwd)
912 {
913 i = 0;
914 while(i < 3 && *user) inbuf[i++] = *(user++);
915 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
916 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
917 while(i < 3) {inbuf[i++] = 0; ++fill; }
918 if(out-buf < size-1)
919 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
920 if(out-buf < size-1)
921 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
922 | ((inbuf [1] & 0xF0) >> 4)];
923 if(out-buf < size-1)
924 {
925 if(fill == 2)
926 *(out++) = '=';
927 else
928 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
929 | ((inbuf [2] & 0xC0) >> 6)];
930 }
931 if(out-buf < size-1)
932 {
933 if(fill >= 1)
934 *(out++) = '=';
935 else
936 *(out++) = encodingTable[inbuf [2] & 0x3F];
937 }
938 bytes += 4;
939 }
940 if(out-buf < size)
941 *out = 0;
942 return bytes;
943}
Note: See TracBrowser for help on using the repository browser.