/* 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(); }