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

Last change on this file since 801 was 768, checked in by stuerze, 17 years ago

minor changes regarding a combined proxy + caster response

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