ntripclient.cpp
Go to the documentation of this file.
1 /*
2  NTRIP client for POSIX.
3  $Id: ntripclient.c,v 1.51 2009/09/11 09:49:19 stoecker Exp $
4  Copyright (C) 2003-2008 by Dirk Stöcker <soft@dstoecker.de>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  or read http://www.gnu.org/licenses/gpl.txt
20 */
21 
22 #include <ctype.h>
23 #include <getopt.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <time.h>
29 #include <regex>
30 #include <thread>
31 #include <mutex>
32 #include <string>
33 #include <iostream>
34 using namespace std;
35 
36 #include "serial.h"
37 #include "ntrip.h"
38 
39 mutex g_mtx;
40 string g_nmea;
41 
42 
44 {
45  Location location;
46  string::size_type position = g_nmea.find('\n');
47  if( position == g_nmea.npos )
48  return location;
49 
50  string candidate = g_nmea.substr(0,position);
51 
52  g_mtx.lock();
53  g_nmea = g_nmea.substr(position + 1, g_nmea.length() - 1 );
54  g_mtx.unlock();
55 
56  smatch m;
57  regex e("\\$GNGGA,(.*?),(.*?),.*?,(.*?),.*?,(.*?),.*?,(.*?),(.*?),");
58  if( std::regex_search (candidate, m, e) )
59  {
60  //for (auto x:m) cout << x << "^_^ ";
61  //cout<<endl;
62  cout<<"Lat:"<<m[2]<<"Longi:"<<m[3]<<endl;
63  location.nmea = candidate;
64  location.lat = m[2];
65  location.lon = m[3];
66  location.fix = m[4];
67  location.hdop = m[5];
68  location.alt = m[6];
69  return location;
70  }
71  else
72  return location;
73 }
74 
75 void appendNMEA(char* buf, int i)
76 {
77  g_mtx.lock();
78  g_nmea.append(buf,i);
79  g_mtx.unlock();
80 
81 
82 }
83 
84 
85 
86 
87 #ifdef WINDOWSVERSION
88  #include <winsock.h>
89  typedef SOCKET sockettype;
90  typedef u_long in_addr_t;
91  typedef size_t socklen_t;
92  void myperror(char *s)
93  {
94  fprintf(stderr, "%s: %d\n", s, WSAGetLastError());
95  }
96 #else
97  typedef int sockettype;
98  #include <signal.h>
99  #include <fcntl.h>
100  #include <unistd.h>
101  #include <arpa/inet.h>
102  #include <sys/socket.h>
103  #include <netinet/in.h>
104  #include <netdb.h>
105 
106  #define closesocket(sock) close(sock)
107  #define ALARMTIME (2*60)
108  #define myperror perror
109 #endif
110 
111 #ifndef COMPILEDATE
112 #define COMPILEDATE " built " __DATE__
113 #endif
114 
115 /* The string, which is send as agent in HTTP request */
116 #define AGENTSTRING "NTRIP NtripClientPOSIX"
117 #define TIME_RESOLUTION 125
118 
119 #define MAXDATASIZE 1000 /* max number of bytes we can get at once */
120 
121 /* CVS revision and version */
122 static char revisionstr[] = "$Revision: 1.51 $";
123 static char datestr[] = "$Date: 2009/09/11 09:49:19 $";
124 
125 
126 
127 /* option parsing */
128 #ifdef NO_LONG_OPTS
129 #define LONG_OPT(a)
130 #else
131 #define LONG_OPT(a) a
132 static struct option opts[] = {
133 { "bitrate", no_argument, 0, 'b'},
134 { "data", required_argument, 0, 'd'}, /* compatibility */
135 { "mountpoint", required_argument, 0, 'm'},
136 { "initudp", no_argument, 0, 'I'},
137 { "udpport", required_argument, 0, 'P'},
138 { "server", required_argument, 0, 's'},
139 { "password", required_argument, 0, 'p'},
140 { "port", required_argument, 0, 'r'},
141 { "proxyport", required_argument, 0, 'R'},
142 { "proxyhost", required_argument, 0, 'S'},
143 { "user", required_argument, 0, 'u'},
144 { "nmea", required_argument, 0, 'n'},
145 { "mode", required_argument, 0, 'M'},
146 { "serdevice", required_argument, 0, 'D'},
147 { "baud", required_argument, 0, 'B'},
148 { "stopbits", required_argument, 0, 'T'},
149 { "protocol", required_argument, 0, 'C'},
150 { "parity", required_argument, 0, 'Y'},
151 { "databits", required_argument, 0, 'A'},
152 { "serlogfile", required_argument, 0, 'l'},
153 { "help", no_argument, 0, 'h'},
154 {0,0,0,0}};
155 #endif
156 #define ARGOPT "-d:m:bhp:r:s:u:n:S:R:M:IP:D:B:T:C:Y:A:l:"
157 
158 int stop = 0;
159 #ifndef WINDOWSVERSION
160 int sigstop = 0;
161 #ifdef __GNUC__
162 static __attribute__ ((noreturn)) void sighandler_alarm(
163 int sig __attribute__((__unused__)))
164 #else /* __GNUC__ */
165 static void sighandler_alarm(int sig)
166 #endif /* __GNUC__ */
167 {
168  if(!sigstop)
169  fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
170  else
171  fprintf(stderr, "ERROR: user break\n");
172  exit(1);
173 }
174 
175 #ifdef __GNUC__
176 static void sighandler_int(int sig __attribute__((__unused__)))
177 #else /* __GNUC__ */
178 static void sighandler_alarm(int sig)
179 #endif /* __GNUC__ */
180 {
181  sigstop = 1;
182  alarm(2);
183  stop = 1;
184 }
185 #endif /* WINDOWSVERSION */
186 
187 static const char *encodeurl(const char *req)
188 {
189  const char *h = "0123456789abcdef";
190  static char buf[128];
191  char *urlenc = buf;
192  char *bufend = buf + sizeof(buf) - 3;
193 
194  while(*req && urlenc < bufend)
195  {
196  if(isalnum(*req)
197  || *req == '-' || *req == '_' || *req == '.')
198  *urlenc++ = *req++;
199  else
200  {
201  *urlenc++ = '%';
202  *urlenc++ = h[*req >> 4];
203  *urlenc++ = h[*req & 0x0f];
204  req++;
205  }
206  }
207  *urlenc = 0;
208  return buf;
209 }
210 
211 static const char *geturl(const char *url, struct Args *args)
212 {
213  static char buf[1000];
214  static char *Buffer = buf;
215  static char *Bufend = buf+sizeof(buf);
216  const char *h = "0123456789abcdef";
217 
218  if(strncmp("ntrip:", url, 6))
219  return "URL must start with 'ntrip:'.";
220  url += 6; /* skip ntrip: */
221 
222  if(*url != '@' && *url != '/')
223  {
224  /* scan for mountpoint */
225  args->data = Buffer;
226  if(*url != '?')
227  {
228  while(*url && *url != '@' && *url != ';' && *url != '/' && Buffer != Bufend)
229  *(Buffer++) = *(url++);
230  }
231  else
232  {
233  while(*url && *url != '@' && *url != '/' && Buffer != Bufend)
234  {
235  if(isalnum(*url) || *url == '-' || *url == '_' || *url == '.')
236  *Buffer++ = *url++;
237  else
238  {
239  *Buffer++ = '%';
240  *Buffer++ = h[*url >> 4];
241  *Buffer++ = h[*url & 0x0f];
242  url++;
243  }
244  }
245  }
246  if(Buffer == args->data)
247  return "Mountpoint required.";
248  else if(Buffer >= Bufend-1)
249  return "Parsing buffer too short.";
250  *(Buffer++) = 0;
251  }
252 
253  if(*url == '/') /* username and password */
254  {
255  ++url;
256  args->user = Buffer;
257  while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
258  *(Buffer++) = *(url++);
259  if(Buffer == args->user)
260  return "Username cannot be empty.";
261  else if(Buffer >= Bufend-1)
262  return "Parsing buffer too short.";
263  *(Buffer++) = 0;
264 
265  if(*url == ':') ++url;
266 
267  args->password = Buffer;
268  while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
269  *(Buffer++) = *(url++);
270  if(Buffer == args->password)
271  return "Password cannot be empty.";
272  else if(Buffer >= Bufend-1)
273  return "Parsing buffer too short.";
274  *(Buffer++) = 0;
275  }
276 
277  if(*url == '@') /* server */
278  {
279  ++url;
280  if(*url != '@' && *url != ':')
281  {
282  args->server = Buffer;
283  while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
284  *(Buffer++) = *(url++);
285  if(Buffer == args->server)
286  return "Servername cannot be empty.";
287  else if(Buffer >= Bufend-1)
288  return "Parsing buffer too short.";
289  *(Buffer++) = 0;
290  }
291 
292  if(*url == ':')
293  {
294  ++url;
295  args->port = Buffer;
296  while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
297  *(Buffer++) = *(url++);
298  if(Buffer == args->port)
299  return "Port cannot be empty.";
300  else if(Buffer >= Bufend-1)
301  return "Parsing buffer too short.";
302  *(Buffer++) = 0;
303  }
304 
305  if(*url == '@') /* proxy */
306  {
307  ++url;
308  args->proxyhost = Buffer;
309  while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
310  *(Buffer++) = *(url++);
311  if(Buffer == args->proxyhost)
312  return "Proxy servername cannot be empty.";
313  else if(Buffer >= Bufend-1)
314  return "Parsing buffer too short.";
315  *(Buffer++) = 0;
316 
317  if(*url == ':')
318  {
319  ++url;
320  args->proxyport = Buffer;
321  while(*url && *url != ';' && Buffer != Bufend)
322  *(Buffer++) = *(url++);
323  if(Buffer == args->proxyport)
324  return "Proxy port cannot be empty.";
325  else if(Buffer >= Bufend-1)
326  return "Parsing buffer too short.";
327  *(Buffer++) = 0;
328  }
329  }
330  }
331  if(*url == ';') /* NMEA */
332  {
333  args->nmea = ++url;
334  while(*url)
335  ++url;
336  }
337 
338  return *url ? "Garbage at end of server string." : 0;
339 }
340 
341 static int getargs(int argc, char **argv, struct Args *args)
342 {
343  int res = 1;
344  int getoptr;
345  char *a;
346  int i = 0, help = 0;
347 
348  args->server = "rtk.ntrip.qxwz.com";
349  args->port = "8002";
350  args->user = "";
351  args->password = "";
352  args->nmea = 0;
353  args->data = 0;
354  args->bitrate = 0;
355  args->proxyhost = 0;
356  args->proxyport = "2101";
357  args->mode = AUTO;
358  args->initudp = 0;
359  args->udpport = 0;
360  args->protocol = SPAPROTOCOL_NONE;
361  args->parity = SPAPARITY_NONE;
362  args->stopbits = SPASTOPBITS_1;
363  args->databits = SPADATABITS_8;
364  args->baud = SPABAUD_9600;
365  args->serdevice = 0;
366  args->serlogfile = 0;
367  help = 0;
368 
369  do
370  {
371 #ifdef NO_LONG_OPTS
372  switch((getoptr = getopt(argc, argv, ARGOPT)))
373 #else
374  switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
375 #endif
376  {
377  case 's': args->server = optarg; break;
378  case 'u': args->user = optarg; break;
379  case 'p': args->password = optarg; break;
380  case 'd': /* legacy option, may get removed in future */
381  fprintf(stderr, "Option -d or --data is deprecated. Use -m instead.\n");
382  case 'm':
383  if(optarg && *optarg == '?')
384  args->data = encodeurl(optarg);
385  else
386  args->data = optarg;
387  break;
388  case 'B':
389  {
390  int i = strtol(optarg, 0, 10);
391 
392  switch(i)
393  {
394  case 50: args->baud = SPABAUD_50; break;
395  case 110: args->baud = SPABAUD_110; break;
396  case 300: args->baud = SPABAUD_300; break;
397  case 600: args->baud = SPABAUD_600; break;
398  case 1200: args->baud = SPABAUD_1200; break;
399  case 2400: args->baud = SPABAUD_2400; break;
400  case 4800: args->baud = SPABAUD_4800; break;
401  case 9600: args->baud = SPABAUD_9600; break;
402  case 19200: args->baud = SPABAUD_19200; break;
403  case 38400: args->baud = SPABAUD_38400; break;
404  case 57600: args->baud = SPABAUD_57600; break;
405  case 115200: args->baud = SPABAUD_115200; break;
406  default:
407  fprintf(stderr, "Baudrate '%s' unknown\n", optarg);
408  res = 0;
409  break;
410  }
411  }
412  break;
413  case 'T':
414  if(!strcmp(optarg, "1")) args->stopbits = SPASTOPBITS_1;
415  else if(!strcmp(optarg, "2")) args->stopbits = SPASTOPBITS_2;
416  else
417  {
418  fprintf(stderr, "Stopbits '%s' unknown\n", optarg);
419  res = 0;
420  }
421  break;
422  case 'A':
423  if(!strcmp(optarg, "5")) args->databits = SPADATABITS_5;
424  else if(!strcmp(optarg, "6")) args->databits = SPADATABITS_6;
425  else if(!strcmp(optarg, "7")) args->databits = SPADATABITS_7;
426  else if(!strcmp(optarg, "8")) args->databits = SPADATABITS_8;
427  else
428  {
429  fprintf(stderr, "Databits '%s' unknown\n", optarg);
430  res = 0;
431  }
432  break;
433  case 'C':
434  {
435  int i = 0;
436  args->protocol = SerialGetProtocol(optarg, &i);
437  if(!i)
438  {
439  fprintf(stderr, "Protocol '%s' unknown\n", optarg);
440  res = 0;
441  }
442  }
443  break;
444  case 'Y':
445  {
446  int i = 0;
447  args->parity = SerialGetParity(optarg, &i);
448  if(!i)
449  {
450  fprintf(stderr, "Parity '%s' unknown\n", optarg);
451  res = 0;
452  }
453  }
454  break;
455  case 'D': args->serdevice = optarg; break;
456  case 'l': args->serlogfile = optarg; break;
457  case 'I': args->initudp = 1; break;
458  case 'P': args->udpport = strtol(optarg, 0, 10); break;
459  case 'n': args->nmea = optarg; break;
460  case 'b': args->bitrate = 1; break;
461  case 'h': help=1; break;
462  case 'r': args->port = optarg; break;
463  case 'S': args->proxyhost = optarg; break;
464  case 'R': args->proxyport = optarg; break;
465  case 'M':
466  args->mode = 0;
467  if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
468  args->mode = NTRIP1;
469  else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
470  args->mode = HTTP;
471  else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
472  args->mode = RTSP;
473  else if(!strcmp(optarg,"u") || !strcmp(optarg,"udp"))
474  args->mode = UDP;
475  else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
476  args->mode = AUTO;
477  else args->mode = atoi(optarg);
478  if((args->mode == 0) || (args->mode >= END))
479  {
480  fprintf(stderr, "Mode %s unknown\n", optarg);
481  res = 0;
482  }
483  break;
484  case 1:
485  {
486  const char *err;
487  if((err = geturl(optarg, args)))
488  {
489  fprintf(stderr, "%s\n\n", err);
490  res = 0;
491  }
492  }
493  break;
494  case -1: break;
495  }
496  } while(getoptr != -1 && res);
497 
498  for(a = revisionstr+11; *a && *a != ' '; ++a)
499  revisionstr[i++] = *a;
500  revisionstr[i] = 0;
501  datestr[0] = datestr[7];
502  datestr[1] = datestr[8];
503  datestr[2] = datestr[9];
504  datestr[3] = datestr[10];
505  datestr[5] = datestr[12];
506  datestr[6] = datestr[13];
507  datestr[8] = datestr[15];
508  datestr[9] = datestr[16];
509  datestr[4] = datestr[7] = '-';
510  datestr[10] = 0;
511 
512  if(!res || help)
513  {
514  fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s -s server -u user ...\n"
515  " -m " LONG_OPT("--mountpoint ") "the requested data set or sourcetable filtering criteria\n"
516  " -s " LONG_OPT("--server ") "the server name or address\n"
517  " -p " LONG_OPT("--password ") "the login password\n"
518  " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
519  " -u " LONG_OPT("--user ") "the user name\n"
520  " -M " LONG_OPT("--mode ") "mode for data request\n"
521  " Valid modes are:\n"
522  " 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
523  " 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
524  " 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
525  " 4, a, auto automatic detection (default)\n"
526  " 5, u, udp NTRIP Version 2.0 Caster in UDP mode\n"
527  "or using an URL:\n%s ntrip:mountpoint[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
528  "\nExpert options:\n"
529  " -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
530  " -b " LONG_OPT("--bitrate ") "output bitrate\n"
531  " -I " LONG_OPT("--initudp ") "send initial UDP packet for firewall handling\n"
532  " -P " LONG_OPT("--udpport ") "set the local UDP port\n"
533  " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
534  " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
535  "\nSerial input/output:\n"
536  " -D " LONG_OPT("--serdevice ") "serial device for output\n"
537  " -B " LONG_OPT("--baud ") "baudrate for serial device\n"
538  " -T " LONG_OPT("--stopbits ") "stopbits for serial device\n"
539  " -C " LONG_OPT("--protocol ") "protocol for serial device\n"
540  " -Y " LONG_OPT("--parity ") "parity for serial device\n"
541  " -A " LONG_OPT("--databits ") "databits for serial device\n"
542  " -l " LONG_OPT("--serlogfile ") "logfile for serial data\n"
543  , revisionstr, datestr, argv[0], argv[0]);
544  exit(1);
545  }
546  return res;
547 }
548 
549 static const char encodingTable [64] = {
550  'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
551  'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
552  'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
553  'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
554 };
555 
556 /* does not buffer overrun, but breaks directly after an error */
557 /* returns the number of required bytes */
558 static int encode(char *buf, int size, const char *user, const char *pwd)
559 {
560  unsigned char inbuf[3];
561  char *out = buf;
562  int i, sep = 0, fill = 0, bytes = 0;
563 
564  while(*user || *pwd)
565  {
566  i = 0;
567  while(i < 3 && *user) inbuf[i++] = *(user++);
568  if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
569  while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
570  while(i < 3) {inbuf[i++] = 0; ++fill; }
571  if(out-buf < size-1)
572  *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
573  if(out-buf < size-1)
574  *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
575  | ((inbuf [1] & 0xF0) >> 4)];
576  if(out-buf < size-1)
577  {
578  if(fill == 2)
579  *(out++) = '=';
580  else
581  *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
582  | ((inbuf [2] & 0xC0) >> 6)];
583  }
584  if(out-buf < size-1)
585  {
586  if(fill >= 1)
587  *(out++) = '=';
588  else
589  *(out++) = encodingTable[inbuf [2] & 0x3F];
590  }
591  bytes += 4;
592  }
593  if(out-buf < size)
594  *out = 0;
595  return bytes;
596 }
597 
598 
599 
600 void ntrip_client(Args* const args )
601 {
602 
603 
604  setbuf(stdout, 0);
605  setbuf(stdin, 0);
606  setbuf(stderr, 0);
607  signal(SIGALRM,sighandler_alarm);
608  alarm(ALARMTIME);
609 
610 
611  if(true)
612  {
613  struct serial sx;
614  FILE *ser = 0;
615  char nmeabuffer[200] = "$GPGGA,"; /* our start string */
616  size_t nmeabufpos = 0;
617  size_t nmeastarpos = 0;
618  int sleeptime = 0;
619  if(args->serdevice)
620  {
621  const char *e = SerialInit(&sx, args->serdevice, args->baud,
622  args->stopbits, args->protocol, args->parity, args->databits, 1);
623  if(e)
624  {
625  fprintf(stderr, "%s\n", e);
626  return;
627  }
628  if(args->serlogfile)
629  {
630  if(!(ser = fopen(args->serlogfile, "a+")))
631  {
632  SerialFree(&sx);
633  fprintf(stderr, "Could not open serial logfile.\n");
634  return ;
635  }
636  }
637  }
638  do
639  {
640  int error = 0;
641  sockettype sockfd = 0;
642  int numbytes;
643  char buf[MAXDATASIZE];
644  struct sockaddr_in their_addr; /* connector's address information */
645  struct hostent *he;
646  struct servent *se;
647  const char *server, *port, *proxyserver = 0;
648  char proxyport[6];
649  char *b;
650  long i;
651  if(sleeptime)
652  {
653 #ifdef WINDOWSVERSION
654  Sleep(sleeptime*1000);
655 #else
656  sleep(sleeptime);
657 #endif
658  sleeptime += 2;
659  }
660  else
661  {
662  sleeptime = 1;
663  }
664 #ifndef WINDOWSVERSION
665  alarm(ALARMTIME);
666 #endif
667  if(args->proxyhost)
668  {
669  int p;
670  if((i = strtol(args->port, &b, 10)) && (!b || !*b))
671  p = i;
672  else if(!(se = getservbyname(args->port, 0)))
673  {
674  fprintf(stderr, "Can't resolve port %s.", args->port);
675  args->stop = true;
676  }
677  else
678  {
679  p = ntohs(se->s_port);
680  }
681  if(!args->stop && !error)
682  {
683  snprintf(proxyport, sizeof(proxyport), "%d", p);
684  port = args->proxyport;
685  proxyserver = args->server;
686  server = args->proxyhost;
687  }
688  }
689  else
690  {
691  server = args->server;
692  port = args->port;
693  }
694  if(!args->stop && !error)
695  {
696  memset(&their_addr, 0, sizeof(struct sockaddr_in));
697  if((i = strtol(port, &b, 10)) && (!b || !*b))
698  their_addr.sin_port = htons(i);
699  else if(!(se = getservbyname(port, 0)))
700  {
701  fprintf(stderr, "Can't resolve port %s.", port);
702  args->stop = 1;
703  }
704  else
705  {
706  their_addr.sin_port = se->s_port;
707  }
708  if(!args->stop && !error)
709  {
710  if(!(he=gethostbyname(server)))
711  {
712  fprintf(stderr, "Server name lookup failed for '%s'.\n", server);
713  error = 1;
714  }
715  else if((sockfd = socket(AF_INET, (args->mode == UDP ? SOCK_DGRAM :
716  SOCK_STREAM), 0)) == -1)
717  {
718  myperror("socket");
719  error = 1;
720  }
721  else
722  {
723  their_addr.sin_family = AF_INET;
724  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
725  }
726  }
727  }
728  if(!args->stop && !error)
729  {
730  if(args->mode == UDP)
731  {
732  unsigned int session;
733  int tim, seq, init;
734  char rtpbuf[1526];
735  int i=12, j;
736 
737  init = time(0);
738  srand(init);
739  session = rand();
740  tim = rand();
741  seq = rand();
742 
743  rtpbuf[0] = (2<<6);
744  /* padding, extension, csrc are empty */
745  rtpbuf[1] = 97;
746  /* marker is empty */
747  rtpbuf[2] = (seq>>8)&0xFF;
748  rtpbuf[3] = (seq)&0xFF;
749  rtpbuf[4] = (tim>>24)&0xFF;
750  rtpbuf[5] = (tim>>16)&0xFF;
751  rtpbuf[6] = (tim>>8)&0xFF;
752  rtpbuf[7] = (tim)&0xFF;
753  /* sequence and timestamp are empty */
754  rtpbuf[8] = (session>>24)&0xFF;
755  rtpbuf[9] = (session>>16)&0xFF;
756  rtpbuf[10] = (session>>8)&0xFF;
757  rtpbuf[11] = (session)&0xFF;
758  ++seq;
759 
760  j = snprintf(rtpbuf+i, sizeof(rtpbuf)-i-40, /* leave some space for login */
761  "GET /%s HTTP/1.1\r\n"
762  "Host: %s\r\n"
763  "Ntrip-Version: Ntrip/2.0\r\n"
764  "User-Agent: %s/%s\r\n"
765  "%s%s%s"
766  "Connection: close%s",
767  args->data ? args->data : "", args->server, AGENTSTRING, revisionstr,
768  args->nmea ? "Ntrip-GGA: " : "", args->nmea ? args->nmea : "",
769  args->nmea ? "\r\n" : "",
770  (*args->user || *args->password) ? "\r\nAuthorization: Basic " : "");
771  i += j;
772  if(i > (int)sizeof(rtpbuf)-40 || j < 0) /* second check for old glibc */
773  {
774  fprintf(stderr, "Requested data too long\n");
775  args->stop = true;
776  }
777  else
778  {
779  i += encode(rtpbuf+i, sizeof(rtpbuf)-i-4, args->user, args->password);
780  if(i > (int)sizeof(rtpbuf)-4)
781  {
782  fprintf(stderr, "Username and/or password too long\n");
783  args->stop = true;
784  }
785  else
786  {
787  struct sockaddr_in local;
788  socklen_t len;
789 
790  rtpbuf[i++] = '\r';
791  rtpbuf[i++] = '\n';
792  rtpbuf[i++] = '\r';
793  rtpbuf[i++] = '\n';
794 
795 
796  /* fill structure with local address information for UDP */
797  memset(&local, 0, sizeof(local));
798  local.sin_family = AF_INET;
799  local.sin_port = htons(args->udpport);
800  local.sin_addr.s_addr = htonl(INADDR_ANY);
801  len = sizeof(local);
802 
803  /* bind() in order to get a random RTP client_port */
804  if((bind(sockfd, (struct sockaddr *)&local, len)) < 0)
805  {
806  myperror("bind");
807  error = 1;
808  }
809  else if(connect(sockfd, (struct sockaddr *)&their_addr,
810  sizeof(struct sockaddr)) == -1)
811  {
812  myperror("connect");
813  error = 1;
814  }
815  else if(send(sockfd, rtpbuf, i, 0) != i)
816  {
817  myperror("Could not send UDP packet");
818  args->stop = true;
819  }
820  else
821  {
822  if((numbytes=recv(sockfd, rtpbuf, sizeof(rtpbuf)-1, 0)) > 0)
823  {
824  int sn = 0x10000, ts=0;
825  /* we don't expect message longer than 1513, so we cut the last
826  byte for security reasons to prevent buffer overrun */
827  rtpbuf[numbytes] = 0;
828  if(numbytes > 17+12 &&
829  (!strncmp(rtpbuf+12, "HTTP/1.1 200 OK\r\n", 17) ||
830  !strncmp(rtpbuf+12, "HTTP/1.0 200 OK\r\n", 17)))
831  {
832  const char *sessioncheck = "session: ";
833  const char *datacheck = "Content-Type: gnss/data\r\n";
834  const char *sourcetablecheck = "Content-Type: gnss/sourcetable\r\n";
835  const char *contentlengthcheck = "Content-Length: ";
836  const char *httpresponseend = "\r\n\r\n";
837  int contentlength = 0, httpresponselength = 0;
838  /* datacheck */
839  int l = strlen(datacheck)-1;
840  int j=0;
841  for(i = 12; j != l && i < numbytes-l; ++i)
842  {
843  for(j = 0; j < l && rtpbuf[i+j] == datacheck[j]; ++j)
844  ;
845  }
846  if(i != numbytes-l)
847  {
848  /* check for Session */
849  l = strlen(sessioncheck)-1;
850  j=0;
851  for(i = 12; j != l && i < numbytes-l; ++i)
852  {
853  for(j = 0; j < l && tolower(rtpbuf[i+j]) == sessioncheck[j]; ++j)
854  ;
855  }
856  if(i != numbytes-l) /* found a session number */
857  {
858  i+=l;
859  session = 0;
860  while(i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9')
861  session = session * 10 + rtpbuf[i++]-'0';
862  if(rtpbuf[i] != '\r')
863  {
864  fprintf(stderr, "Could not extract session number\n");
865  args->stop = true;
866  }
867  }
868  }
869  else
870  {
871  /* sourcetablecheck */
872  l = strlen(sourcetablecheck)-1;
873  j=0;
874  for(i = 12; j != l && i < numbytes-l; ++i)
875  {
876  for(j = 0; j < l && rtpbuf[i+j] == sourcetablecheck[j]; ++j)
877  ;
878  }
879  if(i == numbytes-l)
880  {
881  fprintf(stderr, "No 'Content-Type: gnss/data' or"
882  " 'Content-Type: gnss/sourcetable' found\n");
883  error = 1;
884  }
885  else
886  {
887  /* check for http response end */
888  l = strlen(httpresponseend)-1;
889  j=0;
890  for(i = 12; j != l && i < numbytes-l; ++i)
891  {
892  for(j = 0; j < l && rtpbuf[i+j] == httpresponseend[j]; ++j)
893  ;
894  }
895  if(i != numbytes-l) /* found http response end */
896  {
897  httpresponselength = i+3-12;
898  }
899  /* check for content length */
900  l = strlen(contentlengthcheck)-1;
901  j=0;
902  for(i = 12; j != l && i < numbytes-l; ++i)
903  {
904  for(j = 0; j < l && rtpbuf[i+j] == contentlengthcheck[j]; ++j)
905  ;
906  }
907  if(i != numbytes-l) /* found content length */
908  {
909  i+=l;
910  contentlength = 0;
911  while(i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9')
912  contentlength = contentlength * 10 + rtpbuf[i++]-'0';
913  if(rtpbuf[i] == '\r')
914  {
915  contentlength += httpresponselength;
916  do
917  {
918  fwrite(rtpbuf+12, (size_t)numbytes-12, 1, stdout);
919  if((contentlength -= (numbytes-12)) == 0)
920  {
921  args->stop = true;
922  }
923  else
924  {
925  numbytes = recv(sockfd, rtpbuf, sizeof(rtpbuf), 0);
926  }
927  }while((numbytes >12) && (!args->stop));
928  }
929  else
930  {
931  fprintf(stderr, "Could not extract content length\n");
932  args->stop = true;
933  }
934  }
935  }
936  }
937  }
938  else
939  {
940  int k;
941  fprintf(stderr, "Could not get the requested data: ");
942  for(k = 12; k < numbytes && rtpbuf[k] != '\n' && rtpbuf[k] != '\r'; ++k)
943  {
944  fprintf(stderr, "%c", isprint(rtpbuf[k]) ? rtpbuf[k] : '.');
945  }
946  fprintf(stderr, "\n");
947  error = 1;
948  }
949  while(!args->stop && !error)
950  {
951  struct timeval tv = {1,0};
952  fd_set fdr;
953  fd_set fde;
954 
955  FD_ZERO(&fdr);
956  FD_ZERO(&fde);
957  FD_SET(sockfd, &fdr);
958  FD_SET(sockfd, &fde);
959  if(select(sockfd+1,&fdr,0,&fde,&tv) < 0)
960  {
961  fprintf(stderr, "Select problem.\n");
962  error = 1;
963  continue;
964  }
965  i = recv(sockfd, rtpbuf, sizeof(rtpbuf), 0);
966 #ifndef WINDOWSVERSION
967  alarm(ALARMTIME);
968 #endif
969  if(i >= 12 && (unsigned char)rtpbuf[0] == (2 << 6)
970  && rtpbuf[1] >= 96 && rtpbuf[1] <= 98)
971  {
972  time_t ct;
973  int u,v;
974  unsigned int w;
975  u = ((unsigned char)rtpbuf[2]<<8)+(unsigned char)rtpbuf[3];
976  v = ((unsigned char)rtpbuf[4]<<24)+((unsigned char)rtpbuf[5]<<16)
977  +((unsigned char)rtpbuf[6]<<8)+(unsigned char)rtpbuf[7];
978  w = ((unsigned char)rtpbuf[8]<<24)+((unsigned char)rtpbuf[9]<<16)
979  +((unsigned char)rtpbuf[10]<<8)+(unsigned char)rtpbuf[11];
980 
981  if(sn == 0x10000) {sn = u-1;ts=v-1;}
982  else if(u < -30000 && sn > 30000) sn -= 0xFFFF;
983  if(session != w || ts > v)
984  {
985  fprintf(stderr, "Illegal UDP data received.\n");
986  continue;
987  }
988  else if(u > sn) /* don't show out-of-order packets */
989  {
990  if(rtpbuf[1] == 98)
991  {
992  fprintf(stderr, "Connection closed.\n");
993  error = 1;
994  continue;
995  }
996  else if((rtpbuf[1] == 96) && (i>12))
997  {
998  fwrite(rtpbuf+12, (size_t)i-12, 1, stdout);
999  }
1000  }
1001  sn = u; ts = v;
1002 
1003  /* Keep Alive */
1004  ct = time(0);
1005  if(ct-init > 15)
1006  {
1007  tim += (ct-init)*1000000/TIME_RESOLUTION;
1008  rtpbuf[0] = (2<<6);
1009  /* padding, extension, csrc are empty */
1010  rtpbuf[1] = 96;
1011  /* marker is empty */
1012  rtpbuf[2] = (seq>>8)&0xFF;
1013  rtpbuf[3] = (seq)&0xFF;
1014  rtpbuf[4] = (tim>>24)&0xFF;
1015  rtpbuf[5] = (tim>>16)&0xFF;
1016  rtpbuf[6] = (tim>>8)&0xFF;
1017  rtpbuf[7] = (tim)&0xFF;
1018  /* sequence and timestamp are empty */
1019  rtpbuf[8] = (session>>24)&0xFF;
1020  rtpbuf[9] = (session>>16)&0xFF;
1021  rtpbuf[10] = (session>>8)&0xFF;
1022  rtpbuf[11] = (session)&0xFF;
1023  ++seq;
1024  init = ct;
1025 
1026  if(send(sockfd, rtpbuf, 12, 0) != 12)
1027  {
1028  myperror("send");
1029  error = 1;
1030  }
1031  }
1032  }
1033  else if(i >= 0)
1034  {
1035  fprintf(stderr, "Illegal UDP header.\n");
1036  continue;
1037  }
1038  }
1039  }
1040  /* send connection close always to allow nice session closing */
1041  tim += (time(0)-init)*1000000/TIME_RESOLUTION;
1042  rtpbuf[0] = (2<<6);
1043  /* padding, extension, csrc are empty */
1044  rtpbuf[1] = 98;
1045  /* marker is empty */
1046  rtpbuf[2] = (seq>>8)&0xFF;
1047  rtpbuf[3] = (seq)&0xFF;
1048  rtpbuf[4] = (tim>>24)&0xFF;
1049  rtpbuf[5] = (tim>>16)&0xFF;
1050  rtpbuf[6] = (tim>>8)&0xFF;
1051  rtpbuf[7] = (tim)&0xFF;
1052  /* sequence and timestamp are empty */
1053  rtpbuf[8] = (session>>24)&0xFF;
1054  rtpbuf[9] = (session>>16)&0xFF;
1055  rtpbuf[10] = (session>>8)&0xFF;
1056  rtpbuf[11] = (session)&0xFF;
1057 
1058  send(sockfd, rtpbuf, 12, 0); /* cleanup */
1059  }
1060  }
1061  }
1062  }
1063  else if(args->data && *args->data != '%' && args->mode == RTSP)
1064  {
1065  struct sockaddr_in local;
1066  sockettype sockudp = 0;
1067  int localport;
1068  int cseq = 1;
1069  socklen_t len;
1070 
1071  if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1072  {
1073  myperror("socket");
1074  error = 1;
1075  }
1076  if(!args->stop && !error)
1077  {
1078  /* fill structure with local address information for UDP */
1079  memset(&local, 0, sizeof(local));
1080  local.sin_family = AF_INET;
1081  local.sin_port = htons(args->udpport);
1082  local.sin_addr.s_addr = htonl(INADDR_ANY);
1083  len = sizeof(local);
1084  /* bind() in order to get a random RTP client_port */
1085  if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
1086  {
1087  myperror("bind");
1088  error = 1;
1089  }
1090  else if((getsockname(sockudp, (struct sockaddr*)&local, &len)) == -1)
1091  {
1092  myperror("local access failed");
1093  error = 1;
1094  }
1095  else if(connect(sockfd, (struct sockaddr *)&their_addr,
1096  sizeof(struct sockaddr)) == -1)
1097  {
1098  myperror("connect");
1099  error = 1;
1100  }
1101  localport = ntohs(local.sin_port);
1102  }
1103  if(!args->stop && !error)
1104  {
1105  i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
1106  "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
1107  "CSeq: %d\r\n"
1108  "Ntrip-Version: Ntrip/2.0\r\n"
1109  "Ntrip-Component: Ntripclient\r\n"
1110  "User-Agent: %s/%s\r\n"
1111  "%s%s%s"
1112  "Transport: RTP/GNSS;unicast;client_port=%u%s",
1113  args->server, proxyserver ? ":" : "", proxyserver ? args->port : "",
1114  args->data, cseq++, AGENTSTRING, revisionstr,
1115  args->nmea ? "Ntrip-GGA: " : "", args->nmea ? args->nmea : "",
1116  args->nmea ? "\r\n" : "",
1117  localport,
1118  (*args->user || *args->password) ? "\r\nAuthorization: Basic " : "");
1119  if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
1120  {
1121  fprintf(stderr, "Requested data too long\n");
1122  args->stop = true;
1123  }
1124  i += encode(buf+i, MAXDATASIZE-i-4, args->user, args->password);
1125  if(i > MAXDATASIZE-4)
1126  {
1127  fprintf(stderr, "Username and/or password too long\n");
1128  args->stop = true;
1129  }
1130  buf[i++] = '\r';
1131  buf[i++] = '\n';
1132  buf[i++] = '\r';
1133  buf[i++] = '\n';
1134  }
1135  if(!args->stop && !error)
1136  {
1137  if(send(sockfd, buf, (size_t)i, 0) != i)
1138  {
1139  myperror("send");
1140  error = 1;
1141  }
1142  else if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1)
1143  {
1144  myperror("recv");
1145  error = 1;
1146  }
1147  else if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
1148  {
1149  int serverport = 0, session = 0;
1150  const char *portcheck = "server_port=";
1151  const char *sessioncheck = "session: ";
1152  int l = strlen(portcheck)-1;
1153  int j=0;
1154  for(i = 0; j != l && i < numbytes-l; ++i)
1155  {
1156  for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
1157  ;
1158  }
1159  if(i == numbytes-l)
1160  {
1161  fprintf(stderr, "No server port number found\n");
1162  args->stop = true;
1163  }
1164  else
1165  {
1166  i+=l;
1167  while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
1168  serverport = serverport * 10 + buf[i++]-'0';
1169  if(buf[i] != '\r' && buf[i] != ';')
1170  {
1171  fprintf(stderr, "Could not extract server port\n");
1172  args->stop = true;
1173  }
1174  }
1175  if(!args->stop && !error)
1176  {
1177  l = strlen(sessioncheck)-1;
1178  j=0;
1179  for(i = 0; j != l && i < numbytes-l; ++i)
1180  {
1181  for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
1182  ;
1183  }
1184  if(i == numbytes-l)
1185  {
1186  fprintf(stderr, "No session number found\n");
1187  args->stop = 1;
1188  }
1189  else
1190  {
1191  i+=l;
1192  while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
1193  session = session * 10 + buf[i++]-'0';
1194  if(buf[i] != '\r')
1195  {
1196  fprintf(stderr, "Could not extract session number\n");
1197  args->stop = true;
1198  }
1199  }
1200  }
1201  if(!args->stop && !error && args->initudp)
1202  {
1203  printf("Sending initial UDP packet\n");
1204  struct sockaddr_in casterRTP;
1205  char rtpbuffer[12];
1206  int i;
1207  rtpbuffer[0] = (2<<6);
1208  /* padding, extension, csrc are empty */
1209  rtpbuffer[1] = 96;
1210  /* marker is empty */
1211  rtpbuffer[2] = 0;
1212  rtpbuffer[3] = 0;
1213  rtpbuffer[4] = 0;
1214  rtpbuffer[5] = 0;
1215  rtpbuffer[6] = 0;
1216  rtpbuffer[7] = 0;
1217  /* sequence and timestamp are empty */
1218  rtpbuffer[8] = (session>>24)&0xFF;
1219  rtpbuffer[9] = (session>>16)&0xFF;
1220  rtpbuffer[10] = (session>>8)&0xFF;
1221  rtpbuffer[11] = (session)&0xFF;
1222  /* fill structure with caster address information for UDP */
1223  memset(&casterRTP, 0, sizeof(casterRTP));
1224  casterRTP.sin_family = AF_INET;
1225  casterRTP.sin_port = htons(serverport);
1226  casterRTP.sin_addr = *((struct in_addr *)he->h_addr);
1227 
1228  if((i = sendto(sockudp, rtpbuffer, 12, 0,
1229  (struct sockaddr *) &casterRTP, sizeof(casterRTP))) != 12)
1230  myperror("WARNING: could not send initial UDP packet");
1231  }
1232  if(!args->stop && !error)
1233  {
1234  i = snprintf(buf, MAXDATASIZE,
1235  "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
1236  "CSeq: %d\r\n"
1237  "Session: %u\r\n"
1238  "\r\n",
1239  args->server, proxyserver ? ":" : "", proxyserver ? args->port : "",
1240  args->data, cseq++, session);
1241 
1242  if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
1243  {
1244  fprintf(stderr, "Requested data too long\n");
1245  args->stop=true;
1246  }
1247  else if(send(sockfd, buf, (size_t)i, 0) != i)
1248  {
1249  myperror("send");
1250  error = 1;
1251  }
1252  else if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
1253  {
1254  if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
1255  {
1256  int ts = 0, sn = 0;
1257  time_t init = 0;
1258  struct sockaddr_in addrRTP;
1259 #ifdef WINDOWSVERSION
1260  u_long blockmode = 1;
1261  if(ioctlsocket(sockudp, FIONBIO, &blockmode)
1262  || ioctlsocket(sockfd, FIONBIO, &blockmode))
1263 #else /* WINDOWSVERSION */
1264  if(fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0
1265  || fcntl(sockudp, F_SETFL, O_NONBLOCK) < 0)
1266 #endif /* WINDOWSVERSION */
1267  {
1268  fprintf(stderr, "Could not set nonblocking mode\n");
1269  error = 1;
1270  }
1271 
1272  /* fill structure with caster address information for UDP */
1273  memset(&addrRTP, 0, sizeof(addrRTP));
1274  addrRTP.sin_family = AF_INET;
1275  addrRTP.sin_port = htons(serverport);
1276  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
1277  len = sizeof(addrRTP);
1278 
1279  while(!args->stop && !error)
1280  {
1281  char rtpbuffer[1526];
1282  struct timeval tv = {1,0};
1283  fd_set fdr;
1284  fd_set fde;
1285  int r;
1286 
1287  FD_ZERO(&fdr);
1288  FD_ZERO(&fde);
1289  FD_SET(sockudp, &fdr);
1290  FD_SET(sockfd, &fdr);
1291  FD_SET(sockudp, &fde);
1292  FD_SET(sockfd, &fde);
1293  if(select((sockudp>sockfd?sockudp:sockfd)+1,
1294  &fdr,0,&fde,&tv) < 0)
1295  {
1296  fprintf(stderr, "Select problem.\n");
1297  error = 1;
1298  continue;
1299  }
1300  i = recvfrom(sockudp, rtpbuffer, sizeof(rtpbuffer), 0,
1301  (struct sockaddr*) &addrRTP, &len);
1302 #ifndef WINDOWSVERSION
1303  alarm(ALARMTIME);
1304 #endif
1305  if(i >= 12+1 && (unsigned char)rtpbuffer[0] == (2 << 6) && rtpbuffer[1] == 0x60)
1306  {
1307  int u,v,w;
1308  u = ((unsigned char)rtpbuffer[2]<<8)+(unsigned char)rtpbuffer[3];
1309  v = ((unsigned char)rtpbuffer[4]<<24)+((unsigned char)rtpbuffer[5]<<16)
1310  +((unsigned char)rtpbuffer[6]<<8)+(unsigned char)rtpbuffer[7];
1311  w = ((unsigned char)rtpbuffer[8]<<24)+((unsigned char)rtpbuffer[9]<<16)
1312  +((unsigned char)rtpbuffer[10]<<8)+(unsigned char)rtpbuffer[11];
1313 
1314  if(init)
1315  {
1316  time_t ct;
1317  if(u < -30000 && sn > 30000) sn -= 0xFFFF;
1318  if(session != w || ts > v)
1319  {
1320  fprintf(stderr, "Illegal UDP data received.\n");
1321  continue;
1322  }
1323  else if(u > sn) /* don't show out-of-order packets */
1324  fwrite(rtpbuffer+12, (size_t)i-12, 1, stdout);
1325  ct = time(0);
1326  if(ct-init > 15)
1327  {
1328  i = snprintf(buf, MAXDATASIZE,
1329  "GET_PARAMETER rtsp://%s%s%s/%s RTSP/1.0\r\n"
1330  "CSeq: %d\r\n"
1331  "Session: %u\r\n"
1332  "\r\n",
1333  args->server, proxyserver ? ":" : "", proxyserver
1334  ? args->port : "", args->data, cseq++, session);
1335  if(i > MAXDATASIZE || i < 0)
1336  {
1337  fprintf(stderr, "Requested data too long\n");
1338  args->stop = true;
1339  }
1340  else if(send(sockfd, buf, (size_t)i, 0) != i)
1341  {
1342  myperror("send");
1343  error = 1;
1344  }
1345  init = ct;
1346  }
1347  }
1348  else
1349  {
1350  init = time(0);
1351  }
1352  sn = u; ts = v;
1353  }
1354  else if(i >= 0)
1355  {
1356  fprintf(stderr, "Illegal UDP header.\n");
1357  continue;
1358  }
1359  /* ignore RTSP server replies */
1360  if((r=recv(sockfd, buf, MAXDATASIZE-1, 0)) < 0)
1361  {
1362 #ifdef WINDOWSVERSION
1363  if(WSAGetLastError() != WSAEWOULDBLOCK)
1364 #else /* WINDOWSVERSION */
1365  if(errno != EAGAIN)
1366 #endif /* WINDOWSVERSION */
1367  {
1368  fprintf(stderr, "Control connection closed\n");
1369  error = 1;
1370  }
1371  }
1372  else if(!r)
1373  {
1374  fprintf(stderr, "Control connection read error\n");
1375  error = 1;
1376  }
1377  }
1378  }
1379  i = snprintf(buf, MAXDATASIZE,
1380  "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
1381  "CSeq: %d\r\n"
1382  "Session: %u\r\n"
1383  "\r\n",
1384  args->server, proxyserver ? ":" : "", proxyserver ? args->port : "",
1385  args->data, cseq++, session);
1386 
1387  if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
1388  {
1389  fprintf(stderr, "Requested data too long\n");
1390  args->stop = true;
1391  }
1392  else if(send(sockfd, buf, (size_t)i, 0) != i)
1393  {
1394  myperror("send");
1395  error = 1;
1396  }
1397  }
1398  else
1399  {
1400  fprintf(stderr, "Could not start data stream.\n");
1401  error = 1;
1402  }
1403  }
1404  }
1405  else
1406  {
1407  fprintf(stderr, "Could not setup initial control connection.\n");
1408  error = 1;
1409  }
1410  if(sockudp)
1411  closesocket(sockudp);
1412  }
1413  }
1414  else
1415  {
1416  if(connect(sockfd, (struct sockaddr *)&their_addr,
1417  sizeof(struct sockaddr)) == -1)
1418  {
1419  myperror("connect");
1420  error = 1;
1421  }
1422  if(!args->stop && !error)
1423  {
1424  if(!args->data)
1425  {
1426  i = snprintf(buf, MAXDATASIZE,
1427  "GET %s%s%s%s/ HTTP/1.1\r\n"
1428  "Host: %s\r\n%s"
1429  "User-Agent: %s/%s\r\n"
1430  "Connection: close\r\n"
1431  "\r\n"
1432  , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
1433  proxyserver ? ":" : "", proxyserver ? proxyport : "",
1434  args->server, args->mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
1436  }
1437  else
1438  {
1439  const char *nmeahead = (args->nmea && args->mode == HTTP) ? args->nmea : 0;
1440 
1441  i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
1442  "GET %s%s%s%s/%s HTTP/1.1\r\n"
1443  "Host: %s\r\n%s"
1444  "User-Agent: %s/%s\r\n"
1445  "%s%s%s"
1446  "Connection: close%s"
1447  , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
1448  proxyserver ? ":" : "", proxyserver ? proxyport : "",
1449  args->data, args->server,
1450  args->mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
1452  nmeahead ? "Ntrip-GGA: " : "", nmeahead ? nmeahead : "",
1453  nmeahead ? "\r\n" : "",
1454  (*args->user || *args->password) ? "\r\nAuthorization: Basic " : "");
1455  if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
1456  {
1457  fprintf(stderr, "Requested data too long\n");
1458  args->stop = true;
1459  }
1460  else
1461  {
1462  i += encode(buf+i, MAXDATASIZE-i-4, args->user, args->password);
1463  if(i > MAXDATASIZE-4)
1464  {
1465  fprintf(stderr, "Username and/or password too long\n");
1466  args->stop = true;
1467  }
1468  else
1469  {
1470  buf[i++] = '\r';
1471  buf[i++] = '\n';
1472  buf[i++] = '\r';
1473  buf[i++] = '\n';
1474  if(args->nmea && !nmeahead)
1475  {
1476  int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args->nmea);
1477  if(j >= 0 && j < MAXDATASIZE-i)
1478  i += j;
1479  else
1480  {
1481  fprintf(stderr, "NMEA string too long\n");
1482  args->stop = true;
1483  }
1484  }
1485  }
1486  }
1487  }
1488  }
1489  if(!args->stop && !error)
1490  {
1491  if(send(sockfd, buf, (size_t)i, 0) != i)
1492  {
1493  myperror("send");
1494  error = 1;
1495  }
1496  else if(args->data && *args->data != '%')
1497  {
1498  int k = 0;
1499  int chunkymode = 0;
1500  int starttime = time(0);
1501  int lastout = starttime;
1502  int totalbytes = 0;
1503  int chunksize = 0;
1504 
1505  printf("%s",buf);
1506 
1507  while(!args->stop && !error &&
1508  (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1509  {
1510 #ifndef WINDOWSVERSION
1511  alarm(ALARMTIME);
1512 #endif
1513  if(!k)
1514  {
1515  buf[numbytes] = 0; /* latest end mark for strstr */
1516  if( numbytes > 17 &&
1517  !strstr(buf, "ICY 200 OK") && /* case 'proxy & ntrip 1.0 caster' */
1518  (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) ||
1519  !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)) )
1520  {
1521  const char *datacheck = "Content-Type: gnss/data\r\n";
1522  const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
1523  int l = strlen(datacheck)-1;
1524  int j=0;
1525  for(i = 0; j != l && i < numbytes-l; ++i)
1526  {
1527  for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
1528  ;
1529  }
1530  if(i == numbytes-l)
1531  {
1532  fprintf(stderr, "No 'Content-Type: gnss/data' found\n");
1533  error = 1;
1534  }
1535  l = strlen(chunkycheck)-1;
1536  j=0;
1537  for(i = 0; j != l && i < numbytes-l; ++i)
1538  {
1539  for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
1540  ;
1541  }
1542  if(i < numbytes-l)
1543  chunkymode = 1;
1544  }
1545  else if(!strstr(buf, "ICY 200 OK"))
1546  {
1547  fprintf(stderr, "Could not get the requested data: ");
1548  for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
1549  {
1550  fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
1551  }
1552  fprintf(stderr, "\n");
1553  error = 1;
1554  }
1555  else if(args->mode != NTRIP1)
1556  {
1557  fprintf(stderr, "NTRIP version 2 HTTP connection failed%s.\n",
1558  args->mode == AUTO ? ", falling back to NTRIP1" : "");
1559  if(args->mode == HTTP)
1560  args->stop = true;
1561  }
1562  k = 1;
1563  if(args->mode == NTRIP1)
1564  continue; /* skip old headers for NTRIP1 */
1565  else
1566  {
1567  char *ep = strstr(buf, "\r\n\r\n");
1568  if(!ep || ep+4 == buf+numbytes)
1569  continue;
1570  ep += 4;
1571  memmove(buf, ep, numbytes-(ep-buf));
1572  numbytes -= (ep-buf);
1573  }
1574  }
1575  sleeptime = 0;
1576  if(chunkymode)
1577  {
1578  int cstop = 0;
1579  int pos = 0;
1580  while(!args->stop && !cstop && !error && pos < numbytes)
1581  {
1582  switch(chunkymode)
1583  {
1584  case 1: /* reading number starts */
1585  chunksize = 0;
1586  ++chunkymode; /* no break */
1587  case 2: /* during reading number */
1588  i = buf[pos++];
1589  if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
1590  else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
1591  else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
1592  else if(i == '\r') ++chunkymode;
1593  else if(i == ';') chunkymode = 5;
1594  else cstop = 1;
1595  break;
1596  case 3: /* scanning for return */
1597  if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
1598  else cstop = 1;
1599  break;
1600  case 4: /* output data */
1601  i = numbytes-pos;
1602  if(i > chunksize) i = chunksize;
1603  if(args->serdevice)
1604  {
1605  int ofs = 0;
1606  while(i > ofs && !cstop && !args->stop && !error)
1607  {
1608  int j = SerialWrite(&sx, buf+pos+ofs, i-ofs);
1609  if(j < 0)
1610  {
1611  fprintf(stderr, "Could not access serial device\n");
1612  args->stop = true;
1613  }
1614  else
1615  ofs += j;
1616  }
1617  }
1618  else
1619  fwrite(buf+pos, (size_t)i, 1, stdout);
1620  totalbytes += i;
1621  chunksize -= i;
1622  pos += i;
1623  if(!chunksize)
1624  chunkymode = 1;
1625  break;
1626  case 5:
1627  if(i == '\r') chunkymode = 3;
1628  break;
1629  }
1630  }
1631  if(cstop)
1632  {
1633  fprintf(stderr, "Error in chunky transfer encoding\n");
1634  error = 1;
1635  }
1636  }
1637  else
1638  {
1639  totalbytes += numbytes;
1640  if(args->serdevice)
1641  {
1642  int ofs = 0;
1643  while(numbytes > ofs && !args->stop)
1644  {
1645  int i = SerialWrite(&sx, buf+ofs, numbytes-ofs);
1646  if(i < 0)
1647  {
1648  fprintf(stderr, "Could not access serial device\n");
1649  args->stop = 1;
1650  }
1651  else
1652  ofs += i;
1653  }
1654  }
1655  else
1656  fwrite(buf, (size_t)numbytes, 1, stdout);
1657  }
1658  fflush(stdout);
1659  if(totalbytes < 0) /* overflow */
1660  {
1661  totalbytes = 0;
1662  starttime = time(0);
1663  lastout = starttime;
1664  }
1665  if(args->serdevice && !args->stop)
1666  {
1667  int doloop = 1;
1668  while(doloop && !args->stop)
1669  {
1670  int i = SerialRead(&sx, buf, 200);
1671  if(i < 0)
1672  {
1673  fprintf(stderr, "Could not access serial device\n");
1674  args->stop = true;
1675  }
1676  else
1677  {
1678  int j = 0;
1679  if(i < 200) doloop = 0;
1680  //fwrite(buf, i, 1, stdout);
1681  if(ser)
1682  fwrite(buf, i, 1, ser);
1683  appendNMEA(buf,i);
1684 
1685  while(j < i)
1686  {
1687  if(nmeabufpos < 6)
1688  {
1689  if(nmeabuffer[nmeabufpos] != buf[j])
1690  {
1691  if(nmeabufpos) nmeabufpos = 0;
1692  else ++j;
1693  }
1694  else
1695  {
1696  nmeastarpos = 0;
1697  ++j; ++nmeabufpos;
1698  }
1699  }
1700  else if((nmeastarpos && nmeabufpos == nmeastarpos + 3)
1701  || buf[j] == '\r' || buf[j] == '\n')
1702  {
1703  doloop = 0;
1704  nmeabuffer[nmeabufpos++] = '\r';
1705  nmeabuffer[nmeabufpos++] = '\n';
1706  if(send(sockfd, nmeabuffer, nmeabufpos, 0)
1707  != (int)nmeabufpos)
1708  {
1709  fprintf(stderr, "Could not send NMEA\n");
1710  error = 1;
1711  }
1712  nmeabufpos = 0;
1713  }
1714  else if(nmeabufpos > sizeof(nmeabuffer)-10 ||
1715  buf[j] == '$')
1716  nmeabufpos = 0;
1717  else
1718  {
1719  if(buf[j] == '*') nmeastarpos = nmeabufpos;
1720  nmeabuffer[nmeabufpos++] = buf[j++];
1721  }
1722  }
1723  }
1724  }
1725  }
1726  if(args->bitrate)
1727  {
1728  int t = time(0);
1729  if(t > lastout + 60)
1730  {
1731  lastout = t;
1732  fprintf(stderr, "Bitrate is %dbyte/s (%d seconds accumulated).\n",
1733  totalbytes/(t-starttime), t-starttime);
1734  }
1735  }
1736  }
1737  }
1738  else
1739  {
1740  sleeptime = 0;
1741  while(!args->stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1742  {
1743  #ifndef WINDOWSVERSION
1744  alarm(ALARMTIME);
1745  #endif
1746  fwrite(buf, (size_t)numbytes, 1, stdout);
1747  }
1748  }
1749  }
1750  }
1751  }
1752  if(sockfd)
1753  closesocket(sockfd);
1754  sleep(10);
1755  } while(args->data && *args->data != '%' && !args->stop);
1756  if(args->serdevice)
1757  {
1758  SerialFree(&sx);
1759  }
1760  if(ser)
1761  fclose(ser);
1762  }
1763  return;
1764 }
1765 
1766 
1767 
1768 
#define ALARMTIME
static int encode(char *buf, int size, const char *user, const char *pwd)
#define myperror
int sockettype
Definition: ntripclient.cpp:97
int udpport
Definition: ntrip.h:22
void appendNMEA(char *buf, int i)
Definition: ntripclient.cpp:75
int SerialRead(struct serial *sn, char *buffer, size_t size)
Definition: serial.cpp:73
std::string hdop
Definition: ntrip.h:42
const char * proxyport
Definition: ntrip.h:15
Definition: ntrip.h:7
void init(const M_string &remappings)
#define AGENTSTRING
string g_nmea
Definition: ntripclient.cpp:40
static enum SerialProtocol SerialGetProtocol(const char *buf, int *ressize)
Definition: serial.h:54
XmlRpcServer s
const char * SerialInit(struct serial *sn, const char *Device, enum SerialBaud Baud, enum SerialStopbits StopBits, enum SerialProtocol Protocol, enum SerialParity Parity, enum SerialDatabits DataBits, int dowrite)
Definition: serial.cpp:43
const char * data
Definition: ntrip.h:18
int mode
Definition: ntrip.h:20
static const char encodingTable[64]
#define COMPILEDATE
std::string lat
Definition: ntrip.h:39
void ntrip_client(Args *const args)
static char datestr[]
Location getGNGGA()
Definition: ntripclient.cpp:43
int sigstop
std::string lon
Definition: ntrip.h:40
bool stop
Definition: ntrip.h:31
enum SerialProtocol protocol
Definition: ntrip.h:28
Definition: ntrip.h:7
std::string nmea
Definition: ntrip.h:38
const char * serlogfile
Definition: ntrip.h:30
#define TIME_RESOLUTION
Definition: ntrip.h:9
int stop
Definition: ntrip.h:7
mutex g_mtx
Definition: ntripclient.cpp:39
#define LONG_OPT(a)
Definition: serial.h:25
enum SerialDatabits databits
Definition: ntrip.h:25
Definition: ntrip.h:7
static const char * encodeurl(const char *req)
enum SerialBaud baud
Definition: ntrip.h:24
int bitrate
Definition: ntrip.h:19
static char revisionstr[]
static const char * geturl(const char *url, struct Args *args)
std::string fix
Definition: ntrip.h:44
void SerialFree(struct serial *sn)
Definition: serial.cpp:32
const char * port
Definition: ntrip.h:12
Definition: ntrip.h:7
const char * password
Definition: ntrip.h:16
static void sighandler_alarm(int sig)
#define closesocket(sock)
#define ARGOPT
enum SerialStopbits stopbits
Definition: ntrip.h:26
#define MAXDATASIZE
const char * proxyhost
Definition: ntrip.h:14
static int getargs(int argc, char **argv, struct Args *args)
int SerialWrite(struct serial *sn, const char *buffer, size_t size)
Definition: serial.cpp:86
const char * nmea
Definition: ntrip.h:17
static enum SerialParity SerialGetParity(const char *buf, int *ressize)
Definition: serial.h:32
const char * user
Definition: ntrip.h:13
std::string alt
Definition: ntrip.h:41
int initudp
Definition: ntrip.h:23
const char * serdevice
Definition: ntrip.h:29
const char * server
Definition: ntrip.h:11
std::string help()
enum SerialParity parity
Definition: ntrip.h:27
Definition: ntrip.h:7
Definition: ntrip.h:35
static struct option opts[]


dgps_ros
Author(s):
autogenerated on Wed Jan 20 2021 03:38:34