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

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

fixed warnings

File size: 20.3 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.13 2005/06/07 14:47:52 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
75#include <ctype.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <getopt.h>
79#include <netdb.h>
80#include <signal.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <unistd.h>
85#include <arpa/inet.h>
86#include <netinet/in.h>
87#include <sys/socket.h>
88#include <sys/termios.h>
89#include <sys/types.h>
90
91#ifndef MSG_DONTWAIT
92#define MSG_DONTWAIT 0 /* prevent compiler errors */
93#endif
94#ifndef O_EXLOCK
95#define O_EXLOCK 0 /* prevent compiler errors */
96#endif
97
98enum MODE { SERIAL = 1, TCPSOCKET = 2, INFILE = 3, SISNET = 4, UDPSOCKET = 5 };
99
100#define VERSION "NTRIP NtripServerLinux/0.12"
101#define BUFSZ 1024
102
103/* default socket source */
104#define SERV_HOST_ADDR "127.0.0.1"
105#define SERV_TCP_PORT 1025
106
107/* default destination */
108#define NTRIP_CASTER "www.euref-ip.net"
109#define NTRIP_PORT 80
110
111/* default sisnet source */
112#define SISNET_SERVER "131.176.49.142"
113#define SISNET_PORT 7777
114
115#define ALARMTIME 60
116
117static int ttybaud = 19200;
118static const char *ttyport = "/dev/gps";
119static const char *filepath = "/dev/stdin";
120static enum MODE mode = INFILE;
121static int sisnetv3 = 0;
122static int gpsfd = -1;
123
124/* Forward references */
125static int openserial(const char * tty, int blocksz, int baud);
126static void send_receive_loop(int sock, int fd, int sisnet);
127static void usage(int);
128
129#ifdef __GNUC__
130static __attribute__ ((noreturn)) void sighandler_alarm(
131int sig __attribute__((__unused__)))
132#else /* __GNUC__ */
133static void sighandler_alarm(int sig)
134#endif /* __GNUC__ */
135{
136 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
137 exit(1);
138}
139
140/*
141* main
142*
143* Main entry point for the program. Processes command-line arguments and
144* prepares for action.
145*
146* Parameters:
147* argc : integer : Number of command-line arguments.
148* argv : array of char : Command-line arguments as an array of zero-terminated
149* pointers to strings.
150*
151* Return Value:
152* The function does not return a value (although its return type is int).
153*
154* Remarks:
155*
156*/
157
158int main(int argc, char **argv)
159{
160 int c;
161 int size = 2048; /* for setting send buffer size */
162
163 const char *inhost = 0;
164 const char *outhost = 0;
165 unsigned int outport = 0;
166 unsigned int inport = 0;
167 const char *mountpoint = NULL;
168 const char *password = "";
169 const char *sisnetpassword = "";
170 const char *sisnetuser = "";
171 const char *initfile = NULL;
172 int bindmode = 0;
173 int sock_id;
174 char szSendBuffer[BUFSZ];
175 int nBufferBytes;
176 struct hostent *he;
177 struct sockaddr_in addr;
178
179 signal(SIGALRM,sighandler_alarm);
180 alarm(ALARMTIME);
181 /* get and check program arguments */
182 if(argc <= 1)
183 {
184 usage(2);
185 exit(1);
186 }
187 while((c = getopt(argc, argv, "M:i:h:b:p:s:a:m:c:H:P:f:l:u:V:B")) != EOF)
188 {
189 switch (c)
190 {
191 case 'M':
192 if(!strcmp(optarg, "serial")) mode = 1;
193 else if(!strcmp(optarg, "tcpsocket")) mode = 2;
194 else if(!strcmp(optarg, "file")) mode = 3;
195 else if(!strcmp(optarg, "sisnet")) mode = 4;
196 else if(!strcmp(optarg, "udpsocket")) mode = 5;
197 else mode = atoi(optarg);
198 if((mode == 0) || (mode > 5))
199 {
200 fprintf(stderr, "ERROR: can't convert %s to a valid mode\n", optarg);
201 usage(-1);
202 }
203 break;
204 case 'i': /* gps serial ttyport */
205 ttyport = optarg;
206 break;
207 case 'B':
208 bindmode = 1;
209 break;
210 case 'V':
211 if(!strcmp("3.0", optarg)) sisnetv3 = 1;
212 else if(strcmp("2.1", optarg))
213 {
214 fprintf(stderr, "ERROR: unknown SISNeT version %s\n", optarg);
215 usage(-2);
216 }
217 case 'b': /* serial ttyin speed */
218 ttybaud = atoi(optarg);
219 if(ttybaud <= 1)
220 {
221 fprintf(stderr, "ERROR: can't convert %s to valid serial speed\n", optarg);
222 usage(1);
223 }
224 break;
225 case 'a': /* http server IP address A.B.C.D */
226 outhost = optarg;
227 break;
228 case 'p': /* http server port */
229 outport = atoi(optarg);
230 if(outport <= 1 || outport > 65535)
231 {
232 fprintf(stderr, "ERROR: can't convert %s to a valid HTTP server port\n",
233 optarg);
234 usage(1);
235 }
236 break;
237 case 'm': /* http server mountpoint */
238 mountpoint = optarg;
239 break;
240 case 's': /* datastream from file */
241 filepath = optarg;
242 break;
243 case 'f':
244 initfile = optarg;
245 break;
246 case 'u':
247 sisnetuser = optarg;
248 break;
249 case 'l':
250 sisnetpassword = optarg;
251 break;
252 case 'c': /* password */
253 password = optarg;
254 break;
255 case 'H': /* host */
256 inhost = optarg;
257 break;
258 case 'P': /* port */
259 inport = atoi(optarg);
260 if(inport <= 1 || inport > 65535)
261 {
262 fprintf(stderr, "ERROR: can't convert %s to a valid port number\n",
263 optarg);
264 usage(1);
265 }
266 break;
267 case 'h': /* help */
268 case '?':
269 usage(0);
270 break;
271 default:
272 usage(2);
273 break;
274 }
275 }
276
277 argc -= optind;
278 argv += optind;
279
280 if(argc > 0)
281 {
282 fprintf(stderr, "ERROR: Extra args on command line: ");
283 for(; argc > 0; argc--)
284 {
285 fprintf(stderr, " %s", *argv++);
286 }
287 fprintf(stderr, "\n");
288 usage(1); /* never returns */
289 }
290
291 if(mountpoint == NULL)
292 {
293 fprintf(stderr, "ERROR: Missing mountpoint argument\n");
294 exit(1);
295 }
296 if(!password[0])
297 {
298 fprintf(stderr, "WARNING: Missing password argument - are you really sure?\n");
299 }
300
301 if(!outhost) outhost = NTRIP_CASTER;
302 if(!outport) outport = NTRIP_PORT;
303
304 switch(mode)
305 {
306 case INFILE:
307 {
308 gpsfd = open(filepath, O_RDONLY);
309 if(!gpsfd)
310 {
311 perror("ERROR: opening input file");
312 exit(1);
313 }
314 /* set blocking mode in case it was not set (seems to be sometimes for fifo's) */
315 fcntl(gpsfd, F_SETFL, 0);
316 printf("file input: file = %s\n", filepath);
317 }
318 break;
319 case SERIAL: /* open serial port */
320 {
321 gpsfd = openserial(ttyport, 1, ttybaud);
322 if(gpsfd < 0)
323 {
324 exit(1);
325 }
326 printf("serial input: device = %s, speed = %d\n", ttyport, ttybaud);
327 }
328 break;
329 case TCPSOCKET: case UDPSOCKET: case SISNET:
330 {
331 if(mode == SISNET)
332 {
333 if(!inhost) inhost = SISNET_SERVER;
334 if(!inport) inport = SISNET_PORT;
335 }
336 else
337 {
338 if(!inport) inport = SERV_TCP_PORT;
339 if(!inhost) inhost = "127.0.0.1";
340 }
341
342 if(!(he = gethostbyname(inhost)))
343 {
344 fprintf(stderr, "ERROR: host %s unknown\n", inhost);
345 usage(-2);
346 }
347
348 if((gpsfd = socket(AF_INET, mode == UDPSOCKET ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
349 {
350 fprintf(stderr, "ERROR: can't create socket\n");
351 exit(1);
352 }
353
354 memset((char *) &addr, 0x00, sizeof(addr));
355 if(!bindmode)
356 memcpy(&addr.sin_addr, he->h_addr, (size_t)he->h_length);
357 addr.sin_family = AF_INET;
358 addr.sin_port = htons(inport);
359
360 printf("%s input: host = %s, port = %d%s%s%s\n", mode == SISNET ? "sisnet"
361 : mode == TCPSOCKET ? "tcp socket" : "udp socket",
362 bindmode ? "127.0.0.1" : inet_ntoa(addr.sin_addr), inport,
363 initfile ? ", initfile = " : "",
364 initfile ? initfile : "", bindmode ? " binding mode" : "");
365
366 if(bindmode)
367 {
368 if(bind(gpsfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
369 {
370 fprintf(stderr, "ERROR: can't bind input to port %d\n", inport);
371 exit(1);
372 }
373 }
374 else if(connect(gpsfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
375 {
376 fprintf(stderr, "ERROR: can't connect input to %s at port %d\n",
377 inet_ntoa(addr.sin_addr), inport);
378 exit(1);
379 }
380 if(initfile && mode != SISNET)
381 {
382 char buffer[1024];
383 FILE *fh;
384 int i;
385
386 if((fh = fopen(initfile, "r")))
387 {
388 while((i = fread(buffer, 1, sizeof(buffer), fh)) > 0)
389 {
390 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
391 {
392 perror("ERROR: sending init file");
393 exit(1);
394 }
395 }
396 if(i < 0)
397 {
398 perror("ERROR: reading init file");
399 exit(1);
400 }
401 fclose(fh);
402 }
403 else
404 {
405 fprintf(stderr, "ERROR: can't read init file %s\n", initfile);
406 exit(1);
407 }
408 }
409 }
410 if(mode == SISNET)
411 {
412 int i, j;
413 char buffer[1024];
414
415 i = snprintf(buffer, sizeof(buffer), sisnetv3 ? "AUTH,%s,%s\r\n" : "AUTH,%s,%s",
416 sisnetuser,sisnetpassword);
417 if((send(gpsfd, buffer, (size_t)i, 0)) != i)
418 {
419 perror("ERROR: sending authentication");
420 exit(1);
421 }
422 i = sisnetv3 ? 7 : 5;
423 if((j = recv(gpsfd, buffer, i, 0)) != i && strncmp("*AUTH", buffer, 5))
424 {
425 fprintf(stderr, "ERROR: SISNeT connect failed:");
426 for(i = 0; i < j; ++i)
427 {
428 if(buffer[i] != '\r' && buffer[i] != '\n')
429 {
430 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
431 }
432 }
433 fprintf(stderr, "\n");
434 exit(1);
435 }
436 }
437 break;
438 default:
439 usage(-1);
440 break;
441 }
442
443 /* ----- main part ----- */
444 while(1)
445 {
446 if(!(he = gethostbyname(outhost)))
447 {
448 fprintf(stderr, "ERROR: host %s unknown\n", outhost);
449 usage(-2);
450 }
451
452 /* create socket */
453 if((sock_id = socket(AF_INET, SOCK_STREAM, 0)) < 0)
454 {
455 fprintf(stderr, "ERROR: could not create socket\n");
456 exit(2);
457 }
458
459 memset((char *) &addr, 0x00, sizeof(addr));
460 memcpy(&addr.sin_addr, he->h_addr, (size_t)he->h_length);
461 addr.sin_family = AF_INET;
462 addr.sin_port = htons(outport);
463
464 /* connect to caster */
465 fprintf(stderr, "caster output: host = %s, port = %d, mountpoint = %s\n",
466 inet_ntoa(addr.sin_addr), outport, mountpoint);
467 if(connect(sock_id, (struct sockaddr *) &addr, sizeof(addr)) < 0)
468 {
469 fprintf(stderr, "ERROR: can't connect output to %s at port %d\n",
470 inet_ntoa(addr.sin_addr), outport);
471 close(sock_id);
472 exit(3);
473 }
474
475 /* set socket buffer size */
476 setsockopt(sock_id, SOL_SOCKET, SO_SNDBUF, (const char *) &size,
477 sizeof(const char *));
478 /* send message to caster */
479 szSendBuffer[0] = '\0';
480 sprintf(szSendBuffer, "SOURCE %s /%s\r\n", password, mountpoint);
481 strcat(szSendBuffer, "Source-Agent: ");
482 strcat(szSendBuffer, VERSION);
483 strcat(szSendBuffer, "\r\n");
484 strcat(szSendBuffer, "\r\n");
485 strcat(szSendBuffer, "\0");
486 nBufferBytes = strlen(szSendBuffer);
487 if((send(sock_id, szSendBuffer, (size_t)nBufferBytes, 0)) != nBufferBytes)
488 {
489 fprintf(stderr, "ERROR: could not send to caster\n");
490 close(sock_id);
491 sleep(5);
492 exit(0);
493 }
494 /* check caster's response */
495 nBufferBytes = recv(sock_id, szSendBuffer, sizeof(szSendBuffer), 0);
496 szSendBuffer[nBufferBytes] = '\0';
497 if(strcmp(szSendBuffer, "OK\r\n"))
498 {
499 char *a;
500 fprintf(stderr, "ERROR: caster's reply is not OK : ");
501 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
502 {
503 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
504 }
505 fprintf(stderr, "\n");
506 close(sock_id);
507 sleep(5);
508 exit(0);
509 }
510 printf("connection successfull\n");
511 send_receive_loop(sock_id, gpsfd, mode == SISNET);
512 }
513 exit(0);
514}
515
516static void send_receive_loop(int sock, int fd, int sisnet)
517{
518 char buffer[BUFSZ] = { 0 };
519 char sisnetbackbuffer[200];
520 int nBufferBytes = 0;
521 /* data transmission */
522 printf("transfering data ...\n");
523 while(1)
524 {
525 alarm(ALARMTIME);
526
527 if(!nBufferBytes)
528 {
529 if(sisnet)
530 {
531 int i;
532 /* a somewhat higher rate than 1 second to get really each block */
533 /* means we need to skip double blocks sometimes */
534 struct timeval tv = {0,700000};
535 select(0, 0, 0, 0, &tv);
536 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
537 i = (sisnetv3 ? 5 : 3);
538 if((send(gpsfd, "MSG\r\n", i, 0)) != i)
539 {
540 perror("ERROR: sending data request");
541 exit(1);
542 }
543 }
544 /* receiving data */
545 nBufferBytes = read(fd, buffer, BUFSZ);
546 if(!nBufferBytes)
547 {
548 printf("WARNING: no data received from input\n");
549 continue;
550 }
551 else if(nBufferBytes < 0)
552 {
553 perror("ERROR: reading input failed");
554 exit(1);
555 }
556 /* we can compare the whole buffer, as the additional bytes remain unchanged */
557 if(!memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer)))
558 {
559 nBufferBytes = 0;
560 }
561 }
562 if(nBufferBytes)
563 {
564 int i;
565 /* send data */
566 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
567 != nBufferBytes)
568 {
569 if(i < 0 && errno != EAGAIN)
570 {
571 perror("WARNING: could not send data - retry connection");
572 close(sock);
573 sleep(5);
574 return;
575 }
576 else if(i)
577 {
578 memmove(buffer, buffer+i, (size_t)(nBufferBytes-i));
579 nBufferBytes -= i;
580 }
581 }
582 else
583 {
584 nBufferBytes = 0;
585 }
586 }
587 }
588}
589
590/*
591 * openserial
592 *
593 * Open the serial port with the given device name and configure it for
594 * reading NMEA data from a GPS receiver.
595 *
596 * Parameters:
597 * tty : pointer to : A zero-terminated string containing the device
598 * unsigned char name of the appropriate serial port.
599 * blocksz : integer : Block size for port I/O
600 * baud : integer : Baud rate for port I/O
601 *
602 * Return Value:
603 * The function returns a file descriptor for the opened port if successful.
604 * The function returns -1 in the event of an error.
605 *
606 * Remarks:
607 *
608 */
609
610static int openserial(const char * tty, int blocksz, int baud)
611{
612 int fd;
613 struct termios termios;
614
615 fd = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
616 if(fd < 0)
617 {
618 perror("ERROR: opening serial connection");
619 return (-1);
620 }
621 if(tcgetattr(fd, &termios) < 0)
622 {
623 perror("ERROR: get serial attributes");
624 return (-1);
625 }
626 termios.c_iflag = 0;
627 termios.c_oflag = 0; /* (ONLRET) */
628 termios.c_cflag = CS8 | CLOCAL | CREAD;
629 termios.c_lflag = 0;
630 {
631 int cnt;
632 for(cnt = 0; cnt < NCCS; cnt++)
633 termios.c_cc[cnt] = -1;
634 }
635 termios.c_cc[VMIN] = blocksz;
636 termios.c_cc[VTIME] = 2;
637
638#if (B4800 != 4800)
639 /*
640 * Not every system has speed settings equal to absolute speed value.
641 */
642
643 switch (baud)
644 {
645 case 300:
646 baud = B300;
647 break;
648 case 1200:
649 baud = B1200;
650 break;
651 case 2400:
652 baud = B2400;
653 break;
654 case 4800:
655 baud = B4800;
656 break;
657 case 9600:
658 baud = B9600;
659 break;
660 case 19200:
661 baud = B19200;
662 break;
663 case 38400:
664 baud = B38400;
665 break;
666#ifdef B57600
667 case 57600:
668 baud = B57600;
669 break;
670#endif
671#ifdef B115200
672 case 115200:
673 baud = B115200;
674 break;
675#endif
676#ifdef B230400
677 case 230400:
678 baud = B230400;
679 break;
680#endif
681 default:
682 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
683 baud = B19200;
684 break;
685 }
686#endif
687
688 if(cfsetispeed(&termios, baud) != 0)
689 {
690 perror("ERROR: setting serial speed with cfsetispeed");
691 return (-1);
692 }
693 if(cfsetospeed(&termios, baud) != 0)
694 {
695 perror("ERROR: setting serial speed with cfsetospeed");
696 return (-1);
697 }
698 if(tcsetattr(fd, TCSANOW, &termios) < 0)
699 {
700 perror("ERROR: setting serial attributes");
701 return (-1);
702 }
703 if(fcntl(fd, F_SETFL, 0) == -1)
704 {
705 perror("WARNING: setting blocking mode failed");
706 }
707 return (fd);
708}
709
710/*
711 * usage
712 *
713 * Send a usage message to standard error and quit the program.
714 *
715 * Parameters:
716 * None.
717 *
718 * Return Value:
719 * The function does not return a value.
720 *
721 * Remarks:
722 *
723 */
724
725static
726#ifdef __GNUC__
727__attribute__ ((noreturn))
728#endif /* __GNUC__ */
729void usage(int rc)
730{
731 fprintf(stderr, "Usage: %s [OPTIONS]\n", VERSION);
732 fprintf(stderr, " Options are:\n");
733 fprintf(stderr, " -a caster name or address (default: %s)\n",
734 NTRIP_CASTER);
735 fprintf(stderr, " -p caster port (default: %d)\n", NTRIP_PORT);
736 fprintf(stderr, " -m caster mountpoint\n");
737 fprintf(stderr, " -c password for caster login\n");
738 fprintf(stderr, " -h|? print this help screen\n");
739 fprintf(stderr, " -M <mode> sets the mode\n");
740 fprintf(stderr, " (1=serial, 2=tcpsocket, 3=file, 4=sisnet, 5=udpsocket)\n");
741 fprintf(stderr, " Mode = file:\n");
742 fprintf(stderr, " -s file, simulate data stream by reading log file\n");
743 fprintf(stderr, " default/current setting is %s\n", filepath);
744 fprintf(stderr, " Mode = serial:\n");
745 fprintf(stderr, " -b baud_rate, sets serial input baud rate\n");
746 fprintf(stderr, " default/current value is %d\n", ttybaud);
747 fprintf(stderr, " -i input_device, sets name of serial input device\n");
748 fprintf(stderr, " default/current value is %s\n", ttyport);
749 fprintf(stderr, " (normally a symbolic link to /dev/tty\?\?)\n");
750 fprintf(stderr, " Mode = tcpsocket or udpsocket:\n");
751 fprintf(stderr, " -P receiver port (default: %d)\n", SERV_TCP_PORT);
752 fprintf(stderr, " -H hostname of TCP server (default: %s)\n", SERV_HOST_ADDR);
753 fprintf(stderr, " -f initfile send to server\n");
754 fprintf(stderr, " -B bindmode (bind to incoming UDP stream)\n");
755 fprintf(stderr, " Mode = sisnet:\n");
756 fprintf(stderr, " -P receiver port (default: %d)\n", SISNET_PORT);
757 fprintf(stderr, " -H hostname of TCP server (default: %s)\n", SISNET_SERVER);
758 fprintf(stderr, " -u username\n");
759 fprintf(stderr, " -l password\n");
760 fprintf(stderr, " -V version [2.1 or 3.0] (default: 2.1)\n");
761 fprintf(stderr, "\n");
762 exit(rc);
763}
Note: See TracBrowser for help on using the repository browser.