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

Last change on this file since 9404 was 9404, checked in by stoecker, 4 years ago

drop the deprecated www prefix

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