source: ntrip/trunk/ntripserver/ntripserver.c@ 1148

Last change on this file since 1148 was 1113, checked in by stuerze, 16 years ago

init file option extended for serial ports

File size: 65.1 KB
RevLine 
[485]1/*
[1113]2 * $Id: ntripserver.c,v 1.44 2008/06/06 07:34:09 stuerze Exp $
[485]3 *
4 * Copyright (c) 2003...2007
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 * The BKG disclaims any liability nor responsibility to any person or
13 * entity with respect to any loss or damage caused, or alleged to be
14 * caused, directly or indirectly by the use and application of the NTRIP
15 * technology.
16 *
17 * For latest information and updates, access:
18 * http://igs.bkg.bund.de/index_ntrip_down.htm
19 *
20 * BKG, Frankfurt, Germany, February 2007
21 * E-mail: euref-ip@bkg.bund.de
22 *
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 */
37
38/* CVS revision and version */
[1113]39static char revisionstr[] = "$Revision: 1.44 $";
40static char datestr[] = "$Date: 2008/06/06 07:34:09 $";
[485]41
42#include <ctype.h>
43#include <errno.h>
44#include <fcntl.h>
45#include <getopt.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
[653]49#include <sys/time.h>
50#include <sys/types.h>
51#include <time.h>
52#include <signal.h>
[485]53#include <unistd.h>
54
[653]55#ifdef WINDOWSVERSION
56 #include <winsock2.h>
57 #include <io.h>
58 #include <sys/stat.h>
59 #include <windows.h>
60 typedef SOCKET sockettype;
61 typedef u_long in_addr_t;
62 typedef size_t socklen_t;
63 typedef u_short uint16_t;
64#else
65 typedef int sockettype;
66 #include <arpa/inet.h>
67 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #include <netdb.h>
70 #include <sys/termios.h>
71 #define closesocket(sock) close(sock)
72 #define INVALID_HANDLE_VALUE -1
73 #define INVALID_SOCKET -1
74#endif
75
[485]76#ifndef COMPILEDATE
77#define COMPILEDATE " built " __DATE__
78#endif
79
[653]80#define ALARMTIME (2*60)
81
[485]82#ifndef MSG_DONTWAIT
83#define MSG_DONTWAIT 0 /* prevent compiler errors */
84#endif
85#ifndef O_EXLOCK
86#define O_EXLOCK 0 /* prevent compiler errors */
87#endif
88
89enum MODE { SERIAL = 1, TCPSOCKET = 2, INFILE = 3, SISNET = 4, UDPSOCKET = 5,
90CASTER = 6, LAST };
91
[487]92enum OUTMODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, END };
[485]93
[493]94#define AGENTSTRING "NTRIP NtripServerPOSIX"
[485]95#define BUFSZ 1024
96#define SZ 64
97
98/* default socket source */
99#define SERV_HOST_ADDR "localhost"
100#define SERV_TCP_PORT 2101
101
102/* default destination */
103#define NTRIP_CASTER "www.euref-ip.net"
104#define NTRIP_PORT 2101
105
106#define SISNET_SERVER "131.176.49.142"
107#define SISNET_PORT 7777
108
109#define RTP_VERSION 2
110#define TIME_RESOLUTION 125
111
112static int ttybaud = 19200;
113static const char *ttyport = "/dev/gps";
114static const char *filepath = "/dev/stdin";
115static enum MODE inputmode = INFILE;
116static int sisnet = 31;
[653]117static int gps_file = -1;
118static sockettype gps_socket = INVALID_SOCKET;
119static sockettype socket_tcp = INVALID_SOCKET;
120static sockettype socket_udp = INVALID_SOCKET;
121#ifndef WINDOWSVERSION
122static int gps_serial = INVALID_HANDLE_VALUE;
123static int sigpipe_received = 0;
124#else
125HANDLE gps_serial = INVALID_HANDLE_VALUE;
126#endif
127static int sigalarm_received = 0;
[485]128static int sigint_received = 0;
[487]129static int reconnect_sec = 1;
[915]130static const char * casterouthost = NTRIP_CASTER;
131static char rtsp_extension[SZ] = "";
132static const char * mountpoint = NULL;
133static int udp_cseq = 1;
[485]134
135/* Forward references */
[653]136static void send_receive_loop(sockettype sock, int outmode,
[765]137 struct sockaddr * pcasterRTP, socklen_t length, int rtpssrc);
[485]138static void usage(int, char *);
139static int encode(char *buf, int size, const char *user, const char *pwd);
[653]140static int send_to_caster(char *input, sockettype socket, int input_size);
[915]141static void close_session(const char *caster_addr, const char *mountpoint,
142 int session, char *rtsp_ext, int fallback);
[487]143static int reconnect(int rec_sec, int rec_sec_max);
[485]144static void handle_sigint(int sig);
[653]145static void setup_signal_handler(int sig, void (*handler)(int));
146#ifndef WINDOWSVERSION
147static int openserial(const char * tty, int blocksz, int baud);
148static void handle_sigpipe(int sig);
[487]149static void handle_alarm(int sig);
[653]150#else
151static HANDLE openserial(const char * tty, int baud);
152#endif
[485]153
[653]154
[485]155/*
156* main
157*
158* Main entry point for the program. Processes command-line arguments and
159* prepares for action.
160*
161* Parameters:
162* argc : integer : Number of command-line arguments.
163* argv : array of char : Command-line arguments as an array of
164* zero-terminated pointers to strings.
165*
166* Return Value:
167* The function does not return a value (although its return type is int).
168*
169* Remarks:
170*
171*/
172
173int main(int argc, char **argv)
174{
175 int c;
176 int size = 2048; /* for setting send buffer size */
177 struct sockaddr_in caster;
178 const char * proxyhost = "";
179 unsigned int proxyport = 0;
180 /*** INPUT ***/
181 const char * casterinhost = 0;
182 unsigned int casterinport = 0;
183 const char * inhost = 0;
184 unsigned int inport = 0;
185
186 char get_extension[SZ] = "";
187
188 struct hostent * he;
189
190 const char * sisnetpassword = "";
191 const char * sisnetuser = "";
192
193 const char * stream_name = 0;
194 const char * stream_user = 0;
195 const char * stream_password = 0;
196
197 const char * recvrid= 0;
198 const char * recvrpwd = 0;
199
200 const char * initfile = NULL;
201
202 int bindmode = 0;
203
204 /*** OUTPUT ***/
205 unsigned int casteroutport = NTRIP_PORT;
206 const char * outhost = 0;
207 unsigned int outport = 0;
208 char post_extension[SZ] = "";
209
[933]210 const char * ntrip_str = "";
[485]211
212 const char * user = "";
213 const char * password = "";
214
[487]215 int outputmode = NTRIP1;
[485]216
217 struct sockaddr_in casterRTP;
218 struct sockaddr_in local;
219 int client_port = 0;
220 int server_port = 0;
221 int session = 0;
222 socklen_t len = 0;
223 int i = 0;
224
225 char szSendBuffer[BUFSZ];
226 char authorization[SZ];
227 int nBufferBytes = 0;
228 char * dlim = " \r\n=";
229 char * token;
230 char * tok_buf[BUFSZ];
231
[487]232 int reconnect_sec_max = 0;
233
[485]234 setbuf(stdout, 0);
235 setbuf(stdin, 0);
236 setbuf(stderr, 0);
237
238 {
239 char *a;
240 int i = 0;
241 for(a = revisionstr+11; *a && *a != ' '; ++a)
242 revisionstr[i++] = *a;
243 revisionstr[i] = 0;
244 datestr[0] = datestr[7];
245 datestr[1] = datestr[8];
246 datestr[2] = datestr[9];
247 datestr[3] = datestr[10];
248 datestr[5] = datestr[12];
249 datestr[6] = datestr[13];
250 datestr[8] = datestr[15];
251 datestr[9] = datestr[16];
252 datestr[4] = datestr[7] = '-';
253 datestr[10] = 0;
254 }
255
[653]256 /* setup signal handler for CTRL+C */
257 setup_signal_handler(SIGINT, handle_sigint);
258#ifndef WINDOWSVERSION
259 /* setup signal handler for boken pipe */
260 setup_signal_handler(SIGPIPE, handle_sigpipe);
[485]261 /* setup signal handler for timeout */
[487]262 setup_signal_handler(SIGALRM, handle_alarm);
[485]263 alarm(ALARMTIME);
[653]264#else
265 /* winsock initialization */
266 WSADATA wsaData;
267 if (WSAStartup(MAKEWORD(1,1), &wsaData))
268 {
269 fprintf(stderr, "Could not init network access.\n");
270 return 20;
271 }
272#endif
[487]273
[485]274 /* get and check program arguments */
275 if(argc <= 1)
276 {
277 usage(2, argv[0]);
278 exit(1);
279 }
280 while((c = getopt(argc, argv,
[487]281 "M:i:h:b:p:s:a:m:c:H:P:f:x:y:l:u:V:D:U:W:O:E:F:R:N:n:B")) != EOF)
[485]282 {
283 switch (c)
284 {
285 case 'M': /*** InputMode ***/
286 if(!strcmp(optarg, "serial")) inputmode = SERIAL;
287 else if(!strcmp(optarg, "tcpsocket")) inputmode = TCPSOCKET;
288 else if(!strcmp(optarg, "file")) inputmode = INFILE;
289 else if(!strcmp(optarg, "sisnet")) inputmode = SISNET;
290 else if(!strcmp(optarg, "udpsocket")) inputmode = UDPSOCKET;
291 else if(!strcmp(optarg, "caster")) inputmode = CASTER;
292 else inputmode = atoi(optarg);
293 if((inputmode == 0) || (inputmode >= LAST))
294 {
295 fprintf(stderr, "ERROR: can't convert <%s> to a valid InputMode\n",
296 optarg);
297 usage(-1, argv[0]);
298 }
299 break;
300 case 'i': /* serial input device */
301 ttyport = optarg;
302 break;
303 case 'B': /* bind to incoming UDP stream */
304 bindmode = 1;
305 break;
306 case 'V': /* Sisnet data server version number */
307 if(!strcmp("3.0", optarg)) sisnet = 30;
308 else if(!strcmp("3.1", optarg)) sisnet = 31;
309 else if(!strcmp("2.1", optarg)) sisnet = 21;
310 else
311 {
312 fprintf(stderr, "ERROR: unknown SISNeT version <%s>\n", optarg);
313 usage(-2, argv[0]);
314 }
315 break;
316 case 'b': /* serial input baud rate */
317 ttybaud = atoi(optarg);
318 if(ttybaud <= 1)
319 {
320 fprintf(stderr, "ERROR: can't convert <%s> to valid serial baud rate\n",
321 optarg);
322 usage(1, argv[0]);
323 }
324 break;
325 case 'a': /* Destination caster address */
326 casterouthost = optarg;
327 break;
328 case 'p': /* Destination caster port */
329 casteroutport = atoi(optarg);
330 if(casteroutport <= 1 || casteroutport > 65535)
331 {
332 fprintf(stderr,
333 "ERROR: can't convert <%s> to a valid HTTP server port\n", optarg);
334 usage(1, argv[0]);
335 }
336 break;
337 case 'm': /* Destination caster mountpoint for stream upload */
338 mountpoint = optarg;
339 break;
340 case 's': /* File name for input data simulation from file */
341 filepath = optarg;
342 break;
343 case 'f': /* name of an initialization file */
344 initfile = optarg;
345 break;
346 case 'x': /* user ID to access incoming stream */
347 recvrid = optarg;
348 break;
349 case 'y': /* password to access incoming stream */
350 recvrpwd = optarg;
351 break;
352 case 'u': /* Sisnet data server user ID */
353 sisnetuser = optarg;
354 break;
355 case 'l': /* Sisnet data server password */
356 sisnetpassword = optarg;
357 break;
358 case 'c': /* DestinationCaster password for stream upload to mountpoint */
359 password = optarg;
360 break;
361 case 'H': /* Input host address*/
362 casterinhost = optarg;
363 break;
364 case 'P': /* Input port */
365 casterinport = atoi(optarg);
366 if(casterinport <= 1 || casterinport > 65535)
367 {
368 fprintf(stderr, "ERROR: can't convert <%s> to a valid port number\n",
369 optarg);
370 usage(1, argv[0]);
371 }
372 break;
373 case 'D': /* Source caster mountpoint for stream input */
374 stream_name = optarg;
375 break;
376 case 'U': /* Source caster user ID for input stream access */
377 stream_user = optarg;
378 break;
379 case 'W': /* Source caster password for input stream access */
380 stream_password = optarg;
381 break;
382 case 'E': /* Proxy Server */
383 proxyhost = optarg;
384 break;
385 case 'F': /* Proxy port */
386 proxyport = atoi(optarg);
387 break;
[487]388 case 'R': /* maximum delay between reconnect attempts in seconds */
389 reconnect_sec_max = atoi(optarg);
390 break;
[485]391 case 'O': /* OutputMode */
392 outputmode = 0;
393 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
[487]394 outputmode = NTRIP1;
[485]395 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
396 outputmode = HTTP;
397 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
398 outputmode = RTSP;
399 else outputmode = atoi(optarg);
400 if((outputmode == 0) || (outputmode >= END))
401 {
402 fprintf(stderr, "ERROR: can't convert <%s> to a valid OutputMode\n",
403 optarg);
404 usage(-1, argv[0]);
405 }
406 break;
407 case 'n': /* Destination caster user ID for stream upload to mountpoint */
408 user = optarg;
409 break;
410 case 'N': /* Ntrip-STR, optional for Ntrip Version 2.0 */
411 ntrip_str = optarg;
412 break;
413 case 'h': /* print help screen */
414 case '?':
415 usage(0, argv[0]);
416 break;
417 default:
418 usage(2, argv[0]);
419 break;
420 }
421 }
422
423 argc -= optind;
424 argv += optind;
425
426 /*** argument analysis ***/
427 if(argc > 0)
428 {
429 fprintf(stderr, "ERROR: Extra args on command line: ");
430 for(; argc > 0; argc--)
431 {
432 fprintf(stderr, " %s", *argv++);
433 }
434 fprintf(stderr, "\n");
435 usage(1, argv[0]); /* never returns */
436 }
437
[487]438 if(outputmode != NTRIP1)
[485]439 {
[487]440 fprintf(stderr, "\nWARNING: *** NTRIP VERSION 2 PROTOCOL IS STILL"
441 " BETA AND MAY BE CHANGED ***\n\n");
442 }
[765]443
[915]444 if(ntrip_str && (outputmode == NTRIP1))
[487]445 {
[485]446 fprintf(stderr, "WARNING: OutputMode is Ntrip version 1.0"
447 " - Ntrip-STR will not be considered\n");
448 }
449
[487]450 if((reconnect_sec_max > 0) && (reconnect_sec_max < 256))
451 {
452 fprintf(stderr,
453 "WARNING: maximum delay between reconnect attemts changed from %d to 256 seconds\n"
454 , reconnect_sec_max);
455 reconnect_sec_max = 256;
456 }
457
[485]458 if(!mountpoint)
459 {
460 fprintf(stderr, "ERROR: Missing mountpoint argument for stream upload\n");
461 exit(1);
462 }
463
464 if(!password[0])
465 {
466 fprintf(stderr, "WARNING: Missing password argument for stream upload - "
467 "are you really sure?\n");
468 }
469 else
470 {
471 nBufferBytes += encode(authorization, sizeof(authorization), user,
472 password);
473 if(nBufferBytes > (int)sizeof(authorization))
474 {
475 fprintf(stderr, "ERROR: user ID and/or password too long: %d (%d)\n"
476 " user ID: %s \npassword: <%s>\n",
477 nBufferBytes, (int)sizeof(authorization), user, password);
478 exit(1);
479 }
480 }
481
482 if(stream_name && stream_user && !stream_password)
483 {
484 fprintf(stderr, "WARNING: Missing password argument for stream download"
485 " - are you really sure?\n");
486 }
487
488 /*** proxy server handling ***/
489 if(*proxyhost)
490 {
491 outhost = inhost = proxyhost;
492 outport = inport = proxyport;
493 i = snprintf(szSendBuffer, sizeof(szSendBuffer),"http://%s:%d",
494 casterouthost, casteroutport);
495 if((i > SZ) || (i < 0))
496 {
497 fprintf(stderr, "ERROR: Destination caster name/port to long - "
498 "length = %d (max: %d)\n", i, SZ);
499 exit(0);
500 }
501 else
502 {
503 strncpy(post_extension, szSendBuffer, (size_t)i);
504 strcpy(szSendBuffer, "");
505 i = snprintf(szSendBuffer, sizeof(szSendBuffer),":%d", casteroutport);
506 strncpy(rtsp_extension, szSendBuffer, SZ);
507 strcpy(szSendBuffer,""); i = 0;
508 }
509 i = snprintf(szSendBuffer, sizeof(szSendBuffer),"http://%s:%d", casterinhost, casterinport);
510 if((i > SZ) || (i < 0))
511 {
[487]512 fprintf(stderr,"ERROR: Destination caster name/port to long - length = %d (max: %d)\n", i, SZ);
[485]513 exit(0);
514 }
515 else
516 {
517 strncpy(get_extension, szSendBuffer, (size_t)i);
518 strcpy(szSendBuffer, "");
519 i = 0;
520 }
521 }
522 else
523 {
524 outhost = casterouthost; outport = casteroutport;
525 inhost = casterinhost; inport = casterinport;
526 }
527
[487]528 while(inputmode != LAST)
[485]529 {
[487]530 int input_init = 1;
[653]531 if(sigint_received) break;
[487]532 /*** InputMode handling ***/
533 switch(inputmode)
[485]534 {
[487]535 case INFILE:
[485]536 {
[653]537 if((gps_file = open(filepath, O_RDONLY)) < 0)
[487]538 {
539 perror("ERROR: opening input file");
540 exit(1);
541 }
[653]542#ifndef WINDOWSVERSION
[487]543 /* set blocking inputmode in case it was not set
544 (seems to be sometimes for fifo's) */
[653]545 fcntl(gps_file, F_SETFL, 0);
546#endif
[487]547 printf("file input: file = %s\n", filepath);
[485]548 }
[487]549 break;
550 case SERIAL: /* open serial port */
[485]551 {
[653]552#ifndef WINDOWSVERSION
553 gps_serial = openserial(ttyport, 1, ttybaud);
554#else
555 gps_serial = openserial(ttyport, ttybaud);
556#endif
557 if(gps_serial == INVALID_HANDLE_VALUE) exit(1);
[487]558 printf("serial input: device = %s, speed = %d\n", ttyport, ttybaud);
[1113]559
560 if(initfile)
561 {
562 char buffer[1024];
563 FILE *fh;
564 int i;
565
566 if((fh = fopen(initfile, "r")))
567 {
568 while((i = fread(buffer, 1, sizeof(buffer), fh)) > 0)
569 {
570#ifndef WINDOWSVERSION
571 if((write(gps_serial, buffer, i)) != i)
572 {
573 perror("WARNING: sending init file");
574 input_init = 0;
575 break;
576 }
577#else
578 DWORD nWrite = -1;
579 if(!WriteFile(gps_serial, buffer, sizeof(buffer), &nWrite, NULL))
580 {
581 fprintf(stderr,"ERROR: sending init file \n");
582 input_init = 0;
583 break;
584 }
585 i = (int)nWrite;
586#endif
587 }
588 if(i < 0)
589 {
590 perror("ERROR: reading init file");
591 reconnect_sec_max = 0;
592 input_init = 0;
593 break;
594 }
595 fclose(fh);
596 }
597 else
598 {
599 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
600 reconnect_sec_max = 0;
601 input_init = 0;
602 break;
603 }
604 }
[485]605 }
[487]606 break;
607 case TCPSOCKET: case UDPSOCKET: case SISNET: case CASTER:
[485]608 {
[487]609 if(inputmode == SISNET)
610 {
611 if(!inhost) inhost = SISNET_SERVER;
612 if(!inport) inport = SISNET_PORT;
613 }
614 else if(inputmode == CASTER)
615 {
616 if(!inport) inport = NTRIP_PORT;
617 if(!inhost) inhost = NTRIP_CASTER;
618 }
619 else if((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET))
620 {
621 if(!inport) inport = SERV_TCP_PORT;
622 if(!inhost) inhost = SERV_HOST_ADDR;
623 }
[485]624
[487]625 if(!(he = gethostbyname(inhost)))
626 {
627 fprintf(stderr, "ERROR: Input host <%s> unknown\n", inhost);
628 usage(-2, argv[0]);
629 }
[485]630
[653]631 if((gps_socket = socket(AF_INET, inputmode == UDPSOCKET
632 ? SOCK_DGRAM : SOCK_STREAM, 0)) == INVALID_SOCKET)
[487]633 {
634 fprintf(stderr,
635 "ERROR: can't create socket for incoming data stream\n");
636 exit(1);
637 }
[485]638
[487]639 memset((char *) &caster, 0x00, sizeof(caster));
640 if(!bindmode)
641 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
642 caster.sin_family = AF_INET;
643 caster.sin_port = htons(inport);
[485]644
[487]645 fprintf(stderr, "%s input: host = %s, port = %d, %s%s%s%s%s\n",
646 inputmode == CASTER ? "caster" : inputmode == SISNET ? "sisnet" :
647 inputmode == TCPSOCKET ? "tcp socket" : "udp socket",
648 bindmode ? "127.0.0.1" : inet_ntoa(caster.sin_addr),
649 inport, stream_name ? "stream = " : "", stream_name ? stream_name : "",
650 initfile ? ", initfile = " : "", initfile ? initfile : "",
651 bindmode ? "binding mode" : "");
[485]652
[487]653 if(bindmode)
654 {
[653]655 if(bind(gps_socket, (struct sockaddr *) &caster, sizeof(caster)) < 0)
[487]656 {
657 fprintf(stderr, "ERROR: can't bind input to port %d\n", inport);
658 reconnect_sec_max = 0;
659 input_init = 0;
660 break;
661 }
662 } /* connect to input-caster or proxy server*/
[653]663 else if(connect(gps_socket, (struct sockaddr *)&caster, sizeof(caster)) < 0)
[487]664 {
665 fprintf(stderr, "WARNING: can't connect input to %s at port %d\n",
666 inet_ntoa(caster.sin_addr), inport);
667 input_init = 0;
668 break;
669 }
[485]670
[487]671 if(stream_name) /* input from Ntrip Version 1.0 caster*/
672 {
673 int init = 0;
[485]674
[487]675 /* set socket buffer size */
[653]676 setsockopt(gps_socket, SOL_SOCKET, SO_SNDBUF, (const char *) &size,
[487]677 sizeof(const char *));
678 if(stream_user && stream_password)
[485]679 {
[487]680 /* leave some space for login */
681 nBufferBytes=snprintf(szSendBuffer, sizeof(szSendBuffer)-40,
682 "GET %s/%s HTTP/1.0\r\n"
683 "User-Agent: %s/%s\r\n"
[598]684 "Connection: close\r\n"
[487]685 "Authorization: Basic ", get_extension, stream_name,
686 AGENTSTRING, revisionstr);
687 /* second check for old glibc */
688 if(nBufferBytes > (int)sizeof(szSendBuffer)-40 || nBufferBytes < 0)
689 {
690 fprintf(stderr, "ERROR: Source caster request too long\n");
691 input_init = 0;
692 reconnect_sec_max =0;
693 break;
694 }
695 nBufferBytes += encode(szSendBuffer+nBufferBytes,
696 sizeof(szSendBuffer)-nBufferBytes-4, stream_user, stream_password);
697 if(nBufferBytes > (int)sizeof(szSendBuffer)-4)
698 {
699 fprintf(stderr,
700 "ERROR: Source caster user ID and/or password too long\n");
701 input_init = 0;
702 reconnect_sec_max =0;
703 break;
704 }
705 szSendBuffer[nBufferBytes++] = '\r';
706 szSendBuffer[nBufferBytes++] = '\n';
707 szSendBuffer[nBufferBytes++] = '\r';
708 szSendBuffer[nBufferBytes++] = '\n';
[485]709 }
[487]710 else
[485]711 {
[487]712 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
713 "GET %s/%s HTTP/1.0\r\n"
714 "User-Agent: %s/%s\r\n"
[598]715 "Connection: close\r\n"
[487]716 "\r\n", get_extension, stream_name, AGENTSTRING, revisionstr);
[485]717 }
[653]718 if((send(gps_socket, szSendBuffer, (size_t)nBufferBytes, 0))
[487]719 != nBufferBytes)
[485]720 {
[487]721 fprintf(stderr, "WARNING: could not send Source caster request\n");
722 input_init = 0;
723 break;
724 }
725 nBufferBytes = 0;
726 /* check Source caster's response */
727 while(!init && nBufferBytes < (int)sizeof(szSendBuffer)
[653]728 && (nBufferBytes += recv(gps_socket, szSendBuffer,
[487]729 sizeof(szSendBuffer)-nBufferBytes, 0)) > 0)
730 {
731 if(strstr(szSendBuffer, "\r\n"))
732 {
[768]733 if(!strstr(szSendBuffer, "ICY 200 OK"))
[485]734 {
[487]735 int k;
736 fprintf(stderr,
737 "ERROR: could not get requested data from Source caster: ");
738 for(k = 0; k < nBufferBytes && szSendBuffer[k] != '\n'
739 && szSendBuffer[k] != '\r'; ++k)
740 {
741 fprintf(stderr, "%c", isprint(szSendBuffer[k])
742 ? szSendBuffer[k] : '.');
743 }
744 fprintf(stderr, "\n");
[768]745 if(!strstr(szSendBuffer, "SOURCETABLE 200 OK"))
[487]746 {
747 reconnect_sec_max =0;
748 }
749 input_init = 0;
750 break;
[485]751 }
[487]752 else init = 1;
[485]753 }
754 }
[487]755 } /* end input from Ntrip Version 1.0 caster */
[485]756
[487]757 if(initfile && inputmode != SISNET)
758 {
759 char buffer[1024];
760 FILE *fh;
761 int i;
[485]762
[487]763 if((fh = fopen(initfile, "r")))
[485]764 {
[487]765 while((i = fread(buffer, 1, sizeof(buffer), fh)) > 0)
[485]766 {
[653]767 if((send(gps_socket, buffer, (size_t)i, 0)) != i)
[487]768 {
769 perror("WARNING: sending init file");
770 input_init = 0;
771 break;
772 }
[485]773 }
[487]774 if(i < 0)
775 {
776 perror("ERROR: reading init file");
777 reconnect_sec_max = 0;
778 input_init = 0;
779 break;
780 }
781 fclose(fh);
[485]782 }
[487]783 else
[485]784 {
[487]785 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
786 reconnect_sec_max = 0;
787 input_init = 0;
788 break;
[485]789 }
[487]790 }
[485]791 }
[487]792 if(inputmode == SISNET)
793 {
794 int i, j;
795 char buffer[1024];
[485]796
[487]797 i = snprintf(buffer, sizeof(buffer), sisnet >= 30 ? "AUTH,%s,%s\r\n"
798 : "AUTH,%s,%s", sisnetuser, sisnetpassword);
[653]799 if((send(gps_socket, buffer, (size_t)i, 0)) != i)
[487]800 {
801 perror("WARNING: sending authentication for SISNeT data server");
802 input_init = 0;
803 break;
804 }
805 i = sisnet >= 30 ? 7 : 5;
[653]806 if((j = recv(gps_socket, buffer, i, 0)) != i && strncmp("*AUTH", buffer, 5))
[487]807 {
808 fprintf(stderr, "WARNING: SISNeT connect failed:");
809 for(i = 0; i < j; ++i)
810 {
811 if(buffer[i] != '\r' && buffer[i] != '\n')
812 {
813 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
814 }
815 }
816 fprintf(stderr, "\n");
817 input_init = 0;
818 break;
819 }
820 if(sisnet >= 31)
821 {
[653]822 if((send(gps_socket, "START\r\n", 7, 0)) != i)
[487]823 {
824 perror("WARNING: sending Sisnet start command");
825 input_init = 0;
826 break;
827 }
828 }
[485]829 }
[487]830 /*** receiver authentication ***/
831 if (recvrid && recvrpwd && ((inputmode == TCPSOCKET)
832 || (inputmode == UDPSOCKET)))
[485]833 {
[487]834 if (strlen(recvrid) > (BUFSZ-3))
835 {
836 fprintf(stderr, "ERROR: Receiver ID too long\n");
837 reconnect_sec_max = 0;
838 input_init = 0;
839 break;
840 }
841 else
842 {
843 fprintf(stderr, "Sending user ID for receiver...\n");
[653]844 nBufferBytes = recv(gps_socket, szSendBuffer, BUFSZ, 0);
[487]845 strcpy(szSendBuffer, recvrid);
846 strcat(szSendBuffer,"\r\n");
[653]847 if(send(gps_socket,szSendBuffer, strlen(szSendBuffer), MSG_DONTWAIT) < 0)
[485]848 {
[487]849 perror("WARNING: sending user ID for receiver");
850 input_init = 0;
851 break;
[485]852 }
[487]853 }
854
855 if (strlen(recvrpwd) > (BUFSZ-3))
856 {
857 fprintf(stderr, "ERROR: Receiver password too long\n");
858 reconnect_sec_max = 0;
859 input_init = 0;
860 break;
861 }
862 else
863 {
864 fprintf(stderr, "Sending user password for receiver...\n");
[653]865 nBufferBytes = recv(gps_socket, szSendBuffer, BUFSZ, 0);
[487]866 strcpy(szSendBuffer, recvrpwd);
867 strcat(szSendBuffer,"\r\n");
[653]868 if(send(gps_socket, szSendBuffer, strlen(szSendBuffer), MSG_DONTWAIT) < 0)
[487]869 {
870 perror("WARNING: sending user password for receiver");
871 input_init = 0;
872 break;
873 }
874 }
[485]875 }
[487]876 break;
877 default:
878 usage(-1, argv[0]);
879 break;
[485]880 }
[487]881
882 /* ----- main part ----- */
[925]883 int output_init = 1, fallback = 0;
[487]884
885 while((input_init) && (output_init))
[485]886 {
[653]887#ifndef WINDOWSVERSION
888 if((sigalarm_received) || (sigint_received) || (sigpipe_received)) break;
889#else
890 if((sigalarm_received) || (sigint_received)) break;
891#endif
[487]892 if(!(he = gethostbyname(outhost)))
[485]893 {
[487]894 fprintf(stderr, "ERROR: Destination caster or proxy host <%s> unknown\n",
895 outhost);
[915]896 close_session(casterouthost, mountpoint, session, rtsp_extension, 0);
[487]897 usage(-2, argv[0]);
[485]898 }
899
[487]900 /* create socket */
[653]901 if((socket_tcp = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
[485]902 {
[487]903 perror("ERROR: tcp socket");
904 reconnect_sec_max = 0;
905 break;
[485]906 }
907
[487]908 memset((char *) &caster, 0x00, sizeof(caster));
909 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
910 caster.sin_family = AF_INET;
911 caster.sin_port = htons(outport);
[485]912
[487]913 /* connect to Destination caster or Proxy server*/
914 fprintf(stderr, "caster output: host = %s, port = %d, mountpoint = %s"
915 ", mode = %s\n\n", inet_ntoa(caster.sin_addr), outport, mountpoint,
916 outputmode == NTRIP1 ? "ntrip1" : outputmode == HTTP ? "http" : "rtsp");
[485]917
[487]918 if(connect(socket_tcp, (struct sockaddr *) &caster, sizeof(caster)) < 0)
919 {
920 fprintf(stderr, "WARNING: can't connect output to %s at port %d\n",
921 inet_ntoa(caster.sin_addr), outport);
922 break;
923 }
[485]924
[487]925 /*** OutputMode handling ***/
926 switch(outputmode)
927 {
928 case NTRIP1: /*** OutputMode Ntrip Version 1.0 ***/
[925]929 fallback = 0;
[487]930 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
931 "SOURCE %s %s/%s\r\n"
932 "Source-Agent: %s/%s\r\n\r\n",
933 password, post_extension, mountpoint, AGENTSTRING, revisionstr);
934 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
[485]935 {
[487]936 fprintf(stderr, "ERROR: Destination caster request to long\n");
937 reconnect_sec_max = 0;
938 output_init = 0;
939 break;
[485]940 }
[487]941 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
[485]942 {
[487]943 output_init = 0;
944 break;
[485]945 }
[487]946 /* check Destination caster's response */
947 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
948 szSendBuffer[nBufferBytes] = '\0';
949 if(!strstr(szSendBuffer, "OK"))
[485]950 {
[487]951 char *a;
[485]952 fprintf(stderr,
[487]953 "ERROR: Destination caster's or Proxy's reply is not OK: ");
954 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
955 {
956 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
957 }
958 fprintf(stderr, "\n");
959 if((strstr(szSendBuffer,"ERROR - Bad Password"))
960 || (strstr(szSendBuffer,"400 Bad Request")))
961 reconnect_sec_max = 0;
962 output_init = 0;
[485]963 break;
964 }
965#ifndef NDEBUG
[487]966 else
967 {
968 fprintf(stderr, "Destination caster response:\n%s\n",
969 szSendBuffer);
970 }
[485]971#endif
[765]972 send_receive_loop(socket_tcp, outputmode, NULL, 0, 0);
[653]973 input_init = output_init = 0;
[485]974 break;
[487]975 case HTTP: /*** Ntrip-Version 2.0 HTTP/1.1 ***/
976 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
977 "POST %s/%s HTTP/1.1\r\n"
978 "Host: %s\r\n"
979 "Ntrip-Version: Ntrip/2.0\r\n"
980 "User-Agent: %s/%s\r\n"
[915]981 "Authorization: Basic %s%s%s\r\n"
[598]982 "Connection: close\r\n"
[487]983 "Transfer-Encoding: chunked\r\n\r\n",
984 post_extension, mountpoint, casterouthost, AGENTSTRING,
[915]985 revisionstr, authorization, ntrip_str ? "\r\nNtrip-STR: " : "",
986 ntrip_str);
[487]987 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
988 {
989 fprintf(stderr, "ERROR: Destination caster request to long\n");
990 reconnect_sec_max = 0;
991 output_init = 0;
992 break;
993 }
994 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
995 {
996 output_init = 0;
997 break;
998 }
[485]999 /* check Destination caster's response */
[487]1000 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
[485]1001 szSendBuffer[nBufferBytes] = '\0';
[487]1002 if(!strstr(szSendBuffer, "HTTP/1.1 200 OK"))
[485]1003 {
1004 char *a;
1005 fprintf(stderr,
1006 "ERROR: Destination caster's%s reply is not OK: ",
1007 *proxyhost ? " or Proxy's" : "");
1008 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
1009 {
[487]1010 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
[485]1011 }
1012 fprintf(stderr, "\n");
1013 /* fallback if necessary */
[487]1014 if(!strstr(szSendBuffer,"Ntrip-Version: Ntrip/2.0\r\n"))
[485]1015 {
[487]1016 fprintf(stderr,
1017 " Ntrip Version 2.0 not implemented at Destination caster"
1018 " <%s>%s%s%s\n%s\n"
1019 "ntripserver falls back to Ntrip Version 1.0\n\n",
1020 casterouthost,
1021 *proxyhost ? " or Proxy <" : "", proxyhost, *proxyhost ? ">" : "",
1022 *proxyhost ? " or HTTP/1.1 not implemented at Proxy\n" : "");
[915]1023 close_session(casterouthost, mountpoint, session, rtsp_extension, 1);
[487]1024 outputmode = NTRIP1;
1025 break;
[485]1026 }
[487]1027 else if((strstr(szSendBuffer,"HTTP/1.1 401 Unauthorized"))
1028 || (strstr(szSendBuffer,"501 Not Implemented")))
[485]1029 {
[487]1030 reconnect_sec_max = 0;
[485]1031 }
[487]1032 output_init = 0;
1033 break;
[485]1034 }
1035#ifndef NDEBUG
1036 else
1037 {
1038 fprintf(stderr, "Destination caster response:\n%s\n",szSendBuffer);
1039 }
1040#endif
[765]1041 send_receive_loop(socket_tcp, outputmode, NULL, 0, 0);
[653]1042 input_init = output_init = 0;
[487]1043 break;
1044 case RTSP: /*** Ntrip-Version 2.0 RTSP / RTP ***/
[653]1045 if((socket_udp = socket(AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
[485]1046 {
[487]1047 perror("ERROR: udp socket");
1048 exit(4);
1049 }
1050 /* fill structure with local address information for UDP */
1051 memset(&local, 0, sizeof(local));
1052 local.sin_family = AF_INET;
1053 local.sin_port = htons(0);
1054 local.sin_addr.s_addr = htonl(INADDR_ANY);
1055 len = (socklen_t)sizeof(local);
1056 /* bind() in order to get a random RTP client_port */
1057 if((bind(socket_udp,(struct sockaddr *)&local, len)) < 0)
1058 {
1059 perror("ERROR: udp bind");
1060 reconnect_sec_max = 0;
1061 output_init = 0;
1062 break;
1063 }
1064 if((getsockname(socket_udp, (struct sockaddr*)&local, &len)) != -1)
1065 {
1066 client_port = (unsigned int)ntohs(local.sin_port);
1067 }
1068 else
1069 {
1070 perror("ERROR: getsockname(localhost)");
1071 reconnect_sec_max = 0;
1072 output_init = 0;
1073 break;
1074 }
1075 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
1076 "SETUP rtsp://%s%s/%s RTSP/1.0\r\n"
[915]1077 "CSeq: %d\r\n"
[487]1078 "Ntrip-Version: Ntrip/2.0\r\n"
1079 "Ntrip-Component: Ntripserver\r\n"
1080 "User-Agent: %s/%s\r\n"
1081 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
[915]1082 "Authorization: Basic %s%s%s\r\n\r\n",
1083 casterouthost, rtsp_extension, mountpoint, udp_cseq++, AGENTSTRING,
1084 revisionstr, client_port, authorization, ntrip_str
1085 ? "\r\nNtrip-STR: " : "", ntrip_str);
[487]1086 if((nBufferBytes > (int)sizeof(szSendBuffer)) || (nBufferBytes < 0))
1087 {
1088 fprintf(stderr, "ERROR: Destination caster request to long\n");
1089 reconnect_sec_max = 0;
1090 output_init = 0;
1091 break;
1092 }
1093 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
1094 {
1095 output_init = 0;
1096 break;
1097 }
1098 while((nBufferBytes = recv(socket_tcp, szSendBuffer,
1099 sizeof(szSendBuffer), 0)) > 0)
1100 {
1101 /* check Destination caster's response */
1102 szSendBuffer[nBufferBytes] = '\0';
1103 if(!strstr(szSendBuffer, "RTSP/1.0 200 OK"))
[485]1104 {
[487]1105 char *a;
1106 fprintf(stderr,
1107 "ERROR: Destination caster's%s reply is not OK: ",
1108 *proxyhost ? " or Proxy's" : "");
1109 for(a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a)
1110 {
1111 fprintf(stderr, "%c", isprint(*a) ? *a : '.');
1112 }
1113 fprintf(stderr, "\n");
1114 /* fallback if necessary */
1115 if(strncmp(szSendBuffer, "RTSP",4) != 0)
1116 {
1117 if(strstr(szSendBuffer,"Ntrip-Version: Ntrip/2.0\r\n"))
1118 {
1119 fprintf(stderr,
1120 " RTSP not implemented at Destination caster <%s>%s%s%s\n\n"
1121 "ntripserver falls back to Ntrip Version 2.0 in TCP/IP"
1122 " mode\n\n", casterouthost,
1123 *proxyhost ? " or Proxy <" :"", proxyhost, *proxyhost ? ">":"");
[915]1124 close_session(casterouthost, mountpoint, session, rtsp_extension, 1);
[487]1125 outputmode = HTTP;
[925]1126 fallback = 1;
[487]1127 break;
1128 }
1129 else
1130 {
1131 fprintf(stderr,
1132 " Ntrip-Version 2.0 not implemented at Destination caster"
1133 "<%s>%s%s%s\n%s"
1134 " or RTSP/1.0 not implemented at Destination caster%s\n\n"
1135 "ntripserver falls back to Ntrip Version 1.0\n\n",
1136 casterouthost, *proxyhost ? " or Proxy <" :"", proxyhost,
1137 *proxyhost ? ">":"",
1138 *proxyhost ? " or HTTP/1.1 not implemented at Proxy\n" : "",
1139 *proxyhost ? " or Proxy" :"");
[915]1140 close_session(casterouthost, mountpoint, session, rtsp_extension, 1);
[487]1141 outputmode = NTRIP1;
[925]1142 fallback = 1;
[487]1143 break;
1144 }
1145 }
1146 else if((strstr(szSendBuffer, "RTSP/1.0 401 Unauthorized"))
1147 || (strstr(szSendBuffer, "RTSP/1.0 501 Not Implemented")))
1148 {
1149 reconnect_sec_max = 0;
1150 }
1151 output_init = 0;
1152 break;
[485]1153 }
[487]1154#ifndef NDEBUG
1155 else
[485]1156 {
[487]1157 fprintf(stderr, "Destination caster response:\n%s\n",szSendBuffer);
[485]1158 }
[487]1159#endif
1160 if((strstr(szSendBuffer,"RTSP/1.0 200 OK\r\n"))
1161 && (strstr(szSendBuffer,"CSeq: 1\r\n")))
[485]1162 {
[487]1163 for(token = strtok(szSendBuffer, dlim); token != NULL;
1164 token = strtok(NULL, dlim))
1165 {
1166 tok_buf[i] = token; i++;
1167 }
1168 session = atoi(tok_buf[6]);
1169 server_port = atoi(tok_buf[10]);
1170 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
[765]1171 "RECORD rtsp://%s%s/%s RTSP/1.0\r\n"
[915]1172 "CSeq: %d\r\n"
[487]1173 "Session: %d\r\n"
1174 "\r\n",
[915]1175 casterouthost, rtsp_extension, mountpoint, udp_cseq++,
1176 session);
[487]1177 if((nBufferBytes >= (int)sizeof(szSendBuffer))
1178 || (nBufferBytes < 0))
1179 {
[653]1180 fprintf(stderr, "ERROR: Destination caster request to long\n");
[487]1181 reconnect_sec_max = 0;
1182 output_init = 0;
1183 break;
1184 }
1185 if(!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes))
1186 {
[653]1187 output_init = 0;
1188 break;
[487]1189 }
[485]1190 }
[487]1191 else if((strstr(szSendBuffer,"RTSP/1.0 200 OK\r\n")) && (strstr(szSendBuffer,
1192 "CSeq: 2\r\n")))
1193 {
1194 /* fill structure with caster address information for UDP */
1195 memset(&casterRTP, 0, sizeof(casterRTP));
1196 casterRTP.sin_family = AF_INET;
1197 casterRTP.sin_port = htons(((uint16_t)server_port));
1198 if((he = gethostbyname(outhost))== NULL)
1199 {
1200 fprintf(stderr, "ERROR: Destination caster unknown\n");
1201 reconnect_sec_max = 0;
1202 output_init = 0;
1203 break;
1204 }
1205 else
1206 {
1207 memcpy((char *)&casterRTP.sin_addr.s_addr,
1208 he->h_addr_list[0], (size_t)he->h_length);
1209 }
1210 len = (socklen_t)sizeof(casterRTP);
[653]1211 send_receive_loop(socket_udp, outputmode, (struct sockaddr *)&casterRTP,
[765]1212 (socklen_t)len, session);
[487]1213 break;
[485]1214 }
[487]1215 else{break;}
1216 }
[653]1217 input_init = output_init = 0;
[487]1218 break;
[765]1219 }
[485]1220 }
[915]1221 close_session(casterouthost, mountpoint, session, rtsp_extension, 0);
[925]1222 if( (reconnect_sec_max || fallback) && !sigint_received )
[653]1223 reconnect_sec = reconnect(reconnect_sec, reconnect_sec_max);
[487]1224 else inputmode = LAST;
[485]1225 }
1226 return 0;
1227}
1228
[653]1229static void send_receive_loop(sockettype sock, int outmode, struct sockaddr* pcasterRTP,
[765]1230socklen_t length, int rtpssrc)
[485]1231{
[653]1232 int nodata = 0;
1233 char buffer[BUFSZ] = { 0 };
1234 char sisnetbackbuffer[200];
1235 char szSendBuffer[BUFSZ] = "";
1236 int nBufferBytes = 0;
[485]1237
1238 /* RTSP / RTP Mode */
[653]1239 int isfirstpacket = 1;
1240 struct timeval now;
1241 struct timeval last = {0,0};
[485]1242 long int sendtimediff;
[653]1243 int rtpseq = 0;
1244 int rtptime = 0;
[915]1245 time_t laststate = time(0);
[485]1246
[915]1247 if(outmode == RTSP)
1248 {
1249#ifdef WINDOWSVERSION
1250 u_long blockmode = 1;
1251 if(ioctlsocket(socket_tcp, FIONBIO, &blockmode))
1252#else /* WINDOWSVERSION */
1253 if(fcntl(socket_tcp, F_SETFL, O_NONBLOCK) < 0)
1254#endif /* WINDOWSVERSION */
1255 {
1256 fprintf(stderr, "Could not set nonblocking mode\n");
1257 return;
1258 }
1259 }
1260
[485]1261 /* data transmission */
1262 fprintf(stderr,"transfering data ...\n");
[653]1263 int send_recv_success = 0;
1264#ifdef WINDOWSVERSION
1265 time_t nodata_begin = 0, nodata_current = 0;
1266#endif
[485]1267 while(1)
1268 {
[487]1269 if(send_recv_success < 3) send_recv_success++;
[653]1270 if(!nodata)
1271 {
1272#ifndef WINDOWSVERSION
1273 alarm(ALARMTIME);
1274#else
1275 time(&nodata_begin);
1276#endif
1277 }
1278 else
1279 {
1280 nodata = 0;
1281#ifdef WINDOWSVERSION
1282 time(&nodata_current);
1283 if(difftime(nodata_current, nodata_begin) >= ALARMTIME)
1284 {
1285 sigalarm_received = 1;
1286 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
1287 }
1288#endif
1289 }
[487]1290 /* signal handling*/
[653]1291#ifdef WINDOWSVERSION
1292 if((sigalarm_received) || (sigint_received)) break;
1293#else
1294 if((sigalarm_received) || (sigint_received) || (sigpipe_received)) break;
1295#endif
[485]1296 if(!nBufferBytes)
1297 {
1298 if(inputmode == SISNET && sisnet <= 30)
1299 {
1300 int i;
1301 /* a somewhat higher rate than 1 second to get really each block */
1302 /* means we need to skip double blocks sometimes */
1303 struct timeval tv = {0,700000};
1304 select(0, 0, 0, 0, &tv);
1305 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
1306 i = (sisnet >= 30 ? 5 : 3);
[653]1307 if((send(gps_socket, "MSG\r\n", i, 0)) != i)
[485]1308 {
[487]1309 perror("WARNING: sending SISNeT data request failed");
1310 return;
[485]1311 }
1312 }
1313 /*** receiving data ****/
[653]1314 if(inputmode == INFILE)
1315 nBufferBytes = read(gps_file, buffer, sizeof(buffer));
1316 else if(inputmode == SERIAL)
1317 {
1318#ifndef WINDOWSVERSION
1319 nBufferBytes = read(gps_serial, buffer, sizeof(buffer));
1320#else
1321 DWORD nRead = 0;
1322 if(!ReadFile(gps_serial, buffer, sizeof(buffer), &nRead, NULL))
1323 {
1324 fprintf(stderr,"ERROR: reading serial input failed\n");
1325 return;
1326 }
1327 nBufferBytes = (int)nRead;
1328#endif
1329 }
[768]1330 else
1331#ifdef WINDOWSVERSION
[653]1332 nBufferBytes = recv(gps_socket, buffer, sizeof(buffer), 0);
[768]1333#else
1334 nBufferBytes = read(gps_socket, buffer, sizeof(buffer));
1335#endif
[485]1336 if(!nBufferBytes)
1337 {
[653]1338 fprintf(stderr, "WARNING: no data received from input\n");
1339 nodata = 1;
1340#ifndef WINDOWSVERSION
[485]1341 sleep(3);
[653]1342#else
1343 Sleep(3*1000);
1344#endif
[485]1345 continue;
1346 }
[487]1347 else if((nBufferBytes < 0) && (!sigint_received))
[485]1348 {
[487]1349 perror("WARNING: reading input failed");
1350 return;
[485]1351 }
1352 /* we can compare the whole buffer, as the additional bytes
1353 remain unchanged */
1354 if(inputmode == SISNET && sisnet <= 30 &&
1355 !memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer)))
1356 {
1357 nBufferBytes = 0;
1358 }
1359 }
1360 /** send data ***/
[487]1361 if((nBufferBytes) && (outmode == NTRIP1)) /*** Ntrip-Version 1.0 ***/
[485]1362 {
1363 int i;
1364 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
1365 != nBufferBytes)
1366 {
1367 if(i < 0)
1368 {
1369 if(errno != EAGAIN)
1370 {
[487]1371 perror("WARNING: could not send data to Destination caster");
[485]1372 return;
1373 }
1374 }
1375 else if(i)
1376 {
1377 memmove(buffer, buffer+i, (size_t)(nBufferBytes-i));
1378 nBufferBytes -= i;
1379 }
1380 }else
1381 {
1382 nBufferBytes = 0;
1383 }
1384 }
1385 /*** Ntrip-Version 2.0 HTTP/1.1 ***/
1386 else if((nBufferBytes) && (outmode == HTTP))
1387 {
1388 int i, nChunkBytes, j = 1;
1389 nChunkBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),"%x\r\n",
1390 nBufferBytes);
1391 send(sock, szSendBuffer, nChunkBytes, MSG_DONTWAIT);
1392 if((i = send(sock, buffer, (size_t)nBufferBytes, MSG_DONTWAIT))
1393 != nBufferBytes)
1394 {
1395 if(i < 0)
1396 {
1397 if(errno != EAGAIN)
1398 {
[487]1399 perror("WARNING: could not send data to Destination caster");
[485]1400 return;
1401 }
1402 }
1403 else if(i)
1404 {
1405 while(j>0)
1406 {
1407 j = send(sock, buffer, (size_t)BUFSZ, MSG_DONTWAIT);
1408 }
1409 }
1410 }
1411 else
1412 {
1413 send(sock, "\r\n", strlen("\r\n"), MSG_DONTWAIT);
1414 nBufferBytes = 0;
1415 }
1416 }
1417 /*** Ntrip-Version 2.0 RTSP(TCP) / RTP(UDP) ***/
1418 else if((nBufferBytes) && (outmode == RTSP))
1419 {
[915]1420 time_t ct;
1421 int r;
[485]1422 char rtpbuffer[BUFSZ+12];
1423 int i, j;
1424 gettimeofday(&now, NULL);
1425 /* RTP data packet generation*/
1426 if(isfirstpacket){
1427 rtpseq = rand();
1428 rtptime = rand();
1429 last = now;
1430 isfirstpacket = 0;
1431 }
1432 else
1433 {
1434 ++rtpseq;
1435 sendtimediff = (((now.tv_sec - last.tv_sec)*1000000)
1436 + (now.tv_usec - last.tv_usec));
1437 rtptime += sendtimediff/TIME_RESOLUTION;
1438 }
1439 rtpbuffer[0] = (RTP_VERSION<<6);
1440 /* padding, extension, csrc are empty */
1441 rtpbuffer[1] = 96;
1442 /* marker is empty */
1443 rtpbuffer[2] = rtpseq>>8;
1444 rtpbuffer[3] = rtpseq;
1445 rtpbuffer[4] = rtptime>>24;
1446 rtpbuffer[5] = rtptime>>16;
1447 rtpbuffer[6] = rtptime>>8;
1448 rtpbuffer[7] = rtptime;
1449 rtpbuffer[8] = rtpssrc>>24;
1450 rtpbuffer[9] = rtpssrc>>16;
1451 rtpbuffer[10] = rtpssrc>>8;
1452 rtpbuffer[11] = rtpssrc;
1453 for(j=0; j<nBufferBytes; j++) {rtpbuffer[12+j] = buffer[j];}
1454 last.tv_sec = now.tv_sec;
1455 last.tv_usec = now.tv_usec;
1456 if ((i = sendto(sock, rtpbuffer, 12 + nBufferBytes, 0, pcasterRTP,
1457 length)) != (nBufferBytes + 12))
1458 {
1459 if(i < 0)
1460 {
1461 if(errno != EAGAIN)
1462 {
[487]1463 perror("WARNING: could not send data to Destination caster");
[485]1464 return;
1465 }
1466 }
1467 else if(i)
1468 {
1469 memmove(buffer, buffer+(i-12), (size_t)(nBufferBytes-(i-12)));
1470 nBufferBytes -= i-12;
1471 }
1472 }
1473 else
1474 {
1475 nBufferBytes = 0;
1476 }
[915]1477 ct = time(0);
1478 if(ct-laststate > 15)
1479 {
1480 i = snprintf(buffer, sizeof(buffer),
1481 "GET_PARAMETER rtsp://%s%s/%s RTSP/1.0\r\n"
1482 "CSeq: %d\r\n"
1483 "Session: %d\r\n"
1484 "\r\n",
[916]1485 casterouthost, rtsp_extension, mountpoint, udp_cseq++, rtpssrc);
[915]1486 if(i > (int)sizeof(buffer) || i < 0)
1487 {
1488 fprintf(stderr, "Requested data too long\n");
1489 return;
1490 }
1491 else if(send(socket_tcp, buffer, (size_t)i, 0) != i)
1492 {
1493 perror("send");
1494 return;
1495 }
1496 laststate = ct;
1497 }
1498 /* ignore RTSP server replies */
1499 if((r=recv(socket_tcp, buffer, sizeof(buffer), 0)) < 0)
1500 {
1501#ifdef WINDOWSVERSION
1502 if(WSAGetLastError() != WSAEWOULDBLOCK)
1503#else /* WINDOWSVERSION */
1504 if(errno != EAGAIN)
1505#endif /* WINDOWSVERSION */
1506 {
1507 fprintf(stderr, "Control connection closed\n");
1508 return;
1509 }
1510 }
1511 else if(!r)
1512 {
1513 fprintf(stderr, "Control connection read error\n");
1514 return;
1515 }
[485]1516 }
[487]1517 if(send_recv_success == 3) reconnect_sec = 1;
[485]1518 }
1519 return;
1520}
1521
1522
1523/********************************************************************
1524 * openserial
1525 *
1526 * Open the serial port with the given device name and configure it for
1527 * reading NMEA data from a GPS receiver.
1528 *
1529 * Parameters:
1530 * tty : pointer to : A zero-terminated string containing the device
1531 * unsigned char name of the appropriate serial port.
[653]1532 * blocksz : integer : Block size for port I/O (ifndef WINDOWSVERSION)
[485]1533 * baud : integer : Baud rate for port I/O
1534 *
1535 * Return Value:
1536 * The function returns a file descriptor for the opened port if successful.
[653]1537 * The function returns -1 / INVALID_HANDLE_VALUE in the event of an error.
[485]1538 *
1539 * Remarks:
1540 *
1541 ********************************************************************/
[653]1542#ifndef WINDOWSVERSION
[485]1543static int openserial(const char * tty, int blocksz, int baud)
1544{
1545 struct termios termios;
1546
[653]1547/*** opening the serial port ***/
1548 gps_serial = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
1549 if(gps_serial < 0)
[485]1550 {
1551 perror("ERROR: opening serial connection");
1552 return (-1);
1553 }
[653]1554
1555/*** configuring the serial port ***/
1556 if(tcgetattr(gps_serial, &termios) < 0)
[485]1557 {
1558 perror("ERROR: get serial attributes");
1559 return (-1);
1560 }
1561 termios.c_iflag = 0;
1562 termios.c_oflag = 0; /* (ONLRET) */
1563 termios.c_cflag = CS8 | CLOCAL | CREAD;
1564 termios.c_lflag = 0;
1565 {
1566 int cnt;
1567 for(cnt = 0; cnt < NCCS; cnt++)
1568 termios.c_cc[cnt] = -1;
1569 }
1570 termios.c_cc[VMIN] = blocksz;
1571 termios.c_cc[VTIME] = 2;
1572
1573#if (B4800 != 4800)
1574/* Not every system has speed settings equal to absolute speed value. */
1575 switch (baud)
1576 {
1577 case 300:
1578 baud = B300;
1579 break;
1580 case 1200:
1581 baud = B1200;
1582 break;
1583 case 2400:
1584 baud = B2400;
1585 break;
1586 case 4800:
1587 baud = B4800;
1588 break;
1589 case 9600:
1590 baud = B9600;
1591 break;
1592 case 19200:
1593 baud = B19200;
1594 break;
1595 case 38400:
1596 baud = B38400;
1597 break;
1598#ifdef B57600
1599 case 57600:
1600 baud = B57600;
1601 break;
1602#endif
1603#ifdef B115200
1604 case 115200:
1605 baud = B115200;
1606 break;
1607#endif
1608#ifdef B230400
1609 case 230400:
1610 baud = B230400;
1611 break;
1612#endif
1613 default:
1614 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
1615 baud = B19200;
1616 break;
1617 }
1618#endif
1619
1620 if(cfsetispeed(&termios, baud) != 0)
1621 {
1622 perror("ERROR: setting serial speed with cfsetispeed");
1623 return (-1);
1624 }
1625 if(cfsetospeed(&termios, baud) != 0)
1626 {
1627 perror("ERROR: setting serial speed with cfsetospeed");
1628 return (-1);
1629 }
[653]1630 if(tcsetattr(gps_serial, TCSANOW, &termios) < 0)
[485]1631 {
1632 perror("ERROR: setting serial attributes");
1633 return (-1);
1634 }
[653]1635 if(fcntl(gps_serial, F_SETFL, 0) == -1)
[485]1636 {
1637 perror("WARNING: setting blocking inputmode failed");
1638 }
[653]1639 return (gps_serial);
1640}
1641#else
1642static HANDLE openserial(const char * tty, int baud)
1643{
1644 DCB dcb;
1645 COMMTIMEOUTS cmt;
[654]1646 char compath[15] = "";
[653]1647
[654]1648 snprintf(compath, sizeof(compath), "\\\\.\\%s", tty);
[653]1649/*** opening the serial port ***/
[654]1650 gps_serial = CreateFile(compath, GENERIC_READ | GENERIC_WRITE, 0, 0,
[653]1651 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1652 if(gps_serial == INVALID_HANDLE_VALUE)
1653 {
1654 fprintf(stderr, "ERROR: opening serial connection\n");
1655 return (INVALID_HANDLE_VALUE);
1656 }
1657/*** configuring the serial port ***/
1658 FillMemory(&dcb, sizeof(dcb), 0);
1659 dcb.DCBlength = sizeof(dcb);
1660 if(!GetCommState(gps_serial, &dcb))
1661 {
1662 fprintf(stderr, "ERROR: get serial attributes\n");
1663 return (INVALID_HANDLE_VALUE);
1664 }
1665 switch (baud)
1666 {
1667 case 110:
1668 baud = CBR_110;
1669 break;
1670 case 300:
1671 baud = CBR_300;
1672 break;
1673 case 600:
1674 baud = CBR_600;
1675 break;
1676 case 1200:
1677 baud = CBR_1200;
1678 break;
1679 case 2400:
1680 baud = CBR_2400;
1681 break;
1682 case 4800:
1683 baud = CBR_4800;
1684 break;
1685 case 9600:
1686 baud = CBR_9600;
1687 break;
1688 case 14400:
1689 baud = CBR_14400;
1690 break;
1691 case 19200:
1692 baud = CBR_19200;
1693 break;
1694 case 38400:
1695 baud = CBR_38400;
1696 break;
1697 case 56000:
1698 baud = CBR_56000;
1699 break;
1700 case 57600:
1701 baud = CBR_57600;
1702 break;
1703 case 115200:
1704 baud = CBR_115200;
1705 break;
1706 case 128000:
1707 baud = CBR_128000;
1708 break;
1709 case 256000:
1710 baud = CBR_256000;
1711 break;
1712 default:
1713 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
1714 baud = CBR_19200;
1715 break;
1716 }
1717 dcb.BaudRate = baud;
1718 dcb.ByteSize = 8;
1719 dcb.StopBits = ONESTOPBIT;
1720 dcb.Parity = NOPARITY;
1721 if(!GetCommState(gps_serial, &dcb))
1722 {
1723 fprintf(stderr, "ERROR: get serial attributes\n");
1724 return (INVALID_HANDLE_VALUE);
1725 }
1726 FillMemory(&cmt, sizeof(cmt), 0);
1727 cmt.ReadIntervalTimeout = 1000;
1728 cmt.ReadTotalTimeoutMultiplier = 1;
1729 cmt.ReadTotalTimeoutConstant = 0;
1730 if(!SetCommTimeouts(gps_serial, &cmt))
1731 {
1732 fprintf(stderr, "ERROR: set serial timeouts\n");
1733 return (INVALID_HANDLE_VALUE);
1734 }
1735 return (gps_serial);
[485]1736} /* openserial */
[653]1737#endif
[485]1738
1739/********************************************************************
1740* usage
1741*
1742* Send a usage message to standard error and quit the program.
1743*
1744* Parameters:
1745* None.
1746*
1747* Return Value:
1748* The function does not return a value.
1749*
1750* Remarks:
1751*
1752*********************************************************************/
1753#ifdef __GNUC__
1754__attribute__ ((noreturn))
1755#endif /* __GNUC__ */
1756void usage(int rc, char *name)
1757{
1758 fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s [OPTIONS]\n",
1759 revisionstr, datestr, name);
1760 fprintf(stderr, "PURPOSE\n");
1761 fprintf(stderr, " The purpose of this program is to pick up a GNSS data stream (Input, Source)\n");
1762 fprintf(stderr, " from either\n\n");
1763 fprintf(stderr, " 1. a Serial port, or\n");
1764 fprintf(stderr, " 2. an IP server, or\n");
1765 fprintf(stderr, " 3. a File, or\n");
1766 fprintf(stderr, " 4. a SISNeT Data Server, or\n");
1767 fprintf(stderr, " 5. a UDP server, or\n");
1768 fprintf(stderr, " 6. an NTRIP Version 1.0 Caster\n\n");
1769 fprintf(stderr, " and forward that incoming stream (Output, Destination) to either\n\n");
1770 fprintf(stderr, " - an NTRIP Version 1.0 Caster, or\n");
1771 fprintf(stderr, " - an NTRIP Version 2.0 Caster via TCP/IP or RTSP/RTP.\n\n\n");
1772 fprintf(stderr, "OPTIONS\n");
1773 fprintf(stderr, " -h|? print this help screen\n\n");
1774 fprintf(stderr, " -E <ProxyHost> Proxy server host name or address, required i.e. when\n");
1775 fprintf(stderr, " running the program in a proxy server protected LAN,\n");
1776 fprintf(stderr, " optional\n");
1777 fprintf(stderr, " -F <ProxyPort> Proxy server IP port, required i.e. when running\n");
[487]1778 fprintf(stderr, " the program in a proxy server protected LAN, optional\n");
1779 fprintf(stderr, " -R <maxDelay> Reconnect mechanism with maximum delay between reconnect\n");
1780 fprintf(stderr, " attemts in seconds, default: no reconnect activated,\n");
1781 fprintf(stderr, " optional\n\n");
[485]1782 fprintf(stderr, " -M <InputMode> Sets the input mode (1 = Serial Port, 2 = IP server,\n");
1783 fprintf(stderr, " 3 = File, 4 = SISNeT Data Server, 5 = UDP server, 6 = NTRIP Caster),\n");
1784 fprintf(stderr, " mandatory\n\n");
1785 fprintf(stderr, " <InputMode> = 1 (Serial Port):\n");
1786 fprintf(stderr, " -i <Device> Serial input device, default: /dev/gps, mandatory if\n");
1787 fprintf(stderr, " <InputMode>=1\n");
1788 fprintf(stderr, " -b <BaudRate> Serial input baud rate, default: 19200 bps, mandatory\n");
[1113]1789 fprintf(stderr, " if <InputMode>=1\n");
1790 fprintf(stderr, " -f <InitFile> Name of initialization file to be send to input device,\n");
1791 fprintf(stderr, " optional\n\n");
[485]1792 fprintf(stderr, " <InputMode> = 2|5 (IP port | UDP port):\n");
1793 fprintf(stderr, " -H <ServerHost> Input host name or address, default: 127.0.0.1,\n");
1794 fprintf(stderr, " mandatory if <InputMode> = 2|5\n");
1795 fprintf(stderr, " -P <ServerPort> Input port, default: 1025, mandatory if <InputMode>= 2|5\n");
1796 fprintf(stderr, " -f <ServerFile> Name of initialization file to be send to server,\n");
1797 fprintf(stderr, " optional\n");
1798 fprintf(stderr, " -x <ServerUser> User ID to access incoming stream, optional\n");
1799 fprintf(stderr, " -y <ServerPass> Password, to access incoming stream, optional\n");
1800 fprintf(stderr, " -B Bind to incoming UDP stream, optional for <InputMode> = 5\n\n");
1801 fprintf(stderr, " <InputMode> = 3 (File):\n");
1802 fprintf(stderr, " -s <File> File name to simulate stream by reading data from (log)\n");
1803 fprintf(stderr, " file, default is /dev/stdin, mandatory for <InputMode> = 3\n\n");
1804 fprintf(stderr, " <InputMode> = 4 (SISNeT Data Server):\n");
1805 fprintf(stderr, " -H <SisnetHost> SISNeT Data Server name or address,\n");
1806 fprintf(stderr, " default: 131.176.49.142, mandatory if <InputMode> = 4\n");
1807 fprintf(stderr, " -P <SisnetPort> SISNeT Data Server port, default: 7777, mandatory if\n");
1808 fprintf(stderr, " <InputMode> = 4\n");
1809 fprintf(stderr, " -u <SisnetUser> SISNeT Data Server user ID, mandatory if <InputMode> = 4\n");
1810 fprintf(stderr, " -l <SisnetPass> SISNeT Data Server password, mandatory if <InputMode> = 4\n");
1811 fprintf(stderr, " -V <SisnetVers> SISNeT Data Server Version number, options are 2.1, 3.0\n");
1812 fprintf(stderr, " or 3.1, default: 3.1, mandatory if <InputMode> = 4\n\n");
1813 fprintf(stderr, " <InputMode> = 6 (NTRIP Version 1.0 Caster):\n");
1814 fprintf(stderr, " -H <SourceHost> Source caster name or address, default: 127.0.0.1,\n");
1815 fprintf(stderr, " mandatory if <InputMode> = 6\n");
1816 fprintf(stderr, " -P <SourcePort> Source caster port, default: 2101, mandatory if\n");
1817 fprintf(stderr, " <InputMode> = 6\n");
1818 fprintf(stderr, " -D <SourceMount> Source caster mountpoint for stream input, mandatory if\n");
1819 fprintf(stderr, " <InputMode> = 6\n");
1820 fprintf(stderr, " -U <SourceUser> Source caster user Id for input stream access, mandatory\n");
1821 fprintf(stderr, " for protected streams if <InputMode> = 6\n");
1822 fprintf(stderr, " -W <SourcePass> Source caster password for input stream access, mandatory\n");
1823 fprintf(stderr, " for protected streams if <InputMode> = 6\n\n");
1824 fprintf(stderr, " -O <OutputMode> Sets output mode for communatation with destination caster\n");
[487]1825 fprintf(stderr, " 1 = http: NTRIP Version 2.0 Caster in TCP/IP mode\n");
1826 fprintf(stderr, " 2 = rtsp: NTRIP Version 2.0 Caster in RTSP/RTP mode\n");
1827 fprintf(stderr, " 3 = ntrip1: NTRIP Version 1.0 Caster\n");
1828 fprintf(stderr, " optional\n\n");
1829 fprintf(stderr, " Defaults to NTRIP1.0, but will change to 2.0 in future versions\n");
1830 fprintf(stderr, " Note that the program automatically falls back from mode rtsp to mode http and\n");
1831 fprintf(stderr, " further to mode ntrip1 if necessary.\n\n");
[485]1832 fprintf(stderr, " -a <DestHost> Destination caster name or address, default: 127.0.0.1,\n");
1833 fprintf(stderr, " mandatory\n");
1834 fprintf(stderr, " -p <DestPort> Destination caster port, default: 2101, mandatory\n");
1835 fprintf(stderr, " -m <DestMount> Destination caster mountpoint for stream upload,\n");
1836 fprintf(stderr, " mandatory\n");
1837 fprintf(stderr, " -n <DestUser> Destination caster user ID for stream upload to\n");
1838 fprintf(stderr, " mountpoint, only for NTRIP Version 2.0 destination\n");
1839 fprintf(stderr, " casters, mandatory\n");
1840 fprintf(stderr, " -c <DestPass> Destination caster password for stream upload to\n");
1841 fprintf(stderr, " mountpoint, mandatory\n");
1842 fprintf(stderr, " -N <STR-record> Sourcetable STR-record\n");
[487]1843 fprintf(stderr, " optional for NTRIP Version 2.0 in RTSP/RTP and TCP/IP mode\n\n");
[485]1844 exit(rc);
1845} /* usage */
1846
1847
1848/********************************************************************/
1849/* signal handling */
1850/********************************************************************/
1851#ifdef __GNUC__
1852static void handle_sigint(int sig __attribute__((__unused__)))
1853#else /* __GNUC__ */
1854static void handle_sigint(int sig)
1855#endif /* __GNUC__ */
[487]1856{
1857 sigint_received = 1;
1858 fprintf(stderr, "WARNING: SIGINT received - ntripserver terminates\n");
1859}
[485]1860
[653]1861#ifndef WINDOWSVERSION
[487]1862#ifdef __GNUC__
1863static void handle_alarm(int sig __attribute__((__unused__)))
1864#else /* __GNUC__ */
1865static void handle_alarm(int sig)
1866#endif /* __GNUC__ */
1867{
1868 sigalarm_received = 1;
1869 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
1870}
1871
1872#ifdef __GNUC__
1873static void handle_sigpipe(int sig __attribute__((__unused__)))
1874#else /* __GNUC__ */
1875static void handle_sigpipe(int sig)
1876#endif /* __GNUC__ */
[653]1877{
1878 sigpipe_received = 1;
1879}
1880#endif /* WINDOWSVERSION */
[487]1881
[485]1882static void setup_signal_handler(int sig, void (*handler)(int))
1883{
1884#if _POSIX_VERSION > 198800L
1885 struct sigaction action;
1886
1887 action.sa_handler = handler;
1888 sigemptyset(&(action.sa_mask));
1889 sigaddset(&(action.sa_mask), sig);
1890 action.sa_flags = 0;
1891 sigaction(sig, &action, 0);
1892#else
1893 signal(sig, handler);
1894#endif
1895 return;
1896} /* setupsignal_handler */
1897
[653]1898
[485]1899/********************************************************************
1900 * base64-encoding *
1901*******************************************************************/
1902static const char encodingTable [64] =
1903{
1904 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1905 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1906 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1907 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1908};
1909
1910/* does not buffer overrun, but breaks directly after an error */
1911/* returns the number of required bytes */
1912static int encode(char *buf, int size, const char *user, const char *pwd)
1913{
1914 unsigned char inbuf[3];
1915 char *out = buf;
1916 int i, sep = 0, fill = 0, bytes = 0;
1917
1918 while(*user || *pwd)
1919 {
1920 i = 0;
1921 while(i < 3 && *user) inbuf[i++] = *(user++);
1922 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1923 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1924 while(i < 3) {inbuf[i++] = 0; ++fill; }
1925 if(out-buf < size-1)
1926 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1927 if(out-buf < size-1)
1928 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1929 | ((inbuf [1] & 0xF0) >> 4)];
1930 if(out-buf < size-1)
1931 {
1932 if(fill == 2)
1933 *(out++) = '=';
1934 else
1935 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1936 | ((inbuf [2] & 0xC0) >> 6)];
1937 }
1938 if(out-buf < size-1)
1939 {
1940 if(fill >= 1)
1941 *(out++) = '=';
1942 else
1943 *(out++) = encodingTable[inbuf [2] & 0x3F];
1944 }
1945 bytes += 4;
1946 }
1947 if(out-buf < size)
1948 *out = 0;
1949 return bytes;
1950}/* base64 Encoding */
1951
1952
1953/********************************************************************
1954 * send message to caster *
1955*********************************************************************/
[653]1956static int send_to_caster(char *input, sockettype socket, int input_size)
[485]1957{
1958 int send_error = 1;
1959
1960 if((send(socket, input, (size_t)input_size, 0)) != input_size)
1961 {
[487]1962 fprintf(stderr, "WARNING: could not send full header to Destination caster\n");
[485]1963 send_error = 0;
1964 }
1965#ifndef NDEBUG
1966 else
1967 {
1968 fprintf(stderr, "\nDestination caster request:\n");
1969 fprintf(stderr, "%s", input);
1970 }
1971#endif
1972 return send_error;
1973}/* send_to_caster */
1974
1975
1976/********************************************************************
[487]1977 * reconnect *
1978*********************************************************************/
1979int reconnect(int rec_sec, int rec_sec_max)
1980{
1981 fprintf(stderr,"reconnect in <%d> seconds\n\n", rec_sec);
1982 rec_sec *= 2;
1983 if (rec_sec > rec_sec_max) rec_sec = rec_sec_max;
[653]1984#ifndef WINDOWSVERSION
[487]1985 sleep(rec_sec);
[653]1986 sigpipe_received = 0;
1987#else
1988 Sleep(rec_sec*1000);
1989#endif
[487]1990 sigalarm_received = 0;
1991 return rec_sec;
1992} /* reconnect */
1993
1994
1995/********************************************************************
[485]1996 * close session *
1997*********************************************************************/
[487]1998static void close_session(const char *caster_addr, const char *mountpoint,
[915]1999int session, char *rtsp_ext, int fallback)
[485]2000{
2001 int size_send_buf;
2002 char send_buf[BUFSZ];
2003
[653]2004 if(!fallback)
[485]2005 {
[653]2006 if((gps_socket != INVALID_SOCKET) &&
2007 ((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET) ||
2008 (inputmode == CASTER) || (inputmode == SISNET)))
2009 {
2010 if(closesocket(gps_socket) == -1)
2011 {
2012 perror("ERROR: close input device ");
2013 exit(0);
2014 }
2015 else
2016 {
2017 gps_socket = -1;
2018#ifndef NDEBUG
2019 fprintf(stderr, "close input device: successful\n");
2020#endif
2021 }
[485]2022 }
[653]2023 else if((gps_serial != INVALID_HANDLE_VALUE) && (inputmode == SERIAL))
[485]2024 {
[653]2025#ifndef WINDOWSVERSION
2026 if(close(gps_serial) == INVALID_HANDLE_VALUE)
2027 {
2028 perror("ERROR: close input device ");
2029 exit(0);
2030 }
2031#else
2032 if(!CloseHandle(gps_serial))
2033 {
2034 fprintf(stderr, "ERROR: close input device ");
2035 exit(0);
2036 }
2037#endif
2038 else
2039 {
2040 gps_serial = INVALID_HANDLE_VALUE;
[487]2041#ifndef NDEBUG
[653]2042 fprintf(stderr, "close input device: successful\n");
[487]2043#endif
[653]2044 }
[485]2045 }
[653]2046 else if((gps_file != -1) && (inputmode == INFILE))
2047 {
2048 if(close(gps_file) == -1)
2049 {
2050 perror("ERROR: close input device ");
2051 exit(0);
2052 }
2053 else
2054 {
2055 gps_file = -1;
2056#ifndef NDEBUG
2057 fprintf(stderr, "close input device: successful\n");
2058#endif
2059 }
2060 }
[485]2061 }
2062
[915]2063 if(socket_udp != INVALID_SOCKET)
[485]2064 {
[915]2065 if(udp_cseq > 2)
[485]2066 {
2067 size_send_buf = snprintf(send_buf, sizeof(send_buf),
2068 "TEARDOWN rtsp://%s%s/%s RTSP/1.0\r\n"
[915]2069 "CSeq: %d\r\n"
[485]2070 "Session: %d\r\n"
2071 "\r\n",
[915]2072 caster_addr, rtsp_ext, mountpoint, udp_cseq++, session);
[485]2073 if((size_send_buf >= (int)sizeof(send_buf)) || (size_send_buf < 0))
2074 {
2075 fprintf(stderr, "ERROR: Destination caster request to long\n");
2076 exit(0);
2077 }
[487]2078 send_to_caster(send_buf, socket_tcp, size_send_buf); strcpy(send_buf,"");
2079 size_send_buf = recv(socket_tcp, send_buf, sizeof(send_buf), 0);
[485]2080 send_buf[size_send_buf] = '\0';
2081#ifndef NDEBUG
2082 fprintf(stderr, "Destination caster response:\n%s", send_buf);
2083#endif
2084 }
[653]2085 if(closesocket(socket_udp)==-1)
[485]2086 {
2087 perror("ERROR: close udp socket");
2088 exit(0);
2089 }
2090 else
2091 {
[487]2092 socket_udp = -1;
2093#ifndef NDEBUG
2094 fprintf(stderr, "close udp socket: successful\n");
2095#endif
[485]2096 }
2097 }
2098
[653]2099 if(socket_tcp != INVALID_SOCKET)
[485]2100 {
[653]2101 if(closesocket(socket_tcp) == -1)
[487]2102 {
2103 perror("ERROR: close tcp socket");
2104 exit(0);
2105 }
2106 else
2107 {
2108 socket_tcp = -1;
[485]2109#ifndef NDEBUG
[487]2110 fprintf(stderr, "close tcp socket: successful\n");
2111#endif
2112 }
[485]2113 }
2114} /* close_session */
Note: See TracBrowser for help on using the repository browser.