1 Star 3 Fork 0

Wishin/ntripclient

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ntripclient.c 58.75 KB
一键复制 编辑 原始数据 按行查看 历史
Dirk Stoecker 提交于 2010-03-10 18:28 . added delay
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736
/*
NTRIP client for POSIX.
$Id: ntripclient.c,v 1.51 2009/09/11 09:49:19 stoecker Exp $
Copyright (C) 2003-2008 by Dirk Stöcker <soft@dstoecker.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
or read http://www.gnu.org/licenses/gpl.txt
*/
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include "serial.c"
#ifdef WINDOWSVERSION
#include <winsock.h>
typedef SOCKET sockettype;
typedef u_long in_addr_t;
typedef size_t socklen_t;
void myperror(char *s)
{
fprintf(stderr, "%s: %d\n", s, WSAGetLastError());
}
#else
typedef int sockettype;
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define closesocket(sock) close(sock)
#define ALARMTIME (2*60)
#define myperror perror
#endif
#ifndef COMPILEDATE
#define COMPILEDATE " built " __DATE__
#endif
/* The string, which is send as agent in HTTP request */
#define AGENTSTRING "NTRIP NtripClientPOSIX"
#define TIME_RESOLUTION 125
#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
/* CVS revision and version */
static char revisionstr[] = "$Revision: 1.51 $";
static char datestr[] = "$Date: 2009/09/11 09:49:19 $";
enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, UDP = 5, END };
struct Args
{
const char *server;
const char *port;
const char *user;
const char *proxyhost;
const char *proxyport;
const char *password;
const char *nmea;
const char *data;
int bitrate;
int mode;
int udpport;
int initudp;
enum SerialBaud baud;
enum SerialDatabits databits;
enum SerialStopbits stopbits;
enum SerialParity parity;
enum SerialProtocol protocol;
const char *serdevice;
const char *serlogfile;
};
/* option parsing */
#ifdef NO_LONG_OPTS
#define LONG_OPT(a)
#else
#define LONG_OPT(a) a
static struct option opts[] = {
{ "bitrate", no_argument, 0, 'b'},
{ "data", required_argument, 0, 'd'}, /* compatibility */
{ "mountpoint", required_argument, 0, 'm'},
{ "initudp", no_argument, 0, 'I'},
{ "udpport", required_argument, 0, 'P'},
{ "server", required_argument, 0, 's'},
{ "password", required_argument, 0, 'p'},
{ "port", required_argument, 0, 'r'},
{ "proxyport", required_argument, 0, 'R'},
{ "proxyhost", required_argument, 0, 'S'},
{ "user", required_argument, 0, 'u'},
{ "nmea", required_argument, 0, 'n'},
{ "mode", required_argument, 0, 'M'},
{ "serdevice", required_argument, 0, 'D'},
{ "baud", required_argument, 0, 'B'},
{ "stopbits", required_argument, 0, 'T'},
{ "protocol", required_argument, 0, 'C'},
{ "parity", required_argument, 0, 'Y'},
{ "databits", required_argument, 0, 'A'},
{ "serlogfile", required_argument, 0, 'l'},
{ "help", no_argument, 0, 'h'},
{0,0,0,0}};
#endif
#define ARGOPT "-d:m:bhp:r:s:u:n:S:R:M:IP:D:B:T:C:Y:A:l:"
int stop = 0;
#ifndef WINDOWSVERSION
int sigstop = 0;
#ifdef __GNUC__
static __attribute__ ((noreturn)) void sighandler_alarm(
int sig __attribute__((__unused__)))
#else /* __GNUC__ */
static void sighandler_alarm(int sig)
#endif /* __GNUC__ */
{
if(!sigstop)
fprintf(stderr, "ERROR: more than %d seconds no activity\n", ALARMTIME);
else
fprintf(stderr, "ERROR: user break\n");
exit(1);
}
#ifdef __GNUC__
static void sighandler_int(int sig __attribute__((__unused__)))
#else /* __GNUC__ */
static void sighandler_alarm(int sig)
#endif /* __GNUC__ */
{
sigstop = 1;
alarm(2);
stop = 1;
}
#endif /* WINDOWSVERSION */
static const char *encodeurl(const char *req)
{
char *h = "0123456789abcdef";
static char buf[128];
char *urlenc = buf;
char *bufend = buf + sizeof(buf) - 3;
while(*req && urlenc < bufend)
{
if(isalnum(*req)
|| *req == '-' || *req == '_' || *req == '.')
*urlenc++ = *req++;
else
{
*urlenc++ = '%';
*urlenc++ = h[*req >> 4];
*urlenc++ = h[*req & 0x0f];
req++;
}
}
*urlenc = 0;
return buf;
}
static const char *geturl(const char *url, struct Args *args)
{
static char buf[1000];
static char *Buffer = buf;
static char *Bufend = buf+sizeof(buf);
char *h = "0123456789abcdef";
if(strncmp("ntrip:", url, 6))
return "URL must start with 'ntrip:'.";
url += 6; /* skip ntrip: */
if(*url != '@' && *url != '/')
{
/* scan for mountpoint */
args->data = Buffer;
if(*url != '?')
{
while(*url && *url != '@' && *url != ';' && *url != '/' && Buffer != Bufend)
*(Buffer++) = *(url++);
}
else
{
while(*url && *url != '@' && *url != '/' && Buffer != Bufend)
{
if(isalnum(*url) || *url == '-' || *url == '_' || *url == '.')
*Buffer++ = *url++;
else
{
*Buffer++ = '%';
*Buffer++ = h[*url >> 4];
*Buffer++ = h[*url & 0x0f];
url++;
}
}
}
if(Buffer == args->data)
return "Mountpoint required.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
}
if(*url == '/') /* username and password */
{
++url;
args->user = Buffer;
while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
*(Buffer++) = *(url++);
if(Buffer == args->user)
return "Username cannot be empty.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
if(*url == ':') ++url;
args->password = Buffer;
while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
*(Buffer++) = *(url++);
if(Buffer == args->password)
return "Password cannot be empty.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
}
if(*url == '@') /* server */
{
++url;
if(*url != '@' && *url != ':')
{
args->server = Buffer;
while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
*(Buffer++) = *(url++);
if(Buffer == args->server)
return "Servername cannot be empty.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
}
if(*url == ':')
{
++url;
args->port = Buffer;
while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
*(Buffer++) = *(url++);
if(Buffer == args->port)
return "Port cannot be empty.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
}
if(*url == '@') /* proxy */
{
++url;
args->proxyhost = Buffer;
while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
*(Buffer++) = *(url++);
if(Buffer == args->proxyhost)
return "Proxy servername cannot be empty.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
if(*url == ':')
{
++url;
args->proxyport = Buffer;
while(*url && *url != ';' && Buffer != Bufend)
*(Buffer++) = *(url++);
if(Buffer == args->proxyport)
return "Proxy port cannot be empty.";
else if(Buffer >= Bufend-1)
return "Parsing buffer too short.";
*(Buffer++) = 0;
}
}
}
if(*url == ';') /* NMEA */
{
args->nmea = ++url;
while(*url)
++url;
}
return *url ? "Garbage at end of server string." : 0;
}
static int getargs(int argc, char **argv, struct Args *args)
{
int res = 1;
int getoptr;
char *a;
int i = 0, help = 0;
args->server = "www.euref-ip.net";
args->port = "2101";
args->user = "";
args->password = "";
args->nmea = 0;
args->data = 0;
args->bitrate = 0;
args->proxyhost = 0;
args->proxyport = "2101";
args->mode = AUTO;
args->initudp = 0;
args->udpport = 0;
args->protocol = SPAPROTOCOL_NONE;
args->parity = SPAPARITY_NONE;
args->stopbits = SPASTOPBITS_1;
args->databits = SPADATABITS_8;
args->baud = SPABAUD_9600;
args->serdevice = 0;
args->serlogfile = 0;
help = 0;
do
{
#ifdef NO_LONG_OPTS
switch((getoptr = getopt(argc, argv, ARGOPT)))
#else
switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
#endif
{
case 's': args->server = optarg; break;
case 'u': args->user = optarg; break;
case 'p': args->password = optarg; break;
case 'd': /* legacy option, may get removed in future */
fprintf(stderr, "Option -d or --data is deprecated. Use -m instead.\n");
case 'm':
if(optarg && *optarg == '?')
args->data = encodeurl(optarg);
else
args->data = optarg;
break;
case 'B':
{
int i = strtol(optarg, 0, 10);
switch(i)
{
case 50: args->baud = SPABAUD_50; break;
case 110: args->baud = SPABAUD_110; break;
case 300: args->baud = SPABAUD_300; break;
case 600: args->baud = SPABAUD_600; break;
case 1200: args->baud = SPABAUD_1200; break;
case 2400: args->baud = SPABAUD_2400; break;
case 4800: args->baud = SPABAUD_4800; break;
case 9600: args->baud = SPABAUD_9600; break;
case 19200: args->baud = SPABAUD_19200; break;
case 38400: args->baud = SPABAUD_38400; break;
case 57600: args->baud = SPABAUD_57600; break;
case 115200: args->baud = SPABAUD_115200; break;
default:
fprintf(stderr, "Baudrate '%s' unknown\n", optarg);
res = 0;
break;
}
}
break;
case 'T':
if(!strcmp(optarg, "1")) args->stopbits = SPASTOPBITS_1;
else if(!strcmp(optarg, "2")) args->stopbits = SPASTOPBITS_2;
else
{
fprintf(stderr, "Stopbits '%s' unknown\n", optarg);
res = 0;
}
break;
case 'A':
if(!strcmp(optarg, "5")) args->databits = SPADATABITS_5;
else if(!strcmp(optarg, "6")) args->databits = SPADATABITS_6;
else if(!strcmp(optarg, "7")) args->databits = SPADATABITS_7;
else if(!strcmp(optarg, "8")) args->databits = SPADATABITS_8;
else
{
fprintf(stderr, "Databits '%s' unknown\n", optarg);
res = 0;
}
break;
case 'C':
{
int i = 0;
args->protocol = SerialGetProtocol(optarg, &i);
if(!i)
{
fprintf(stderr, "Protocol '%s' unknown\n", optarg);
res = 0;
}
}
break;
case 'Y':
{
int i = 0;
args->parity = SerialGetParity(optarg, &i);
if(!i)
{
fprintf(stderr, "Parity '%s' unknown\n", optarg);
res = 0;
}
}
break;
case 'D': args->serdevice = optarg; break;
case 'l': args->serlogfile = optarg; break;
case 'I': args->initudp = 1; break;
case 'P': args->udpport = strtol(optarg, 0, 10); break;
case 'n': args->nmea = optarg; break;
case 'b': args->bitrate = 1; break;
case 'h': help=1; break;
case 'r': args->port = optarg; break;
case 'S': args->proxyhost = optarg; break;
case 'R': args->proxyport = optarg; break;
case 'M':
args->mode = 0;
if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
args->mode = NTRIP1;
else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
args->mode = HTTP;
else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
args->mode = RTSP;
else if(!strcmp(optarg,"u") || !strcmp(optarg,"udp"))
args->mode = UDP;
else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
args->mode = AUTO;
else args->mode = atoi(optarg);
if((args->mode == 0) || (args->mode >= END))
{
fprintf(stderr, "Mode %s unknown\n", optarg);
res = 0;
}
break;
case 1:
{
const char *err;
if((err = geturl(optarg, args)))
{
fprintf(stderr, "%s\n\n", err);
res = 0;
}
}
break;
case -1: break;
}
} while(getoptr != -1 && res);
for(a = revisionstr+11; *a && *a != ' '; ++a)
revisionstr[i++] = *a;
revisionstr[i] = 0;
datestr[0] = datestr[7];
datestr[1] = datestr[8];
datestr[2] = datestr[9];
datestr[3] = datestr[10];
datestr[5] = datestr[12];
datestr[6] = datestr[13];
datestr[8] = datestr[15];
datestr[9] = datestr[16];
datestr[4] = datestr[7] = '-';
datestr[10] = 0;
if(!res || help)
{
fprintf(stderr, "Version %s (%s) GPL" COMPILEDATE "\nUsage:\n%s -s server -u user ...\n"
" -m " LONG_OPT("--mountpoint ") "the requested data set or sourcetable filtering criteria\n"
" -s " LONG_OPT("--server ") "the server name or address\n"
" -p " LONG_OPT("--password ") "the login password\n"
" -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
" -u " LONG_OPT("--user ") "the user name\n"
" -M " LONG_OPT("--mode ") "mode for data request\n"
" Valid modes are:\n"
" 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
" 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
" 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
" 4, a, auto automatic detection (default)\n"
" 5, u, udp NTRIP Version 2.0 Caster in UDP mode\n"
"or using an URL:\n%s ntrip:mountpoint[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
"\nExpert options:\n"
" -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
" -b " LONG_OPT("--bitrate ") "output bitrate\n"
" -I " LONG_OPT("--initudp ") "send initial UDP packet for firewall handling\n"
" -P " LONG_OPT("--udpport ") "set the local UDP port\n"
" -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
" -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
"\nSerial input/output:\n"
" -D " LONG_OPT("--serdevice ") "serial device for output\n"
" -B " LONG_OPT("--baud ") "baudrate for serial device\n"
" -T " LONG_OPT("--stopbits ") "stopbits for serial device\n"
" -C " LONG_OPT("--protocol ") "protocol for serial device\n"
" -Y " LONG_OPT("--parity ") "parity for serial device\n"
" -A " LONG_OPT("--databits ") "databits for serial device\n"
" -l " LONG_OPT("--serlogfile ") "logfile for serial data\n"
, revisionstr, datestr, argv[0], argv[0]);
exit(1);
}
return res;
}
static const char encodingTable [64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
/* does not buffer overrun, but breaks directly after an error */
/* returns the number of required bytes */
static int encode(char *buf, int size, const char *user, const char *pwd)
{
unsigned char inbuf[3];
char *out = buf;
int i, sep = 0, fill = 0, bytes = 0;
while(*user || *pwd)
{
i = 0;
while(i < 3 && *user) inbuf[i++] = *(user++);
if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
while(i < 3) {inbuf[i++] = 0; ++fill; }
if(out-buf < size-1)
*(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
if(out-buf < size-1)
*(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
| ((inbuf [1] & 0xF0) >> 4)];
if(out-buf < size-1)
{
if(fill == 2)
*(out++) = '=';
else
*(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
| ((inbuf [2] & 0xC0) >> 6)];
}
if(out-buf < size-1)
{
if(fill >= 1)
*(out++) = '=';
else
*(out++) = encodingTable[inbuf [2] & 0x3F];
}
bytes += 4;
}
if(out-buf < size)
*out = 0;
return bytes;
}
int main(int argc, char **argv)
{
struct Args args;
setbuf(stdout, 0);
setbuf(stdin, 0);
setbuf(stderr, 0);
#ifndef WINDOWSVERSION
signal(SIGALRM,sighandler_alarm);
signal(SIGINT,sighandler_int);
alarm(ALARMTIME);
#else
WSADATA wsaData;
if(WSAStartup(MAKEWORD(1,1),&wsaData))
{
fprintf(stderr, "Could not init network access.\n");
return 20;
}
#endif
if(getargs(argc, argv, &args))
{
struct serial sx;
FILE *ser = 0;
char nmeabuffer[200] = "$GPGGA,"; /* our start string */
size_t nmeabufpos = 0;
size_t nmeastarpos = 0;
int sleeptime = 0;
if(args.serdevice)
{
const char *e = SerialInit(&sx, args.serdevice, args.baud,
args.stopbits, args.protocol, args.parity, args.databits, 1);
if(e)
{
fprintf(stderr, "%s\n", e);
return 20;
}
if(args.serlogfile)
{
if(!(ser = fopen(args.serlogfile, "a+")))
{
SerialFree(&sx);
fprintf(stderr, "Could not open serial logfile.\n");
return 20;
}
}
}
do
{
int error = 0;
sockettype sockfd = 0;
int numbytes;
char buf[MAXDATASIZE];
struct sockaddr_in their_addr; /* connector's address information */
struct hostent *he;
struct servent *se;
const char *server, *port, *proxyserver = 0;
char proxyport[6];
char *b;
long i;
if(sleeptime)
{
#ifdef WINDOWSVERSION
Sleep(sleeptime*1000);
#else
sleep(sleeptime);
#endif
sleeptime += 2;
}
else
{
sleeptime = 1;
}
#ifndef WINDOWSVERSION
alarm(ALARMTIME);
#endif
if(args.proxyhost)
{
int p;
if((i = strtol(args.port, &b, 10)) && (!b || !*b))
p = i;
else if(!(se = getservbyname(args.port, 0)))
{
fprintf(stderr, "Can't resolve port %s.", args.port);
stop = 1;
}
else
{
p = ntohs(se->s_port);
}
if(!stop && !error)
{
snprintf(proxyport, sizeof(proxyport), "%d", p);
port = args.proxyport;
proxyserver = args.server;
server = args.proxyhost;
}
}
else
{
server = args.server;
port = args.port;
}
if(!stop && !error)
{
memset(&their_addr, 0, sizeof(struct sockaddr_in));
if((i = strtol(port, &b, 10)) && (!b || !*b))
their_addr.sin_port = htons(i);
else if(!(se = getservbyname(port, 0)))
{
fprintf(stderr, "Can't resolve port %s.", port);
stop = 1;
}
else
{
their_addr.sin_port = se->s_port;
}
if(!stop && !error)
{
if(!(he=gethostbyname(server)))
{
fprintf(stderr, "Server name lookup failed for '%s'.\n", server);
error = 1;
}
else if((sockfd = socket(AF_INET, (args.mode == UDP ? SOCK_DGRAM :
SOCK_STREAM), 0)) == -1)
{
myperror("socket");
error = 1;
}
else
{
their_addr.sin_family = AF_INET;
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
}
}
}
if(!stop && !error)
{
if(args.mode == UDP)
{
unsigned int session;
int tim, seq, init;
char rtpbuf[1526];
int i=12, j;
init = time(0);
srand(init);
session = rand();
tim = rand();
seq = rand();
rtpbuf[0] = (2<<6);
/* padding, extension, csrc are empty */
rtpbuf[1] = 97;
/* marker is empty */
rtpbuf[2] = (seq>>8)&0xFF;
rtpbuf[3] = (seq)&0xFF;
rtpbuf[4] = (tim>>24)&0xFF;
rtpbuf[5] = (tim>>16)&0xFF;
rtpbuf[6] = (tim>>8)&0xFF;
rtpbuf[7] = (tim)&0xFF;
/* sequence and timestamp are empty */
rtpbuf[8] = (session>>24)&0xFF;
rtpbuf[9] = (session>>16)&0xFF;
rtpbuf[10] = (session>>8)&0xFF;
rtpbuf[11] = (session)&0xFF;
++seq;
j = snprintf(rtpbuf+i, sizeof(rtpbuf)-i-40, /* leave some space for login */
"GET /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"Ntrip-Version: Ntrip/2.0\r\n"
"User-Agent: %s/%s\r\n"
"%s%s%s"
"Connection: close%s",
args.data ? args.data : "", args.server, AGENTSTRING, revisionstr,
args.nmea ? "Ntrip-GGA: " : "", args.nmea ? args.nmea : "",
args.nmea ? "\r\n" : "",
(*args.user || *args.password) ? "\r\nAuthorization: Basic " : "");
i += j;
if(i > (int)sizeof(rtpbuf)-40 || j < 0) /* second check for old glibc */
{
fprintf(stderr, "Requested data too long\n");
stop = 1;
}
else
{
i += encode(rtpbuf+i, sizeof(rtpbuf)-i-4, args.user, args.password);
if(i > (int)sizeof(rtpbuf)-4)
{
fprintf(stderr, "Username and/or password too long\n");
stop = 1;
}
else
{
struct sockaddr_in local;
socklen_t len;
rtpbuf[i++] = '\r';
rtpbuf[i++] = '\n';
rtpbuf[i++] = '\r';
rtpbuf[i++] = '\n';
/* fill structure with local address information for UDP */
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(args.udpport);
local.sin_addr.s_addr = htonl(INADDR_ANY);
len = sizeof(local);
/* bind() in order to get a random RTP client_port */
if((bind(sockfd, (struct sockaddr *)&local, len)) < 0)
{
myperror("bind");
error = 1;
}
else if(connect(sockfd, (struct sockaddr *)&their_addr,
sizeof(struct sockaddr)) == -1)
{
myperror("connect");
error = 1;
}
else if(send(sockfd, rtpbuf, i, 0) != i)
{
myperror("Could not send UDP packet");
stop = 1;
}
else
{
if((numbytes=recv(sockfd, rtpbuf, sizeof(rtpbuf)-1, 0)) > 0)
{
int sn = 0x10000, ts=0;
/* we don't expect message longer than 1513, so we cut the last
byte for security reasons to prevent buffer overrun */
rtpbuf[numbytes] = 0;
if(numbytes > 17+12 &&
(!strncmp(rtpbuf+12, "HTTP/1.1 200 OK\r\n", 17) ||
!strncmp(rtpbuf+12, "HTTP/1.0 200 OK\r\n", 17)))
{
const char *sessioncheck = "session: ";
const char *datacheck = "Content-Type: gnss/data\r\n";
const char *sourcetablecheck = "Content-Type: gnss/sourcetable\r\n";
const char *contentlengthcheck = "Content-Length: ";
const char *httpresponseend = "\r\n\r\n";
int contentlength = 0, httpresponselength = 0;
/* datacheck */
int l = strlen(datacheck)-1;
int j=0;
for(i = 12; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && rtpbuf[i+j] == datacheck[j]; ++j)
;
}
if(i != numbytes-l)
{
/* check for Session */
l = strlen(sessioncheck)-1;
j=0;
for(i = 12; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && tolower(rtpbuf[i+j]) == sessioncheck[j]; ++j)
;
}
if(i != numbytes-l) /* found a session number */
{
i+=l;
session = 0;
while(i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9')
session = session * 10 + rtpbuf[i++]-'0';
if(rtpbuf[i] != '\r')
{
fprintf(stderr, "Could not extract session number\n");
stop = 1;
}
}
}
else
{
/* sourcetablecheck */
l = strlen(sourcetablecheck)-1;
j=0;
for(i = 12; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && rtpbuf[i+j] == sourcetablecheck[j]; ++j)
;
}
if(i == numbytes-l)
{
fprintf(stderr, "No 'Content-Type: gnss/data' or"
" 'Content-Type: gnss/sourcetable' found\n");
error = 1;
}
else
{
/* check for http response end */
l = strlen(httpresponseend)-1;
j=0;
for(i = 12; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && rtpbuf[i+j] == httpresponseend[j]; ++j)
;
}
if(i != numbytes-l) /* found http response end */
{
httpresponselength = i+3-12;
}
/* check for content length */
l = strlen(contentlengthcheck)-1;
j=0;
for(i = 12; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && rtpbuf[i+j] == contentlengthcheck[j]; ++j)
;
}
if(i != numbytes-l) /* found content length */
{
i+=l;
contentlength = 0;
while(i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9')
contentlength = contentlength * 10 + rtpbuf[i++]-'0';
if(rtpbuf[i] == '\r')
{
contentlength += httpresponselength;
do
{
fwrite(rtpbuf+12, (size_t)numbytes-12, 1, stdout);
if((contentlength -= (numbytes-12)) == 0)
{
stop = 1;
}
else
{
numbytes = recv(sockfd, rtpbuf, sizeof(rtpbuf), 0);
}
}while((numbytes >12) && (!stop));
}
else
{
fprintf(stderr, "Could not extract content length\n");
stop = 1;
}
}
}
}
}
else
{
int k;
fprintf(stderr, "Could not get the requested data: ");
for(k = 12; k < numbytes && rtpbuf[k] != '\n' && rtpbuf[k] != '\r'; ++k)
{
fprintf(stderr, "%c", isprint(rtpbuf[k]) ? rtpbuf[k] : '.');
}
fprintf(stderr, "\n");
error = 1;
}
while(!stop && !error)
{
struct timeval tv = {1,0};
fd_set fdr;
fd_set fde;
FD_ZERO(&fdr);
FD_ZERO(&fde);
FD_SET(sockfd, &fdr);
FD_SET(sockfd, &fde);
if(select(sockfd+1,&fdr,0,&fde,&tv) < 0)
{
fprintf(stderr, "Select problem.\n");
error = 1;
continue;
}
i = recv(sockfd, rtpbuf, sizeof(rtpbuf), 0);
#ifndef WINDOWSVERSION
alarm(ALARMTIME);
#endif
if(i >= 12 && (unsigned char)rtpbuf[0] == (2 << 6)
&& rtpbuf[1] >= 96 && rtpbuf[1] <= 98)
{
time_t ct;
int u,v;
unsigned int w;
u = ((unsigned char)rtpbuf[2]<<8)+(unsigned char)rtpbuf[3];
v = ((unsigned char)rtpbuf[4]<<24)+((unsigned char)rtpbuf[5]<<16)
+((unsigned char)rtpbuf[6]<<8)+(unsigned char)rtpbuf[7];
w = ((unsigned char)rtpbuf[8]<<24)+((unsigned char)rtpbuf[9]<<16)
+((unsigned char)rtpbuf[10]<<8)+(unsigned char)rtpbuf[11];
if(sn == 0x10000) {sn = u-1;ts=v-1;}
else if(u < -30000 && sn > 30000) sn -= 0xFFFF;
if(session != w || ts > v)
{
fprintf(stderr, "Illegal UDP data received.\n");
continue;
}
else if(u > sn) /* don't show out-of-order packets */
{
if(rtpbuf[1] == 98)
{
fprintf(stderr, "Connection closed.\n");
error = 1;
continue;
}
else if((rtpbuf[1] == 96) && (i>12))
{
fwrite(rtpbuf+12, (size_t)i-12, 1, stdout);
}
}
sn = u; ts = v;
/* Keep Alive */
ct = time(0);
if(ct-init > 15)
{
tim += (ct-init)*1000000/TIME_RESOLUTION;
rtpbuf[0] = (2<<6);
/* padding, extension, csrc are empty */
rtpbuf[1] = 96;
/* marker is empty */
rtpbuf[2] = (seq>>8)&0xFF;
rtpbuf[3] = (seq)&0xFF;
rtpbuf[4] = (tim>>24)&0xFF;
rtpbuf[5] = (tim>>16)&0xFF;
rtpbuf[6] = (tim>>8)&0xFF;
rtpbuf[7] = (tim)&0xFF;
/* sequence and timestamp are empty */
rtpbuf[8] = (session>>24)&0xFF;
rtpbuf[9] = (session>>16)&0xFF;
rtpbuf[10] = (session>>8)&0xFF;
rtpbuf[11] = (session)&0xFF;
++seq;
init = ct;
if(send(sockfd, rtpbuf, 12, 0) != 12)
{
myperror("send");
error = 1;
}
}
}
else if(i >= 0)
{
fprintf(stderr, "Illegal UDP header.\n");
continue;
}
}
}
/* send connection close always to allow nice session closing */
tim += (time(0)-init)*1000000/TIME_RESOLUTION;
rtpbuf[0] = (2<<6);
/* padding, extension, csrc are empty */
rtpbuf[1] = 98;
/* marker is empty */
rtpbuf[2] = (seq>>8)&0xFF;
rtpbuf[3] = (seq)&0xFF;
rtpbuf[4] = (tim>>24)&0xFF;
rtpbuf[5] = (tim>>16)&0xFF;
rtpbuf[6] = (tim>>8)&0xFF;
rtpbuf[7] = (tim)&0xFF;
/* sequence and timestamp are empty */
rtpbuf[8] = (session>>24)&0xFF;
rtpbuf[9] = (session>>16)&0xFF;
rtpbuf[10] = (session>>8)&0xFF;
rtpbuf[11] = (session)&0xFF;
send(sockfd, rtpbuf, 12, 0); /* cleanup */
}
}
}
}
else if(args.data && *args.data != '%' && args.mode == RTSP)
{
struct sockaddr_in local;
sockettype sockudp = 0;
int localport;
int cseq = 1;
socklen_t len;
if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
myperror("socket");
error = 1;
}
if(!stop && !error)
{
/* fill structure with local address information for UDP */
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(args.udpport);
local.sin_addr.s_addr = htonl(INADDR_ANY);
len = sizeof(local);
/* bind() in order to get a random RTP client_port */
if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
{
myperror("bind");
error = 1;
}
else if((getsockname(sockudp, (struct sockaddr*)&local, &len)) == -1)
{
myperror("local access failed");
error = 1;
}
else if(connect(sockfd, (struct sockaddr *)&their_addr,
sizeof(struct sockaddr)) == -1)
{
myperror("connect");
error = 1;
}
localport = ntohs(local.sin_port);
}
if(!stop && !error)
{
i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
"SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Ntrip-Version: Ntrip/2.0\r\n"
"Ntrip-Component: Ntripclient\r\n"
"User-Agent: %s/%s\r\n"
"%s%s%s"
"Transport: RTP/GNSS;unicast;client_port=%u%s",
args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
args.data, cseq++, AGENTSTRING, revisionstr,
args.nmea ? "Ntrip-GGA: " : "", args.nmea ? args.nmea : "",
args.nmea ? "\r\n" : "",
localport,
(*args.user || *args.password) ? "\r\nAuthorization: Basic " : "");
if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
{
fprintf(stderr, "Requested data too long\n");
stop = 1;
}
i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
if(i > MAXDATASIZE-4)
{
fprintf(stderr, "Username and/or password too long\n");
stop = 1;
}
buf[i++] = '\r';
buf[i++] = '\n';
buf[i++] = '\r';
buf[i++] = '\n';
}
if(!stop && !error)
{
if(send(sockfd, buf, (size_t)i, 0) != i)
{
myperror("send");
error = 1;
}
else if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1)
{
myperror("recv");
error = 1;
}
else if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
{
int serverport = 0, session = 0;
const char *portcheck = "server_port=";
const char *sessioncheck = "session: ";
int l = strlen(portcheck)-1;
int j=0;
for(i = 0; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
;
}
if(i == numbytes-l)
{
fprintf(stderr, "No server port number found\n");
stop = 1;
}
else
{
i+=l;
while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
serverport = serverport * 10 + buf[i++]-'0';
if(buf[i] != '\r' && buf[i] != ';')
{
fprintf(stderr, "Could not extract server port\n");
stop = 1;
}
}
if(!stop && !error)
{
l = strlen(sessioncheck)-1;
j=0;
for(i = 0; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
;
}
if(i == numbytes-l)
{
fprintf(stderr, "No session number found\n");
stop = 1;
}
else
{
i+=l;
while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
session = session * 10 + buf[i++]-'0';
if(buf[i] != '\r')
{
fprintf(stderr, "Could not extract session number\n");
stop = 1;
}
}
}
if(!stop && !error && args.initudp)
{
printf("Sending initial UDP packet\n");
struct sockaddr_in casterRTP;
char rtpbuffer[12];
int i;
rtpbuffer[0] = (2<<6);
/* padding, extension, csrc are empty */
rtpbuffer[1] = 96;
/* marker is empty */
rtpbuffer[2] = 0;
rtpbuffer[3] = 0;
rtpbuffer[4] = 0;
rtpbuffer[5] = 0;
rtpbuffer[6] = 0;
rtpbuffer[7] = 0;
/* sequence and timestamp are empty */
rtpbuffer[8] = (session>>24)&0xFF;
rtpbuffer[9] = (session>>16)&0xFF;
rtpbuffer[10] = (session>>8)&0xFF;
rtpbuffer[11] = (session)&0xFF;
/* fill structure with caster address information for UDP */
memset(&casterRTP, 0, sizeof(casterRTP));
casterRTP.sin_family = AF_INET;
casterRTP.sin_port = htons(serverport);
casterRTP.sin_addr = *((struct in_addr *)he->h_addr);
if((i = sendto(sockudp, rtpbuffer, 12, 0,
(struct sockaddr *) &casterRTP, sizeof(casterRTP))) != 12)
myperror("WARNING: could not send initial UDP packet");
}
if(!stop && !error)
{
i = snprintf(buf, MAXDATASIZE,
"PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Session: %u\r\n"
"\r\n",
args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
args.data, cseq++, session);
if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
{
fprintf(stderr, "Requested data too long\n");
stop=1;
}
else if(send(sockfd, buf, (size_t)i, 0) != i)
{
myperror("send");
error = 1;
}
else if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
{
if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
{
int ts = 0, sn = 0;
time_t init = 0;
struct sockaddr_in addrRTP;
#ifdef WINDOWSVERSION
u_long blockmode = 1;
if(ioctlsocket(sockudp, FIONBIO, &blockmode)
|| ioctlsocket(sockfd, FIONBIO, &blockmode))
#else /* WINDOWSVERSION */
if(fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0
|| fcntl(sockudp, F_SETFL, O_NONBLOCK) < 0)
#endif /* WINDOWSVERSION */
{
fprintf(stderr, "Could not set nonblocking mode\n");
error = 1;
}
/* fill structure with caster address information for UDP */
memset(&addrRTP, 0, sizeof(addrRTP));
addrRTP.sin_family = AF_INET;
addrRTP.sin_port = htons(serverport);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
len = sizeof(addrRTP);
while(!stop && !error)
{
char rtpbuffer[1526];
struct timeval tv = {1,0};
fd_set fdr;
fd_set fde;
int r;
FD_ZERO(&fdr);
FD_ZERO(&fde);
FD_SET(sockudp, &fdr);
FD_SET(sockfd, &fdr);
FD_SET(sockudp, &fde);
FD_SET(sockfd, &fde);
if(select((sockudp>sockfd?sockudp:sockfd)+1,
&fdr,0,&fde,&tv) < 0)
{
fprintf(stderr, "Select problem.\n");
error = 1;
continue;
}
i = recvfrom(sockudp, rtpbuffer, sizeof(rtpbuffer), 0,
(struct sockaddr*) &addrRTP, &len);
#ifndef WINDOWSVERSION
alarm(ALARMTIME);
#endif
if(i >= 12+1 && (unsigned char)rtpbuffer[0] == (2 << 6) && rtpbuffer[1] == 0x60)
{
int u,v,w;
u = ((unsigned char)rtpbuffer[2]<<8)+(unsigned char)rtpbuffer[3];
v = ((unsigned char)rtpbuffer[4]<<24)+((unsigned char)rtpbuffer[5]<<16)
+((unsigned char)rtpbuffer[6]<<8)+(unsigned char)rtpbuffer[7];
w = ((unsigned char)rtpbuffer[8]<<24)+((unsigned char)rtpbuffer[9]<<16)
+((unsigned char)rtpbuffer[10]<<8)+(unsigned char)rtpbuffer[11];
if(init)
{
time_t ct;
if(u < -30000 && sn > 30000) sn -= 0xFFFF;
if(session != w || ts > v)
{
fprintf(stderr, "Illegal UDP data received.\n");
continue;
}
else if(u > sn) /* don't show out-of-order packets */
fwrite(rtpbuffer+12, (size_t)i-12, 1, stdout);
ct = time(0);
if(ct-init > 15)
{
i = snprintf(buf, MAXDATASIZE,
"GET_PARAMETER rtsp://%s%s%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Session: %u\r\n"
"\r\n",
args.server, proxyserver ? ":" : "", proxyserver
? args.port : "", args.data, cseq++, session);
if(i > MAXDATASIZE || i < 0)
{
fprintf(stderr, "Requested data too long\n");
stop = 1;
}
else if(send(sockfd, buf, (size_t)i, 0) != i)
{
myperror("send");
error = 1;
}
init = ct;
}
}
else
{
init = time(0);
}
sn = u; ts = v;
}
else if(i >= 0)
{
fprintf(stderr, "Illegal UDP header.\n");
continue;
}
/* ignore RTSP server replies */
if((r=recv(sockfd, buf, MAXDATASIZE-1, 0)) < 0)
{
#ifdef WINDOWSVERSION
if(WSAGetLastError() != WSAEWOULDBLOCK)
#else /* WINDOWSVERSION */
if(errno != EAGAIN)
#endif /* WINDOWSVERSION */
{
fprintf(stderr, "Control connection closed\n");
error = 1;
}
}
else if(!r)
{
fprintf(stderr, "Control connection read error\n");
error = 1;
}
}
}
i = snprintf(buf, MAXDATASIZE,
"TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Session: %u\r\n"
"\r\n",
args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
args.data, cseq++, session);
if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
{
fprintf(stderr, "Requested data too long\n");
stop = 1;
}
else if(send(sockfd, buf, (size_t)i, 0) != i)
{
myperror("send");
error = 1;
}
}
else
{
fprintf(stderr, "Could not start data stream.\n");
error = 1;
}
}
}
else
{
fprintf(stderr, "Could not setup initial control connection.\n");
error = 1;
}
if(sockudp)
closesocket(sockudp);
}
}
else
{
if(connect(sockfd, (struct sockaddr *)&their_addr,
sizeof(struct sockaddr)) == -1)
{
myperror("connect");
error = 1;
}
if(!stop && !error)
{
if(!args.data)
{
i = snprintf(buf, MAXDATASIZE,
"GET %s%s%s%s/ HTTP/1.1\r\n"
"Host: %s\r\n%s"
"User-Agent: %s/%s\r\n"
"Connection: close\r\n"
"\r\n"
, proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
proxyserver ? ":" : "", proxyserver ? proxyport : "",
args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
AGENTSTRING, revisionstr);
}
else
{
const char *nmeahead = (args.nmea && args.mode == HTTP) ? args.nmea : 0;
i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
"GET %s%s%s%s/%s HTTP/1.1\r\n"
"Host: %s\r\n%s"
"User-Agent: %s/%s\r\n"
"%s%s%s"
"Connection: close%s"
, proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
proxyserver ? ":" : "", proxyserver ? proxyport : "",
args.data, args.server,
args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
AGENTSTRING, revisionstr,
nmeahead ? "Ntrip-GGA: " : "", nmeahead ? nmeahead : "",
nmeahead ? "\r\n" : "",
(*args.user || *args.password) ? "\r\nAuthorization: Basic " : "");
if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
{
fprintf(stderr, "Requested data too long\n");
stop = 1;
}
else
{
i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
if(i > MAXDATASIZE-4)
{
fprintf(stderr, "Username and/or password too long\n");
stop = 1;
}
else
{
buf[i++] = '\r';
buf[i++] = '\n';
buf[i++] = '\r';
buf[i++] = '\n';
if(args.nmea && !nmeahead)
{
int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
if(j >= 0 && j < MAXDATASIZE-i)
i += j;
else
{
fprintf(stderr, "NMEA string too long\n");
stop = 1;
}
}
}
}
}
}
if(!stop && !error)
{
if(send(sockfd, buf, (size_t)i, 0) != i)
{
myperror("send");
error = 1;
}
else if(args.data && *args.data != '%')
{
int k = 0;
int chunkymode = 0;
int starttime = time(0);
int lastout = starttime;
int totalbytes = 0;
int chunksize = 0;
while(!stop && !error &&
(numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
{
#ifndef WINDOWSVERSION
alarm(ALARMTIME);
#endif
if(!k)
{
buf[numbytes] = 0; /* latest end mark for strstr */
if( numbytes > 17 &&
!strstr(buf, "ICY 200 OK") && /* case 'proxy & ntrip 1.0 caster' */
(!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) ||
!strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)) )
{
const char *datacheck = "Content-Type: gnss/data\r\n";
const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
int l = strlen(datacheck)-1;
int j=0;
for(i = 0; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
;
}
if(i == numbytes-l)
{
fprintf(stderr, "No 'Content-Type: gnss/data' found\n");
error = 1;
}
l = strlen(chunkycheck)-1;
j=0;
for(i = 0; j != l && i < numbytes-l; ++i)
{
for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
;
}
if(i < numbytes-l)
chunkymode = 1;
}
else if(!strstr(buf, "ICY 200 OK"))
{
fprintf(stderr, "Could not get the requested data: ");
for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
{
fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
}
fprintf(stderr, "\n");
error = 1;
}
else if(args.mode != NTRIP1)
{
fprintf(stderr, "NTRIP version 2 HTTP connection failed%s.\n",
args.mode == AUTO ? ", falling back to NTRIP1" : "");
if(args.mode == HTTP)
stop = 1;
}
k = 1;
if(args.mode == NTRIP1)
continue; /* skip old headers for NTRIP1 */
else
{
char *ep = strstr(buf, "\r\n\r\n");
if(!ep || ep+4 == buf+numbytes)
continue;
ep += 4;
memmove(buf, ep, numbytes-(ep-buf));
numbytes -= (ep-buf);
}
}
sleeptime = 0;
if(chunkymode)
{
int cstop = 0;
int pos = 0;
while(!stop && !cstop && !error && pos < numbytes)
{
switch(chunkymode)
{
case 1: /* reading number starts */
chunksize = 0;
++chunkymode; /* no break */
case 2: /* during reading number */
i = buf[pos++];
if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
else if(i == '\r') ++chunkymode;
else if(i == ';') chunkymode = 5;
else cstop = 1;
break;
case 3: /* scanning for return */
if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
else cstop = 1;
break;
case 4: /* output data */
i = numbytes-pos;
if(i > chunksize) i = chunksize;
if(args.serdevice)
{
int ofs = 0;
while(i > ofs && !cstop && !stop && !error)
{
int j = SerialWrite(&sx, buf+pos+ofs, i-ofs);
if(j < 0)
{
fprintf(stderr, "Could not access serial device\n");
stop = 1;
}
else
ofs += j;
}
}
else
fwrite(buf+pos, (size_t)i, 1, stdout);
totalbytes += i;
chunksize -= i;
pos += i;
if(!chunksize)
chunkymode = 1;
break;
case 5:
if(i == '\r') chunkymode = 3;
break;
}
}
if(cstop)
{
fprintf(stderr, "Error in chunky transfer encoding\n");
error = 1;
}
}
else
{
totalbytes += numbytes;
if(args.serdevice)
{
int ofs = 0;
while(numbytes > ofs && !stop)
{
int i = SerialWrite(&sx, buf+ofs, numbytes-ofs);
if(i < 0)
{
fprintf(stderr, "Could not access serial device\n");
stop = 1;
}
else
ofs += i;
}
}
else
fwrite(buf, (size_t)numbytes, 1, stdout);
}
fflush(stdout);
if(totalbytes < 0) /* overflow */
{
totalbytes = 0;
starttime = time(0);
lastout = starttime;
}
if(args.serdevice && !stop)
{
int doloop = 1;
while(doloop && !stop)
{
int i = SerialRead(&sx, buf, 200);
if(i < 0)
{
fprintf(stderr, "Could not access serial device\n");
stop = 1;
}
else
{
int j = 0;
if(i < 200) doloop = 0;
fwrite(buf, i, 1, stdout);
if(ser)
fwrite(buf, i, 1, ser);
while(j < i)
{
if(nmeabufpos < 6)
{
if(nmeabuffer[nmeabufpos] != buf[j])
{
if(nmeabufpos) nmeabufpos = 0;
else ++j;
}
else
{
nmeastarpos = 0;
++j; ++nmeabufpos;
}
}
else if((nmeastarpos && nmeabufpos == nmeastarpos + 3)
|| buf[j] == '\r' || buf[j] == '\n')
{
doloop = 0;
nmeabuffer[nmeabufpos++] = '\r';
nmeabuffer[nmeabufpos++] = '\n';
if(send(sockfd, nmeabuffer, nmeabufpos, 0)
!= (int)nmeabufpos)
{
fprintf(stderr, "Could not send NMEA\n");
error = 1;
}
nmeabufpos = 0;
}
else if(nmeabufpos > sizeof(nmeabuffer)-10 ||
buf[j] == '$')
nmeabufpos = 0;
else
{
if(buf[j] == '*') nmeastarpos = nmeabufpos;
nmeabuffer[nmeabufpos++] = buf[j++];
}
}
}
}
}
if(args.bitrate)
{
int t = time(0);
if(t > lastout + 60)
{
lastout = t;
fprintf(stderr, "Bitrate is %dbyte/s (%d seconds accumulated).\n",
totalbytes/(t-starttime), t-starttime);
}
}
}
}
else
{
sleeptime = 0;
while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
{
#ifndef WINDOWSVERSION
alarm(ALARMTIME);
#endif
fwrite(buf, (size_t)numbytes, 1, stdout);
}
}
}
}
}
if(sockfd)
closesocket(sockfd);
sleep(10);
} while(args.data && *args.data != '%' && !stop);
if(args.serdevice)
{
SerialFree(&sx);
}
if(ser)
fclose(ser);
}
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/gu-ping/ntripclient.git
git@gitee.com:gu-ping/ntripclient.git
gu-ping
ntripclient
ntripclient
master

搜索帮助