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

Last change on this file since 9460 was 9460, checked in by stuerze, 3 years ago

minor changes

  • Property svn:keywords set to Id Revision Date
File size: 77.4 KB
RevLine 
[485]1/*
[8784]2 * $Id: ntripserver.c 9460 2021-06-08 10:04:45Z stuerze $
[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: 9460 $";
[9401]41static char datestr[] = "$Date: 2021-06-08 10:04:45 +0000 (Tue, 08 Jun 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,
[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 */
674 int init = 0;
675 /* set socket buffer size */
676 setsockopt(gps_socket, SOL_SOCKET, SO_SNDBUF, (const char*) &size, sizeof(const char*));
677 /* input from Ntrip caster*/
678 nBufferBytes=snprintf(szSendBuffer, sizeof(szSendBuffer) - 40,/* leave some space for login */
679 "GET %s/%s HTTP/1.1\r\n"
680 "Host: %s\r\n"
681 "%s"
682 "User-Agent: %s/%s\r\n"
683 //"%s%s%s" // nmea
684 "Connection: close%s",
685 get_extension,
686 stream_name ? stream_name : "",
687 casterinhost,
688 inputmode == NTRIP1_IN ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
689 AGENTSTRING, revisionstr,
690 //args.nmea ? "Ntrip-GGA: " : "", args.nmea ? args.nmea : "", args.nmea ? "\r\n" : "", // TODO: add argument
691 (*stream_user || *stream_password) ? "\r\nAuthorization: Basic " : "");
692 /* second check for old glibc */
693 if (nBufferBytes > (int) sizeof(szSendBuffer) - 40 || nBufferBytes < 0) {
694 fprintf(stderr, "ERROR: Source caster request too long\n");
695 input_init = 0;
696 reconnect_sec_max = 0;
697 break;
698 }
699 nBufferBytes += encode(szSendBuffer + nBufferBytes, sizeof(szSendBuffer) - nBufferBytes - 4,
700 stream_user, stream_password);
701 if (nBufferBytes > (int) sizeof(szSendBuffer) - 4) {
702 fprintf(stderr, "ERROR: Source caster user ID and/or password too long\n");
703 input_init = 0;
704 reconnect_sec_max = 0;
705 break;
706 }
707 szSendBuffer[nBufferBytes++] = '\r';
708 szSendBuffer[nBufferBytes++] = '\n';
709 szSendBuffer[nBufferBytes++] = '\r';
710 szSendBuffer[nBufferBytes++] = '\n';
[9448]711 fprintf(stdout, "%s\n", szSendBuffer);
[9401]712 if ((send(gps_socket, szSendBuffer, (size_t) nBufferBytes, 0)) != nBufferBytes) {
713 fprintf(stderr, "WARNING: could not send Source caster request\n");
714 input_init = 0;
715 break;
716 }
717 nBufferBytes = 0;
718 /* check Source caster's response */
719 while (!init && nBufferBytes < (int) sizeof(szSendBuffer) &&
720 (nBufferBytes += recv(gps_socket, szSendBuffer, sizeof(szSendBuffer) - nBufferBytes, 0)) > 0) {
721 if( nBufferBytes > 17 && !strstr(szSendBuffer, "ICY 200 OK") && /* case 'proxy & ntrip 1.0 caster' */
722 (!strncmp(szSendBuffer, "HTTP/1.1 200 OK\r\n", 17) ||
723 !strncmp(szSendBuffer, "HTTP/1.0 200 OK\r\n", 17)) ) {
724 const char *datacheck = "Content-Type: gnss/data\r\n";
725 const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
726 int l = strlen(datacheck)-1;
727 int j=0;
728 for(i = 0; j != l && i < nBufferBytes-l; ++i) {
729 for(j = 0; j < l && szSendBuffer[i+j] == datacheck[j]; ++j)
730 ;
[487]731 }
[9401]732 if(i == nBufferBytes-l) {
733 fprintf(stderr, "No 'Content-Type: gnss/data' found\n");
[487]734 input_init = 0;
[1570]735 }
[9401]736 l = strlen(chunkycheck)-1;
737 j=0;
738 for(i = 0; j != l && i < nBufferBytes-l; ++i) {
739 for(j = 0; j < l && szSendBuffer[i+j] == chunkycheck[j]; ++j)
740 ;
741 }
742 if(i < nBufferBytes-l)
743 chunkymode = 1;
744 init = 1;
[485]745 }
[9401]746 else if (strstr(szSendBuffer, "\r\n")) {
747 if (!strstr(szSendBuffer, "ICY 200 OK")) {
748 int k;
749 fprintf(stderr, "ERROR: could not get requested data from Source caster: ");
750 for (k = 0; k < nBufferBytes && szSendBuffer[k] != '\n' && szSendBuffer[k] != '\r'; ++k) {
751 fprintf(stderr, "%c", isprint(szSendBuffer[k]) ? szSendBuffer[k] : '.');
[485]752 }
[9401]753 fprintf(stderr, "\n");
754 if (!strstr(szSendBuffer, "SOURCETABLE 200 OK")) {
755 reconnect_sec_max = 0;
756 }
757 input_init = 0;
758 break;
759 } else {// eventuell auskommentieren!
760 init = 1;
[485]761 }
762 }
763
[9401]764 }
765 /* end input from NTRIP caster */
766
767 if (initfile && inputmode != SISNET) {
[487]768 char buffer[1024];
769 FILE *fh;
770 int i;
[485]771
[9401]772 if ((fh = fopen(initfile, "r"))) {
773 while ((i = fread(buffer, 1, sizeof(buffer), fh)) > 0) {
774 if ((send(gps_socket, buffer, (size_t) i, 0)) != i) {
[1570]775 perror("WARNING: sending init file");
776 input_init = 0;
777 break;
[487]778 }
[485]779 }
[9401]780 if (i < 0) {
[487]781 perror("ERROR: reading init file");
782 reconnect_sec_max = 0;
783 input_init = 0;
784 break;
785 }
786 fclose(fh);
[9401]787 } else {
[487]788 fprintf(stderr, "ERROR: can't read init file <%s>\n", initfile);
789 reconnect_sec_max = 0;
790 input_init = 0;
791 break;
[485]792 }
[1570]793 }
[485]794 }
[9401]795 if (inputmode == SISNET) {
796 int i, j;
797 char buffer[1024];
[485]798
[9401]799 i = snprintf(buffer, sizeof(buffer),
800 sisnet >= 30 ? "AUTH,%s,%s\r\n" : "AUTH,%s,%s", sisnetuser,
801 sisnetpassword);
802 if ((send(gps_socket, buffer, (size_t) i, 0)) != i) {
803 perror("WARNING: sending authentication for SISNeT data server");
804 input_init = 0;
805 break;
806 }
807 i = sisnet >= 30 ? 7 : 5;
808 if ((j = recv(gps_socket, buffer, i, 0)) != i
809 && strncmp("*AUTH", buffer, 5)) {
810 fprintf(stderr, "WARNING: SISNeT connect failed:");
811 for (i = 0; i < j; ++i) {
812 if (buffer[i] != '\r' && buffer[i] != '\n') {
813 fprintf(stderr, "%c", isprint(buffer[i]) ? buffer[i] : '.');
814 }
[487]815 }
[9401]816 fprintf(stderr, "\n");
[487]817 input_init = 0;
818 break;
819 }
[9401]820 if (sisnet >= 31) {
821 if ((send(gps_socket, "START\r\n", 7, 0)) != i) {
822 perror("WARNING: sending Sisnet start command");
823 input_init = 0;
824 break;
825 }
826 }
[1570]827 }
[9401]828 /*** receiver authentication ***/
829 if (recvrid && recvrpwd
830 && ((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET))) {
831 if (strlen(recvrid) > (BUFSZ - 3)) {
832 fprintf(stderr, "ERROR: Receiver ID too long\n");
833 reconnect_sec_max = 0;
[487]834 input_init = 0;
835 break;
[9401]836 } else {
837 fprintf(stderr, "Sending user ID for receiver...\n");
838 nBufferBytes = recv(gps_socket, szSendBuffer, BUFSZ, 0);
839 strcpy(szSendBuffer, recvrid);
840 strcat(szSendBuffer, "\r\n");
841 if (send(gps_socket, szSendBuffer, strlen(szSendBuffer),
842 MSG_DONTWAIT) < 0) {
843 perror("WARNING: sending user ID for receiver");
844 input_init = 0;
845 break;
846 }
[485]847 }
[487]848
[9401]849 if (strlen(recvrpwd) > (BUFSZ - 3)) {
850 fprintf(stderr, "ERROR: Receiver password too long\n");
851 reconnect_sec_max = 0;
[487]852 input_init = 0;
853 break;
[9401]854 } else {
855 fprintf(stderr, "Sending user password for receiver...\n");
856 nBufferBytes = recv(gps_socket, szSendBuffer, BUFSZ, 0);
857 strcpy(szSendBuffer, recvrpwd);
858 strcat(szSendBuffer, "\r\n");
859 if (send(gps_socket, szSendBuffer, strlen(szSendBuffer),
860 MSG_DONTWAIT) < 0) {
861 perror("WARNING: sending user password for receiver");
862 input_init = 0;
863 break;
864 }
[487]865 }
[1570]866 }
[9401]867 break;
868 default:
869 usage(-1, argv[0]);
870 break;
[485]871 }
[1570]872
[487]873 /* ----- main part ----- */
[925]874 int output_init = 1, fallback = 0;
[487]875
[9401]876 while ((input_init) && (output_init)) {
[653]877#ifndef WINDOWSVERSION
[9401]878 if ((sigalarm_received) || (sigint_received) || (sigpipe_received))
879 break;
[653]880#else
881 if((sigalarm_received) || (sigint_received)) break;
882#endif
[9403]883
[9401]884 if (!(he = gethostbyname(outhost))) {
885 fprintf(stderr,
886 "ERROR: Destination caster, server or proxy host <%s> unknown\n",
887 outhost);
[915]888 close_session(casterouthost, mountpoint, session, rtsp_extension, 0);
[1570]889 usage(-2, argv[0]);
[9403]890 }else {fprintf(stderr,
891 "Destination caster, server or proxy host <%s> \n",
892 outhost);}
[485]893
[487]894 /* create socket */
[9401]895 if ((socket_tcp = socket(AF_INET, (outputmode == UDP ? SOCK_DGRAM : SOCK_STREAM), 0)) == INVALID_SOCKET) {
[1570]896 perror("ERROR: tcp socket");
[487]897 reconnect_sec_max = 0;
898 break;
[485]899 }
[9453]900
901 if (outputmode == TCPIP) {
902 // Forcefully attaching socket to the local port
903 int opt = 1;
904 if (setsockopt(socket_tcp, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
905 &opt, sizeof(opt))) {
906 perror("setsockopt");
907 break;
908 }
909 }
[9401]910 memset((char*) &caster, 0x00, sizeof(caster));
[487]911 memcpy(&caster.sin_addr, he->h_addr, (size_t)he->h_length);
912 caster.sin_family = AF_INET;
913 caster.sin_port = htons(outport);
[485]914
[9401]915 /* connect to Destination caster, server or proxy host */
[9403]916 fprintf(stderr, "caster|server output: host = %s, port = %d, mountpoint = %s"
[9401]917 ", mode = %s\n\n", inet_ntoa(caster.sin_addr), outport, mountpoint,
[9403]918 outputmode == NTRIP1 ? "ntrip1" :
919 outputmode == HTTP ? "http" :
920 outputmode == UDP ? "udp" :
[9448]921 outputmode == RTSP ? "rtsp" : "tcpip");
[485]922
[9453]923 if (outputmode == TCPIP) {
[9454]924 caster.sin_addr.s_addr = INADDR_ANY;
[9453]925 // Forcefully attaching socket to the local port
926 if (bind(socket_tcp, (struct sockaddr *)&caster, sizeof(caster)) < 0) {
927 perror("bind failed");
928 break;
929 }
930 if (listen(socket_tcp, 3) < 0) {
931 perror("listen");
932 break;
933 }
934 int addrlen = sizeof(caster);
935 if ((local_socket_tcp = accept(socket_tcp, (struct sockaddr *)&caster,
[9454]936 (socklen_t*)&addrlen)) < 0) {
[9453]937 perror("accept");
[9454]938 break;
[9453]939 }
[487]940 }
[9453]941 else {
942 if (connect(socket_tcp, (struct sockaddr*) &caster, sizeof(caster)) < 0) {
943 fprintf(stderr, "WARNING: can't connect output to %s at port %d",
944 inet_ntoa(caster.sin_addr), outport);
945 break;
946 }
947 }
[485]948
[487]949 /*** OutputMode handling ***/
[9401]950 switch (outputmode) {
951 case UDP: {
952 unsigned int session;
953 char rtpbuf[1526];
954 int i = 12, j;
[1570]955
[9401]956 udp_init = time(0);
957 srand(udp_init);
958 session = rand();
959 udp_tim = rand();
960 udp_seq = rand();
[1570]961
[9401]962 rtpbuf[0] = (2 << 6);
963 /* padding, extension, csrc are empty */
964 rtpbuf[1] = 97;
965 /* marker is empty */
966 rtpbuf[2] = (udp_seq >> 8) & 0xFF;
967 rtpbuf[3] = (udp_seq) & 0xFF;
968 rtpbuf[4] = (udp_tim >> 24) & 0xFF;
969 rtpbuf[5] = (udp_tim >> 16) & 0xFF;
970 rtpbuf[6] = (udp_tim >> 8) & 0xFF;
971 rtpbuf[7] = (udp_tim) & 0xFF;
972 /* sequence and timestamp are empty */
973 rtpbuf[8] = (session >> 24) & 0xFF;
974 rtpbuf[9] = (session >> 16) & 0xFF;
975 rtpbuf[10] = (session >> 8) & 0xFF;
976 rtpbuf[11] = (session) & 0xFF;
977 ++udp_seq;
[1570]978
[9401]979 j = snprintf(rtpbuf + i, sizeof(rtpbuf) - i - 40, /* leave some space for login */
980 "POST /%s HTTP/1.1\r\n"
981 "Host: %s\r\n"
982 "Ntrip-Version: Ntrip/2.0\r\n"
983 "User-Agent: %s/%s\r\n"
984 "Authorization: Basic %s%s%s\r\n"
985 "Connection: close\r\n"
986 "Transfer-Encoding: chunked\r\n\r\n", mountpoint, casterouthost,
987 AGENTSTRING, revisionstr, authorization,
988 ntrip_str ?
989 (outputmode == NTRIP1 ? "\r\nSTR: " : "\r\nNtrip-STR: ") : "",
990 ntrip_str);
991 i += j;
992 if (i > (int) sizeof(rtpbuf) - 40 || j < 0) /* second check for old glibc */
993 {
994 fprintf(stderr, "Requested data too long\n");
995 reconnect_sec_max = 0;
996 output_init = 0;
997 break;
998 } else {
999 rtpbuf[i++] = '\r';
1000 rtpbuf[i++] = '\n';
1001 rtpbuf[i++] = '\r';
1002 rtpbuf[i++] = '\n';
1003
1004 if (send(socket_tcp, rtpbuf, i, 0) != i) {
1005 perror("Could not send UDP packet");
[1570]1006 reconnect_sec_max = 0;
1007 output_init = 0;
1008 break;
[9401]1009 } else {
1010 int stop = 0;
1011 int numbytes;
1012 if ((numbytes = recv(socket_tcp, rtpbuf, sizeof(rtpbuf) - 1, 0))
1013 > 0) {
1014 /* we don't expect message longer than 1513, so we cut the last
1015 byte for security reasons to prevent buffer overrun */
1016 rtpbuf[numbytes] = 0;
1017 if (numbytes > 17 + 12
1018 && (!strncmp(rtpbuf + 12, "HTTP/1.1 200 OK\r\n", 17)
1019 || !strncmp(rtpbuf + 12, "HTTP/1.0 200 OK\r\n", 17))) {
1020 const char *sessioncheck = "session: ";
1021 int l = strlen(sessioncheck) - 1;
1022 int j = 0;
1023 for (i = 12; j != l && i < numbytes - l; ++i) {
1024 for (j = 0;
1025 j < l && tolower(rtpbuf[i + j]) == sessioncheck[j]; ++j)
1026 ;
[1570]1027 }
[9401]1028 if (i != numbytes - l) /* found a session number */
[1570]1029 {
[9401]1030 i += l;
1031 session = 0;
1032 while (i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9')
1033 session = session * 10 + rtpbuf[i++] - '0';
1034 if (rtpbuf[i] != '\r') {
1035 fprintf(stderr, "Could not extract session number\n");
1036 stop = 1;
[1570]1037 }
1038 }
[9401]1039 } else {
1040 int k;
1041 fprintf(stderr, "Could not access mountpoint: ");
1042 for (k = 12;
1043 k < numbytes && rtpbuf[k] != '\n' && rtpbuf[k] != '\r';
1044 ++k) {
1045 fprintf(stderr, "%c", isprint(rtpbuf[k]) ? rtpbuf[k] : '.');
1046 }
1047 fprintf(stderr, "\n");
1048 stop = 1;
[1570]1049 }
[9401]1050 }
1051 if (!stop) {
1052 send_receive_loop(socket_tcp, outputmode, NULL, 0, session, chunkymode);
1053 input_init = output_init = 0;
1054 /* send connection close always to allow nice session closing */
1055 udp_tim += (time(0) - udp_init) * 1000000 / TIME_RESOLUTION;
1056 rtpbuf[0] = (2 << 6);
1057 /* padding, extension, csrc are empty */
1058 rtpbuf[1] = 98;
1059 /* marker is empty */
1060 rtpbuf[2] = (udp_seq >> 8) & 0xFF;
1061 rtpbuf[3] = (udp_seq) & 0xFF;
1062 rtpbuf[4] = (udp_tim >> 24) & 0xFF;
1063 rtpbuf[5] = (udp_tim >> 16) & 0xFF;
1064 rtpbuf[6] = (udp_tim >> 8) & 0xFF;
1065 rtpbuf[7] = (udp_tim) & 0xFF;
1066 /* sequence and timestamp are empty */
1067 rtpbuf[8] = (session >> 24) & 0xFF;
1068 rtpbuf[9] = (session >> 16) & 0xFF;
1069 rtpbuf[10] = (session >> 8) & 0xFF;
1070 rtpbuf[11] = (session) & 0xFF;
[1570]1071
[9401]1072 send(socket_tcp, rtpbuf, 12, 0); /* cleanup */
1073 } else {
1074 reconnect_sec_max = 600;
1075 output_init = 0;
[1570]1076 }
1077 }
1078 }
[9401]1079 }
[1570]1080 break;
1081 case NTRIP1: /*** OutputMode Ntrip Version 1.0 ***/
[925]1082 fallback = 0;
[487]1083 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
[9401]1084 "SOURCE %s %s/%s\r\n"
1085 "Source-Agent: %s/%s\r\n\r\n", password, post_extension,
1086 mountpoint, AGENTSTRING, revisionstr);
1087 if ((nBufferBytes > (int) sizeof(szSendBuffer))
1088 || (nBufferBytes < 0)) {
[487]1089 fprintf(stderr, "ERROR: Destination caster request to long\n");
1090 reconnect_sec_max = 0;
1091 output_init = 0;
1092 break;
[485]1093 }
[9401]1094 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
[487]1095 output_init = 0;
1096 break;
[485]1097 }
[487]1098 /* check Destination caster's response */
[9403]1099 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
[487]1100 szSendBuffer[nBufferBytes] = '\0';
[9401]1101 if (!strstr(szSendBuffer, "OK")) {
[487]1102 char *a;
[485]1103 fprintf(stderr,
[9401]1104 "ERROR: Destination caster's or Proxy's reply is not OK: ");
1105 for (a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a) {
[487]1106 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
1107 }
1108 fprintf(stderr, "\n");
[9401]1109 if ((strstr(szSendBuffer, "ERROR - Bad Password"))
1110 || (strstr(szSendBuffer, "400 Bad Request")))
1111 reconnect_sec_max = 0;
[487]1112 output_init = 0;
[485]1113 break;
1114 }
1115#ifndef NDEBUG
[9401]1116 else {
1117 fprintf(stderr, "Destination caster response:\n%s\n", szSendBuffer);
[487]1118 }
[485]1119#endif
[9401]1120 send_receive_loop(socket_tcp, outputmode, NULL, 0, 0, chunkymode);
[653]1121 input_init = output_init = 0;
[485]1122 break;
[1570]1123 case HTTP: /*** Ntrip-Version 2.0 HTTP/1.1 ***/
[487]1124 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
[9401]1125 "POST %s/%s HTTP/1.1\r\n"
1126 "Host: %s\r\n"
1127 "Ntrip-Version: Ntrip/2.0\r\n"
1128 "User-Agent: %s/%s\r\n"
1129 "Authorization: Basic %s%s%s\r\n"
1130 "Connection: close\r\n"
1131 "Transfer-Encoding: chunked\r\n\r\n", post_extension,
1132 mountpoint, casterouthost, AGENTSTRING, revisionstr,
1133 authorization, ntrip_str ? "\r\nNtrip-STR: " : "", ntrip_str);
1134 if ((nBufferBytes > (int) sizeof(szSendBuffer))
1135 || (nBufferBytes < 0)) {
[487]1136 fprintf(stderr, "ERROR: Destination caster request to long\n");
1137 reconnect_sec_max = 0;
1138 output_init = 0;
1139 break;
1140 }
[9401]1141 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
[487]1142 output_init = 0;
1143 break;
1144 }
[485]1145 /* check Destination caster's response */
[9401]1146 nBufferBytes = recv(socket_tcp, szSendBuffer, sizeof(szSendBuffer), 0);
[485]1147 szSendBuffer[nBufferBytes] = '\0';
[9401]1148 if (!strstr(szSendBuffer, "HTTP/1.1 200 OK")) {
[485]1149 char *a;
[9401]1150 fprintf(stderr, "ERROR: Destination caster's%s reply is not OK: ",
1151 *proxyhost ? " or Proxy's" : "");
1152 for (a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a) {
[487]1153 fprintf(stderr, "%.1s", isprint(*a) ? a : ".");
[485]1154 }
1155 fprintf(stderr, "\n");
1156 /* fallback if necessary */
[9401]1157 if (!strstr(szSendBuffer, "Ntrip-Version: Ntrip/2.0\r\n")) {
[487]1158 fprintf(stderr,
[9401]1159 " Ntrip Version 2.0 not implemented at Destination caster"
1160 " <%s>%s%s%s\n%s\n"
1161 "ntripserver falls back to Ntrip Version 1.0\n\n",
1162 casterouthost, *proxyhost ? " or Proxy <" : "", proxyhost,
1163 *proxyhost ? ">" : "",
1164 *proxyhost ?
1165 " or HTTP/1.1 not implemented at Proxy\n" : "");
[915]1166 close_session(casterouthost, mountpoint, session, rtsp_extension, 1);
[487]1167 outputmode = NTRIP1;
1168 break;
[9401]1169 } else if ((strstr(szSendBuffer, "HTTP/1.1 401 Unauthorized"))
1170 || (strstr(szSendBuffer, "501 Not Implemented"))) {
1171 reconnect_sec_max = 0;
[485]1172 }
[487]1173 output_init = 0;
1174 break;
[485]1175 }
1176#ifndef NDEBUG
[9401]1177 else {
1178 fprintf(stderr, "Destination caster response:\n%s\n", szSendBuffer);
[485]1179 }
1180#endif
[9401]1181 send_receive_loop(socket_tcp, outputmode, NULL, 0, 0, chunkymode);
[653]1182 input_init = output_init = 0;
[487]1183 break;
[1570]1184 case RTSP: /*** Ntrip-Version 2.0 RTSP / RTP ***/
[9401]1185 if ((socket_udp = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
[487]1186 perror("ERROR: udp socket");
1187 exit(4);
1188 }
1189 /* fill structure with local address information for UDP */
1190 memset(&local, 0, sizeof(local));
1191 local.sin_family = AF_INET;
1192 local.sin_port = htons(0);
1193 local.sin_addr.s_addr = htonl(INADDR_ANY);
[9401]1194 len = (socklen_t) sizeof(local);
[487]1195 /* bind() in order to get a random RTP client_port */
[9401]1196 if ((bind(socket_udp, (struct sockaddr*) &local, len)) < 0) {
[487]1197 perror("ERROR: udp bind");
1198 reconnect_sec_max = 0;
1199 output_init = 0;
1200 break;
1201 }
[9448]1202 if ((getsockname(socket_udp, (struct sockaddr*) &local, &len)) != -1) {
[9401]1203 client_port = (unsigned int) ntohs(local.sin_port);
1204 } else {
[487]1205 perror("ERROR: getsockname(localhost)");
1206 reconnect_sec_max = 0;
1207 output_init = 0;
1208 break;
1209 }
1210 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
[9401]1211 "SETUP rtsp://%s%s/%s RTSP/1.0\r\n"
1212 "CSeq: %d\r\n"
1213 "Ntrip-Version: Ntrip/2.0\r\n"
1214 "Ntrip-Component: Ntripserver\r\n"
1215 "User-Agent: %s/%s\r\n"
1216 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
1217 "Authorization: Basic %s%s%s\r\n\r\n", casterouthost,
1218 rtsp_extension, mountpoint, udp_cseq++, AGENTSTRING, revisionstr,
1219 client_port, authorization, ntrip_str ? "\r\nNtrip-STR: " : "",
1220 ntrip_str);
1221 if ((nBufferBytes > (int) sizeof(szSendBuffer))
1222 || (nBufferBytes < 0)) {
[487]1223 fprintf(stderr, "ERROR: Destination caster request to long\n");
1224 reconnect_sec_max = 0;
1225 output_init = 0;
1226 break;
1227 }
[9401]1228 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
[487]1229 output_init = 0;
1230 break;
1231 }
[9401]1232 while ((nBufferBytes = recv(socket_tcp, szSendBuffer,
1233 sizeof(szSendBuffer), 0)) > 0) {
[487]1234 /* check Destination caster's response */
1235 szSendBuffer[nBufferBytes] = '\0';
[9401]1236 if (!strstr(szSendBuffer, "RTSP/1.0 200 OK")) {
[487]1237 char *a;
[9401]1238 fprintf(stderr, "ERROR: Destination caster's%s reply is not OK: ",
1239 *proxyhost ? " or Proxy's" : "");
1240 for (a = szSendBuffer; *a && *a != '\n' && *a != '\r'; ++a) {
[1570]1241 fprintf(stderr, "%c", isprint(*a) ? *a : '.');
[487]1242 }
1243 fprintf(stderr, "\n");
1244 /* fallback if necessary */
[9401]1245 if (strncmp(szSendBuffer, "RTSP", 4) != 0) {
1246 if (strstr(szSendBuffer, "Ntrip-Version: Ntrip/2.0\r\n")) {
[487]1247 fprintf(stderr,
[9401]1248 " RTSP not implemented at Destination caster <%s>%s%s%s\n\n"
1249 "ntripserver falls back to Ntrip Version 2.0 in TCP/IP"
1250 " mode\n\n", casterouthost,
1251 *proxyhost ? " or Proxy <" : "", proxyhost,
1252 *proxyhost ? ">" : "");
1253 close_session(casterouthost, mountpoint, session,
1254 rtsp_extension, 1);
[487]1255 outputmode = HTTP;
[925]1256 fallback = 1;
[487]1257 break;
[9401]1258 } else {
[487]1259 fprintf(stderr,
[9401]1260 " Ntrip-Version 2.0 not implemented at Destination caster"
1261 "<%s>%s%s%s\n%s"
1262 " or RTSP/1.0 not implemented at Destination caster%s\n\n"
1263 "ntripserver falls back to Ntrip Version 1.0\n\n",
1264 casterouthost, *proxyhost ? " or Proxy <" : "", proxyhost,
1265 *proxyhost ? ">" : "",
1266 *proxyhost ?
1267 " or HTTP/1.1 not implemented at Proxy\n" : "",
1268 *proxyhost ? " or Proxy" : "");
1269 close_session(casterouthost, mountpoint, session,
1270 rtsp_extension, 1);
[487]1271 outputmode = NTRIP1;
[925]1272 fallback = 1;
[487]1273 break;
[1570]1274 }
[9401]1275 } else if ((strstr(szSendBuffer, "RTSP/1.0 401 Unauthorized"))
1276 || (strstr(szSendBuffer, "RTSP/1.0 501 Not Implemented"))) {
[487]1277 reconnect_sec_max = 0;
1278 }
1279 output_init = 0;
1280 break;
[485]1281 }
[487]1282#ifndef NDEBUG
[9401]1283 else {
1284 fprintf(stderr, "Destination caster response:\n%s\n", szSendBuffer);
[485]1285 }
[487]1286#endif
[9401]1287 if ((strstr(szSendBuffer, "RTSP/1.0 200 OK\r\n"))
1288 && (strstr(szSendBuffer, "CSeq: 1\r\n"))) {
1289 for (token = strtok(szSendBuffer, dlim); token != NULL; token =
1290 strtok(NULL, dlim)) {
1291 tok_buf[i] = token;
1292 i++;
[487]1293 }
1294 session = atoi(tok_buf[6]);
1295 server_port = atoi(tok_buf[10]);
1296 nBufferBytes = snprintf(szSendBuffer, sizeof(szSendBuffer),
[9401]1297 "RECORD rtsp://%s%s/%s RTSP/1.0\r\n"
1298 "CSeq: %d\r\n"
1299 "Session: %u\r\n"
1300 "\r\n", casterouthost, rtsp_extension, mountpoint,
1301 udp_cseq++, session);
1302 if ((nBufferBytes >= (int) sizeof(szSendBuffer))
1303 || (nBufferBytes < 0)) {
1304 fprintf(stderr, "ERROR: Destination caster request to long\n");
[487]1305 reconnect_sec_max = 0;
1306 output_init = 0;
[1570]1307 break;
[487]1308 }
[9401]1309 if (!send_to_caster(szSendBuffer, socket_tcp, nBufferBytes)) {
[653]1310 output_init = 0;
[9401]1311 break;
[487]1312 }
[9401]1313 } else if ((strstr(szSendBuffer, "RTSP/1.0 200 OK\r\n"))
1314 && (strstr(szSendBuffer, "CSeq: 2\r\n"))) {
[487]1315 /* fill structure with caster address information for UDP */
1316 memset(&casterRTP, 0, sizeof(casterRTP));
1317 casterRTP.sin_family = AF_INET;
[9401]1318 casterRTP.sin_port = htons(((uint16_t) server_port));
1319 if ((he = gethostbyname(outhost)) == NULL) {
[1570]1320 fprintf(stderr, "ERROR: Destination caster unknown\n");
[487]1321 reconnect_sec_max = 0;
1322 output_init = 0;
1323 break;
[9401]1324 } else {
1325 memcpy((char*) &casterRTP.sin_addr.s_addr, he->h_addr_list[0],
1326 (size_t) he->h_length);
[487]1327 }
[9401]1328 len = (socklen_t) sizeof(casterRTP);
1329 send_receive_loop(socket_udp, outputmode,
1330 (struct sockaddr*) &casterRTP, (socklen_t) len, session, chunkymode);
[487]1331 break;
[9401]1332 } else {
1333 break;
[485]1334 }
[487]1335 }
[653]1336 input_init = output_init = 0;
[487]1337 break;
[9448]1338 case TCPIP:
[9403]1339 fallback = 0;
[9453]1340 send_receive_loop(local_socket_tcp, outputmode, NULL, 0, 0, chunkymode);
[9403]1341 input_init = output_init = 0;
[9401]1342 break;
[765]1343 }
[485]1344 }
[915]1345 close_session(casterouthost, mountpoint, session, rtsp_extension, 0);
[9401]1346 if ((reconnect_sec_max || fallback) && !sigint_received)
[653]1347 reconnect_sec = reconnect(reconnect_sec, reconnect_sec_max);
[9401]1348 else
1349 inputmode = LAST;
[485]1350 }
1351 return 0;
1352}
1353
[9401]1354static void send_receive_loop(sockettype sock, int outmode,
1355 struct sockaddr *pcasterRTP, socklen_t length, unsigned int rtpssrc,
1356 int chunkymode) {
1357 int nodata = 0;
1358 char buffer[BUFSZ] = { 0 };
1359 char sisnetbackbuffer[200];
1360 char szSendBuffer[BUFSZ] = "";
1361 int nBufferBytes = 0;
1362 int remainChunk = 0;
[485]1363
[9401]1364 /* RTSP / RTP Mode */
1365 int isfirstpacket = 1;
1366 struct timeval now;
1367 struct timeval last = { 0, 0 };
[485]1368 long int sendtimediff;
[9401]1369 int rtpseq = 0;
1370 int rtptime = 0;
1371 time_t laststate = time(0);
[485]1372
[9401]1373 if (outmode == UDP) {
[1570]1374 rtptime = time(0);
[915]1375#ifdef WINDOWSVERSION
1376 u_long blockmode = 1;
1377 if(ioctlsocket(socket_tcp, FIONBIO, &blockmode))
1378#else /* WINDOWSVERSION */
[9401]1379 if (fcntl(socket_tcp, F_SETFL, O_NONBLOCK) < 0)
[915]1380#endif /* WINDOWSVERSION */
[9401]1381 {
[915]1382 fprintf(stderr, "Could not set nonblocking mode\n");
1383 return;
1384 }
[9401]1385 } else if (outmode == RTSP) {
[1570]1386#ifdef WINDOWSVERSION
1387 u_long blockmode = 1;
1388 if(ioctlsocket(socket_tcp, FIONBIO, &blockmode))
1389#else /* WINDOWSVERSION */
[9401]1390 if (fcntl(socket_tcp, F_SETFL, O_NONBLOCK) < 0)
[1570]1391#endif /* WINDOWSVERSION */
[9401]1392 {
[1570]1393 fprintf(stderr, "Could not set nonblocking mode\n");
1394 return;
1395 }
1396 }
[915]1397
[485]1398 /* data transmission */
[9401]1399 fprintf(stderr, "transfering data ...\n");
1400 int send_recv_success = 0;
[1570]1401#ifdef WINDOWSVERSION
1402 time_t nodata_begin = 0, nodata_current = 0;
[653]1403#endif
[9401]1404 while (1) {
1405 if (send_recv_success < 3)
1406 send_recv_success++;
1407 if (!nodata) {
[653]1408#ifndef WINDOWSVERSION
1409 alarm(ALARMTIME);
1410#else
1411 time(&nodata_begin);
1412#endif
[9401]1413 } else {
[1570]1414 nodata = 0;
1415#ifdef WINDOWSVERSION
[653]1416 time(&nodata_current);
[9401]1417 if(difftime(nodata_current, nodata_begin) >= ALARMTIME) {
[653]1418 sigalarm_received = 1;
1419 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
1420 }
1421#endif
1422 }
[487]1423 /* signal handling*/
[653]1424#ifdef WINDOWSVERSION
1425 if((sigalarm_received) || (sigint_received)) break;
1426#else
[9401]1427 if ((sigalarm_received) || (sigint_received) || (sigpipe_received))
1428 break;
[653]1429#endif
[9401]1430 if (!nBufferBytes) {
1431 if (inputmode == SISNET && sisnet <= 30) {
[485]1432 int i;
1433 /* a somewhat higher rate than 1 second to get really each block */
1434 /* means we need to skip double blocks sometimes */
[9401]1435 struct timeval tv = { 0, 700000 };
[485]1436 select(0, 0, 0, 0, &tv);
1437 memcpy(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer));
1438 i = (sisnet >= 30 ? 5 : 3);
[9401]1439 if ((send(gps_socket, "MSG\r\n", i, 0)) != i) {
[487]1440 perror("WARNING: sending SISNeT data request failed");
1441 return;
[485]1442 }
1443 }
[9403]1444 /***********************/
1445 /* receiving data */
1446 /***********************/
1447
1448 /* INFILE */
[9401]1449 if (inputmode == INFILE)
[653]1450 nBufferBytes = read(gps_file, buffer, sizeof(buffer));
[9403]1451
1452 /* SERIAL */
[9401]1453 else if (inputmode == SERIAL) {
[1570]1454#ifndef WINDOWSVERSION
[653]1455 nBufferBytes = read(gps_serial, buffer, sizeof(buffer));
1456#else
[1570]1457 DWORD nRead = 0;
[653]1458 if(!ReadFile(gps_serial, buffer, sizeof(buffer), &nRead, NULL))
1459 {
1460 fprintf(stderr,"ERROR: reading serial input failed\n");
1461 return;
1462 }
1463 nBufferBytes = (int)nRead;
1464#endif
1465 }
[9403]1466
1467 /* ALL OTHER MODES */
[768]1468 else
1469#ifdef WINDOWSVERSION
[653]1470 nBufferBytes = recv(gps_socket, buffer, sizeof(buffer), 0);
[768]1471#else
1472 nBufferBytes = read(gps_socket, buffer, sizeof(buffer));
1473#endif
[9401]1474 if (!nBufferBytes) {
[653]1475 fprintf(stderr, "WARNING: no data received from input\n");
1476 nodata = 1;
1477#ifndef WINDOWSVERSION
[485]1478 sleep(3);
[653]1479#else
1480 Sleep(3*1000);
1481#endif
[485]1482 continue;
[9401]1483 } else if ((nBufferBytes < 0) && (!sigint_received)) {
[487]1484 perror("WARNING: reading input failed");
1485 return;
[485]1486 }
1487 /* we can compare the whole buffer, as the additional bytes
[9401]1488 remain unchanged */
1489 if (inputmode == SISNET && sisnet <= 30
1490 && !memcmp(sisnetbackbuffer, buffer, sizeof(sisnetbackbuffer))) {
[485]1491 nBufferBytes = 0;
1492 }
1493 }
[9401]1494 if (nBufferBytes < 0)
[1570]1495 return;
[9401]1496
1497 if (chunkymode) {
1498 int cstop = 0;
1499 int pos = 0;
1500 int chunksize = 0;
1501 int totalbytes = 0;
1502 int nChunkBytes = 0;
[9457]1503 char chunkBytes[BUFSZ] = { 0 };
[9401]1504
[9402]1505 long i;
[9401]1506 while (!sigint_received && !cstop && pos < nBufferBytes) {
1507 switch (chunkymode) {
1508 case 1: /* reading number starts */
1509 chunksize = 0;
1510 ++chunkymode; /* no break */
1511 break;
1512 case 2: /* during reading number */
1513 i = buffer[pos++];
1514 if (i >= '0' && i <= '9')
1515 chunksize = chunksize * 16 + i - '0';
1516 else if (i >= 'a' && i <= 'f')
1517 chunksize = chunksize * 16 + i - 'a' + 10;
1518 else if (i >= 'A' && i <= 'F')
1519 chunksize = chunksize * 16 + i - 'A' + 10;
1520 else if (i == '\r')
1521 ++chunkymode;
1522 else if (i == ';')
1523 chunkymode = 5;
1524 else
1525 cstop = 1;
1526 break;
1527 case 3: /* scanning for return */
1528 if (buffer[pos++] == '\n')
1529 chunkymode = chunksize ? 4 : 1;
1530 else
1531 cstop = 1;
1532 break;
1533 case 4: /* output data */
1534 i = nBufferBytes - pos;
1535 if (i > chunksize) {
1536 i = chunksize;
1537 }
[9460]1538// if (nChunkBytes <= nBufferBytes) {
[9401]1539 memcpy(chunkBytes + nChunkBytes, buffer + pos, (size_t) i);
1540 nChunkBytes += i;
[9460]1541// }
[9401]1542 totalbytes += i;
1543 chunksize -= i;
1544 pos += i;
1545 if (!chunksize)
1546 chunkymode = 1;
1547 break;
1548 case 5:
1549 if (i == '\r')
1550 chunkymode = 3;
1551 break;
1552 }
1553 }
1554 if (cstop) {
1555 fprintf(stderr, "Error in chunky transfer encoding\n");
1556 return;
1557 }
1558 else {
[9458]1559 memset((char*) &buffer, 0x00, sizeof(buffer));
1560 memcpy(buffer, chunkBytes, (size_t) nChunkBytes);
1561 nBufferBytes = nChunkBytes;
[9401]1562 }
1563 }
[9403]1564
1565 /*****************/
1566 /* send data */
1567 /*****************/
[9448]1568 if ((nBufferBytes) && (outmode == NTRIP1 || outmode == TCPIP)) {
[485]1569 int i;
[9401]1570 if ((i = send(sock, buffer, (size_t) nBufferBytes, MSG_DONTWAIT)) != nBufferBytes) {
1571 if (i < 0) {
1572 if (errno != EAGAIN) {
[9460]1573 perror("WARNING: could not send data to Destination caster or localhost");
1574 return;
[485]1575 }
[9401]1576 } else if (i) {
1577 memmove(buffer, buffer + i, (size_t) (nBufferBytes - i));
[485]1578 nBufferBytes -= i;
1579 }
[9401]1580 } else {
[485]1581 nBufferBytes = 0;
1582 }
[9454]1583 }
1584 else if ((nBufferBytes) && (outmode == UDP)) {
[1570]1585 char rtpbuf[1592];
1586 int i;
1587 int ct = time(0);
[9401]1588 udp_tim += (ct - udp_init) * 1000000 / TIME_RESOLUTION;
[1570]1589 udp_init = ct;
[9401]1590 rtpbuf[0] = (2 << 6);
[1570]1591 rtpbuf[1] = 96;
[9401]1592 rtpbuf[2] = (udp_seq >> 8) & 0xFF;
1593 rtpbuf[3] = (udp_seq) & 0xFF;
1594 rtpbuf[4] = (udp_tim >> 24) & 0xFF;
1595 rtpbuf[5] = (udp_tim >> 16) & 0xFF;
1596 rtpbuf[6] = (udp_tim >> 8) & 0xFF;
1597 rtpbuf[7] = (udp_tim) & 0xFF;
1598 rtpbuf[8] = (rtpssrc >> 24) & 0xFF;
1599 rtpbuf[9] = (rtpssrc >> 16) & 0xFF;
1600 rtpbuf[10] = (rtpssrc >> 8) & 0xFF;
1601 rtpbuf[11] = (rtpssrc) & 0xFF;
[1570]1602 ++udp_seq;
[9401]1603 memcpy(rtpbuf + 12, buffer, nBufferBytes);
1604 if ((i = send(socket_tcp, rtpbuf, (size_t) nBufferBytes + 12, MSG_DONTWAIT)) != nBufferBytes + 12) {
1605 if (errno != EAGAIN) {
[1570]1606 perror("WARNING: could not send data to Destination caster");
1607 return;
1608 }
[9401]1609 } else
[1570]1610 nBufferBytes = 0;
1611 i = recv(socket_tcp, rtpbuf, sizeof(rtpbuf), 0);
[9401]1612 if (i >= 12 && (unsigned char) rtpbuf[0] == (2 << 6)
1613 && rtpssrc
1614 == (unsigned int) (((unsigned char) rtpbuf[8] << 24)
1615 + ((unsigned char) rtpbuf[9] << 16)
1616 + ((unsigned char) rtpbuf[10] << 8)
1617 + (unsigned char) rtpbuf[11])) {
1618 if (rtpbuf[1] == 96)
1619 rtptime = time(0);
1620 else if (rtpbuf[1] == 98) {
1621 fprintf(stderr, "Connection end\n");
1622 return;
[1573]1623 }
[9401]1624 } else if (time(0) > rtptime + 60) {
[1570]1625 fprintf(stderr, "Timeout\n");
1626 return;
1627 }
1628 }
[485]1629 /*** Ntrip-Version 2.0 HTTP/1.1 ***/
[9401]1630 else if ((nBufferBytes) && (outmode == HTTP)) {
1631 if (!remainChunk) {
1632 int nChunkBytes = snprintf(szSendBuffer, sizeof(szSendBuffer), "%x\r\n", nBufferBytes);
[8788]1633 send(sock, szSendBuffer, nChunkBytes, 0);
1634 remainChunk = nBufferBytes;
[8784]1635 }
[9401]1636 int i = send(sock, buffer, (size_t) remainChunk, MSG_DONTWAIT);
1637 if (i < 0) {
1638 if (errno != EAGAIN) {
[8788]1639 perror("WARNING: could not send data to Destination caster");
1640 return;
[485]1641 }
[9401]1642 } else if (i) {
1643 memmove(buffer, buffer + i, (size_t) (nBufferBytes - i));
[8788]1644 nBufferBytes -= i;
1645 remainChunk -= i;
[9401]1646 } else {
1647 nBufferBytes = 0;
1648 remainChunk = 0;
[8788]1649 }
[9401]1650 if (!remainChunk)
[8787]1651 send(sock, "\r\n", strlen("\r\n"), 0);
[485]1652 }
1653 /*** Ntrip-Version 2.0 RTSP(TCP) / RTP(UDP) ***/
[9401]1654 else if ((nBufferBytes) && (outmode == RTSP)) {
[915]1655 time_t ct;
1656 int r;
[9401]1657 char rtpbuffer[BUFSZ + 12];
[485]1658 int i, j;
1659 gettimeofday(&now, NULL);
1660 /* RTP data packet generation*/
[9401]1661 if (isfirstpacket) {
[485]1662 rtpseq = rand();
1663 rtptime = rand();
1664 last = now;
1665 isfirstpacket = 0;
[9401]1666 } else {
[485]1667 ++rtpseq;
[9401]1668 sendtimediff = (((now.tv_sec - last.tv_sec) * 1000000)
1669 + (now.tv_usec - last.tv_usec));
1670 rtptime += sendtimediff / TIME_RESOLUTION;
[485]1671 }
[9401]1672 rtpbuffer[0] = (RTP_VERSION << 6);
[485]1673 /* padding, extension, csrc are empty */
1674 rtpbuffer[1] = 96;
1675 /* marker is empty */
[9401]1676 rtpbuffer[2] = rtpseq >> 8;
[485]1677 rtpbuffer[3] = rtpseq;
[9401]1678 rtpbuffer[4] = rtptime >> 24;
1679 rtpbuffer[5] = rtptime >> 16;
1680 rtpbuffer[6] = rtptime >> 8;
[485]1681 rtpbuffer[7] = rtptime;
[9401]1682 rtpbuffer[8] = rtpssrc >> 24;
1683 rtpbuffer[9] = rtpssrc >> 16;
1684 rtpbuffer[10] = rtpssrc >> 8;
[485]1685 rtpbuffer[11] = rtpssrc;
[9401]1686 for (j = 0; j < nBufferBytes; j++) {
1687 rtpbuffer[12 + j] = buffer[j];
1688 }
1689 last.tv_sec = now.tv_sec;
[485]1690 last.tv_usec = now.tv_usec;
[9401]1691 if ((i = sendto(sock, rtpbuffer, 12 + nBufferBytes, 0, pcasterRTP, length))
1692 != (nBufferBytes + 12)) {
1693 if (i < 0) {
1694 if (errno != EAGAIN) {
[487]1695 perror("WARNING: could not send data to Destination caster");
[485]1696 return;
1697 }
[9401]1698 } else if (i) {
1699 memmove(buffer, buffer + (i - 12),
1700 (size_t) (nBufferBytes - (i - 12)));
1701 nBufferBytes -= i - 12;
[485]1702 }
[9401]1703 } else {
[485]1704 nBufferBytes = 0;
1705 }
[915]1706 ct = time(0);
[9401]1707 if (ct - laststate > 15) {
[915]1708 i = snprintf(buffer, sizeof(buffer),
[9401]1709 "GET_PARAMETER rtsp://%s%s/%s RTSP/1.0\r\n"
1710 "CSeq: %d\r\n"
1711 "Session: %u\r\n"
1712 "\r\n", casterouthost, rtsp_extension, mountpoint, udp_cseq++,
1713 rtpssrc);
1714 if (i > (int) sizeof(buffer) || i < 0) {
[915]1715 fprintf(stderr, "Requested data too long\n");
1716 return;
[9401]1717 } else if (send(socket_tcp, buffer, (size_t) i, 0) != i) {
[915]1718 perror("send");
1719 return;
1720 }
1721 laststate = ct;
1722 }
1723 /* ignore RTSP server replies */
[9401]1724 if ((r = recv(socket_tcp, buffer, sizeof(buffer), 0)) < 0) {
[915]1725#ifdef WINDOWSVERSION
1726 if(WSAGetLastError() != WSAEWOULDBLOCK)
1727#else /* WINDOWSVERSION */
[9401]1728 if (errno != EAGAIN)
[915]1729#endif /* WINDOWSVERSION */
1730 {
1731 fprintf(stderr, "Control connection closed\n");
1732 return;
1733 }
[9401]1734 } else if (!r) {
[915]1735 fprintf(stderr, "Control connection read error\n");
1736 return;
1737 }
[485]1738 }
[9401]1739 if (send_recv_success == 3)
1740 reconnect_sec = 1;
[485]1741 }
1742 return;
1743}
1744
1745/********************************************************************
1746 * openserial
1747 *
1748 * Open the serial port with the given device name and configure it for
1749 * reading NMEA data from a GPS receiver.
1750 *
1751 * Parameters:
1752 * tty : pointer to : A zero-terminated string containing the device
1753 * unsigned char name of the appropriate serial port.
[653]1754 * blocksz : integer : Block size for port I/O (ifndef WINDOWSVERSION)
[485]1755 * baud : integer : Baud rate for port I/O
1756 *
1757 * Return Value:
1758 * The function returns a file descriptor for the opened port if successful.
[653]1759 * The function returns -1 / INVALID_HANDLE_VALUE in the event of an error.
[485]1760 *
1761 * Remarks:
1762 *
1763 ********************************************************************/
[653]1764#ifndef WINDOWSVERSION
[9401]1765static int openserial(const char *tty, int blocksz, int baud) {
[485]1766 struct termios termios;
1767
[9401]1768 /*** opening the serial port ***/
[653]1769 gps_serial = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK);
[9401]1770 if (gps_serial < 0) {
[485]1771 perror("ERROR: opening serial connection");
1772 return (-1);
1773 }
[653]1774
[9401]1775 /*** configuring the serial port ***/
1776 if (tcgetattr(gps_serial, &termios) < 0) {
[485]1777 perror("ERROR: get serial attributes");
1778 return (-1);
1779 }
1780 termios.c_iflag = 0;
[9401]1781 termios.c_oflag = 0; /* (ONLRET) */
[485]1782 termios.c_cflag = CS8 | CLOCAL | CREAD;
1783 termios.c_lflag = 0;
1784 {
1785 int cnt;
[9401]1786 for (cnt = 0; cnt < NCCS; cnt++)
[485]1787 termios.c_cc[cnt] = -1;
1788 }
1789 termios.c_cc[VMIN] = blocksz;
1790 termios.c_cc[VTIME] = 2;
1791
1792#if (B4800 != 4800)
[9401]1793 /* Not every system has speed settings equal to absolute speed value. */
1794 switch (baud) {
1795 case 300:
1796 baud = B300;
1797 break;
1798 case 1200:
1799 baud = B1200;
1800 break;
1801 case 2400:
1802 baud = B2400;
1803 break;
1804 case 4800:
1805 baud = B4800;
1806 break;
1807 case 9600:
1808 baud = B9600;
1809 break;
1810 case 19200:
1811 baud = B19200;
1812 break;
1813 case 38400:
1814 baud = B38400;
1815 break;
[485]1816#ifdef B57600
[9401]1817 case 57600:
1818 baud = B57600;
1819 break;
[485]1820#endif
1821#ifdef B115200
[9401]1822 case 115200:
1823 baud = B115200;
1824 break;
[485]1825#endif
1826#ifdef B230400
[9401]1827 case 230400:
1828 baud = B230400;
1829 break;
[485]1830#endif
[9401]1831 default:
1832 fprintf(stderr, "WARNING: Baud settings not useful, using 19200\n");
1833 baud = B19200;
1834 break;
[485]1835 }
1836#endif
1837
[9401]1838 if (cfsetispeed(&termios, baud) != 0) {
[485]1839 perror("ERROR: setting serial speed with cfsetispeed");
1840 return (-1);
1841 }
[9401]1842 if (cfsetospeed(&termios, baud) != 0) {
[485]1843 perror("ERROR: setting serial speed with cfsetospeed");
1844 return (-1);
1845 }
[9401]1846 if (tcsetattr(gps_serial, TCSANOW, &termios) < 0) {
[485]1847 perror("ERROR: setting serial attributes");
1848 return (-1);
1849 }
[9401]1850 if (fcntl(gps_serial, F_SETFL, 0) == -1) {
[485]1851 perror("WARNING: setting blocking inputmode failed");
1852 }
[653]1853 return (gps_serial);
1854}
1855#else
[9401]1856static HANDLE openserial(const char * tty, int baud) {
[654]1857 char compath[15] = "";
[653]1858
[654]1859 snprintf(compath, sizeof(compath), "\\\\.\\%s", tty);
[2273]1860 if((gps_serial = CreateFile(compath, GENERIC_WRITE|GENERIC_READ
[9401]1861 , 0, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
[653]1862 fprintf(stderr, "ERROR: opening serial connection\n");
1863 return (INVALID_HANDLE_VALUE);
1864 }
[2273]1865
1866 DCB dcb;
1867 memset(&dcb, 0, sizeof(dcb));
1868 char str[100];
1869 snprintf(str,sizeof(str),
1870 "baud=%d parity=N data=8 stop=1 xon=off octs=off rts=off",
1871 baud);
1872
1873 COMMTIMEOUTS ct = {1000, 1, 0, 0, 0};
1874
[9401]1875 if(!BuildCommDCB(str, &dcb)) {
[653]1876 fprintf(stderr, "ERROR: get serial attributes\n");
1877 return (INVALID_HANDLE_VALUE);
1878 }
[9401]1879 else if(!SetCommState(gps_serial, &dcb)) {
[2273]1880 fprintf(stderr, "ERROR: set serial attributes\n");
[653]1881 return (INVALID_HANDLE_VALUE);
1882 }
[9401]1883 else if(!SetCommTimeouts(gps_serial, &ct)) {
[653]1884 fprintf(stderr, "ERROR: set serial timeouts\n");
[1570]1885 return (INVALID_HANDLE_VALUE);
[653]1886 }
[2273]1887
[653]1888 return (gps_serial);
[2273]1889}
[653]1890#endif
[485]1891
1892/********************************************************************
[9401]1893 * usage
1894 *
1895 * Send a usage message to standard error and quit the program.
1896 *
1897 * Parameters:
1898 * None.
1899 *
1900 * Return Value:
1901 * The function does not return a value.
1902 *
1903 * Remarks:
1904 *
1905 *********************************************************************/
[485]1906#ifdef __GNUC__
1907__attribute__ ((noreturn))
1908#endif /* __GNUC__ */
[9401]1909void usage(int rc, char *name) {
[485]1910 fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s [OPTIONS]\n",
[9401]1911 revisionstr, datestr, name);
[485]1912 fprintf(stderr, "PURPOSE\n");
[9401]1913 fprintf(stderr,
1914 " The purpose of this program is to pick up a GNSS data stream (Input, Source)\n");
[485]1915 fprintf(stderr, " from either\n\n");
1916 fprintf(stderr, " 1. a Serial port, or\n");
1917 fprintf(stderr, " 2. an IP server, or\n");
1918 fprintf(stderr, " 3. a File, or\n");
1919 fprintf(stderr, " 4. a SISNeT Data Server, or\n");
1920 fprintf(stderr, " 5. a UDP server, or\n");
[9401]1921 fprintf(stderr, " 6. an NTRIP Version 1.0 Caster\n");
1922 fprintf(stderr, " 7. an NTRIP Version 2.0 Caster in HTTP mode \n\n");
1923 fprintf(stderr,
1924 " and forward that incoming stream (Output, Destination) to either\n\n");
[9448]1925 fprintf(stderr, " 1. an NTRIP Version 2.0 Caster via TCP/IP (Output, Destination), or\n");
1926 fprintf(stderr, " 2. an NTRIP Version 2.0 Caster via RTSP/RTP (Output, Destination), or\n");
1927 fprintf(stderr, " 3. an NTRIP Version 2.0 Caster via plain UDP (Output, Destination), or\n");
1928 fprintf(stderr, " 4. an NTRIP Version 1.0 Caster, or\n");
1929 fprintf(stderr, " 5. an IP server via TCP/IP\n\n\n");
[485]1930 fprintf(stderr, "OPTIONS\n");
1931 fprintf(stderr, " -h|? print this help screen\n\n");
[9403]1932 fprintf(stderr, " -E <ProxyHost> Proxy server host name or address, required i.e. when\n");
1933 fprintf(stderr, " running the program in a proxy server protected LAN,\n");
[485]1934 fprintf(stderr, " optional\n");
[9403]1935 fprintf(stderr, " -F <ProxyPort> Proxy server IP port, required i.e. when running\n");
1936 fprintf(stderr, " the program in a proxy server protected LAN, optional\n");
1937 fprintf(stderr, " -R <maxDelay> Reconnect mechanism with maximum delay between reconnect\n");
1938 fprintf(stderr, " attemts in seconds, default: no reconnect activated,\n");
[487]1939 fprintf(stderr, " optional\n\n");
[9403]1940 fprintf(stderr, " -M <InputMode> Sets the input mode (1 = Serial Port, 2 = IP server,\n");
[9448]1941 fprintf(stderr, " 3 = File, 4 = SISNeT Data Server, 5 = UDP server, 6 = NTRIP1 Caster,\n");
1942 fprintf(stderr, " 7 = NTRIP2 Caster in HTTP mode),\n");
[485]1943 fprintf(stderr, " mandatory\n\n");
1944 fprintf(stderr, " <InputMode> = 1 (Serial Port):\n");
[9403]1945 fprintf(stderr, " -i <Device> Serial input device, default: %s, mandatory if\n", ttyport);
[485]1946 fprintf(stderr, " <InputMode>=1\n");
[9403]1947 fprintf(stderr, " -b <BaudRate> Serial input baud rate, default: 19200 bps, mandatory\n");
[1113]1948 fprintf(stderr, " if <InputMode>=1\n");
[9403]1949 fprintf(stderr, " -f <InitFile> Name of initialization file to be send to input device,\n");
[1113]1950 fprintf(stderr, " optional\n\n");
[485]1951 fprintf(stderr, " <InputMode> = 2|5 (IP port | UDP port):\n");
[9403]1952 fprintf(stderr, " -H <ServerHost> Input host name or address, default: 127.0.0.1,\n");
[485]1953 fprintf(stderr, " mandatory if <InputMode> = 2|5\n");
[9403]1954 fprintf(stderr, " -P <ServerPort> Input port, default: 1025, mandatory if <InputMode>= 2|5\n");
1955 fprintf(stderr, " -f <ServerFile> Name of initialization file to be send to server,\n");
[485]1956 fprintf(stderr, " optional\n");
[9403]1957 fprintf(stderr, " -x <ServerUser> User ID to access incoming stream, optional\n");
1958 fprintf(stderr, " -y <ServerPass> Password, to access incoming stream, optional\n");
1959 fprintf(stderr, " -B Bind to incoming UDP stream, optional for <InputMode> = 5\n\n");
[485]1960 fprintf(stderr, " <InputMode> = 3 (File):\n");
[9403]1961 fprintf(stderr, " -s <File> File name to simulate stream by reading data from (log)\n");
1962 fprintf(stderr, " file, default is %s, mandatory for <InputMode> = 3\n\n", filepath);
[485]1963 fprintf(stderr, " <InputMode> = 4 (SISNeT Data Server):\n");
[9403]1964 fprintf(stderr, " -H <SisnetHost> SISNeT Data Server name or address,\n");
1965 fprintf(stderr, " default: 131.176.49.142, mandatory if <InputMode> = 4\n");
1966 fprintf(stderr, " -P <SisnetPort> SISNeT Data Server port, default: 7777, mandatory if\n");
[485]1967 fprintf(stderr, " <InputMode> = 4\n");
[9403]1968 fprintf(stderr, " -u <SisnetUser> SISNeT Data Server user ID, mandatory if <InputMode> = 4\n");
1969 fprintf(stderr, " -l <SisnetPass> SISNeT Data Server password, mandatory if <InputMode> = 4\n");
1970 fprintf(stderr, " -V <SisnetVers> SISNeT Data Server Version number, options are 2.1, 3.0\n");
1971 fprintf(stderr, " or 3.1, default: 3.1, mandatory if <InputMode> = 4\n\n");
1972 fprintf(stderr, " <InputMode> = 6|7 (NTRIP Version 1.0|2.0 Caster):\n");
1973 fprintf(stderr, " -H <SourceHost> Source caster name or address, default: 127.0.0.1,\n");
1974 fprintf(stderr, " mandatory if <InputMode> = 6|7\n");
1975 fprintf(stderr, " -P <SourcePort> Source caster port, default: 2101, mandatory if\n");
[9401]1976 fprintf(stderr, " <InputMode> = 6|7\n");
[9403]1977 fprintf(stderr, " -D <SourceMount> Source caster mountpoint for stream input, mandatory if\n");
1978 fprintf(stderr, " <InputMode> = 6|7\n");
1979 fprintf(stderr, " -U <SourceUser> Source caster user Id for input stream access, mandatory\n");
1980 fprintf(stderr, " for protected streams if <InputMode> = 6|7\n");
1981 fprintf(stderr, " -W <SourcePass> Source caster password for input stream access, mandatory\n");
1982 fprintf(stderr, " for protected streams if <InputMode> = 6|7\n\n");
1983 fprintf(stderr, " -O <OutputMode> Sets output mode for communication with destination caster / server\n");
[9448]1984 fprintf(stderr, " 1 = http : NTRIP Version 2.0 Caster in TCP/IP mode\n");
1985 fprintf(stderr, " 2 = rtsp : NTRIP Version 2.0 Caster in RTSP/RTP mode\n");
[487]1986 fprintf(stderr, " 3 = ntrip1: NTRIP Version 1.0 Caster\n");
[9448]1987 fprintf(stderr, " 4 = udp : NTRIP Version 2.0 Caster in Plain UDP mode\n");
1988 fprintf(stderr, " 5 = tcpip : IP server in TCP/IP mode\n\n\n");
[9403]1989 fprintf(stderr, " Defaults to NTRIP1.0, but will change to 2.0 in future versions\n");
1990 fprintf(stderr, " Note that the program automatically falls back from mode rtsp to mode http and\n");
[487]1991 fprintf(stderr, " further to mode ntrip1 if necessary.\n\n");
[9448]1992 fprintf(stderr, " -a <DestHost> Destination caster/server name or address, default: 127.0.0.1,\n");
[485]1993 fprintf(stderr, " mandatory\n");
[9448]1994 fprintf(stderr, " -p <DestPort> Destination caster/server port, default: 2101,\n");
[485]1995 fprintf(stderr, " mandatory\n");
[9403]1996 fprintf(stderr, " -m <DestMount> Destination caster mountpoint for stream upload,\n");
1997 fprintf(stderr, " only for NTRIP destination casters, mandatory\n");
1998 fprintf(stderr, " -n <DestUser> Destination caster user ID for stream upload to mountpoint,\n");
1999 fprintf(stderr, " only for NTRIP Version 2.0 destination casters, mandatory\n");
2000 fprintf(stderr, " -c <DestPass> Destination caster password for stream upload to mountpoint,\n");
2001 fprintf(stderr, " only for NTRIP destination casters, mandatory\n");
[485]2002 fprintf(stderr, " -N <STR-record> Sourcetable STR-record\n");
[9403]2003 fprintf(stderr, " optional for NTRIP Version 2.0 in RTSP/RTP and TCP/IP mode\n\n");
[485]2004 exit(rc);
2005} /* usage */
2006
2007/********************************************************************/
2008/* signal handling */
2009/********************************************************************/
2010#ifdef __GNUC__
2011static void handle_sigint(int sig __attribute__((__unused__)))
2012#else /* __GNUC__ */
2013static void handle_sigint(int sig)
2014#endif /* __GNUC__ */
[487]2015{
[9401]2016 sigint_received = 1;
[487]2017 fprintf(stderr, "WARNING: SIGINT received - ntripserver terminates\n");
2018}
[485]2019
[653]2020#ifndef WINDOWSVERSION
[487]2021#ifdef __GNUC__
2022static void handle_alarm(int sig __attribute__((__unused__)))
2023#else /* __GNUC__ */
2024static void handle_alarm(int sig)
2025#endif /* __GNUC__ */
2026{
2027 sigalarm_received = 1;
2028 fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
2029}
2030
2031#ifdef __GNUC__
2032static void handle_sigpipe(int sig __attribute__((__unused__)))
2033#else /* __GNUC__ */
2034static void handle_sigpipe(int sig)
2035#endif /* __GNUC__ */
[653]2036{
2037 sigpipe_received = 1;
2038}
2039#endif /* WINDOWSVERSION */
[487]2040
[9401]2041static void setup_signal_handler(int sig, void (*handler)(int)) {
[485]2042#if _POSIX_VERSION > 198800L
2043 struct sigaction action;
2044
2045 action.sa_handler = handler;
2046 sigemptyset(&(action.sa_mask));
2047 sigaddset(&(action.sa_mask), sig);
2048 action.sa_flags = 0;
2049 sigaction(sig, &action, 0);
2050#else
2051 signal(sig, handler);
2052#endif
2053 return;
2054} /* setupsignal_handler */
2055
2056/********************************************************************
2057 * base64-encoding *
[9401]2058 *******************************************************************/
2059static const char encodingTable[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2060 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2061 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
2062 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
2063 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
[485]2064
2065/* does not buffer overrun, but breaks directly after an error */
2066/* returns the number of required bytes */
[9401]2067static int encode(char *buf, int size, const char *user, const char *pwd) {
[485]2068 unsigned char inbuf[3];
2069 char *out = buf;
2070 int i, sep = 0, fill = 0, bytes = 0;
2071
[9401]2072 while (*user || *pwd) {
[485]2073 i = 0;
[9401]2074 while (i < 3 && *user)
2075 inbuf[i++] = *(user++);
2076 if (i < 3 && !sep) {
2077 inbuf[i++] = ':';
2078 ++sep;
2079 }
2080 while (i < 3 && *pwd)
2081 inbuf[i++] = *(pwd++);
2082 while (i < 3) {
2083 inbuf[i++] = 0;
2084 ++fill;
2085 }
2086 if (out - buf < size - 1)
2087 *(out++) = encodingTable[(inbuf[0] & 0xFC) >> 2];
2088 if (out - buf < size - 1)
2089 *(out++) = encodingTable[((inbuf[0] & 0x03) << 4)
2090 | ((inbuf[1] & 0xF0) >> 4)];
2091 if (out - buf < size - 1) {
2092 if (fill == 2)
[485]2093 *(out++) = '=';
2094 else
[9401]2095 *(out++) = encodingTable[((inbuf[1] & 0x0F) << 2)
2096 | ((inbuf[2] & 0xC0) >> 6)];
[485]2097 }
[9401]2098 if (out - buf < size - 1) {
2099 if (fill >= 1)
[485]2100 *(out++) = '=';
2101 else
[9401]2102 *(out++) = encodingTable[inbuf[2] & 0x3F];
[485]2103 }
2104 bytes += 4;
2105 }
[9401]2106 if (out - buf < size)
[485]2107 *out = 0;
2108 return bytes;
2109}/* base64 Encoding */
2110
2111/********************************************************************
2112 * send message to caster *
[9401]2113 *********************************************************************/
2114static int send_to_caster(char *input, sockettype socket, int input_size) {
2115 int send_error = 1;
[485]2116
[9401]2117 if ((send(socket, input, (size_t) input_size, 0)) != input_size) {
2118 fprintf(stderr,
2119 "WARNING: could not send full header to Destination caster\n");
[485]2120 send_error = 0;
2121 }
2122#ifndef NDEBUG
[9401]2123 else {
[485]2124 fprintf(stderr, "\nDestination caster request:\n");
[9403]2125 fprintf(stderr, "%s\n", input);
[485]2126 }
2127#endif
2128 return send_error;
2129}/* send_to_caster */
2130
2131/********************************************************************
[487]2132 * reconnect *
[9401]2133 *********************************************************************/
2134int reconnect(int rec_sec, int rec_sec_max) {
2135 fprintf(stderr, "reconnect in <%d> seconds\n\n", rec_sec);
[487]2136 rec_sec *= 2;
[9401]2137 if (rec_sec > rec_sec_max)
2138 rec_sec = rec_sec_max;
[653]2139#ifndef WINDOWSVERSION
[487]2140 sleep(rec_sec);
[653]2141 sigpipe_received = 0;
2142#else
2143 Sleep(rec_sec*1000);
2144#endif
[487]2145 sigalarm_received = 0;
2146 return rec_sec;
2147} /* reconnect */
2148
2149/********************************************************************
[485]2150 * close session *
[9401]2151 *********************************************************************/
[1570]2152static void close_session(const char *caster_addr, const char *mountpoint,
[9401]2153 int session, char *rtsp_ext, int fallback) {
2154 int size_send_buf;
[485]2155 char send_buf[BUFSZ];
2156
[9401]2157 if (!fallback) {
2158 if ((gps_socket != INVALID_SOCKET)
2159 && ((inputmode == TCPSOCKET) || (inputmode == UDPSOCKET)
2160 || (inputmode == NTRIP1_IN) || (inputmode == NTRIP2_HTTP_IN)
2161 || (inputmode == SISNET))) {
2162 if (closesocket(gps_socket) == -1) {
[653]2163 perror("ERROR: close input device ");
2164 exit(0);
[9401]2165 } else {
[653]2166 gps_socket = -1;
[1570]2167#ifndef NDEBUG
[653]2168 fprintf(stderr, "close input device: successful\n");
2169#endif
2170 }
[9401]2171 } else if ((gps_serial != INVALID_HANDLE_VALUE) && (inputmode == SERIAL)) {
[653]2172#ifndef WINDOWSVERSION
[9401]2173 if (close(gps_serial) == INVALID_HANDLE_VALUE) {
[653]2174 perror("ERROR: close input device ");
2175 exit(0);
2176 }
2177#else
2178 if(!CloseHandle(gps_serial))
2179 {
2180 fprintf(stderr, "ERROR: close input device ");
2181 exit(0);
2182 }
2183#endif
[9401]2184 else {
[653]2185 gps_serial = INVALID_HANDLE_VALUE;
[1570]2186#ifndef NDEBUG
[653]2187 fprintf(stderr, "close input device: successful\n");
[487]2188#endif
[653]2189 }
[9401]2190 } else if ((gps_file != -1) && (inputmode == INFILE)) {
2191 if (close(gps_file) == -1) {
[653]2192 perror("ERROR: close input device ");
2193 exit(0);
[9401]2194 } else {
[653]2195 gps_file = -1;
[1570]2196#ifndef NDEBUG
[653]2197 fprintf(stderr, "close input device: successful\n");
2198#endif
2199 }
2200 }
[485]2201 }
2202
[9401]2203 if (socket_udp != INVALID_SOCKET) {
2204 if (udp_cseq > 2) {
[485]2205 size_send_buf = snprintf(send_buf, sizeof(send_buf),
[9401]2206 "TEARDOWN rtsp://%s%s/%s RTSP/1.0\r\n"
2207 "CSeq: %d\r\n"
2208 "Session: %u\r\n"
2209 "\r\n", caster_addr, rtsp_ext, mountpoint, udp_cseq++, session);
2210 if ((size_send_buf >= (int) sizeof(send_buf)) || (size_send_buf < 0)) {
[485]2211 fprintf(stderr, "ERROR: Destination caster request to long\n");
2212 exit(0);
2213 }
[9401]2214 send_to_caster(send_buf, socket_tcp, size_send_buf);
2215 strcpy(send_buf, "");
[487]2216 size_send_buf = recv(socket_tcp, send_buf, sizeof(send_buf), 0);
[485]2217 send_buf[size_send_buf] = '\0';
2218#ifndef NDEBUG
2219 fprintf(stderr, "Destination caster response:\n%s", send_buf);
2220#endif
2221 }
[9401]2222 if (closesocket(socket_udp) == -1) {
[485]2223 perror("ERROR: close udp socket");
2224 exit(0);
[9401]2225 } else {
[487]2226 socket_udp = -1;
2227#ifndef NDEBUG
2228 fprintf(stderr, "close udp socket: successful\n");
2229#endif
[485]2230 }
2231 }
2232
[9401]2233 if (socket_tcp != INVALID_SOCKET) {
2234 if (closesocket(socket_tcp) == -1) {
[487]2235 perror("ERROR: close tcp socket");
2236 exit(0);
[9401]2237 } else {
[487]2238 socket_tcp = -1;
[485]2239#ifndef NDEBUG
[487]2240 fprintf(stderr, "close tcp socket: successful\n");
2241#endif
2242 }
[485]2243 }
2244} /* close_session */
Note: See TracBrowser for help on using the repository browser.