/*! * \file rtklib_stream.cc * \brief streaming functions * \authors * * This is a derived work from RTKLIB http://www.rtklib.com/ * The original source code at https://github.com/tomojitakasu/RTKLIB is * released under the BSD 2-clause license with an additional exclusive clause * that does not apply here. This additional clause is reproduced below: * * " The software package includes some companion executive binaries or shared * libraries necessary to execute APs on Windows. These licenses succeed to the * original ones of these software. " * * Neither the executive binaries nor the shared libraries are required by, used * or included in GNSS-SDR. * * ------------------------------------------------------------------------- * Copyright (C) 2007-2013, T. Takasu * Copyright (C) 2017, Javier Arribas * Copyright (C) 2017, Carles Fernandez * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *----------------------------------------------------------------------------*/ #include "rtklib_stream.h" #include "rtklib_rtkcmn.h" #include "rtklib_solution.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* global options ------------------------------------------------------------*/ static int toinact = 10000; /* inactive timeout (ms) */ static int ticonnect = 10000; /* interval to re-connect (ms) */ static int tirate = 1000; /* avraging time for data rate (ms) */ static int buffsize = 32768; /* receive/send buffer size (bytes) */ static char localdir[1024] = ""; /* local directory for ftp/http */ static char proxyaddr[256] = ""; /* http/ntrip/ftp proxy address */ static unsigned int tick_master = 0; /* time tick master for replay */ static int fswapmargin = 30; /* file swap margin (s) */ /* open serial ---------------------------------------------------------------*/ serial_t *openserial(const char *path, int mode, char *msg) { const int br[] = { 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400}; serial_t *serial; int i; int brate = 9600; int bsize = 8; int stopb = 1; char *p; char parity = 'N'; char dev[128]; char port[128]; char fctr[64] = ""; const speed_t bs[] = { B300, B600, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400}; struct termios ios { }; int rw = 0; tracet(3, "openserial: path=%s mode=%d\n", path, mode); if (!(serial = static_cast(malloc(sizeof(serial_t))))) { return nullptr; } if ((p = strchr(const_cast(path), ':'))) { strncpy(port, path, p - path); port[p - path] = '\0'; sscanf(p, ":%d:%d:%c:%d:%s", &brate, &bsize, &parity, &stopb, fctr); } else if (strlen(path) < 128) { strcpy(port, path); } for (i = 0; i < 10; i++) { if (br[i] == brate) { break; } } if (i >= 11) { sprintf(msg, "bitrate error (%d)", brate); tracet(1, "openserial: %s path=%s\n", msg, path); free(serial); return nullptr; } parity = static_cast(toupper(static_cast(parity))); // sprintf(dev, "/dev/%s", port); This line triggers a warning. Replaced by: std::string s_aux = "/dev/" + std::string(port); s_aux.resize(128, '\0'); int n = s_aux.length(); for (int i = 0; i < n; i++) { dev[i] = s_aux[i]; } if (n == 0) { dev[0] = '\0'; } if ((mode & STR_MODE_R) && (mode & STR_MODE_W)) { rw = O_RDWR; } else if (mode & STR_MODE_R) { rw = O_RDONLY; } else if (mode & STR_MODE_W) { rw = O_WRONLY; } if ((serial->dev = open(dev, rw | O_NOCTTY | O_NONBLOCK)) < 0) { sprintf(msg, "device open error (%d)", errno); tracet(1, "openserial: %s dev=%s\n", msg, dev); free(serial); return nullptr; } tcgetattr(serial->dev, &ios); ios.c_iflag = 0; ios.c_oflag = 0; ios.c_lflag = 0; /* non-canonical */ ios.c_cc[VMIN] = 0; /* non-block-mode */ ios.c_cc[VTIME] = 0; cfsetospeed(&ios, bs[i]); cfsetispeed(&ios, bs[i]); ios.c_cflag |= bsize == 7 ? CS7 : CS8; ios.c_cflag |= parity == 'O' ? (PARENB | PARODD) : (parity == 'E' ? PARENB : 0); ios.c_cflag |= stopb == 2 ? CSTOPB : 0; ios.c_cflag |= !strcmp(fctr, "rts") ? CRTSCTS : 0; tcsetattr(serial->dev, TCSANOW, &ios); tcflush(serial->dev, TCIOFLUSH); return serial; } /* close serial --------------------------------------------------------------*/ void closeserial(serial_t *serial) { if (!serial) { return; } tracet(3, "closeserial: dev=%d\n", serial->dev); close(serial->dev); free(serial); } /* read serial ---------------------------------------------------------------*/ int readserial(serial_t *serial, unsigned char *buff, int n, char *msg __attribute__((unused))) { int nr; if (!serial) { return 0; } tracet(4, "readserial: dev=%d n=%d\n", serial->dev, n); if ((nr = read(serial->dev, buff, n)) < 0) { return 0; } tracet(5, "readserial: exit dev=%d nr=%d\n", serial->dev, nr); return nr; } /* write serial --------------------------------------------------------------*/ int writeserial(serial_t *serial, unsigned char *buff, int n, char *msg __attribute__((unused))) { int ns; if (!serial) { return 0; } tracet(3, "writeserial: dev=%d n=%d\n", serial->dev, n); if ((ns = write(serial->dev, buff, n)) < 0) { return 0; } tracet(5, "writeserial: exit dev=%d ns=%d\n", serial->dev, ns); return ns; } /* get state serial ----------------------------------------------------------*/ int stateserial(serial_t *serial) { return !serial ? 0 : (serial->error ? -1 : 2); } /* open file -----------------------------------------------------------------*/ int openfile_(file_t *file, gtime_t time, char *msg) { FILE *fp; char *rw; char tagpath[MAXSTRPATH + 4] = ""; char tagh[TIMETAGH_LEN + 1] = ""; tracet(3, "openfile_: path=%s time=%s\n", file->path, time_str(time, 0)); file->time = utc2gpst(timeget()); file->tick = file->tick_f = tickget(); file->fpos = 0; /* use stdin or stdout if file path is null */ if (!*file->path) { file->fp = file->mode & STR_MODE_R ? stdin : stdout; return 1; } /* replace keywords */ reppath(file->path, file->openpath, time, "", ""); /* create directory */ if ((file->mode & STR_MODE_W) && !(file->mode & STR_MODE_R)) { createdir(file->openpath); } if (file->mode & STR_MODE_R) { rw = (char *)"rb"; } else { rw = (char *)"wb"; } if (!(file->fp = fopen(file->openpath, rw))) { sprintf(msg, "file open error: %s", file->openpath); tracet(1, "openfile: %s\n", msg); return 0; } tracet(4, "openfile_: open file %s (%s)\n", file->openpath, rw); sprintf(tagpath, "%s.tag", file->openpath); if (file->timetag) { /* output/sync time-tag */ if (!(file->fp_tag = fopen(tagpath, rw))) { sprintf(msg, "tag open error: %s", tagpath); tracet(1, "openfile: %s\n", msg); fclose(file->fp); return 0; } tracet(4, "openfile_: open tag file %s (%s)\n", tagpath, rw); if (file->mode & STR_MODE_R) { if (fread(&tagh, TIMETAGH_LEN, 1, file->fp_tag) == 1 && fread(&file->time, sizeof(file->time), 1, file->fp_tag) == 1) { memcpy(&file->tick_f, tagh + TIMETAGH_LEN - 4, sizeof(file->tick_f)); } else { file->tick_f = 0; } /* adust time to read playback file */ timeset(file->time); } else { sprintf(tagh, "TIMETAG RTKLIB %s", VER_RTKLIB); memcpy(tagh + TIMETAGH_LEN - 4, &file->tick_f, sizeof(file->tick_f)); fwrite(&tagh, 1, TIMETAGH_LEN, file->fp_tag); fwrite(&file->time, 1, sizeof(file->time), file->fp_tag); /* time tag file structure */ /* HEADER(60)+TICK(4)+TIME(12)+ */ /* TICK0(4)+FPOS0(4/8)+ */ /* TICK1(4)+FPOS1(4/8)+... */ } } else if (file->mode & STR_MODE_W) { /* remove time-tag */ if ((fp = fopen(tagpath, "rbe"))) { fclose(fp); if (remove(tagpath) != 0) { trace(1, "Error removing file"); } } } return 1; } /* close file ----------------------------------------------------------------*/ void closefile_(file_t *file) { tracet(3, "closefile_: path=%s\n", file->path); if (file->fp) { fclose(file->fp); } if (file->fp_tag) { fclose(file->fp_tag); } if (file->fp_tmp) { fclose(file->fp_tmp); } if (file->fp_tag_tmp) { fclose(file->fp_tag_tmp); } file->fp = file->fp_tag = file->fp_tmp = file->fp_tag_tmp = nullptr; } /* open file (path=filepath[::T[::+][::x]][::S=swapintv]) --------*/ file_t *openfile(const char *path, int mode, char *msg) { file_t *file; gtime_t time; gtime_t time0 = {0, 0.0}; double speed = 0.0; double start = 0.0; double swapintv = 0.0; char *p; int timetag = 0; tracet(3, "openfile: path=%s mode=%d\n", path, mode); if (!(mode & (STR_MODE_R | STR_MODE_W))) { return nullptr; } /* file options */ for (p = const_cast(path); (p = strstr(p, "::")); p += 2) { /* file options */ if (*(p + 2) == 'T') { timetag = 1; } else if (*(p + 2) == '+') { sscanf(p + 2, "+%lf", &start); } else if (*(p + 2) == 'x') { sscanf(p + 2, "x%lf", &speed); } else if (*(p + 2) == 'S') { sscanf(p + 2, "S=%lf", &swapintv); } } if (start <= 0.0) { start = 0.0; } if (swapintv <= 0.0) { swapintv = 0.0; } if (!(file = static_cast(malloc(sizeof(file_t))))) { return nullptr; } file->fp = file->fp_tag = file->fp_tmp = file->fp_tag_tmp = nullptr; if (strlen(path) < MAXSTRPATH) { strcpy(file->path, path); } if ((p = strstr(file->path, "::"))) { *p = '\0'; } file->openpath[0] = '\0'; file->mode = mode; file->timetag = timetag; file->repmode = 0; file->offset = 0; file->time = file->wtime = time0; file->tick = file->tick_f = file->fpos = 0; file->start = start; file->speed = speed; file->swapintv = swapintv; initlock(&file->lock); time = utc2gpst(timeget()); /* open new file */ if (!openfile_(file, time, msg)) { free(file); return nullptr; } return file; } /* close file ----------------------------------------------------------------*/ void closefile(file_t *file) { if (!file) { return; } tracet(3, "closefile: fp=%d\n", file->fp); closefile_(file); free(file); } /* open new swap file --------------------------------------------------------*/ void swapfile(file_t *file, gtime_t time, char *msg) { char openpath[MAXSTRPATH]; tracet(3, "swapfile: fp=%d time=%s\n", file->fp, time_str(time, 0)); /* return if old swap file open */ if (file->fp_tmp || file->fp_tag_tmp) { return; } /* check path of new swap file */ reppath(file->path, openpath, time, "", ""); if (!strcmp(openpath, file->openpath)) { tracet(2, "swapfile: no need to swap %s\n", openpath); return; } /* save file pointer to temporary pointer */ file->fp_tmp = file->fp; file->fp_tag_tmp = file->fp_tag; /* open new swap file */ openfile_(file, time, msg); } /* close old swap file -------------------------------------------------------*/ void swapclose(file_t *file) { tracet(3, "swapclose: fp_tmp=%d\n", file->fp_tmp); if (file->fp_tmp) { fclose(file->fp_tmp); } if (file->fp_tag_tmp) { fclose(file->fp_tag_tmp); } file->fp_tmp = file->fp_tag_tmp = nullptr; } /* get state file ------------------------------------------------------------*/ int statefile(file_t *file) { return file ? 2 : 0; } /* read file -----------------------------------------------------------------*/ int readfile(file_t *file, unsigned char *buff, int nmax, char *msg) { struct timeval tv = {0, 0}; fd_set rs; unsigned int t; unsigned int tick; int nr = 0; size_t fpos; if (!file) { return 0; } tracet(4, "readfile: fp=%d nmax=%d\n", file->fp, nmax); if (file->fp == stdin) { /* input from stdin */ FD_ZERO(&rs); FD_SET(0, &rs); if (!select(1, &rs, nullptr, nullptr, &tv)) { return 0; } if ((nr = read(0, buff, nmax)) < 0) { return 0; } return nr; } if (file->fp_tag) { if (file->repmode) { /* slave */ t = (tick_master + file->offset); } else { /* master */ t = static_cast((tickget() - file->tick) * file->speed + file->start * 1000.0); } for (;;) { /* seek file position */ if (fread(&tick, sizeof(tick), 1, file->fp_tag) < 1 || fread(&fpos, sizeof(fpos), 1, file->fp_tag) < 1) { if (fseek(file->fp, 0, SEEK_END) != 0) { trace(1, "fseek error"); } sprintf(msg, "end"); break; } if (file->repmode || file->speed > 0.0) { if (static_cast(tick - t) < 1) { continue; } } if (!file->repmode) { tick_master = tick; } sprintf(msg, "T%+.1fs", static_cast(tick) < 0 ? 0.0 : static_cast(tick) / 1000.0); if (static_cast(fpos - file->fpos) >= nmax) { if (fseek(file->fp, fpos, SEEK_SET) != 0) { trace(1, "Error fseek"); } file->fpos = fpos; return 0; } nmax = static_cast(fpos - file->fpos); if (file->repmode || file->speed > 0.0) { if (fseek(file->fp_tag, -static_cast(sizeof(tick) + sizeof(fpos)), SEEK_CUR) != 0) { trace(1, "Error fseek"); } } break; } } if (nmax > 0) { nr = fread(buff, 1, nmax, file->fp); file->fpos += nr; if (nr <= 0) { sprintf(msg, "end"); } } tracet(5, "readfile: fp=%d nr=%d fpos=%d\n", file->fp, nr, file->fpos); return nr; } /* write file ----------------------------------------------------------------*/ int writefile(file_t *file, unsigned char *buff, int n, char *msg) { gtime_t wtime; unsigned int ns; unsigned int tick = tickget(); int week1; int week2; double tow1; double tow2; double intv; size_t fpos; size_t fpos_tmp; if (!file) { return 0; } tracet(3, "writefile: fp=%d n=%d\n", file->fp, n); wtime = utc2gpst(timeget()); /* write time in gpst */ /* swap writing file */ if (file->swapintv > 0.0 && file->wtime.time != 0) { intv = file->swapintv * 3600.0; tow1 = time2gpst(file->wtime, &week1); tow2 = time2gpst(wtime, &week2); tow2 += 604800.0 * (week2 - week1); /* open new swap file */ if (floor((tow1 + fswapmargin) / intv) < floor((tow2 + fswapmargin) / intv)) { swapfile(file, timeadd(wtime, fswapmargin), msg); } /* close old swap file */ if (floor((tow1 - fswapmargin) / intv) < floor((tow2 - fswapmargin) / intv)) { swapclose(file); } } if (!file->fp) { return 0; } ns = fwrite(buff, 1, n, file->fp); fpos = ftell(file->fp); fflush(file->fp); file->wtime = wtime; if (file->fp_tmp) { fwrite(buff, 1, n, file->fp_tmp); fpos_tmp = ftell(file->fp_tmp); fflush(file->fp_tmp); } if (file->fp_tag) { tick -= file->tick; fwrite(&tick, 1, sizeof(tick), file->fp_tag); fwrite(&fpos, 1, sizeof(fpos), file->fp_tag); fflush(file->fp_tag); if (file->fp_tag_tmp) { fwrite(&tick, 1, sizeof(tick), file->fp_tag_tmp); fwrite(&fpos_tmp, 1, sizeof(fpos_tmp), file->fp_tag_tmp); fflush(file->fp_tag_tmp); } } tracet(5, "writefile: fp=%d ns=%d tick=%5d fpos=%d\n", file->fp, ns, tick, fpos); return static_cast(ns); } /* sync files by time-tag ----------------------------------------------------*/ void syncfile(file_t *file1, file_t *file2) { if (!file1->fp_tag || !file2->fp_tag) { return; } file1->repmode = 0; file2->repmode = 1; file2->offset = static_cast(file1->tick_f - file2->tick_f); } /* decode tcp/ntrip path (path=[user[:passwd]@]addr[:port][/mntpnt[:str]]) ---*/ void decodetcppath(const char *path, char *addr, char *port, char *user, char *passwd, char *mntpnt, char *str) { char buff[MAXSTRPATH]; char *p; char *q; tracet(4, "decodetcpepath: path=%s\n", path); if (port) { *port = '\0'; } if (user) { *user = '\0'; } if (passwd) { *passwd = '\0'; } if (mntpnt) { *mntpnt = '\0'; } if (str) { *str = '\0'; } if (strlen(path) < MAXSTRPATH) { strcpy(buff, path); } if (!(p = strrchr(buff, '@'))) { p = buff; } if ((p = strchr(p, '/'))) { if ((q = strchr(p + 1, ':'))) { *q = '\0'; if (str) { strcpy(str, q + 1); } } *p = '\0'; if (mntpnt) { strcpy(mntpnt, p + 1); } } if ((p = strrchr(buff, '@'))) { *p++ = '\0'; if ((q = strchr(buff, ':'))) { *q = '\0'; if (passwd) { strcpy(passwd, q + 1); } } if (user) { strcpy(user, buff); } } else { p = buff; } if ((q = strchr(p, ':'))) { *q = '\0'; if (port) { strcpy(port, q + 1); } } if (addr) { strcpy(addr, p); } } /* get socket error ----------------------------------------------------------*/ int errsock(void) { return errno; } /* set socket option ---------------------------------------------------------*/ int setsock(socket_t sock, char *msg) { int bs = buffsize; int mode = 1; struct timeval tv = {0, 0}; tracet(3, "setsock: sock=%d\n", sock); if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&tv), sizeof(tv)) == -1 || setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast(&tv), sizeof(tv)) == -1) { sprintf(msg, "sockopt error: notimeo"); tracet(1, "setsock: setsockopt error 1 sock=%d err=%d\n", sock, errsock()); closesocket(sock); return 0; } if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&bs), sizeof(bs)) == -1 || setsockopt(sock, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&bs), sizeof(bs)) == -1) { tracet(1, "setsock: setsockopt error 2 sock=%d err=%d bs=%d\n", sock, errsock(), bs); sprintf(msg, "sockopt error: bufsiz"); } if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&mode), sizeof(mode)) == -1) { tracet(1, "setsock: setsockopt error 3 sock=%d err=%d\n", sock, errsock()); sprintf(msg, "sockopt error: nodelay"); } return 1; } /* non-block accept ----------------------------------------------------------*/ socket_t accept_nb(socket_t sock, struct sockaddr *addr, socklen_t *len) { struct timeval tv = {0, 0}; fd_set rs; FD_ZERO(&rs); FD_SET(sock, &rs); if (!select(sock + 1, &rs, nullptr, nullptr, &tv)) { return 0; } return accept(sock, addr, len); } /* non-block connect ---------------------------------------------------------*/ int connect_nb(socket_t sock, struct sockaddr *addr, socklen_t len) { struct timeval tv = {0, 0}; fd_set rs; fd_set ws; int err; int flag; flag = fcntl(sock, F_GETFL, 0); if (fcntl(sock, F_SETFL, flag | O_NONBLOCK) == -1) { trace(1, "fcntl error"); } if (connect(sock, addr, len) == -1) { err = errsock(); if (err != EISCONN && err != EINPROGRESS && err != EALREADY) { return -1; } FD_ZERO(&rs); FD_SET(sock, &rs); ws = rs; if (select(sock + 1, &rs, &ws, nullptr, &tv) == 0) { return 0; } } return 1; } /* non-block receive ---------------------------------------------------------*/ int recv_nb(socket_t sock, unsigned char *buff, int n) { struct timeval tv = {0, 0}; fd_set rs; FD_ZERO(&rs); FD_SET(sock, &rs); if (!select(sock + 1, &rs, nullptr, nullptr, &tv)) { return 0; } return recv(sock, reinterpret_cast(buff), n, 0); } /* non-block send ------------------------------------------------------------*/ int send_nb(socket_t sock, unsigned char *buff, int n) { struct timeval tv = {0, 0}; fd_set ws; FD_ZERO(&ws); FD_SET(sock, &ws); if (!select(sock + 1, nullptr, &ws, nullptr, &tv)) { return 0; } return send(sock, reinterpret_cast(buff), n, 0); } /* generate tcp socket -------------------------------------------------------*/ int gentcp(tcp_t *tcp, int type, char *msg) { struct hostent *hp; #ifdef SVR_REUSEADDR int opt = 1; #endif tracet(3, "gentcp: type=%d\n", type); /* generate socket */ if ((tcp->sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { sprintf(msg, "socket error (%d)", errsock()); tracet(1, "gentcp: socket error err=%d\n", errsock()); tcp->state = -1; return 0; } if (!setsock(tcp->sock, msg)) { tcp->state = -1; return 0; } memset(&tcp->addr, 0, sizeof(tcp->addr)); tcp->addr.sin_family = AF_INET; tcp->addr.sin_port = htons(tcp->port); if (type == 0) { /* server socket */ #ifdef SVR_REUSEADDR /* multiple-use of server socket */ setsockopt(tcp->sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); #endif if (bind(tcp->sock, reinterpret_cast(&tcp->addr), sizeof(tcp->addr)) == -1) { sprintf(msg, "bind error (%d) : %d", errsock(), tcp->port); tracet(1, "gentcp: bind error port=%d err=%d\n", tcp->port, errsock()); closesocket(tcp->sock); tcp->state = -1; return 0; } listen(tcp->sock, 5); } else { /* client socket */ if (!(hp = gethostbyname(tcp->saddr))) { sprintf(msg, "address error (%s)", tcp->saddr); tracet(1, "gentcp: gethostbyname error addr=%s err=%d\n", tcp->saddr, errsock()); closesocket(tcp->sock); tcp->state = 0; tcp->tcon = ticonnect; tcp->tdis = tickget(); return 0; } memcpy(&tcp->addr.sin_addr, hp->h_addr, hp->h_length); } tcp->state = 1; tcp->tact = tickget(); tracet(5, "gentcp: exit sock=%d\n", tcp->sock); return 1; } /* disconnect tcp ------------------------------------------------------------*/ void discontcp(tcp_t *tcp, int tcon) { tracet(3, "discontcp: sock=%d tcon=%d\n", tcp->sock, tcon); closesocket(tcp->sock); tcp->state = 0; tcp->tcon = tcon; tcp->tdis = tickget(); } /* open tcp server -----------------------------------------------------------*/ tcpsvr_t *opentcpsvr(const char *path, char *msg) { tcpsvr_t *tcpsvr; tcpsvr_t tcpsvr0{}; char port[256] = ""; tracet(3, "opentcpsvr: path=%s\n", path); if (!(tcpsvr = static_cast(malloc(sizeof(tcpsvr_t))))) { return nullptr; } *tcpsvr = tcpsvr0; decodetcppath(path, tcpsvr->svr.saddr, port, nullptr, nullptr, nullptr, nullptr); if (sscanf(port, "%d", &tcpsvr->svr.port) < 1) { sprintf(msg, "port error: %s", port); tracet(1, "opentcpsvr: port error port=%s\n", port); free(tcpsvr); return nullptr; } if (!gentcp(&tcpsvr->svr, 0, msg)) { free(tcpsvr); return nullptr; } tcpsvr->svr.tcon = 0; return tcpsvr; } /* close tcp server ----------------------------------------------------------*/ void closetcpsvr(tcpsvr_t *tcpsvr) { int i; tracet(3, "closetcpsvr:\n"); for (i = 0; i < MAXCLI; i++) { if (tcpsvr->cli[i].state) { closesocket(tcpsvr->cli[i].sock); } } closesocket(tcpsvr->svr.sock); free(tcpsvr); } /* update tcp server ---------------------------------------------------------*/ void updatetcpsvr(tcpsvr_t *tcpsvr, char *msg) { char saddr[256] = ""; int i; int j; int n = 0; tracet(3, "updatetcpsvr: state=%d\n", tcpsvr->svr.state); if (tcpsvr->svr.state == 0) { return; } for (i = 0; i < MAXCLI; i++) { if (tcpsvr->cli[i].state) { continue; } for (j = i + 1; j < MAXCLI; j++) { if (!tcpsvr->cli[j].state) { continue; } tcpsvr->cli[i] = tcpsvr->cli[j]; tcpsvr->cli[j].state = 0; break; } } for (i = 0; i < MAXCLI; i++) { if (!tcpsvr->cli[i].state) { continue; } strcpy(saddr, tcpsvr->cli[i].saddr); n++; } if (n == 0) { tcpsvr->svr.state = 1; sprintf(msg, "waiting..."); return; } tcpsvr->svr.state = 2; if (n == 1) { sprintf(msg, "%s", saddr); } else { sprintf(msg, "%d clients", n); } } /* accept client connection --------------------------------------------------*/ int accsock(tcpsvr_t *tcpsvr, char *msg) { struct sockaddr_in addr { }; socket_t sock; socklen_t len = sizeof(addr); int i; int err; tracet(3, "accsock: sock=%d\n", tcpsvr->svr.sock); for (i = 0; i < MAXCLI; i++) { if (tcpsvr->cli[i].state == 0) { break; } } if (i >= MAXCLI) { return 0; /* too many client */ } if ((sock = accept_nb(tcpsvr->svr.sock, reinterpret_cast(&addr), &len)) == -1) { err = errsock(); sprintf(msg, "accept error (%d)", err); tracet(1, "accsock: accept error sock=%d err=%d\n", tcpsvr->svr.sock, err); closesocket(tcpsvr->svr.sock); tcpsvr->svr.state = 0; return 0; } if (sock == 0) { return 0; } tcpsvr->cli[i].sock = sock; if (!setsock(tcpsvr->cli[i].sock, msg)) { return 0; } memcpy(&tcpsvr->cli[i].addr, &addr, sizeof(addr)); if (strlen(inet_ntoa(addr.sin_addr)) < 256) { strcpy(tcpsvr->cli[i].saddr, inet_ntoa(addr.sin_addr)); } sprintf(msg, "%s", tcpsvr->cli[i].saddr); tracet(2, "accsock: connected sock=%d addr=%s\n", tcpsvr->cli[i].sock, tcpsvr->cli[i].saddr); tcpsvr->cli[i].state = 2; tcpsvr->cli[i].tact = tickget(); return 1; } /* wait socket accept --------------------------------------------------------*/ int waittcpsvr(tcpsvr_t *tcpsvr, char *msg) { tracet(4, "waittcpsvr: sock=%d state=%d\n", tcpsvr->svr.sock, tcpsvr->svr.state); if (tcpsvr->svr.state <= 0) { return 0; } while (accsock(tcpsvr, msg)) { ; } updatetcpsvr(tcpsvr, msg); return tcpsvr->svr.state == 2; } /* read tcp server -----------------------------------------------------------*/ int readtcpsvr(tcpsvr_t *tcpsvr, unsigned char *buff, int n, char *msg) { int nr; int err; tracet(4, "readtcpsvr: state=%d n=%d\n", tcpsvr->svr.state, n); if (!waittcpsvr(tcpsvr, msg) || tcpsvr->cli[0].state != 2) { return 0; } if ((nr = recv_nb(tcpsvr->cli[0].sock, buff, n)) == -1) { err = errsock(); tracet(1, "readtcpsvr: recv error sock=%d err=%d\n", tcpsvr->cli[0].sock, err); sprintf(msg, "recv error (%d)", err); discontcp(&tcpsvr->cli[0], ticonnect); updatetcpsvr(tcpsvr, msg); return 0; } if (nr > 0) { tcpsvr->cli[0].tact = tickget(); } tracet(5, "readtcpsvr: exit sock=%d nr=%d\n", tcpsvr->cli[0].sock, nr); return nr; } /* write tcp server ----------------------------------------------------------*/ int writetcpsvr(tcpsvr_t *tcpsvr, unsigned char *buff, int n, char *msg) { int i; int ns = 0; int err; tracet(3, "writetcpsvr: state=%d n=%d\n", tcpsvr->svr.state, n); if (!waittcpsvr(tcpsvr, msg)) { return 0; } for (i = 0; i < MAXCLI; i++) { if (tcpsvr->cli[i].state != 2) { continue; } if ((ns = send_nb(tcpsvr->cli[i].sock, buff, n)) == -1) { err = errsock(); tracet(1, "writetcpsvr: send error i=%d sock=%d err=%d\n", i, tcpsvr->cli[i].sock, err); sprintf(msg, "send error (%d)", err); discontcp(&tcpsvr->cli[i], ticonnect); updatetcpsvr(tcpsvr, msg); return 0; } if (ns > 0) { tcpsvr->cli[i].tact = tickget(); } tracet(5, "writetcpsvr: send i=%d ns=%d\n", i, ns); } return ns; } /* get state tcp server ------------------------------------------------------*/ int statetcpsvr(tcpsvr_t *tcpsvr) { return tcpsvr ? tcpsvr->svr.state : 0; } /* connect server ------------------------------------------------------------*/ int consock(tcpcli_t *tcpcli, char *msg) { int stat; int err; tracet(3, "consock: sock=%d\n", tcpcli->svr.sock); /* wait re-connect */ if (tcpcli->svr.tcon < 0 || (tcpcli->svr.tcon > 0 && static_cast(tickget() - tcpcli->svr.tdis) < tcpcli->svr.tcon)) { return 0; } /* non-block connect */ if ((stat = connect_nb(tcpcli->svr.sock, reinterpret_cast(&tcpcli->svr.addr), sizeof(tcpcli->svr.addr))) == -1) { err = errsock(); sprintf(msg, "connect error (%d)", err); tracet(1, "consock: connect error sock=%d err=%d\n", tcpcli->svr.sock, err); closesocket(tcpcli->svr.sock); tcpcli->svr.state = 0; return 0; } if (!stat) { /* not connect */ sprintf(msg, "connecting..."); return 0; } sprintf(msg, "%s", tcpcli->svr.saddr); tracet(2, "consock: connected sock=%d addr=%s\n", tcpcli->svr.sock, tcpcli->svr.saddr); tcpcli->svr.state = 2; tcpcli->svr.tact = tickget(); return 1; } /* open tcp client -----------------------------------------------------------*/ tcpcli_t *opentcpcli(const char *path, char *msg) { tcpcli_t *tcpcli; tcpcli_t tcpcli0{}; char port[256] = ""; tracet(3, "opentcpcli: path=%s\n", path); if (!(tcpcli = static_cast(malloc(sizeof(tcpcli_t))))) { return nullptr; } *tcpcli = tcpcli0; decodetcppath(path, tcpcli->svr.saddr, port, nullptr, nullptr, nullptr, nullptr); if (sscanf(port, "%d", &tcpcli->svr.port) < 1) { sprintf(msg, "port error: %s", port); tracet(1, "opentcp: port error port=%s\n", port); free(tcpcli); return nullptr; } tcpcli->svr.tcon = 0; tcpcli->toinact = toinact; tcpcli->tirecon = ticonnect; return tcpcli; } /* close tcp client ----------------------------------------------------------*/ void closetcpcli(tcpcli_t *tcpcli) { tracet(3, "closetcpcli: sock=%d\n", tcpcli->svr.sock); closesocket(tcpcli->svr.sock); free(tcpcli); } /* wait socket connect -------------------------------------------------------*/ int waittcpcli(tcpcli_t *tcpcli, char *msg) { tracet(4, "waittcpcli: sock=%d state=%d\n", tcpcli->svr.sock, tcpcli->svr.state); if (tcpcli->svr.state < 0) { return 0; } if (tcpcli->svr.state == 0) { /* close */ if (!gentcp(&tcpcli->svr, 1, msg)) { return 0; } } if (tcpcli->svr.state == 1) { /* wait */ if (!consock(tcpcli, msg)) { return 0; } } if (tcpcli->svr.state == 2) { /* connect */ if (tcpcli->toinact > 0 && static_cast(tickget() - tcpcli->svr.tact) > tcpcli->toinact) { sprintf(msg, "timeout"); tracet(2, "waittcpcli: inactive timeout sock=%d\n", tcpcli->svr.sock); discontcp(&tcpcli->svr, tcpcli->tirecon); return 0; } } return 1; } /* read tcp client -----------------------------------------------------------*/ int readtcpcli(tcpcli_t *tcpcli, unsigned char *buff, int n, char *msg) { int nr; int err; tracet(4, "readtcpcli: sock=%d state=%d n=%d\n", tcpcli->svr.sock, tcpcli->svr.state, n); if (!waittcpcli(tcpcli, msg)) { return 0; } if ((nr = recv_nb(tcpcli->svr.sock, buff, n)) == -1) { err = errsock(); tracet(1, "readtcpcli: recv error sock=%d err=%d\n", tcpcli->svr.sock, err); sprintf(msg, "recv error (%d)", err); discontcp(&tcpcli->svr, tcpcli->tirecon); return 0; } if (nr > 0) { tcpcli->svr.tact = tickget(); } tracet(5, "readtcpcli: exit sock=%d nr=%d\n", tcpcli->svr.sock, nr); return nr; } /* write tcp client ----------------------------------------------------------*/ int writetcpcli(tcpcli_t *tcpcli, unsigned char *buff, int n, char *msg) { int ns; int err; tracet(3, "writetcpcli: sock=%d state=%d n=%d\n", tcpcli->svr.sock, tcpcli->svr.state, n); if (!waittcpcli(tcpcli, msg)) { return 0; } if ((ns = send_nb(tcpcli->svr.sock, buff, n)) == -1) { err = errsock(); tracet(1, "writetcp: send error sock=%d err=%d\n", tcpcli->svr.sock, err); sprintf(msg, "send error (%d)", err); discontcp(&tcpcli->svr, tcpcli->tirecon); return 0; } if (ns > 0) { tcpcli->svr.tact = tickget(); } tracet(5, "writetcpcli: exit sock=%d ns=%d\n", tcpcli->svr.sock, ns); return ns; } /* get state tcp client ------------------------------------------------------*/ int statetcpcli(tcpcli_t *tcpcli) { return tcpcli ? tcpcli->svr.state : 0; } /* base64 encoder ------------------------------------------------------------*/ int encbase64(char *str, const unsigned char *byte, int n) { const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int i; int j; int k; int b; tracet(4, "encbase64: n=%d\n", n); for (i = j = 0; i / 8 < n;) { for (k = b = 0; k < 6; k++, i++) { b <<= 1; if (i / 8 < n) { b |= (byte[i / 8] >> (7 - i % 8)) & 0x1; } } str[j++] = table[b]; } while (j & 0x3) { str[j++] = '='; } str[j] = '\0'; tracet(5, "encbase64: str=%s\n", str); return j; } /* send ntrip server request -------------------------------------------------*/ int reqntrip_s(ntrip_t *ntrip, char *msg) { char buff[256 + NTRIP_MAXSTR]; char *p = buff; tracet(3, "reqntrip_s: state=%d\n", ntrip->state); p += snprintf(p, 256 + NTRIP_MAXSTR, "SOURCE %s %s\r\n", ntrip->passwd, ntrip->mntpnt); p += sprintf(p, "Source-Agent: NTRIP %s\r\n", NTRIP_AGENT); p += sprintf(p, "STR: %s\r\n", ntrip->str); p += sprintf(p, "\r\n"); if (writetcpcli(ntrip->tcp, reinterpret_cast(buff), p - buff, msg) != p - buff) { return 0; } tracet(2, "reqntrip_s: send request state=%d ns=%d\n", ntrip->state, p - buff); tracet(5, "reqntrip_s: n=%d buff=\n%s\n", p - buff, buff); ntrip->state = 1; return 1; } /* send ntrip client request -------------------------------------------------*/ int reqntrip_c(ntrip_t *ntrip, char *msg) { char buff[1024]; char user[512]; char *p = buff; tracet(3, "reqntrip_c: state=%d\n", ntrip->state); p += sprintf(p, "GET %s/%s HTTP/1.0\r\n", ntrip->url, ntrip->mntpnt); p += sprintf(p, "User-Agent: NTRIP %s\r\n", NTRIP_AGENT); if (!*ntrip->user) { p += sprintf(p, "Accept: */*\r\n"); p += sprintf(p, "Connection: close\r\n"); } else { sprintf(user, "%s:%s", ntrip->user, ntrip->passwd); p += sprintf(p, "Authorization: Basic "); p += encbase64(p, reinterpret_cast(user), strlen(user)); p += sprintf(p, "\r\n"); } p += sprintf(p, "\r\n"); if (writetcpcli(ntrip->tcp, reinterpret_cast(buff), p - buff, msg) != p - buff) { return 0; } tracet(2, "reqntrip_c: send request state=%d ns=%d\n", ntrip->state, p - buff); tracet(5, "reqntrip_c: n=%d buff=\n%s\n", p - buff, buff); ntrip->state = 1; return 1; } /* test ntrip server response ------------------------------------------------*/ int rspntrip_s(ntrip_t *ntrip, char *msg) { int i; int nb; char *p; char *q; tracet(3, "rspntrip_s: state=%d nb=%d\n", ntrip->state, ntrip->nb); ntrip->buff[ntrip->nb] = '0'; tracet(5, "rspntrip_s: n=%d buff=\n%s\n", ntrip->nb, ntrip->buff); if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_OK_SVR))) { /* ok */ q = reinterpret_cast(ntrip->buff); p += strlen(NTRIP_RSP_OK_SVR); ntrip->nb -= p - q; for (i = 0; i < ntrip->nb; i++) { *q++ = *p++; } ntrip->state = 2; sprintf(msg, "%s/%s", ntrip->tcp->svr.saddr, ntrip->mntpnt); tracet(2, "rspntrip_s: response ok nb=%d\n", ntrip->nb); return 1; } if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_ERROR))) { /* error */ nb = ntrip->nb < MAXSTATMSG ? ntrip->nb : MAXSTATMSG; // strncpy(msg, (char *)ntrip->buff, nb); This line triggers a warning. Replaced by; std::string s_aux(reinterpret_cast(ntrip->buff)); s_aux.resize(nb, '\0'); for (int i = 0; i < nb; i++) { msg[i] = s_aux[i]; } msg[nb] = 0; tracet(1, "rspntrip_s: %s nb=%d\n", msg, ntrip->nb); ntrip->nb = 0; ntrip->buff[0] = '\0'; ntrip->state = 0; discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); } else if (ntrip->nb >= NTRIP_MAXRSP) { /* buffer overflow */ sprintf(msg, "response overflow"); tracet(1, "rspntrip_s: response overflow nb=%d\n", ntrip->nb); ntrip->nb = 0; ntrip->buff[0] = '\0'; ntrip->state = 0; discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); } tracet(5, "rspntrip_s: exit state=%d nb=%d\n", ntrip->state, ntrip->nb); return 0; } /* test ntrip client response ------------------------------------------------*/ int rspntrip_c(ntrip_t *ntrip, char *msg) { int i; char *p; char *q; tracet(3, "rspntrip_c: state=%d nb=%d\n", ntrip->state, ntrip->nb); ntrip->buff[ntrip->nb] = '0'; tracet(5, "rspntrip_c: n=%d buff=\n%s\n", ntrip->nb, ntrip->buff); if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_OK_CLI))) { /* ok */ q = reinterpret_cast(ntrip->buff); p += strlen(NTRIP_RSP_OK_CLI); ntrip->nb -= p - q; for (i = 0; i < ntrip->nb; i++) { *q++ = *p++; } ntrip->state = 2; sprintf(msg, "%s/%s", ntrip->tcp->svr.saddr, ntrip->mntpnt); tracet(2, "rspntrip_c: response ok nb=%d\n", ntrip->nb); return 1; } if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_SRCTBL))) { /* source table */ if (!*ntrip->mntpnt) { /* source table request */ ntrip->state = 2; sprintf(msg, "source table received"); tracet(2, "rspntrip_c: receive source table nb=%d\n", ntrip->nb); return 1; } sprintf(msg, "no mountp. reconnect..."); tracet(2, "rspntrip_c: no mount point nb=%d\n", ntrip->nb); ntrip->nb = 0; ntrip->buff[0] = '\0'; ntrip->state = 0; discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); } else if ((p = strstr(reinterpret_cast(ntrip->buff), NTRIP_RSP_HTTP))) { /* http response */ if ((q = strchr(p, '\r'))) { *q = '\0'; } else { ntrip->buff[128] = '\0'; } strcpy(msg, p); tracet(1, "rspntrip_s: %s nb=%d\n", msg, ntrip->nb); ntrip->nb = 0; ntrip->buff[0] = '\0'; ntrip->state = 0; discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); } else if (ntrip->nb >= NTRIP_MAXRSP) { /* buffer overflow */ sprintf(msg, "response overflow"); tracet(1, "rspntrip_s: response overflow nb=%d\n", ntrip->nb); ntrip->nb = 0; ntrip->buff[0] = '\0'; ntrip->state = 0; discontcp(&ntrip->tcp->svr, ntrip->tcp->tirecon); } tracet(5, "rspntrip_c: exit state=%d nb=%d\n", ntrip->state, ntrip->nb); return 0; } /* wait ntrip request/response -----------------------------------------------*/ int waitntrip(ntrip_t *ntrip, char *msg) { int n; char *p; tracet(4, "waitntrip: state=%d nb=%d\n", ntrip->state, ntrip->nb); if (ntrip->state < 0) { return 0; /* error */ } if (ntrip->tcp->svr.state < 2) { ntrip->state = 0; /* tcp disconnected */ } if (ntrip->state == 0) { /* send request */ if (!(ntrip->type == 0 ? reqntrip_s(ntrip, msg) : reqntrip_c(ntrip, msg))) { return 0; } tracet(2, "waitntrip: state=%d nb=%d\n", ntrip->state, ntrip->nb); } if (ntrip->state == 1) { /* read response */ p = reinterpret_cast(ntrip->buff) + ntrip->nb; if ((n = readtcpcli(ntrip->tcp, reinterpret_cast(p), NTRIP_MAXRSP - ntrip->nb - 1, msg)) == 0) { tracet(5, "waitntrip: readtcp n=%d\n", n); return 0; } ntrip->nb += n; ntrip->buff[ntrip->nb] = '\0'; /* wait response */ return ntrip->type == 0 ? rspntrip_s(ntrip, msg) : rspntrip_c(ntrip, msg); } return 1; } /* open ntrip ----------------------------------------------------------------*/ ntrip_t *openntrip(const char *path, int type, char *msg) { ntrip_t *ntrip; int i; char addr[256] = ""; char port[256] = ""; char tpath[MAXSTRPATH]; tracet(3, "openntrip: path=%s type=%d\n", path, type); if (!(ntrip = static_cast(malloc(sizeof(ntrip_t))))) { return nullptr; } ntrip->state = 0; ntrip->type = type; /* 0:server, 1:client */ ntrip->nb = 0; ntrip->url[0] = '\0'; ntrip->mntpnt[0] = ntrip->user[0] = ntrip->passwd[0] = ntrip->str[0] = '\0'; for (i = 0; i < NTRIP_MAXRSP; i++) { ntrip->buff[i] = 0; } /* decode tcp/ntrip path */ decodetcppath(path, addr, port, ntrip->user, ntrip->passwd, ntrip->mntpnt, ntrip->str); /* use default port if no port specified */ if (!*port) { sprintf(port, "%d", type ? NTRIP_CLI_PORT : NTRIP_SVR_PORT); } sprintf(tpath, "%s:%s", addr, port); /* ntrip access via proxy server */ if (*proxyaddr) { // sprintf(ntrip->url, "http://%s", tpath); This line triggers a warning. Replaced by: std::string s_aux = "http://" + std::string(tpath); int n = s_aux.length(); if (n < 256) { for (int k = 0; k < n; k++) { ntrip->url[k] = s_aux[k]; } } strcpy(tpath, proxyaddr); } /* open tcp client stream */ if (!(ntrip->tcp = opentcpcli(tpath, msg))) { tracet(1, "openntrip: opentcp error\n"); free(ntrip); return nullptr; } return ntrip; } /* close ntrip ---------------------------------------------------------------*/ void closentrip(ntrip_t *ntrip) { tracet(3, "closentrip: state=%d\n", ntrip->state); closetcpcli(ntrip->tcp); free(ntrip); } /* read ntrip ----------------------------------------------------------------*/ int readntrip(ntrip_t *ntrip, unsigned char *buff, int n, char *msg) { int nb; tracet(4, "readntrip: n=%d\n", n); if (!waitntrip(ntrip, msg)) { return 0; } if (ntrip->nb > 0) { /* read response buffer first */ nb = ntrip->nb <= n ? ntrip->nb : n; memcpy(buff, ntrip->buff + ntrip->nb - nb, nb); ntrip->nb = 0; return nb; } return readtcpcli(ntrip->tcp, buff, n, msg); } /* write ntrip ---------------------------------------------------------------*/ int writentrip(ntrip_t *ntrip, unsigned char *buff, int n, char *msg) { tracet(3, "writentrip: n=%d\n", n); if (!waitntrip(ntrip, msg)) { return 0; } return writetcpcli(ntrip->tcp, buff, n, msg); } /* get state ntrip -----------------------------------------------------------*/ int statentrip(ntrip_t *ntrip) { return !ntrip ? 0 : (ntrip->state == 0 ? ntrip->tcp->svr.state : ntrip->state); } /* decode ftp path ----------------------------------------------------------*/ void decodeftppath(const char *path, char *addr, char *file, char *user, char *passwd, int *topts) { char buff[MAXSTRPATH]; char *p; char *q; tracet(4, "decodeftpath: path=%s\n", path); if (user) { *user = '\0'; } if (passwd) { *passwd = '\0'; } if (topts) { topts[0] = 0; /* time offset in path (s) */ topts[1] = 3600; /* download interval (s) */ topts[2] = 0; /* download time offset (s) */ topts[3] = 0; /* retry interval (s) (0: no retry) */ } if (strlen(path) < MAXSTRPATH) { strcpy(buff, path); } if ((p = strchr(buff, '/'))) { if ((q = strstr(p + 1, "::"))) { *q = '\0'; if (topts) { sscanf(q + 2, "T=%d, %d, %d, %d", topts, topts + 1, topts + 2, topts + 3); } } strcpy(file, p + 1); *p = '\0'; } else { file[0] = '\0'; } if ((p = strrchr(buff, '@'))) { *p++ = '\0'; if ((q = strchr(buff, ':'))) { *q = '\0'; if (passwd) { strcpy(passwd, q + 1); } } if (user) { strcpy(user, buff); } } else { p = buff; } strcpy(addr, p); } /* next download time --------------------------------------------------------*/ gtime_t nextdltime(const int *topts, int stat) { gtime_t time; double tow; int week; int tint; tracet(3, "nextdltime: topts=%d %d %d %d stat=%d\n", topts[0], topts[1], topts[2], topts[3], stat); /* current time (gpst) */ time = utc2gpst(timeget()); tow = time2gpst(time, &week); /* next retry time */ if (stat == 0 && topts[3] > 0) { tow = (floor((tow - topts[2]) / topts[3]) + 1.0) * topts[3] + topts[2]; return gpst2time(week, tow); } /* next interval time */ tint = topts[1] <= 0 ? 3600 : topts[1]; tow = (floor((tow - topts[2]) / tint) + 1.0) * tint + topts[2]; time = gpst2time(week, tow); return time; } /* ftp thread ----------------------------------------------------------------*/ void *ftpthread(void *arg) { auto *ftp = static_cast(arg); FILE *fp; gtime_t time; char remote[1024]; char local[1024]; char tmpfile[1024]; char errfile[1024]; char *p; char cmd[2048]; char env[1024] = ""; char opt[1024]; char *proxyopt = (char *)""; char *proto; int ret; tracet(3, "ftpthread:\n"); if (!*localdir) { tracet(1, "no local directory\n"); ftp->error = 11; ftp->state = 3; return nullptr; } /* replace keyword in file path and local path */ time = timeadd(utc2gpst(timeget()), ftp->topts[0]); reppath(ftp->file, remote, time, "", ""); if ((p = strrchr(remote, '/'))) { p++; } else { p = remote; } // sprintf(local, "%s%c%s", localdir, FILEPATHSEP, p); This line triggers a warning. Replaced by: std::string s_aux = std::string(localdir) + std::to_string(FILEPATHSEP) + std::string(p); int n = s_aux.length(); if (n < 1024) { for (int i = 0; i < n; i++) { local[i] = s_aux[i]; } } // sprintf(errfile, "%s.err", local); This line triggers a warning. Replaced by: std::string s_aux2 = std::string(local) + ".err"; n = s_aux2.length(); if (n < 1024) { for (int i = 0; i < n; i++) { errfile[i] = s_aux2[i]; } } /* if local file exist, skip download */ strcpy(tmpfile, local); if ((p = strrchr(tmpfile, '.')) && (!strcmp(p, ".z") || !strcmp(p, ".gz") || !strcmp(p, ".zip") || !strcmp(p, ".Z") || !strcmp(p, ".GZ") || !strcmp(p, ".ZIP"))) { *p = '\0'; } if ((fp = fopen(tmpfile, "rbe"))) { fclose(fp); strcpy(ftp->local, tmpfile); tracet(3, "ftpthread: file exists %s\n", ftp->local); ftp->state = 2; return nullptr; } /* proxy settings for wget (ref [2]) */ if (*proxyaddr) { proto = ftp->proto ? (char *)"http" : (char *)"ftp"; sprintf(env, "set %s_proxy=http://%s & ", proto, proxyaddr); proxyopt = (char *)"--proxy=on "; } /* download command (ref [2]) */ if (ftp->proto == 0) { /* ftp */ // sprintf(opt, "--ftp-user=%s --ftp-password=%s --glob=off --passive-ftp %s-t 1 -T %d -O \"%s\"", // ftp->user, ftp->passwd, proxyopt, FTP_TIMEOUT, local); This line triggers a warning. Replaced by: std::string s_aux = "--ftp-user=" + std::string(ftp->user) + " --ftp-password=" + std::string(ftp->passwd) + " --glob=off --passive-ftp " + std::string(proxyopt) + "s-t 1 -T " + std::to_string(FTP_TIMEOUT) + " -O \"" + std::string(local) + "\""; int k = s_aux.length(); if (k < 1024) { for (int i = 0; i < k; i++) { opt[i] = s_aux[i]; } } // sprintf(cmd, "%s%s %s \"ftp://%s/%s\" 2> \"%s\"\n", env, FTP_CMD, opt, ftp->addr, // remote, errfile); This line triggers a warning. Replaced by: std::string s_aux2 = std::string(env) + std::string(FTP_CMD) + " " + std::string(opt) + " " + "\"ftp://" + std::string(ftp->addr) + "/" + std::string(remote) + "\" 2> \"" + std::string(errfile) + "\"\n"; k = s_aux2.length(); for (int i = 0; (i < k) && (i < 1024); i++) { cmd[i] = s_aux2[i]; } } else { /* http */ // sprintf(opt, "%s-t 1 -T %d -O \"%s\"", proxyopt, FTP_TIMEOUT, local); This line triggers a warning. Replaced by: std::string s_aux = std::string(proxyopt) + " -t 1 -T " + std::to_string(FTP_TIMEOUT) + " -O \"" + std::string(local) + "\""; int l = s_aux.length(); for (int i = 0; (i < l) && (i < 1024); i++) { opt[i] = s_aux[i]; } // sprintf(cmd, "%s%s %s \"http://%s/%s\" 2> \"%s\"\n", env, FTP_CMD, opt, ftp->addr, // remote, errfile); This line triggers a warning. Replaced by: std::string s_aux2 = std::string(env) + std::string(FTP_CMD) + " " + std::string(opt) + " " + "\"http://" + std::string(ftp->addr) + "/" + std::string(remote) + "\" 2> \"" + std::string(errfile) + "\"\n"; l = s_aux2.length(); for (int i = 0; (i < l) && (i < 1024); i++) { cmd[i] = s_aux2[i]; } } /* execute download command */ if ((ret = execcmd(cmd))) { if (remove(local) != 0) { trace(1, "Error removing file"); } tracet(1, "execcmd error: cmd=%s ret=%d\n", cmd, ret); ftp->error = ret; ftp->state = 3; return nullptr; } if (remove(errfile) != 0) { trace(1, "Error removing file"); } /* uncompress downloaded file */ if ((p = strrchr(local, '.')) && (!strcmp(p, ".z") || !strcmp(p, ".gz") || !strcmp(p, ".zip") || !strcmp(p, ".Z") || !strcmp(p, ".GZ") || !strcmp(p, ".ZIP"))) { if (rtk_uncompress(local, tmpfile)) { if (remove(local) != 0) { trace(1, "Error removing file"); } if (strlen(tmpfile) < 1024) { strcpy(local, tmpfile); } } else { tracet(1, "file uncompact error: %s\n", local); ftp->error = 12; ftp->state = 3; return nullptr; } } if (strlen(local) < 1024) { strcpy(ftp->local, local); } ftp->state = 2; /* ftp completed */ tracet(3, "ftpthread: complete cmd=%s\n", cmd); return nullptr; } /* open ftp ------------------------------------------------------------------*/ ftp_t *openftp(const char *path, int type, char *msg) { ftp_t *ftp; tracet(3, "openftp: path=%s type=%d\n", path, type); msg[0] = '\0'; if (!(ftp = static_cast(malloc(sizeof(ftp_t))))) { return nullptr; } ftp->state = 0; ftp->proto = type; ftp->error = 0; ftp->thread = 0; // NOLINT ftp->local[0] = '\0'; /* decode ftp path */ decodeftppath(path, ftp->addr, ftp->file, ftp->user, ftp->passwd, ftp->topts); /* set first download time */ ftp->tnext = timeadd(timeget(), 10.0); return ftp; } /* close ftp -----------------------------------------------------------------*/ void closeftp(ftp_t *ftp) { tracet(3, "closeftp: state=%d\n", ftp->state); if (ftp->state != 1) { free(ftp); } } /* read ftp ------------------------------------------------------------------*/ int readftp(ftp_t *ftp, unsigned char *buff, int n, char *msg) { gtime_t time; unsigned char *p; unsigned char *q; tracet(4, "readftp: n=%d\n", n); time = utc2gpst(timeget()); if (timediff(time, ftp->tnext) < 0.0) { /* until download time? */ return 0; } if (ftp->state <= 0) { /* ftp/http not executed? */ ftp->state = 1; sprintf(msg, "%s://%s", ftp->proto ? "http" : "ftp", ftp->addr); if (pthread_create(&ftp->thread, nullptr, ftpthread, ftp)) { tracet(1, "readftp: ftp thread create error\n"); ftp->state = 3; strcpy(msg, "ftp thread error"); return 0; } } if (ftp->state <= 1) { return 0; /* ftp/http on going? */ } if (ftp->state == 3) { /* ftp error */ sprintf(msg, "%s error (%d)", ftp->proto ? "http" : "ftp", ftp->error); /* set next retry time */ ftp->tnext = nextdltime(ftp->topts, 0); ftp->state = 0; return 0; } /* return local file path if ftp completed */ p = buff; q = reinterpret_cast(ftp->local); while (*q && static_cast(p - buff) < n) { *p++ = *q++; } p += sprintf(reinterpret_cast(p), "\r\n"); /* set next download time */ ftp->tnext = nextdltime(ftp->topts, 1); ftp->state = 0; strcpy(msg, ""); return static_cast(p - buff); } /* get state ftp -------------------------------------------------------------*/ int stateftp(ftp_t *ftp) { return !ftp ? 0 : (ftp->state == 0 ? 2 : (ftp->state <= 2 ? 3 : -1)); } /* initialize stream environment ----------------------------------------------- * initialize stream environment * args : none * return : none *-----------------------------------------------------------------------------*/ void strinitcom(void) { tracet(3, "strinitcom:\n"); } /* initialize stream ----------------------------------------------------------- * initialize stream struct * args : stream_t *stream IO stream * return : none *-----------------------------------------------------------------------------*/ void strinit(stream_t *stream) { tracet(3, "strinit:\n"); stream->type = 0; stream->mode = 0; stream->state = 0; stream->inb = stream->inr = stream->outb = stream->outr = 0; stream->tick = stream->tact = stream->inbt = stream->outbt = 0; initlock(&stream->lock); stream->port = nullptr; stream->path[0] = '\0'; stream->msg[0] = '\0'; } /* open stream ----------------------------------------------------------------- * open stream for read or write * args : stream_t *stream IO stream * int type I stream type (STR_SERIAL, STR_FILE, STR_TCPSVR, ...) * int mode I stream mode (STR_MODE_???) * char *path I stream path (see below) * return : status (0:error, 1:ok) * notes : see reference [1] for NTRIP * STR_FTP/HTTP needs "wget" in command search paths * * stream path ([] options): * * STR_SERIAL port[:brate[:bsize[:parity[:stopb[:fctr]]]]] * port = COM?? (windows), tty??? (linuex, omit /dev/) * brate = bit rate (bps) * bsize = bit size (7|8) * parity= parity (n|o|e) * stopb = stop bits (1|2) * fctr = flow control (off|rts) * STR_FILE file_path[::T][::+start][::xseppd][::S=swap] * ::T = enable time tag * start = replay start offset (s) * speed = replay speed factor * swap = output swap interval (hr) (0: no swap) * STR_TCPSVR :port * STR_TCPCLI address:port * STR_NTRIPSVR user[:passwd]@address[:port]/moutpoint[:string] * STR_NTRIPCLI [user[:passwd]]@address[:port][/mountpoint] * STR_FTP [user[:passwd]]@address/file_path[::T=poff[, tint[, toff, tret]]]] * STR_HTTP address/file_path[::T=poff[, tint[, toff, tret]]]] * poff = time offset for path extension (s) * tint = download interval (s) * toff = download time offset (s) * tret = download retry interval (s) (0:no retry) *-----------------------------------------------------------------------------*/ int stropen(stream_t *stream, int type, int mode, const char *path) { tracet(3, "stropen: type=%d mode=%d path=%s\n", type, mode, path); stream->type = type; stream->mode = mode; if (strlen(path) < MAXSTRPATH) { strcpy(stream->path, path); } stream->inb = stream->inr = stream->outb = stream->outr = 0; stream->tick = tickget(); stream->inbt = stream->outbt = 0; stream->msg[0] = '\0'; stream->port = nullptr; switch (type) { case STR_SERIAL: stream->port = openserial(path, mode, stream->msg); break; case STR_FILE: stream->port = openfile(path, mode, stream->msg); break; case STR_TCPSVR: stream->port = opentcpsvr(path, stream->msg); break; case STR_TCPCLI: stream->port = opentcpcli(path, stream->msg); break; case STR_NTRIPSVR: stream->port = openntrip(path, 0, stream->msg); break; case STR_NTRIPCLI: stream->port = openntrip(path, 1, stream->msg); break; case STR_FTP: stream->port = openftp(path, 0, stream->msg); break; case STR_HTTP: stream->port = openftp(path, 1, stream->msg); break; default: stream->state = 0; return 1; } stream->state = !stream->port ? -1 : 1; return stream->port != nullptr; } /* close stream ---------------------------------------------------------------- * close stream * args : stream_t *stream IO stream * return : none *-----------------------------------------------------------------------------*/ void strclose(stream_t *stream) { tracet(3, "strclose: type=%d mode=%d\n", stream->type, stream->mode); if (stream->port) { switch (stream->type) { case STR_SERIAL: closeserial(static_cast(stream->port)); break; case STR_FILE: closefile(static_cast(stream->port)); break; case STR_TCPSVR: closetcpsvr(static_cast(stream->port)); break; case STR_TCPCLI: closetcpcli(static_cast(stream->port)); break; case STR_NTRIPSVR: closentrip(static_cast(stream->port)); break; case STR_NTRIPCLI: closentrip(static_cast(stream->port)); break; case STR_FTP: closeftp(static_cast(stream->port)); break; case STR_HTTP: closeftp(static_cast(stream->port)); break; } } else { trace(2, "no port to close stream: type=%d\n", stream->type); } stream->type = 0; stream->mode = 0; stream->state = 0; stream->inr = stream->outr = 0; stream->path[0] = '\0'; stream->msg[0] = '\0'; stream->port = nullptr; } /* sync streams ---------------------------------------------------------------- * sync time for streams * args : stream_t *stream1 IO stream 1 * stream_t *stream2 IO stream 2 * return : none * notes : for replay files with time tags *-----------------------------------------------------------------------------*/ void strsync(stream_t *stream1, stream_t *stream2) { file_t *file1; file_t *file2; if (stream1->type != STR_FILE || stream2->type != STR_FILE) { return; } file1 = static_cast(stream1->port); file2 = static_cast(stream2->port); if (file1 && file2) { syncfile(file1, file2); } } /* lock/unlock stream ---------------------------------------------------------- * lock/unlock stream * args : stream_t *stream I stream * return : none *-----------------------------------------------------------------------------*/ void strlock(stream_t *stream) { rtk_lock(&stream->lock); } void strunlock(stream_t *stream) { rtk_unlock(&stream->lock); } /* read stream ----------------------------------------------------------------- * read data from stream (unblocked) * args : stream_t *stream I stream * unsigned char *buff O data buffer * int n I maximum data length * return : read data length * notes : if no data, return immediately with no data *-----------------------------------------------------------------------------*/ int strread(stream_t *stream, unsigned char *buff, int n) { unsigned int tick; char *msg = stream->msg; int nr; tracet(4, "strread: n=%d\n", n); if (!(stream->mode & STR_MODE_R) || !stream->port) { return 0; } strlock(stream); switch (stream->type) { case STR_SERIAL: nr = readserial(static_cast(stream->port), buff, n, msg); break; case STR_FILE: nr = readfile(static_cast(stream->port), buff, n, msg); break; case STR_TCPSVR: nr = readtcpsvr(static_cast(stream->port), buff, n, msg); break; case STR_TCPCLI: nr = readtcpcli(static_cast(stream->port), buff, n, msg); break; case STR_NTRIPCLI: nr = readntrip(static_cast(stream->port), buff, n, msg); break; case STR_FTP: nr = readftp(static_cast(stream->port), buff, n, msg); break; case STR_HTTP: nr = readftp(static_cast(stream->port), buff, n, msg); break; default: strunlock(stream); return 0; } stream->inb += nr; tick = tickget(); if (nr > 0) { stream->tact = tick; } if (static_cast(tick - stream->tick) >= tirate) { stream->inr = (stream->inb - stream->inbt) * 8000 / (tick - stream->tick); stream->tick = tick; stream->inbt = stream->inb; } strunlock(stream); return nr; } /* write stream ---------------------------------------------------------------- * write data to stream (unblocked) * args : stream_t *stream I stream * unsigned char *buff I data buffer * int n I data length * return : status (0:error, 1:ok) * notes : write data to buffer and return immediately *-----------------------------------------------------------------------------*/ int strwrite(stream_t *stream, unsigned char *buff, int n) { unsigned int tick; char *msg = stream->msg; int ns; tracet(3, "strwrite: n=%d\n", n); if (!(stream->mode & STR_MODE_W) || !stream->port) { return 0; } strlock(stream); switch (stream->type) { case STR_SERIAL: ns = writeserial(static_cast(stream->port), buff, n, msg); break; case STR_FILE: ns = writefile(static_cast(stream->port), buff, n, msg); break; case STR_TCPSVR: ns = writetcpsvr(static_cast(stream->port), buff, n, msg); break; case STR_TCPCLI: ns = writetcpcli(static_cast(stream->port), buff, n, msg); break; case STR_NTRIPCLI: case STR_NTRIPSVR: ns = writentrip(static_cast(stream->port), buff, n, msg); break; case STR_FTP: case STR_HTTP: default: strunlock(stream); return 0; } stream->outb += ns; tick = tickget(); if (ns > 0) { stream->tact = tick; } if (static_cast(tick - stream->tick) > tirate) { stream->outr = (stream->outb - stream->outbt) * 8000 / (tick - stream->tick); stream->tick = tick; stream->outbt = stream->outb; } strunlock(stream); return ns; } /* get stream status ----------------------------------------------------------- * get stream status * args : stream_t *stream I stream * char *msg IO status message (NULL: no output) * return : status (-1:error, 0:close, 1:wait, 2:connect, 3:active) *-----------------------------------------------------------------------------*/ int strstat(stream_t *stream, char *msg) { int state; tracet(4, "strstat:\n"); strlock(stream); if (msg) { // strncpy(msg, stream->msg, MAXSTRMSG - 1); This line triggers a warning. Replaced by: std::string aux_s(stream->msg); aux_s.resize(MAXSTRMSG - 1, '0'); for (int i = 0; i < MAXSTRMSG - 1; i++) { msg[i] = aux_s[i]; } msg[MAXSTRMSG - 1] = '\0'; } if (!stream->port) { strunlock(stream); return stream->state; } switch (stream->type) { case STR_SERIAL: state = stateserial(static_cast(stream->port)); break; case STR_FILE: state = statefile(static_cast(stream->port)); break; case STR_TCPSVR: state = statetcpsvr(static_cast(stream->port)); break; case STR_TCPCLI: state = statetcpcli(static_cast(stream->port)); break; case STR_NTRIPSVR: case STR_NTRIPCLI: state = statentrip(static_cast(stream->port)); break; case STR_FTP: state = stateftp(static_cast(stream->port)); break; case STR_HTTP: state = stateftp(static_cast(stream->port)); break; default: strunlock(stream); return 0; } if (state == 2 && static_cast(tickget() - stream->tact) <= TINTACT) { state = 3; } strunlock(stream); return state; } /* get stream statistics summary ----------------------------------------------- * get stream statistics summary * args : stream_t *stream I stream * int *inb IO bytes of input (NULL: no output) * int *inr IO bps of input (NULL: no output) * int *outb IO bytes of output (NULL: no output) * int *outr IO bps of output (NULL: no output) * return : none *-----------------------------------------------------------------------------*/ void strsum(stream_t *stream, int *inb, int *inr, int *outb, int *outr) { tracet(4, "strsum:\n"); strlock(stream); if (inb) { *inb = stream->inb; } if (inr) { *inr = stream->inr; } if (outb) { *outb = stream->outb; } if (outr) { *outr = stream->outr; } strunlock(stream); } /* set global stream options --------------------------------------------------- * set global stream options * args : int *opt I options * opt[0]= inactive timeout (ms) (0: no timeout) * opt[1]= interval to reconnect (ms) * opt[2]= averaging time of data rate (ms) * opt[3]= receive/send buffer size (bytes); * opt[4]= file swap margin (s) * opt[5]= reserved * opt[6]= reserved * opt[7]= reserved * return : none *-----------------------------------------------------------------------------*/ void strsetopt(const int *opt) { tracet(3, "strsetopt: opt=%d %d %d %d %d %d %d %d\n", opt[0], opt[1], opt[2], opt[3], opt[4], opt[5], opt[6], opt[7]); toinact = 0 < opt[0] && opt[0] < 1000 ? 1000 : opt[0]; /* >=1s */ ticonnect = opt[1] < 1000 ? 1000 : opt[1]; /* >=1s */ tirate = opt[2] < 100 ? 100 : opt[2]; /* >=0.1s */ buffsize = opt[3] < 4096 ? 4096 : opt[3]; /* >=4096byte */ fswapmargin = opt[4] < 0 ? 0 : opt[4]; } /* set timeout time ------------------------------------------------------------ * set timeout time * args : stream_t *stream I stream (STR_TCPCLI, STR_NTRIPCLI, STR_NTRIPSVR) * int toinact I inactive timeout (ms) (0: no timeout) * int tirecon I reconnect interval (ms) (0: no reconnect) * return : none *-----------------------------------------------------------------------------*/ void strsettimeout(stream_t *stream, int toinact, int tirecon) { tcpcli_t *tcpcli; tracet(3, "strsettimeout: toinact=%d tirecon=%d\n", toinact, tirecon); if (stream->type == STR_TCPCLI) { tcpcli = static_cast(stream->port); } else if (stream->type == STR_NTRIPCLI || stream->type == STR_NTRIPSVR) { tcpcli = (static_cast(stream->port))->tcp; } else { return; } tcpcli->toinact = toinact; tcpcli->tirecon = tirecon; } /* set local directory --------------------------------------------------------- * set local directory path for ftp/http download * args : char *dir I directory for download files * return : none *-----------------------------------------------------------------------------*/ void strsetdir(const char *dir) { tracet(3, "strsetdir: dir=%s\n", dir); if (strlen(dir) < 1024) { strcpy(localdir, dir); } } /* set http/ntrip proxy address ------------------------------------------------ * set http/ntrip proxy address * args : char *addr I http/ntrip proxy address
: * return : none *-----------------------------------------------------------------------------*/ void strsetproxy(const char *addr) { tracet(3, "strsetproxy: addr=%s\n", addr); if (strlen(addr) < 256) { strcpy(proxyaddr, addr); } } /* get stream time ------------------------------------------------------------- * get stream time * args : stream_t *stream I stream * return : current time or replay time for playback file *-----------------------------------------------------------------------------*/ gtime_t strgettime(stream_t *stream) { file_t *file; if (stream->type == STR_FILE && (stream->mode & STR_MODE_R) && (file = static_cast(stream->port))) { return timeadd(file->time, file->start); /* replay start time */ } return utc2gpst(timeget()); } /* send nmea request ----------------------------------------------------------- * send nmea gpgga message to stream * args : stream_t *stream I stream * double *pos I position {x, y, z} (ecef) (m) * return : none *-----------------------------------------------------------------------------*/ void strsendnmea(stream_t *stream, const double *pos) { sol_t sol = {{0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, '0', '0', '0', 0, 0, 0}; unsigned char buff[1024]; int i; int n; tracet(3, "strsendnmea: pos=%.3f %.3f %.3f\n", pos[0], pos[1], pos[2]); sol.stat = SOLQ_SINGLE; sol.time = utc2gpst(timeget()); for (i = 0; i < 3; i++) { sol.rr[i] = pos[i]; } n = outnmea_gga(buff, &sol); strwrite(stream, buff, n); } /* generate general hex message ----------------------------------------------*/ int gen_hex(const char *msg, unsigned char *buff) { unsigned char *q = buff; char mbuff[1024] = ""; char *args[256]; char *p; unsigned int byte; int i; int narg = 0; trace(4, "gen_hex: msg=%s\n", msg); strncpy(mbuff, msg, 1023); for (p = strtok(mbuff, " "); p && narg < 256; p = strtok(nullptr, " ")) { args[narg++] = p; } for (i = 0; i < narg; i++) { if (sscanf(args[i], "%x", &byte)) { *q++ = static_cast(byte); } } return static_cast(q - buff); } /* send receiver command ------------------------------------------------------- * send receiver commands to stream * args : stream_t *stream I stream * char *cmd I receiver command strings * return : none *-----------------------------------------------------------------------------*/ void strsendcmd(stream_t *str, const char *cmd) { unsigned char buff[1024]; const char *p = cmd; const char *q; char msg[1024]; char cmdend[] = "\r\n"; int n; int m; int ms; tracet(3, "strsendcmd: cmd=%s\n", cmd); for (;;) { for (q = p;; q++) { if (*q == '\r' || *q == '\n' || *q == '\0') { break; } } n = static_cast(q - p); strncpy(msg, p, n); msg[n] = '\0'; if (!*msg || *msg == '#') { /* null or comment */ ; } else if (*msg == '!') { /* binary escape */ if (!strncmp(msg + 1, "WAIT", 4)) { /* wait */ if (sscanf(msg + 5, "%d", &ms) < 1) { ms = 100; } if (ms > 3000) { ms = 3000; /* max 3 s */ } sleepms(ms); } //else if (!strncmp(msg+1, "UBX", 3)) //{ /* ublox */ // if ((m=gen_ubx(msg+4, buff))>0) strwrite(str, buff, m); //} //else if (!strncmp(msg+1, "STQ", 3)) //{ /* skytraq */ // if ((m=gen_stq(msg+4, buff))>0) strwrite(str, buff, m); //} //else if (!strncmp(msg+1, "NVS", 3)) //{ /* nvs */ // if ((m=gen_nvs(msg+4, buff))>0) strwrite(str, buff, m); //} //else if (!strncmp(msg+1, "LEXR", 4)) //{ /* lex receiver */ // if ((m=gen_lexr(msg+5, buff))>0) strwrite(str, buff, m); //} else if (!strncmp(msg + 1, "HEX", 3)) { /* general hex message */ if ((m = gen_hex(msg + 4, buff)) > 0) { strwrite(str, buff, m); } } } else { strwrite(str, reinterpret_cast(msg), n); strwrite(str, reinterpret_cast(cmdend), 2); } if (*q == '\0') { break; } p = q + 1; } }