diff --git a/src_main/io_utils/piethutilbase.cpp b/src_main/io_utils/piethutilbase.cpp
new file mode 100644
index 00000000..91adaa10
--- /dev/null
+++ b/src_main/io_utils/piethutilbase.cpp
@@ -0,0 +1,52 @@
+/*
+ PIP - Platform Independent Primitives
+ Base class for ethernet utils
+ Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "piethutilbase.h"
+#include "picrypt.h"
+
+
+PIEthUtilBase::PIEthUtilBase() {
+ _crypt = false;
+}
+
+
+PIEthUtilBase::~PIEthUtilBase() {
+}
+
+
+void PIEthUtilBase::createCryptKey(const PIString & k) {
+ _key = PICrypt::hash("sodium_bug");
+ _key = PICrypt::hash(k);
+ _crypt = true;
+}
+
+
+PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
+ if (!_crypt) return data;
+ return PICrypt::crypt(data, _key);
+}
+
+
+PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
+ if (!_crypt) return data;
+ bool ok = false;
+ PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
+ if (!ok) return PIByteArray();
+ return ret;
+}
diff --git a/src_main/io_utils/piethutilbase.h b/src_main/io_utils/piethutilbase.h
new file mode 100644
index 00000000..a7c0c986
--- /dev/null
+++ b/src_main/io_utils/piethutilbase.h
@@ -0,0 +1,52 @@
+/*! \file piethutilbase.h
+ * \brief Base class for ethernet utils
+*/
+/*
+ PIP - Platform Independent Primitives
+ Base class for ethernet utils
+ Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PIETHUTILBASE_H
+#define PIETHUTILBASE_H
+
+#include "pibytearray.h"
+
+class PIEthUtilBase {
+public:
+ PIEthUtilBase();
+ ~PIEthUtilBase();
+
+ void setCryptEnabled(bool on) {_crypt = on;}
+ void cryptEnable() {setCryptEnabled(true);}
+ void cryptDisable() {setCryptEnabled(false);}
+ bool isCryptEnabled() const {return _crypt;}
+
+ void setCryptKey(const PIByteArray & k) {_key = k;}
+ void createCryptKey(const PIString & k);
+ PIByteArray cryptKey() const {return _key;}
+
+protected:
+ PIByteArray cryptData(const PIByteArray & data);
+ PIByteArray decryptData(const PIByteArray & data);
+
+private:
+ PIByteArray _key;
+ bool _crypt;
+
+};
+
+#endif // PIETHUTILBASE_H
diff --git a/src_main/io_utils/pimulticast.cpp b/src_main/io_utils/pimulticast.cpp
new file mode 100644
index 00000000..1ab7a1e8
--- /dev/null
+++ b/src_main/io_utils/pimulticast.cpp
@@ -0,0 +1,178 @@
+/*
+ PIP - Platform Independent Primitives
+ Multicast for all interfaces, including loopback
+ Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "pimulticast.h"
+
+#define MULTICAST_TTL 4
+
+
+PIMulticast::PIMulticast(bool send_only): PIThread(), PIEthUtilBase() {
+ eth_lo = 0;
+ _send_only = send_only;
+ mcast_address.set("232.13.3.14", 14100);
+ lo_port = 14200;
+ lo_pcnt = 5;
+ _started = false;
+ _reinit = true;
+ //initMcast(PIEthernet::allAddresses());
+ PIThread::start(3000);
+}
+
+
+PIMulticast::~PIMulticast() {
+ PIThread::stop();
+ mcast_mutex.unlock();
+ destroyAll();
+}
+
+
+void PIMulticast::destroyAll() {
+ piForeach (PIEthernet * e, eth_mcast) {
+ e->stopThreadedRead();
+ delete e;
+ }
+ eth_mcast.clear();
+ if (eth_lo) {
+ eth_lo->stopThreadedRead();
+ delete eth_lo;
+ eth_lo = 0;
+ }
+}
+
+
+void PIMulticast::initAll(PIVector al) {
+ PIMutexLocker ml(mcast_mutex);
+ destroyAll();
+ _reinit = false;
+ prev_al = al;
+ al.removeAll(PIEthernet::Address("127.0.0.1"));
+ al << mcast_address;
+ eth_mcast.clear();
+ PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
+ piForeachC (PIEthernet::Address & a, al) {
+// piCout << "mcast try" << a;
+ PIEthernet * ce = new PIEthernet();
+ ce->setDebug(false);
+ ce->setName("PIMulticast_" + a.toString());
+ ce->setParameters(0);
+ ce->setSendAddress(mcast_address);
+ ce->setMulticastTTL(MULTICAST_TTL);
+ if (!_send_only) {
+ ce->setReadAddress(a.ipString(), mcast_address.port());
+ ce->joinMulticastGroup(mcast_address.ipString());
+ // piCout << "mcast " << ce->readAddress() << ce->sendAddress();
+ if (ce->open()) {
+ eth_mcast << ce;
+ CONNECTU(ce, threadedReadEvent, this, mcastRead);
+ } else {
+ delete ce;
+ }
+ } else {
+ eth_mcast << ce;
+ }
+
+ ce = new PIEthernet();
+ ce->setDebug(false);
+ ce->setName("PIMulticast_" + a.toString());
+ ce->setParameters(PIEthernet::Broadcast);
+ const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
+ PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask);
+ ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
+ if (!_send_only) {
+ ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
+ // piCout << "bcast " << ce->readAddress() << ce->sendAddress();
+ if (ce->open()) {
+ eth_mcast << ce;
+ CONNECTU(ce, threadedReadEvent, this, mcastRead);
+ } else {
+ delete ce;
+ }
+ } else {
+ eth_mcast << ce;
+ }
+ }
+ eth_lo = new PIEthernet();
+ eth_lo->setDebug(false);
+ ce->setName("PIMulticast_loopback");
+ if (!_send_only) {
+ eth_lo->setParameter(PIEthernet::ReuseAddress, false);
+ CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
+ for (int i = 0; i < lo_pcnt; ++i) {
+ eth_lo->setReadAddress("127.0.0.1", lo_port + i);
+ if (eth_lo->open()) {
+ // piCout << "bind local to" << (lo_port + i);
+ break;
+ }
+ }
+ }
+}
+
+
+void PIMulticast::send(const PIByteArray & data) {
+ PIByteArray cd = cryptData(data);
+ if (cd.isEmpty()) return;
+ piForeach (PIEthernet * e, eth_mcast)
+ e->send(cd);
+ if (eth_lo) {
+ for (int i = 0; i < lo_pcnt; ++i) {
+ eth_lo->send("127.0.0.1", lo_port + i, cd);
+ }
+ }
+}
+
+
+void PIMulticast::startRead() {
+ if (_send_only) return;
+ piForeach (PIEthernet * e, eth_mcast)
+ e->startThreadedRead();
+ if (eth_lo)
+ eth_lo->startThreadedRead();
+ _started = true;
+}
+
+
+void PIMulticast::stopRead() {
+ piForeach (PIEthernet * e, eth_mcast)
+ e->stopThreadedRead();
+ if (eth_lo)
+ eth_lo->stopThreadedRead();
+ _started = false;
+}
+
+
+void PIMulticast::reinit() {
+
+}
+
+
+void PIMulticast::mcastRead(uchar * data, int size) {
+ PIByteArray cd = decryptData(PIByteArray(data, size));
+ if (cd.isEmpty()) return;
+ received(cd);
+ receiveEvent(cd);
+}
+
+
+void PIMulticast::run() {
+ PIVector al = PIEthernet::allAddresses();
+ if (al == prev_al) return;
+ initAll(al);
+ if (_started)
+ startRead();
+}
diff --git a/src_main/io_utils/pimulticast.h b/src_main/io_utils/pimulticast.h
new file mode 100644
index 00000000..ff53fd53
--- /dev/null
+++ b/src_main/io_utils/pimulticast.h
@@ -0,0 +1,79 @@
+/*! \file pimulticast.h
+ * \brief Multicast for all interfaces, including loopback
+*/
+/*
+ PIP - Platform Independent Primitives
+ Multicast for all interfaces, including loopback
+ Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PIMULTICAST_H
+#define PIMULTICAST_H
+
+#include "piethutilbase.h"
+#include "piethernet.h"
+
+#define SMDEVICE_PORT 22555
+
+class PIMulticast: public PIThread, public PIEthUtilBase {
+ PIOBJECT(PIMulticast)
+public:
+ PIMulticast(bool send_only = false);
+ ~PIMulticast();
+
+ void setMulticastGroup(const PIString & mg) {mcast_address.setIP(mg);}
+ PIString multicastGroup() const {return mcast_address.ipString();}
+ void setMulticastPort(ushort port) {mcast_address.setPort(port);}
+ ushort multicastPort() const {return mcast_address.port();}
+ void setMulticastAddress(const PIEthernet::Address & addr) {mcast_address = addr;}
+ PIEthernet::Address multicastAddress() const {return mcast_address;}
+
+ void setBroadcastPort(ushort port) {bcast_port = port;}
+ ushort broadcastPort() {return bcast_port;}
+
+ void setLoopbackPort(ushort port) {lo_port = port;}
+ ushort loopbackPort() {return lo_port;}
+ void setLoopbackPortsCount(int count) {lo_pcnt = count;}
+ int loopbackPortsCount() const {return lo_pcnt;}
+
+ void startRead();
+ void stopRead();
+ void reinit();
+
+ void send(const PIByteArray & data);
+ EVENT1(receiveEvent, PIByteArray, data)
+
+protected:
+ virtual void received(PIByteArray data) {}
+
+private:
+ EVENT_HANDLER2(void, mcastRead, uchar * , data, int, size);
+ void destroyAll();
+ void initAll(PIVector al);
+ void run();
+
+ PIEthernet::Address mcast_address;
+ PIMutex mcast_mutex;
+ PIVector eth_mcast;
+ PIEthernet * eth_lo;
+ PIVector prev_al;
+ ushort lo_port, bcast_port;
+ int lo_pcnt;
+ bool _started, _send_only, _reinit;
+
+};
+
+#endif // PIMULTICAST_H
diff --git a/src_main/io_utils/pistreampacker.cpp b/src_main/io_utils/pistreampacker.cpp
new file mode 100644
index 00000000..b1c3d16f
--- /dev/null
+++ b/src_main/io_utils/pistreampacker.cpp
@@ -0,0 +1,94 @@
+/*
+ PIP - Platform Independent Primitives
+ Simple packet wrap aroud any PIIODevice
+ Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "pistreampacker.h"
+#include "piiodevice.h"
+
+
+PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
+ packet_size = -1;
+ max_packet_size = 1000;
+ packet_sign = 0xAFBE;
+ assignDevice(dev);
+}
+
+
+void PIStreamPacker::send(const PIByteArray &data) {
+ if (data.isEmpty()) return;
+ PIByteArray cd = cryptData(data);
+ //piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
+ PIByteArray hdr, part;
+ hdr << packet_sign << int(cd.size_s());
+ cd.insert(0, hdr);
+ int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
+ for (int i = 0; i < pcnt; ++i) {
+ if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
+ else part = PIByteArray(cd.data(pst), max_packet_size);
+ //piCout << "send" << part.size();
+ sendRequest(part);
+ pst += max_packet_size;
+ }
+}
+
+
+void PIStreamPacker::received(const PIByteArray & data) {
+ stream.append(data);
+ //piCout << "rec" << data.size();
+ while (stream.size_s() >= 4) {
+ if (packet_size < 0) {
+ ushort sign(0);
+ memcpy(&sign, stream.data(), 2);
+ if (sign != packet_sign) {
+ stream.pop_front();
+ continue;
+ }
+ int sz = -1;
+ memcpy(&sz, stream.data(2), 4);
+ if (sz < 0) {
+ stream.pop_front();
+ continue;
+ }
+ stream.remove(0, 6);
+ packet.clear();
+ packet_size = sz;
+ if (packet_size == 0)
+ packet_size = -1;
+ continue;
+ } else {
+ int ps = piMini(stream.size_s(), packet_size - packet.size_s());
+ packet.append(stream.data(), ps);
+ stream.remove(0, ps);
+ if (packet.size_s() == packet_size) {
+ PIByteArray cd = decryptData(packet);
+ //piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
+ if (!cd.isEmpty()) packetReceiveEvent(cd);
+ packet.clear();
+ packet_size = -1;
+ }
+ }
+ }
+}
+
+
+void PIStreamPacker::assignDevice(PIIODevice * dev) {
+ if (!dev) return;
+ CONNECTU(dev, threadedReadEvent, this, received);
+ CONNECTU(this, sendRequest, dev, write);
+}
+
diff --git a/src_main/io_utils/pistreampacker.h b/src_main/io_utils/pistreampacker.h
new file mode 100644
index 00000000..90fbdb50
--- /dev/null
+++ b/src_main/io_utils/pistreampacker.h
@@ -0,0 +1,60 @@
+/*! \file pistreampacker.h
+ * \brief Simple packet wrap aroud any PIIODevice
+*/
+/*
+ PIP - Platform Independent Primitives
+ Simple packet wrap aroud any PIIODevice
+ Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PISTREAMPACKER_H
+#define PISTREAMPACKER_H
+
+#include "piobject.h"
+#include "piethutilbase.h"
+
+
+class PIIODevice;
+
+class PIStreamPacker: public PIObject, public PIEthUtilBase {
+ PIOBJECT(PIStreamPacker)
+public:
+ PIStreamPacker(PIIODevice * dev = 0);
+
+ int maxPacketSize() {return max_packet_size;}
+ void setMaxPacketSize(int max_size) {max_packet_size = max_size;}
+
+ ushort packetSign() {return packet_sign;}
+ void setPacketSign(ushort sign_) {packet_sign = sign_;}
+
+ void send(const PIByteArray & data);
+ void received(const PIByteArray & data);
+ EVENT_HANDLER2(void, received, uchar * , readed, int, size) {received(PIByteArray(readed, size));}
+
+ void assignDevice(PIIODevice * dev);
+
+ EVENT1(packetReceiveEvent, PIByteArray, data)
+ EVENT1(sendRequest, PIByteArray, data)
+
+protected:
+ PIByteArray stream, packet;
+ int packet_size;
+ ushort packet_sign;
+ int max_packet_size;
+
+};
+
+#endif // PISTREAMPACKER_H