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

Last change on this file since 10206 was 9812, checked in by stoecker, 2 years ago

prevent large UDP packets

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