Merge branch 'master' into pico_sdk
This commit is contained in:
@@ -577,28 +577,36 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
|
||||
|
||||
PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc) {
|
||||
static const PIString s_ss = PIStringAscii(" ");
|
||||
static const PIString s_M = PIStringAscii("$M");
|
||||
static const PIString s_class = PIStringAscii("class");
|
||||
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
|
||||
static const PIString s_ss = PIStringAscii(" ");
|
||||
static const PIString s_M = PIStringAscii("$M");
|
||||
static const PIString s_class = PIStringAscii("class");
|
||||
static const PIString s_public = PIStringAscii("public");
|
||||
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
|
||||
MetaMap meta;
|
||||
int ind = cd.find(s_M);
|
||||
if (ind >= 0) {
|
||||
meta = tmp_meta.value(cd.takeMid(ind, 5));
|
||||
cd.replaceAll(s_ss, ' ');
|
||||
}
|
||||
PIString typename_ = cd.left(6).trim();
|
||||
bool is_class = typename_ == s_class;
|
||||
ind = cd.find(':');
|
||||
// piCout << "found class <****\n" << cd << "\n****>";
|
||||
ind = cd.find(':');
|
||||
PIVector<Entity *> parents;
|
||||
if (ind > 0) {
|
||||
PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
|
||||
cd.cutRight(1);
|
||||
Entity * pe = 0;
|
||||
for (const auto & p: pl) {
|
||||
if (p.contains(' '))
|
||||
pn = p.mid(p.find(' ') + 1);
|
||||
else
|
||||
PIString access;
|
||||
if (p.contains(' ')) {
|
||||
access = p.left(p.find(' ')).trim();
|
||||
pn = p.mid(p.find(' ') + 1);
|
||||
} else {
|
||||
pn = p;
|
||||
}
|
||||
bool is_public = access.isEmpty() ? !is_class : access == s_public;
|
||||
if (!is_public) continue;
|
||||
pe = findEntityByName(pn);
|
||||
if (pe == 0)
|
||||
; //{piCout << "Error: can`t find" << pn;}
|
||||
@@ -606,12 +614,10 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
|
||||
parents << pe;
|
||||
}
|
||||
}
|
||||
PIString typename_ = cd.left(6).trim();
|
||||
bool is_class = typename_ == s_class;
|
||||
Visibility vis = cur_def_vis;
|
||||
cur_def_vis = (is_class ? Private : Public);
|
||||
PIString cn = cd.mid(6).trim();
|
||||
bool is_anonymous = cn.isEmpty();
|
||||
Visibility vis = cur_def_vis;
|
||||
cur_def_vis = (is_class ? Private : Public);
|
||||
PIString cn = cd.mid(6).trim();
|
||||
bool is_anonymous = cn.isEmpty();
|
||||
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
|
||||
// piCout << "found " << typename_ << cn;
|
||||
Entity * e = new Entity();
|
||||
|
||||
@@ -66,9 +66,9 @@ void PIWaitEvent::destroy() {
|
||||
}
|
||||
# else
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (pipe_fd[i] != 0) {
|
||||
if (pipe_fd[i] != -1) {
|
||||
::close(pipe_fd[i]);
|
||||
pipe_fd[i] = 0;
|
||||
pipe_fd[i] = -1;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
@@ -90,12 +90,13 @@ bool PIWaitEvent::wait(int fd, CheckRole role) {
|
||||
FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead]));
|
||||
FD_SET(fd, &(fds[CheckExeption]));
|
||||
if (fd_index != CheckExeption) FD_SET(fd, &(fds[fd_index]));
|
||||
int sr = ::select(nfds, &(fds[CheckRead]), &(fds[CheckWrite]), &(fds[CheckExeption]), nullptr);
|
||||
int sr = ::select(nfds, &(fds[CheckRead]), &(fds[CheckWrite]), &(fds[CheckExeption]), nullptr);
|
||||
if (sr < 0) return false;
|
||||
errorClear();
|
||||
int buf = 0;
|
||||
while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0)
|
||||
;
|
||||
while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0) {}
|
||||
// piCout << "wait result" << sr << FD_ISSET(fd, &(fds[CheckExeption])) << FD_ISSET(fd, &(fds[fd_index]));
|
||||
if (sr == EBADF || sr == EINTR) return false;
|
||||
if (errno == EBADF || errno == EINTR) return false;
|
||||
if (FD_ISSET(fd, &(fds[CheckExeption]))) return true;
|
||||
return FD_ISSET(fd, &(fds[fd_index]));
|
||||
# endif
|
||||
@@ -140,7 +141,7 @@ bool PIWaitEvent::isCreate() const {
|
||||
# ifdef WINDOWS
|
||||
return event;
|
||||
# else
|
||||
return pipe_fd[ReadEnd] != 0;
|
||||
return pipe_fd[ReadEnd] != -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ private:
|
||||
# ifdef WINDOWS
|
||||
void * event = nullptr;
|
||||
# else
|
||||
int pipe_fd[2] = {0, 0};
|
||||
int pipe_fd[2] = {-1, -1};
|
||||
fd_set fds[3];
|
||||
enum {
|
||||
ReadEnd = 0,
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#include "piliterals_string.h"
|
||||
#include "piserverendpoint_p.h"
|
||||
|
||||
|
||||
PIStringList PIHTTP::ServerEndpoint::splitPath(const PIString & path) {
|
||||
auto ret = path.split("/");
|
||||
ret.removeAll({});
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIHTTP::ServerEndpoint::PathElement::PathElement(const PIString & reg) {
|
||||
source = reg;
|
||||
if (reg == "*"_a) {
|
||||
type = Type::AnyOne;
|
||||
} else if (reg == "**"_a) {
|
||||
type = Type::AnyMany;
|
||||
} else if (reg.contains('*')) {
|
||||
type = Type::AnyPart;
|
||||
parts = reg.split('*');
|
||||
} else if (reg.contains('{')) {
|
||||
type = Type::Arguments;
|
||||
int ind = 0, eind = 0, pind = 0;
|
||||
for (;;) {
|
||||
ind = reg.find('{', ind);
|
||||
if (ind < 0) break;
|
||||
eind = reg.find('}', ind + 1);
|
||||
if (eind < 0) break;
|
||||
arguments.insert(arguments.size_s(), reg.mid(ind + 1, eind - ind - 1));
|
||||
if (ind == 0)
|
||||
parts << PIString();
|
||||
else {
|
||||
if (ind > pind)
|
||||
parts << reg.mid(pind, ind - pind);
|
||||
else if (parts.isNotEmpty()) {
|
||||
piCout << "[PIHTTP::ServerEndpoint] Warning: sequential arguments, ignoring this path!";
|
||||
type = Type::Invalid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
ind = pind = eind + 1;
|
||||
}
|
||||
if (eind < reg.size_s() - 1) parts << reg.mid(eind + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIHTTP::ServerEndpoint::PathElement::match(const PIString & in, PIMap<PIString, PIString> & ext_args) const {
|
||||
// piCout << "match" << source << "with" << in;
|
||||
if (type == Type::AnyOne) return true;
|
||||
if (type == Type::AnyPart) {
|
||||
int ind = 0;
|
||||
for (const auto & m: parts) {
|
||||
ind = in.find(m, ind);
|
||||
if (ind < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (type == Type::Arguments) {
|
||||
int ind = 0, eind = 0;
|
||||
for (int i = 0; i < parts.size_s(); ++i) {
|
||||
const auto & m(parts[i]);
|
||||
if (m.isNotEmpty()) {
|
||||
ind = in.find(m, eind);
|
||||
if (ind < 0) return false;
|
||||
}
|
||||
if (i > 0) {
|
||||
ext_args[arguments.value(i - 1)] = in.mid(eind, ind - eind);
|
||||
}
|
||||
eind = ind + m.size_s();
|
||||
}
|
||||
if (parts.size() == arguments.size()) {
|
||||
ext_args[arguments.value(arguments.size_s() - 1)] = in.mid(eind);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return source == in;
|
||||
}
|
||||
|
||||
|
||||
uint PIHTTP::ServerEndpoint::PathElement::priority() const {
|
||||
switch (type) {
|
||||
case Type::Fixed: return 0x10000; break;
|
||||
case Type::Arguments: return 0x1000; break;
|
||||
case Type::AnyPart: return 0x100; break;
|
||||
case Type::AnyOne: return 0x10; break;
|
||||
case Type::AnyMany: return 0x1; break;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIHTTP::ServerEndpoint::create(const PIString & p) {
|
||||
path = splitPath(p);
|
||||
prepared_path.clear();
|
||||
priority = 0;
|
||||
for (const auto & i: path) {
|
||||
PathElement pe(i);
|
||||
prepared_path << pe;
|
||||
path_types |= pe.type;
|
||||
priority += pe.priority();
|
||||
}
|
||||
return !path_types[PathElement::Type::Invalid];
|
||||
}
|
||||
|
||||
|
||||
bool PIHTTP::ServerEndpoint::match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const {
|
||||
if (path_types[PathElement::Type::AnyMany]) {
|
||||
int any_ind = path.indexOf("**"_a);
|
||||
for (int i = 0; i < any_ind; ++i) {
|
||||
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
|
||||
}
|
||||
int si = prepared_path.size_s() - 1, ii = in_path.size_s() - 1;
|
||||
for (; si > any_ind && ii >= 0; --si, --ii) {
|
||||
if (!prepared_path[si].match(in_path[ii], ext_args)) return false;
|
||||
}
|
||||
} else {
|
||||
if (in_path.size() != prepared_path.size()) return false;
|
||||
for (int i = 0; i < prepared_path.size_s(); ++i) {
|
||||
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//! \~\file piserverendpoint_p.h
|
||||
//! \~\ingroup HTTP
|
||||
//! \~\brief
|
||||
//! \~english Shared HTTP message container types
|
||||
//! \~russian Общие типы контейнеров HTTP-сообщений
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Shared HTTP message container types
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef piserverendpoint_p_h
|
||||
#define piserverendpoint_p_h
|
||||
|
||||
#include "pip_export.h"
|
||||
#include "pistringlist.h"
|
||||
|
||||
|
||||
namespace PIHTTP {
|
||||
|
||||
|
||||
struct PIP_EXPORT ServerEndpoint {
|
||||
struct PIP_EXPORT PathElement {
|
||||
enum class Type {
|
||||
Invalid = 0x01,
|
||||
Fixed = 0x02,
|
||||
Arguments = 0x04,
|
||||
AnyOne = 0x08,
|
||||
AnyPart = 0x10,
|
||||
AnyMany = 0x20
|
||||
};
|
||||
|
||||
Type type = Type::Fixed;
|
||||
PIString source;
|
||||
PIStringList parts;
|
||||
PIMap<int, PIString> arguments;
|
||||
|
||||
PathElement(const PIString & reg = {});
|
||||
|
||||
bool match(const PIString & in, PIMap<PIString, PIString> & ext_args) const;
|
||||
uint priority() const;
|
||||
};
|
||||
|
||||
PIStringList path;
|
||||
PIFlags<PathElement::Type> path_types;
|
||||
PIVector<PathElement> prepared_path;
|
||||
uint priority = 0;
|
||||
|
||||
bool create(const PIString & p);
|
||||
bool match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const;
|
||||
|
||||
static PIStringList splitPath(const PIString & path);
|
||||
};
|
||||
|
||||
|
||||
}; // namespace PIHTTP
|
||||
|
||||
|
||||
#endif
|
||||
@@ -102,43 +102,9 @@ public:
|
||||
void clearReplyHeaders() { reply_headers.clear(); }
|
||||
|
||||
private:
|
||||
struct PathElement {
|
||||
enum class Type {
|
||||
Invalid = 0x01,
|
||||
Fixed = 0x02,
|
||||
Arguments = 0x04,
|
||||
AnyOne = 0x08,
|
||||
AnyPart = 0x10,
|
||||
AnyMany = 0x20
|
||||
};
|
||||
|
||||
Type type = Type::Fixed;
|
||||
PIString source;
|
||||
PIStringList parts;
|
||||
PIMap<int, PIString> arguments;
|
||||
|
||||
PathElement(const PIString & reg = {});
|
||||
|
||||
bool match(const PIString & in, PIMap<PIString, PIString> & ext_args) const;
|
||||
uint priority() const;
|
||||
};
|
||||
|
||||
struct Endpoint {
|
||||
PIStringList path;
|
||||
PIHTTP::Method method = PIHTTP::Method::Unknown;
|
||||
RequestFunction function;
|
||||
PIFlags<PathElement::Type> path_types;
|
||||
PIVector<PathElement> prepared_path;
|
||||
uint priority = 0;
|
||||
|
||||
bool create(const PIString & p);
|
||||
bool match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const;
|
||||
};
|
||||
|
||||
static PIStringList splitPath(const PIString & path);
|
||||
PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
|
||||
|
||||
PIMap<PIString, PIString> reply_headers;
|
||||
PIMap<uint, PIVector<Endpoint>> endpoints;
|
||||
RequestFunction unhandled;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
# define PIP_CAN
|
||||
#endif
|
||||
#ifdef PIP_CAN
|
||||
# include <fcntl.h>
|
||||
# include <linux/can.h>
|
||||
# include <linux/can/raw.h>
|
||||
# include <net/if.h>
|
||||
@@ -50,7 +51,7 @@ PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(pat
|
||||
setPath(path);
|
||||
#ifdef PIP_CAN
|
||||
can_id = 0;
|
||||
sock = 0;
|
||||
sock = -1;
|
||||
PRIVATE->event.create();
|
||||
#endif
|
||||
}
|
||||
@@ -71,19 +72,25 @@ bool PICAN::openDevice() {
|
||||
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (sock < 0) {
|
||||
piCoutObj << "Error! while opening socket";
|
||||
sock = -1;
|
||||
return false;
|
||||
}
|
||||
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
|
||||
ifreq ifr;
|
||||
strcpy(ifr.ifr_name, path().dataAscii());
|
||||
piCout << "PICAN try to get interface index...";
|
||||
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
|
||||
piCoutObj << "Error! while determin the interface ioctl";
|
||||
::close(sock);
|
||||
sock = -1;
|
||||
return false;
|
||||
}
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv);
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) < 0) {
|
||||
piCoutObj << "Error! while setting socket receive timeout";
|
||||
}
|
||||
// bind socket to all CAN interface
|
||||
sockaddr_can addr;
|
||||
addr.can_family = AF_CAN;
|
||||
@@ -91,6 +98,8 @@ bool PICAN::openDevice() {
|
||||
piCout << "PICAN try to bind socket to interface" << ifr.ifr_ifindex;
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
piCoutObj << "Error! while binding socket";
|
||||
::close(sock);
|
||||
sock = -1;
|
||||
return false;
|
||||
}
|
||||
piCout << "PICAN Open OK!";
|
||||
@@ -105,7 +114,11 @@ bool PICAN::openDevice() {
|
||||
bool PICAN::closeDevice() {
|
||||
#ifdef PIP_CAN
|
||||
interrupt();
|
||||
if (sock > 0) ::close(sock);
|
||||
if (sock != -1) {
|
||||
::shutdown(sock, SHUT_RDWR);
|
||||
::close(sock);
|
||||
sock = -1;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -113,6 +126,7 @@ bool PICAN::closeDevice() {
|
||||
|
||||
ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
|
||||
#ifdef PIP_CAN
|
||||
if (sock == -1) return -1;
|
||||
// piCout << "PICAN read";
|
||||
can_frame frame;
|
||||
ssize_t ret = 0;
|
||||
@@ -131,6 +145,7 @@ ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
|
||||
|
||||
ssize_t PICAN::writeDevice(const void * data, ssize_t max_size) {
|
||||
#ifdef PIP_CAN
|
||||
if (sock == -1) return -1;
|
||||
// piCout << "PICAN write" << can_id << max_size;
|
||||
if (max_size > 8) {
|
||||
piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!";
|
||||
|
||||
@@ -73,7 +73,7 @@ protected:
|
||||
|
||||
private:
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
int sock;
|
||||
int sock = -1;
|
||||
int can_id, readed_id;
|
||||
};
|
||||
|
||||
|
||||
@@ -103,7 +103,11 @@
|
||||
|
||||
# ifndef WINDOWS
|
||||
PIString getSockAddr(sockaddr * s) {
|
||||
return s == 0 ? PIString() : PIStringAscii(inet_ntoa(((sockaddr_in *)s)->sin_addr));
|
||||
if (!s) return PIString();
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
piZeroMemory(buf, sizeof(buf));
|
||||
const char * r = inet_ntop(AF_INET, &((sockaddr_in *)s)->sin_addr, buf, sizeof(buf));
|
||||
return r ? PIStringAscii(r) : PIString();
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -862,6 +866,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ret += sr;
|
||||
remain_data += sr;
|
||||
remain_size -= sr;
|
||||
}
|
||||
@@ -1176,13 +1181,19 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
# else
|
||||
# ifdef ANDROID
|
||||
struct ifconf ifc;
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (s == -1) {
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Can`t create socket: %1"_tr("PIEthernet").arg(errorString());
|
||||
return il;
|
||||
}
|
||||
ifc.ifc_len = 256;
|
||||
ifc.ifc_buf = new char[ifc.ifc_len];
|
||||
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString());
|
||||
delete[] ifc.ifc_buf;
|
||||
::close(s);
|
||||
return il;
|
||||
}
|
||||
int icnt = ifc.ifc_len / sizeof(ifreq);
|
||||
@@ -1201,7 +1212,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
if (ci.address == "127.0.0.1") ci.flags |= PIEthernet::ifLoopback;
|
||||
il << ci;
|
||||
}
|
||||
delete ifc.ifc_buf;
|
||||
delete[] ifc.ifc_buf;
|
||||
::close(s);
|
||||
# else
|
||||
struct ifaddrs *ret, *cif = 0;
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
@@ -1223,7 +1235,7 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
# ifdef QNX
|
||||
# ifndef BLACKBERRY
|
||||
int fd = ::open((PIString("/dev/io-net/") + ci.name).dataAscii(), O_RDONLY);
|
||||
if (fd != 0) {
|
||||
if (fd >= 0) {
|
||||
nic_config_t nic;
|
||||
devctl(fd, DCMD_IO_NET_GET_CONFIG, &nic, sizeof(nic), 0);
|
||||
::close(fd);
|
||||
@@ -1292,8 +1304,10 @@ PINetworkAddress PIEthernet::interfaceAddress(const PIString & interface_) {
|
||||
piZeroMemory(ifr);
|
||||
strcpy(ifr.ifr_name, interface_.dataAscii());
|
||||
int s = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ioctl(s, SIOCGIFADDR, &ifr);
|
||||
::close(s);
|
||||
if (s != -1) {
|
||||
ioctl(s, SIOCGIFADDR, &ifr);
|
||||
::close(s);
|
||||
}
|
||||
struct sockaddr_in * sa = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
return PINetworkAddress(uint(sa->sin_addr.s_addr));
|
||||
# endif
|
||||
|
||||
@@ -62,8 +62,7 @@ ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
|
||||
if (ret <= 0) return -1;
|
||||
memcpy(read_to, data_->data(pos), ret);
|
||||
// piCout << "readed" << ret;
|
||||
pos += size;
|
||||
if (pos > data_->size_s()) pos = data_->size_s();
|
||||
pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -623,7 +623,10 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
return true;
|
||||
}
|
||||
cnt++;
|
||||
if (cnt > _PIPEER_MSG_TTL || from == dp->name) return true;
|
||||
if (cnt > _PIPEER_MSG_TTL || from == dp->name) {
|
||||
eth_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
sba << type << from << to << cnt << pba;
|
||||
// piCout << "translate packet" << from << "->" << to << ", ttl =" << cnt;
|
||||
sendToNeighbour(dp, sba);
|
||||
|
||||
@@ -512,7 +512,10 @@ bool PISerial::read(void * data, int size, double timeout_ms) {
|
||||
all = readDevice(data, 1);
|
||||
while (all < size) {
|
||||
ret = readDevice(&((uchar *)data)[all], size - all);
|
||||
if (ret > 0) all += ret;
|
||||
if (ret > 0)
|
||||
all += ret;
|
||||
else
|
||||
break;
|
||||
}
|
||||
setOption(BlockingRead, br);
|
||||
received(data, all);
|
||||
|
||||
@@ -131,6 +131,12 @@ bool PIFileTransfer::sendFiles(const PIVector<PFTFileInfo> & files) {
|
||||
|
||||
void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
|
||||
// piCout << "processFile" << id << files_.size();
|
||||
if (id <= 0 || id > files_.size_s()) {
|
||||
cur_file_string = "Error: Invalid file id " + PIString::fromNumber(id);
|
||||
piCoutObj << cur_file_string;
|
||||
stopReceive();
|
||||
return;
|
||||
}
|
||||
PFTFileInfo fi = files_[id - 1];
|
||||
bytes_file_all = fi.size;
|
||||
bytes_file_cur = start;
|
||||
|
||||
@@ -308,10 +308,12 @@ inline PIVector<T> piAbs(const PIVector<T> & v) {
|
||||
//! \~russian Нормализует угол к диапазону `[0; 360]` градусов на месте.
|
||||
template<typename T>
|
||||
void normalizeAngleDeg360(T & a) {
|
||||
while (a < 0.)
|
||||
a += 360.;
|
||||
while (a > 360.)
|
||||
a -= 360.;
|
||||
if (std::isnan(a) || std::isinf(a)) {
|
||||
a = 0.;
|
||||
return;
|
||||
}
|
||||
a -= std::floor(a / 360.) * 360.;
|
||||
if (a < 0) a += 360;
|
||||
}
|
||||
|
||||
//! \~english Returns an angle normalized to the `[0; 360]` degree range.
|
||||
@@ -327,10 +329,13 @@ double normalizedAngleDeg360(T a) {
|
||||
//! \~russian Нормализует угол к диапазону `[-180; 180]` градусов на месте.
|
||||
template<typename T>
|
||||
void normalizeAngleDeg180(T & a) {
|
||||
while (a < -180.)
|
||||
a += 360.;
|
||||
while (a > 180.)
|
||||
a -= 360.;
|
||||
if (std::isnan(a) || std::isinf(a)) {
|
||||
a = 0.;
|
||||
return;
|
||||
}
|
||||
a -= std::floor(a / 360.) * 360.;
|
||||
if (a < -180) a += 360;
|
||||
if (a >= 180) a -= 360;
|
||||
}
|
||||
|
||||
//! \~english Returns an angle normalized to the `[-180; 180]` degree range.
|
||||
|
||||
@@ -167,6 +167,22 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Multiplies by-coordinates by `v`.
|
||||
//! \~russian Умножает по-координатно на `v`.
|
||||
PIPoint<Type> & operator*=(const PIPoint<Type> & v) {
|
||||
x *= v.x;
|
||||
y *= v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Divides by-coordinates by `v`.
|
||||
//! \~russian Делит по-координатно на `v`.
|
||||
PIPoint<Type> & operator/=(const PIPoint<Type> & v) {
|
||||
x /= v.x;
|
||||
y /= v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Returns sum of two points.
|
||||
//! \~russian Возвращает сумму двух точек.
|
||||
PIPoint<Type> operator+(const PIPoint<Type> & p) const { return PIPoint<Type>(x + p.x, y + p.y); }
|
||||
@@ -195,6 +211,14 @@ public:
|
||||
//! \~russian Возвращает точку, деленную на `v`.
|
||||
PIPoint<Type> operator/(Type v) const { return PIPoint<Type>(x / v, y / v); }
|
||||
|
||||
//! \~english Returns point multiplied by `v`.
|
||||
//! \~russian Возвращает точку, умноженную на `v`.
|
||||
PIPoint<Type> operator*(const PIPoint<Type> & v) const { return PIPoint<Type>(x * v.x, y * v.y); }
|
||||
|
||||
//! \~english Returns point divided by `v`.
|
||||
//! \~russian Возвращает точку, деленную на `v`.
|
||||
PIPoint<Type> operator/(const PIPoint<Type> & v) const { return PIPoint<Type>(x / v.x, y / v.y); }
|
||||
|
||||
//! \~english Checks whether point coordinates are equal.
|
||||
//! \~russian Проверяет равенство координат точек.
|
||||
bool operator==(const PIPoint<Type> & p) const { return (x == p.x && y == p.y); }
|
||||
|
||||
@@ -41,24 +41,39 @@ public:
|
||||
Client();
|
||||
virtual ~Client();
|
||||
|
||||
//! \~english Request handler used by registered routes and fallback processing.
|
||||
//! \~russian Обработчик запроса, используемый зарегистрированными маршрутами и fallback-обработкой.
|
||||
using MessageFunction = std::function<void(const PIMQTT::MessageConst &)>;
|
||||
|
||||
void setConnectTimeout(PISystemTime time) { connect_timeout = time; }
|
||||
|
||||
void connect(const PIString & address, const PIString & client, const PIString & username = {}, const PIString & password = {});
|
||||
void disconnect();
|
||||
|
||||
void subscribe(const PIString & topic, QoS qos = QoS::Level1);
|
||||
void subscribe(const PIString & topic, MessageFunction functor, QoS qos = QoS::Level1);
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
subscribe(const PIString & topic, T * o, PIMQTT::MessageMutable (T::*function)(const PIMQTT::MessageConst &), QoS qos = QoS::Level1) {
|
||||
subscribe(topic, [o, function](const PIMQTT::MessageConst & m) { return (o->*function)(m); }, qos);
|
||||
}
|
||||
|
||||
void unsubscribe(const PIString & topic);
|
||||
void unsubscribeAll();
|
||||
|
||||
void publish(const PIString & topic, const PIByteArray & msg, QoS qos = QoS::Level0);
|
||||
void publish(const MessageConst & msg);
|
||||
void unsubscribeAll() { unsubscribe("#"); }
|
||||
|
||||
bool isConnecting() const { return m_status == Connecting; }
|
||||
bool isConnected() const { return m_status == Connected; }
|
||||
|
||||
PIStringList usedTopics() const;
|
||||
|
||||
EVENT0(connected);
|
||||
EVENT1(disconnected, PIMQTT::Error, code);
|
||||
EVENT1(received, PIMQTT::MessageConst, message);
|
||||
EVENT1(receivedUnhandled, PIMQTT::MessageConst, message);
|
||||
|
||||
struct Endpoint;
|
||||
|
||||
private:
|
||||
NO_COPY_CLASS(Client)
|
||||
@@ -79,23 +94,34 @@ private:
|
||||
};
|
||||
struct Subscribe {
|
||||
PIString topic;
|
||||
MessageFunction functor;
|
||||
QoS qos;
|
||||
};
|
||||
|
||||
void mqtt_connectionLost();
|
||||
void mqtt_deliveryComplete(int token);
|
||||
void mqtt_messageArrived(const MessageConst & msg);
|
||||
void mqtt_messageArrived(MessageMutable & msg);
|
||||
|
||||
PIString registerSubscribe(const Subscribe & sub);
|
||||
PIString unregisterSubscribe(const PIString & mqtt_topic);
|
||||
void unregisterAll();
|
||||
|
||||
void connectInternal(const ConnectInfo & ci);
|
||||
void disconnectInternal();
|
||||
void publishInternal(const MessageConst & m);
|
||||
void subscribeInternal(const Subscribe & sub);
|
||||
void unsubscribeInternal(const PIString & topic);
|
||||
void unsubscribeInternal(const PIString & mqtt_topic);
|
||||
void destroy();
|
||||
void changeStatus(Status s);
|
||||
|
||||
void run();
|
||||
|
||||
// from HTTP format
|
||||
static PIString convertTopic2MQTT(const PIString & topic);
|
||||
|
||||
// from MQTT format
|
||||
static PIString convertTopic2HTTP(const PIString & topic);
|
||||
|
||||
std::atomic_int m_status = {Idle};
|
||||
std::atomic_bool is_destoying = {false};
|
||||
PISystemTime connect_timeout = 10_s;
|
||||
|
||||
@@ -56,17 +56,17 @@
|
||||
|
||||
#else
|
||||
|
||||
# define BINARY_STREAM_FRIEND(T) \
|
||||
template<typename P> \
|
||||
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v); \
|
||||
template<typename P> \
|
||||
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v);
|
||||
# define BINARY_STREAM_FRIEND(T) \
|
||||
template<typename P> \
|
||||
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v); \
|
||||
template<typename P> \
|
||||
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v);
|
||||
# define BINARY_STREAM_WRITE(T) \
|
||||
template<typename P> \
|
||||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v)
|
||||
template<typename P> \
|
||||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v)
|
||||
# define BINARY_STREAM_READ(T) \
|
||||
template<typename P> \
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v)
|
||||
template<typename P> \
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -410,7 +410,7 @@ template<typename P,
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
// piCout << ">> vector trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -433,7 +433,7 @@ template<typename P,
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
// piCout << ">> vector trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -462,7 +462,7 @@ template<typename P,
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
// piCout << ">> deque trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -485,7 +485,7 @@ template<typename P,
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
// piCout << ">> deque trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -516,7 +516,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
int r, c;
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || r < 0 || c < 0) {
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -542,6 +542,11 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
PIVector<T> tmp;
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError() || r < 0 || c < 0) {
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
s >> tmp;
|
||||
if (s.wasReadError()) {
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
@@ -618,7 +623,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
|
||||
//! \~russian Восстанавливает %PIVector из нетривиальных элементов по одному.
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -641,7 +646,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
|
||||
//! \~russian Восстанавливает %PIDeque из нетривиальных элементов по одному.
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -667,6 +672,11 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
PIVector<T> tmp;
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError() || r < 0 || c < 0) {
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
s >> tmp;
|
||||
if (s.wasReadError()) {
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
@@ -700,7 +710,7 @@ template<typename P, typename Key, typename T>
|
||||
//! \~russian Восстанавливает ключи и значения %PIMap.
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
@@ -749,7 +759,7 @@ template<typename P, typename Key>
|
||||
//! \~russian Восстанавливает ключи %PISet.
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<Key> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
if (s.wasReadError() || sz < 0) {
|
||||
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
|
||||
v.clear();
|
||||
return s;
|
||||
|
||||
@@ -547,7 +547,7 @@ void PIJSON::print(PIString & s, const PIJSON & v, PIString tab, bool spaces, bo
|
||||
if (spaces) s += ' ';
|
||||
}
|
||||
switch (v.c_type) {
|
||||
case PIJSON::Invalid: break;
|
||||
case PIJSON::Invalid:
|
||||
case PIJSON::Null: s += "null"; break;
|
||||
case PIJSON::Boolean: s += PIString::fromBool(v.c_value.toBool()); break;
|
||||
case PIJSON::Number: s += v.c_value.toString(); break;
|
||||
|
||||
@@ -291,6 +291,13 @@ inline PIJSON piSerializeJSON(const PIMathVectorT<Size, T> & v) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<>
|
||||
//! \~english Serializes %PIStringList as JSON array.
|
||||
//! \~russian Сериализует %PIStringList как JSON-массив.
|
||||
inline PIJSON piSerializeJSON(const PIStringList & v) {
|
||||
return piSerializeJSON((const PIDeque<PIString> &)v);
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// deserialize, piDeserializeJSON(T, PIJSON)
|
||||
@@ -538,6 +545,13 @@ inline void piDeserializeJSON(PIMathVectorT<Size, T> & v, const PIJSON & js) {
|
||||
piDeserializeJSON(v[i], js[i]);
|
||||
}
|
||||
|
||||
template<>
|
||||
//! \~english Deserializes %PIStringList from JSON array.
|
||||
//! \~russian Десериализует %PIStringList из JSON-массива.
|
||||
inline void piDeserializeJSON(PIStringList & v, const PIJSON & js) {
|
||||
piDeserializeJSON((PIDeque<PIString> &)v, js);
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// PIJSON static wrapper
|
||||
|
||||
@@ -215,10 +215,10 @@ PRIVATE_DEFINITION_START(PIProcess)
|
||||
PeekNamedPipe(pipes[pipe_type][PipeRead], nullptr, 0, nullptr, &available, nullptr);
|
||||
if (available > 0) {
|
||||
BOOL ok = ReadFile(pipes[pipe_type][PipeRead],
|
||||
read_buffer.data(offset),
|
||||
piMini(available, read_buffer.size() - offset),
|
||||
&bytes_read,
|
||||
nullptr);
|
||||
read_buffer.data(offset),
|
||||
piMini(available, read_buffer.size() - offset),
|
||||
&bytes_read,
|
||||
nullptr);
|
||||
if (!ok) bytes_read = 0;
|
||||
}
|
||||
# else
|
||||
@@ -293,10 +293,10 @@ void PIProcess::startProc(bool detached) {
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
const auto cmd = convertWindowsCmd(args);
|
||||
if (CreateProcessA(0, // No module name (use command line)
|
||||
(LPSTR)cmd.data(), // Command line
|
||||
(LPSTR)cmd.data(), // Command line
|
||||
0, // Process handle not inheritable
|
||||
0, // Thread handle not inheritable
|
||||
true, // Set handle inheritance to FALSE
|
||||
true, // Set handle inheritance to FALSE
|
||||
detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
|
||||
0, // Use environment
|
||||
wd.isEmpty() ? 0 : wd.data(), // Use working directory
|
||||
@@ -319,10 +319,17 @@ void PIProcess::startProc(bool detached) {
|
||||
auto largs = convertToCharArrays(args);
|
||||
auto lenv = convertToCharArrays(env);
|
||||
int pid_ = fork();
|
||||
if (pid_ < 0) {
|
||||
piCoutObj << "\"fork\" error: " << errorString();
|
||||
PRIVATE->closeAllPipes();
|
||||
delete[] largs;
|
||||
delete[] lenv;
|
||||
return;
|
||||
}
|
||||
if (!detached) PRIVATE->pid = pid_;
|
||||
if (pid_ == 0) {
|
||||
if (!wd.isEmpty()) {
|
||||
if (!chdir(wd.data())) piCoutObj << "Error while set working directory";
|
||||
if (chdir(wd.data()) != 0) piCoutObj << "Error while set working directory";
|
||||
}
|
||||
PRIVATE->closePipe(StdIn, PipeWrite);
|
||||
PRIVATE->closePipe(StdOut, PipeRead);
|
||||
|
||||
@@ -671,7 +671,7 @@ PIString & PIString::operator+=(const PIConstChars & str) {
|
||||
if (!str.isEmpty()) {
|
||||
size_t os = d.size();
|
||||
d.enlarge(str.size());
|
||||
for (size_t l = 0; l < d.size(); ++l) {
|
||||
for (size_t l = 0; l < str.size(); ++l) {
|
||||
d[os + l] = str[l];
|
||||
}
|
||||
}
|
||||
@@ -1763,7 +1763,7 @@ PIString PIString::toLowerCase() const {
|
||||
|
||||
|
||||
char PIString::toChar() const {
|
||||
char v;
|
||||
char v = 0;
|
||||
sscanf(dataAscii(), "%c", &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -1107,9 +1107,11 @@ public:
|
||||
PIByteArray & append(const PIByteArray & data_) {
|
||||
#ifdef CC_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
# pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
# pragma GCC diagnostic ignored "-Wrestrict"
|
||||
# ifndef ANDROID
|
||||
# pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
# pragma GCC diagnostic ignored "-Wrestrict"
|
||||
# endif
|
||||
#endif
|
||||
const size_t ps = size();
|
||||
enlarge(data_.size_s());
|
||||
|
||||
@@ -217,7 +217,7 @@ PIValueTree & PIValueTree::child(const PIStringList & path) {
|
||||
if (_is_null || path.isEmpty()) return *this;
|
||||
PIValueTree * ret = &child(path[0]);
|
||||
for (int i = 1; i < path.size_s(); ++i)
|
||||
ret = &child(path[i]);
|
||||
ret = &(ret->child(path[i]));
|
||||
return *ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user