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

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

minor fixes

File size: 16.5 KB
Line 
1/*
2 * main.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.7 2005/02/17 09:22:23 stoecker Exp $
44 * Changes - Version 0.7
45 * Thu Sep 22 08:10:45 2003 actina AG <http://www.actina.de>
46 *
47 * Steffen Tschirpke <St.Tschirpke@actina.de>
48 * * main.c
49 * - socket support
50 * - command line option handling
51 * - error handling
52 * - help screen
53 */
54
55/* Changes - Version 0.9
56 * Feb 15 2005 Dirk Stoecker <soft@dstoecker.de>
57 */
58
59#include <stdio.h>
60#include <string.h>
61#include <unistd.h>
62#include <stdlib.h>
63#include <sys/types.h>
64#include <sys/socket.h>
65#include <netinet/in.h>
66#include <arpa/inet.h>
67#include <netdb.h>
68#include <getopt.h>
69#include <sys/termios.h>
70#include <fcntl.h>
71#include "NtripServerLinux.h"
72
73#define VERSION "NTRIP NtripServerLinux/0.9"
74
75#define SIMULATE 0
76#define SERIAL 1
77#define TCPSOCKET 2
78
79/* default socket source */
80#define SERV_HOST_ADDR "127.0.0.1"
81#define SERV_TCP_PORT 1025
82
83/* default destination */
84#define NTRIP_CASTER "www.euref-ip.net"
85#define NTRIP_PORT 80
86
87int verbose = 0;
88int simulate = 0;
89int tickinterval = 1;
90int ttybaud = 19200;
91char * ttyport = "/dev/gps";
92int mode = 0;
93
94/* Forward references */
95int openserial (u_char * tty, int blocksz, int ttybaud);
96int send_receive_loop(int socket, int fd);
97void usage (int);
98
99/*
100* main
101*
102* Main entry point for the program. Processes command-line arguments and
103* prepares for action.
104*
105* Parameters:
106* argc : integer : Number of command-line arguments.
107* argv : array of char : Command-line arguments as an array of zero-terminated
108* pointers to strings.
109*
110* Return Value:
111* The function does not return a value (although its return type is int).
112*
113* Remarks:
114*
115*/
116
117int main (int argc, char ** argv)
118{
119 u_char * ttyin = ttyport;
120 char * logfilepath = NULL;
121 FILE * fp = NULL;
122 int c, gpsfd = -1;
123 int size = 2048; //for setting send buffer size
124
125 unsigned int out_port = 0;
126 unsigned int in_port = 0;
127 char *mountpoint = NULL;
128 char *password = NULL;
129 int sock_id;
130 char szSendBuffer[BUFSZ];
131 int nBufferBytes;
132 int sockfd;
133
134 struct hostent *inhost;
135 struct hostent *outhost;
136
137 struct sockaddr_in in_addr;
138 struct sockaddr_in out_addr;
139
140 if(!(outhost = gethostbyname(NTRIP_CASTER)))
141 {
142 fprintf(stderr, "host %s unknown\n\n", NTRIP_CASTER);
143 }
144 else
145 {
146 memset((char *) &out_addr, 0x00, sizeof(out_addr));
147 memcpy(&out_addr.sin_addr, outhost->h_addr, outhost->h_length);
148 }
149
150 //get and check program arguments
151 if (argc <=1)
152 {
153 usage(2);
154 exit(1);
155 }
156 while ((c = getopt (argc, argv, "M:i:h:b:p:s:a:m:c:H:P:")) != EOF)
157 {
158 switch (c)
159 {
160 case 'M':
161 mode = atoi(optarg);
162 if ((mode == 0) || (mode > 3))
163 {
164 fprintf (stderr, "can't convert %s to a valid mode\n\n", optarg);
165 usage(-1);
166 }
167 break;
168 case 'i': /* gps serial ttyin */
169 ttyin = optarg;
170 break;
171 case 'b': /* serial ttyin speed */
172 ttybaud = atoi (optarg);
173 if (ttybaud <= 1)
174 {
175 fprintf (stderr, "can't convert %s to valid ttyin speed\n\n", optarg);
176 usage(1);
177 }
178 break;
179 case 'a': /* http server IP address A.B.C.D*/
180 outhost = gethostbyname(optarg);
181 if (outhost == NULL)
182 {
183 fprintf (stderr, "host %s unknown\n\n", optarg);
184 usage(-2);
185 }
186 memset((char *) &out_addr, 0x00, sizeof(out_addr));
187 memcpy(&out_addr.sin_addr, outhost->h_addr, outhost->h_length);
188 break;
189 case 'p': /* http server port*/
190 out_port = atoi(optarg);
191 if (out_port <= 1)
192 {
193 fprintf (stderr, "can't convert %s to a valid http server port\n\n", optarg);
194 usage(1);
195 }
196 break;
197 case 'm': /* http server mountpoint*/
198 mountpoint = optarg;
199 break;
200 case 's': /* simulate datastream from file */
201 logfilepath = optarg;
202 break;
203 case 'c': /* password */
204 password=optarg;
205 break;
206 case 'H': /* host */
207 inhost = gethostbyname(optarg);
208 if (inhost == NULL)
209 {
210 /* TODO Errorhandling/Debugging - Output */
211 fprintf (stderr, "host %s unknown\n\n", optarg);
212 usage(-2);
213 }
214 memset((char *) &in_addr, 0x00, sizeof(in_addr));
215 memcpy(&in_addr.sin_addr, inhost->h_addr, inhost->h_length);
216 break;
217 case 'P': /* port */
218 in_port = atoi(optarg);
219 if (in_port <= 1)
220 {
221 /* TODO Errorhandling/Debugging - Output */
222 fprintf (stderr, "can't convert %s to a valid receiver port\n\n", optarg);
223 usage(1);
224 }
225 break;
226 case 'h': /* help */
227 case '?':
228 usage(0);
229 break;
230 default:
231 usage(2);
232 break;
233 }
234
235 if (in_port <= 0 )
236 {
237 in_port = SERV_TCP_PORT;
238 }
239 if (out_port <= 0 )
240 {
241 out_port = NTRIP_PORT;
242 }
243 }
244
245 argc -= optind;
246 argv += optind;
247
248 if (argc > 0)
249 {
250 /* TODO Errorhandling/Debugging - Output */
251 fprintf (stderr, "Extra args on command line.\n");
252 for (; argc > 0; argc--)
253 {
254 fprintf (stderr, " %s", *argv++);
255 }
256 fprintf (stderr, "\n");
257 usage (1); /* never returns */
258 }
259
260 if ((mode ==SIMULATE) && (tickinterval <= 0))
261 {
262 /* TODO Errorhandling/Debugging - Output */
263 fprintf (stderr, "-t parameter must be positive in simulator mode\n");
264 exit (1);
265 }
266
267 if (verbose >= 1)
268 fprintf (stderr, "%s\n", VERSION);
269 if (mountpoint == NULL)
270 {
271 /* TODO Errorhandling/Debugging - Output */
272 fprintf(stderr,"missing mountpoint arguement\n");
273 exit(1);
274 }
275 //print program arguments on screen
276 /* TODO Errorhandling/Debugging - Output */
277 // printf("\ncaster IP :\t%s\nport :\t%d\nmountpoint :\t%s\npassword :\t%s\n\n",address,port,mountpoint,(password==NULL)?"none":"yes");
278 if (password == NULL)
279 {
280 password="\0";
281 }
282
283 switch (mode)
284 {
285 case SIMULATE:
286 {
287 fp = fopen (logfilepath, "r");
288 if (!fp)
289 {
290 /* TODO Errorhandling/Debugging - Output */
291 perror ("fopen logfile");
292 exit (1);
293 }
294 }
295 break;
296 case SERIAL: //open serial port
297 {
298 gpsfd = openserial (ttyin, 1, ttybaud);
299 fp = fdopen (gpsfd, "r");
300 if (!fp)
301 {
302 /* TODO Errorhandling/Debugging - Output */
303 perror ("fdopen gps");
304 exit (1);
305 }
306 }
307 break;
308 case TCPSOCKET:
309 {
310 in_addr.sin_family = AF_INET;
311 in_addr.sin_port = htons(in_port);
312
313 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
314 {
315 /* TODO Errorhandling/Debugging - Output */
316 fprintf (stderr, "can't create socket\n");
317 exit(1);
318 }
319
320 /* TODO Errorhandling/Debugging - Output */
321 printf("connecting input ...\n");
322 fprintf (stderr, "socket input:\n");
323 fprintf (stderr, "\tHost: %s\n", inet_ntoa(in_addr.sin_addr));
324 fprintf (stderr, "\tPort: %d\n", in_port);
325
326 if (connect(sockfd, (struct sockaddr *) &in_addr, sizeof(in_addr)) < 0)
327 {
328 /* TODO Errorhandling/Debugging - Output */
329 fprintf (stderr, "can't connect input to %s at port %d\n", inet_ntoa(in_addr.sin_addr), in_port);
330 // exit(1);
331 }
332 gpsfd = sockfd;
333 }
334 break;
335 default:
336 usage(-1);
337 break;
338 }
339
340 out_addr.sin_family = AF_INET;
341 out_addr.sin_port = htons((u_short)(out_port));
342
343 // ----- main part -----
344 while(1)
345 {
346 //create socket
347 if ((sock_id = socket(AF_INET, SOCK_STREAM, 0)) < 0)
348 {
349 /* TODO Errorhandling/Debugging - Output */
350 printf("ERROR : could not create socket\n");
351 // sleep(5);
352 exit(2);
353 }
354 //connect to caster
355 printf("connecting output ...\n");
356 fprintf (stderr, "caster output:\n");
357 fprintf (stderr, "\tHost: %s\n", inet_ntoa(out_addr.sin_addr));
358 fprintf (stderr, "\tPort: %d\n", out_port);
359 if (connect(sock_id, (struct sockaddr *) &out_addr, sizeof(out_addr)) < 0)
360 {
361 /* TODO Errorhandling/Debugging - Output */
362 fprintf (stderr, "can't connect output to %s at port %d\n", inet_ntoa(out_addr.sin_addr), out_port);
363 close(sock_id);
364 // sleep(5);
365 exit(3);
366 }
367
368 /* TODO Errorhandling/Debugging - Output */
369 printf("connection succesfull\n");
370 //set socket buffer size
371 setsockopt(sock_id,SOL_SOCKET,SO_SNDBUF,(const char *) &size,sizeof(const char *));
372 //send message to caster
373 szSendBuffer[0] = '\0';
374 sprintf(szSendBuffer,"SOURCE %s /%s\r\n",password,mountpoint);
375 strcat(szSendBuffer,"Source-Agent: ");
376 strcat(szSendBuffer,VERSION);
377 strcat(szSendBuffer, "\r\n");
378 strcat(szSendBuffer, "\r\n");
379 strcat(szSendBuffer, "\0");
380 nBufferBytes=strlen(szSendBuffer);
381 if ((send(sock_id, szSendBuffer, nBufferBytes, 0)) != nBufferBytes)
382 {
383 /* TODO Errorhandling/Debugging - Output */
384 fprintf(stderr, "ERROR : could not send to caster\n");
385 close(sock_id);
386 sleep(5);
387 exit(0);
388 }
389 //check caster's response
390 nBufferBytes=recv(sock_id,szSendBuffer,sizeof(szSendBuffer),0);
391 szSendBuffer[nBufferBytes]='\0';
392 if(strcmp(szSendBuffer,"OK\r\n"))
393 {
394 /* TODO Errorhandling/Debugging - Output */
395 fprintf(stderr,"caster's reply is not OK\n");
396 close(sock_id);
397 sleep(5);
398 exit(0);
399 }
400 send_receive_loop(sock_id, gpsfd);
401 }
402 exit(0);
403}
404
405int send_receive_loop(int socket, int fd)
406{
407 char buffer[BUFSZ]={0};
408 int nBufferBytes=0;
409 //data transmission
410 printf("transfering data ...\n");
411 while(1)
412 {
413 // recieving data
414 nBufferBytes = read(fd, buffer, BUFSZ);
415 if (nBufferBytes<=0)
416 {
417 /* TODO Errorhandling/Debugging - Output */
418 printf("ERROR : no data recieved from serial port or socket\n");
419 }
420 // send data
421 if((send(socket, buffer, nBufferBytes, MSG_DONTWAIT)) != nBufferBytes)
422 { //MSG_DONTWAIT : send works in non-blocking mode
423 /* TODO Errorhandling/Debugging - Output */
424 fprintf(stderr,"ERROR : could not send data\n");
425 close(socket);
426 sleep(5);
427 exit(4);
428 }
429 }
430}
431
432/*
433 * openserial
434 *
435 * Open the serial port with the given device name and configure it for
436 * reading NMEA data from a GPS receiver.
437 *
438 * Parameters:
439 * tty : pointer to : A zero-terminated string containing the device
440 * unsigned char name of the appropriate serial port.
441 * blocksz : integer : Block size for port I/O
442 * ttybaud : integer : Baud rate for port I/O
443 *
444 * Return Value:
445 * The function returns a file descriptor for the opened port if successful.
446 * The function returns -1 in the event of an error.
447 *
448 * Remarks:
449 *
450 */
451
452int openserial (u_char * tty, int blocksz, int ttybaud)
453{
454 int fd;
455 struct termios termios;
456
457 fd = open(tty, O_RDWR | O_NONBLOCK
458#ifdef O_EXLOCK /* for Linux */
459 | O_EXLOCK
460#endif
461 );
462 if (fd < 0) {
463 perror("open");
464 return (-1);
465 }
466 if (tcgetattr(fd, &termios) < 0) {
467
468 perror("tcgetattr");
469 return (-1);
470 }
471 termios.c_iflag = 0;
472 termios.c_oflag = 0; /* (ONLRET) */
473 termios.c_cflag = CS8 | CLOCAL | CREAD;
474 termios.c_lflag = 0;
475 {
476 int cnt;
477 for (cnt = 0; cnt < NCCS; cnt++)
478 termios.c_cc[cnt] = -1;
479 }
480 termios.c_cc[VMIN] = blocksz;
481 termios.c_cc[VTIME] = 2;
482
483#if (B4800 != 4800)
484 /*
485 * Not every system has speed settings equal to absolute speed value.
486 */
487
488 switch (ttybaud)
489 {
490 case 300:
491 ttybaud = B300;
492 break;
493 case 1200:
494 ttybaud = B1200;
495 break;
496 case 2400:
497 ttybaud = B2400;
498 break;
499 case 4800:
500 ttybaud = B4800;
501 break;
502 case 9600:
503 ttybaud = B9600;
504 break;
505 case 19200:
506 ttybaud = B19200;
507 break;
508 case 38400:
509 ttybaud = B38400;
510 break;
511#ifdef B57600
512 case 57600:
513 ttybaud = B57600;
514 break;
515#endif
516#ifdef B115200
517 case 115200:
518 ttybaud = B115200;
519 break;
520#endif
521#ifdef B230400
522 case 230400:
523 ttybaud = B230400;
524 break;
525#endif
526 default:
527 fprintf(stderr, "Baud settings not useful, using 19200\n");
528 ttybaud = B19200;
529 break;
530 }
531#endif
532
533 if (cfsetispeed(&termios, ttybaud) != 0)
534 {
535 perror("cfsetispeed");
536 return (-1);
537 }
538 if (cfsetospeed(&termios, ttybaud) != 0)
539 {
540 perror("cfsetospeed");
541 return (-1);
542 }
543 if (tcsetattr(fd, TCSANOW, &termios) < 0)
544 {
545 perror("tcsetattr");
546 return (-1);
547 }
548#if 1 /* WANT_BLOCKING_READ */
549 if (fcntl(fd, F_SETFL, 0) == -1)
550 {
551 perror("fcntl: set nonblock");
552 }
553#endif
554 return (fd);
555}
556
557/*
558 * usage
559 *
560 * Send a usage message to standard error and quit the program.
561 *
562 * Parameters:
563 * None.
564 *
565 * Return Value:
566 * The function does not return a value.
567 *
568 * Remarks:
569 *
570 */
571
572void usage (int rc)
573{
574 fprintf (stderr, "%s: application\n",VERSION);
575 fprintf (stderr, "Usage: %s [OPTIONS]\n",VERSION);
576 fprintf (stderr, " Options are:\n");
577 fprintf (stderr, " -a caster name or address (default: %s)\n", NTRIP_CASTER);
578 fprintf (stderr, " -p caster port (default: %d)\n", NTRIP_PORT);
579 fprintf (stderr, " -m caster mountpoint\n");
580 fprintf (stderr, " -c password for caster login\n");
581 fprintf (stderr, " -h|? print this help screen\n");
582 fprintf (stderr, " -M <mode> sets the mode\n");
583 fprintf (stderr, " (1=serial, 2=tcpsocket, 3=simulate)\n");
584 fprintf (stderr, " Mode = simulate:\n");
585 fprintf (stderr, " -s file, simulate data stream by reading log file\n");
586 fprintf (stderr, " default/current setting is %s\n", (simulate ? "enabled" : "disabled"));
587 fprintf (stderr, " Mode = serial:\n");
588 fprintf (stderr, " -b baud_rate, sets serial input baud rate\n");
589 fprintf (stderr, " default/current value is %d\n", ttybaud);
590 fprintf (stderr, " -i input_device, sets name of serial input device\n");
591 fprintf (stderr, " default/current value is %s\n", ttyport);
592 fprintf (stderr, " (normally a symbolic link to /dev/tty\?\?)\n");
593 fprintf (stderr, " Mode = tcpsocket:\n");
594 fprintf (stderr, " -P receiver port (default: 1025)\n");
595 fprintf (stderr, " -H hostname of TCP server (default: 127.0.0.1)\n");
596 fprintf (stderr, " \n");
597 exit (rc);
598}
Note: See TracBrowser for help on using the repository browser.