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

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

bug fixed

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