different modes for UDP writer, allow to select network
This commit is contained in:
parent
490a5b9ba1
commit
a5827e24d8
|
@ -17,4 +17,9 @@ class GwSocketHelper{
|
|||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) != ESP_OK) return false;
|
||||
return true;
|
||||
}
|
||||
static bool isMulticast(const String &addr){
|
||||
in_addr iaddr;
|
||||
if (inet_pton(AF_INET,addr.c_str(),&iaddr) != 1) return false;
|
||||
return IN_MULTICAST(ntohl(iaddr.s_addr));
|
||||
}
|
||||
};
|
|
@ -4,36 +4,175 @@
|
|||
#include "GwBuffer.h"
|
||||
#include "GwSocketConnection.h"
|
||||
#include "GwSocketHelper.h"
|
||||
#include "GWWifi.h"
|
||||
|
||||
GwUdpWriter::WriterSocket::WriterSocket(GwLog *l,int p,const String &src,const String &dst, SourceMode sm) :
|
||||
sourceMode(sm), source(src), destination(dst), port(p),logger(l)
|
||||
{
|
||||
if (inet_pton(AF_INET, dst.c_str(), &dstA.sin_addr) != 1)
|
||||
{
|
||||
LOG_ERROR("UDPW: invalid destination ip address %s", dst.c_str());
|
||||
return;
|
||||
}
|
||||
if (sourceMode != SourceMode::S_UNBOUND)
|
||||
{
|
||||
if (inet_pton(AF_INET, src.c_str(), &srcA) != 1)
|
||||
{
|
||||
LOG_ERROR("UDPW: invalid source ip address %s", src.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
dstA.sin_family=AF_INET;
|
||||
dstA.sin_port=htons(port);
|
||||
fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
|
||||
if (fd < 0){
|
||||
LOG_ERROR("UDPW: unable to create udp socket: %d",errno);
|
||||
return;
|
||||
}
|
||||
int enable = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int));
|
||||
switch (sourceMode)
|
||||
{
|
||||
case SourceMode::S_SRC:
|
||||
{
|
||||
sockaddr_in bindA;
|
||||
bindA.sin_family = AF_INET;
|
||||
bindA.sin_port = htons(0); // let system select
|
||||
bindA.sin_addr = srcA;
|
||||
if (bind(fd, (struct sockaddr *)&bindA, sizeof(bindA)) != 0)
|
||||
{
|
||||
LOG_ERROR("UDPW: bind failed for address %s: %d", source.c_str(), errno);
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SourceMode::S_MC:
|
||||
{
|
||||
if (setsockopt(fd,IPPROTO_IP,IP_MULTICAST_IF,&srcA,sizeof(srcA)) != 0){
|
||||
LOG_ERROR("UDPW: unable to set MC source %s: %d",source.c_str(),errno);
|
||||
::close(fd);
|
||||
fd=-1;
|
||||
return;
|
||||
}
|
||||
int loop=0;
|
||||
setsockopt(fd,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//not bound
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool GwUdpWriter::WriterSocket::changed(const String &newSrc, const String &newDst){
|
||||
if (newDst != destination) return true;
|
||||
if (sourceMode == SourceMode::S_UNBOUND) return false;
|
||||
return newSrc != source;
|
||||
}
|
||||
size_t GwUdpWriter::WriterSocket::send(const char *buf,size_t len){
|
||||
if (fd < 0) return 0;
|
||||
ssize_t err = sendto(fd,buf,len,0,(struct sockaddr *)&dstA, sizeof(dstA));
|
||||
if (err < 0){
|
||||
LOG_DEBUG(GwLog::DEBUG,"UDPW %s error sending: %d",destination.c_str(), errno);
|
||||
return 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
GwUdpWriter::GwUdpWriter(const GwConfigHandler *config, GwLog *logger, int minId)
|
||||
{
|
||||
this->config = config;
|
||||
this->logger = logger;
|
||||
this->minId = minId;
|
||||
port=config->getInt(GwConfigDefinitions::udpwPort);
|
||||
|
||||
}
|
||||
void GwUdpWriter::checkStaSocket(){
|
||||
String src;
|
||||
String bc;
|
||||
if (type == T_BCAP || type == T_MCAP || type == T_NORM || type == T_UNKNOWN ) return;
|
||||
bool connected=false;
|
||||
if (WiFi.isConnected()){
|
||||
src=WiFi.localIP().toString();
|
||||
bc=WiFi.broadcastIP().toString();
|
||||
connected=true;
|
||||
}
|
||||
else{
|
||||
if (staSocket == nullptr) return;
|
||||
}
|
||||
String dst;
|
||||
WriterSocket::SourceMode sm=WriterSocket::SourceMode::S_SRC;
|
||||
switch (type){
|
||||
case T_BCALL:
|
||||
case T_BCSTA:
|
||||
sm=WriterSocket::SourceMode::S_SRC;
|
||||
dst=bc;
|
||||
break;
|
||||
case T_MCALL:
|
||||
case T_MCSTA:
|
||||
dst=config->getString(GwConfigDefinitions::udpwMC);
|
||||
sm=WriterSocket::SourceMode::S_MC;
|
||||
break;
|
||||
|
||||
}
|
||||
if (staSocket != nullptr)
|
||||
{
|
||||
if (!connected || staSocket->changed(src, dst))
|
||||
{
|
||||
staSocket->close();
|
||||
delete staSocket;
|
||||
staSocket = nullptr;
|
||||
LOG_INFO("changing/stopping UDPW(sta) socket");
|
||||
}
|
||||
}
|
||||
if (staSocket == nullptr && connected)
|
||||
{
|
||||
LOG_INFO("creating new UDP(sta) socket src=%s, dst=%s", src.c_str(), dst.c_str());
|
||||
staSocket = new WriterSocket(logger, port, src, dst, WriterSocket::SourceMode::S_SRC);
|
||||
}
|
||||
}
|
||||
|
||||
void GwUdpWriter::begin()
|
||||
{
|
||||
fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
|
||||
if (fd < 0){
|
||||
LOG_ERROR("unable to create udp socket");
|
||||
return;
|
||||
if (type != T_UNKNOWN) return; //already started
|
||||
type=(UType)(config->getInt(GwConfigDefinitions::udpwType));
|
||||
LOG_INFO("UDPW begin, mode=%d",(int)type);
|
||||
String src=WiFi.softAPIP().toString();
|
||||
String dst;
|
||||
WriterSocket::SourceMode sm=WriterSocket::SourceMode::S_UNBOUND;
|
||||
bool createApSocket=false;
|
||||
switch(type){
|
||||
case T_BCALL:
|
||||
case T_BCAP:
|
||||
createApSocket=true;
|
||||
dst=WiFi.softAPBroadcastIP().toString();
|
||||
sm=WriterSocket::SourceMode::S_SRC;
|
||||
break;
|
||||
case T_MCALL:
|
||||
case T_MCAP:
|
||||
createApSocket=true;
|
||||
dst=config->getString(GwConfigDefinitions::udpwMC);
|
||||
sm=WriterSocket::SourceMode::S_SRC;
|
||||
break;
|
||||
case T_NORM:
|
||||
createApSocket=true;
|
||||
dst=config->getString(GwConfigDefinitions::udpwAddress);
|
||||
sm=WriterSocket::SourceMode::S_UNBOUND;
|
||||
}
|
||||
int enable = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int));
|
||||
port=config->getInt(GwConfigDefinitions::udpwPort);
|
||||
//TODO: check port
|
||||
address=config->getString(GwConfigDefinitions::udpwAddress);
|
||||
LOG_INFO("UDP writer created, address=%s, port=%d",
|
||||
address.c_str(),port);
|
||||
inet_pton(AF_INET, address.c_str(), &destination.sin_addr);
|
||||
destination.sin_family = AF_INET;
|
||||
destination.sin_port = htons(port);
|
||||
if (createApSocket){
|
||||
LOG_INFO("creating new UDPW(ap) socket src=%s, dst=%s", src.c_str(), dst.c_str());
|
||||
apSocket=new WriterSocket(logger,port,src,dst,sm);
|
||||
}
|
||||
checkStaSocket();
|
||||
}
|
||||
|
||||
void GwUdpWriter::loop(bool handleRead, bool handleWrite)
|
||||
{
|
||||
if (handleWrite){
|
||||
checkStaSocket();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -45,12 +184,17 @@ size_t GwUdpWriter::sendToClients(const char *buf, int source,bool partial)
|
|||
{
|
||||
if (source == minId) return 0;
|
||||
size_t len=strlen(buf);
|
||||
ssize_t err = sendto(fd,buf,len,0,(struct sockaddr *)&destination, sizeof(destination));
|
||||
if (err < 0){
|
||||
LOG_DEBUG(GwLog::DEBUG,"UDP writer error sending: %d",errno);
|
||||
return 0;
|
||||
bool hasSent=false;
|
||||
size_t res=0;
|
||||
if (apSocket != nullptr){
|
||||
res=apSocket->send(buf,len);
|
||||
if (res > 0) hasSent=true;
|
||||
}
|
||||
return err;
|
||||
if (staSocket != nullptr){
|
||||
res=staSocket->send(buf,len);
|
||||
if (res > 0) hasSent=true;
|
||||
}
|
||||
return hasSent?len:0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,14 +9,59 @@
|
|||
#include <arpa/inet.h>
|
||||
|
||||
class GwUdpWriter: public GwChannelInterface{
|
||||
public:
|
||||
using UType=enum{
|
||||
T_BCALL=0,
|
||||
T_BCAP=1,
|
||||
T_BCSTA=2,
|
||||
T_NORM=3,
|
||||
T_MCALL=4,
|
||||
T_MCAP=5,
|
||||
T_MCSTA=6,
|
||||
T_UNKNOWN=-1
|
||||
};
|
||||
private:
|
||||
class WriterSocket{
|
||||
public:
|
||||
int fd=-1;
|
||||
struct in_addr srcA;
|
||||
struct sockaddr_in dstA;
|
||||
String source;
|
||||
String destination;
|
||||
int port;
|
||||
GwLog *logger;
|
||||
using SourceMode=enum {
|
||||
S_UNBOUND=0,
|
||||
S_MC,
|
||||
S_SRC
|
||||
};
|
||||
SourceMode sourceMode;
|
||||
WriterSocket(GwLog *logger,int p,const String &src,const String &dst, SourceMode sm);
|
||||
void close(){
|
||||
if (fd > 0){
|
||||
::close(fd);
|
||||
}
|
||||
fd=-1;
|
||||
}
|
||||
~WriterSocket(){
|
||||
close();
|
||||
}
|
||||
bool changed(const String &newSrc, const String &newDst);
|
||||
size_t send(const char *buf,size_t len);
|
||||
};
|
||||
const GwConfigHandler *config;
|
||||
GwLog *logger;
|
||||
int fd=-1;
|
||||
/**
|
||||
* we use fd/address to send to the AP network
|
||||
* and fd2,address2 to send to the station network
|
||||
* for type "normal" we only use fd
|
||||
*/
|
||||
WriterSocket *apSocket=nullptr; //also for T_NORM
|
||||
WriterSocket *staSocket=nullptr;
|
||||
int minId;
|
||||
int port;
|
||||
String address;
|
||||
struct sockaddr_in destination;
|
||||
UType type=T_UNKNOWN;
|
||||
void checkStaSocket();
|
||||
public:
|
||||
GwUdpWriter(const GwConfigHandler *config,GwLog *logger,int minId);
|
||||
~GwUdpWriter();
|
||||
|
|
|
@ -842,6 +842,23 @@
|
|||
"description": "the UDP port we send to",
|
||||
"category": "UDP writer"
|
||||
},
|
||||
{
|
||||
"name": "udpwType",
|
||||
"label": "remote address type",
|
||||
"type": "list",
|
||||
"default": "0",
|
||||
"description": "to which networks/addresses do we send\nbc-all: send broadcast to AP and wifi client network\nbc-ap: send broadcast to access point only\nbc-cli: send broadcast to wifi client network\nnormal: normal target address\nmc-all: multicast to AP and wifi client network\nmc-ap:multicast to AP network\nmc-cli: muticast to wifi client network",
|
||||
"list":[
|
||||
{"l":"bc-all","v":"0"},
|
||||
{"l":"bc-ap","v":"1"},
|
||||
{"l":"bc-cli","v":"2"},
|
||||
{"l":"normal","v":"3"},
|
||||
{"l":"mc-all","v":"4"},
|
||||
{"l":"mc-ap","v":"5"},
|
||||
{"l":"mc-cli","v":"6"}
|
||||
],
|
||||
"category": "UDP writer"
|
||||
},
|
||||
{
|
||||
"name": "udpwAddress",
|
||||
"label": "remote address",
|
||||
|
@ -849,7 +866,22 @@
|
|||
"default": "",
|
||||
"check": "checkIpAddress",
|
||||
"description": "the IP address we connect to in the form 192.168.1.2",
|
||||
"category": "UDP writer"
|
||||
"category": "UDP writer",
|
||||
"condition":{
|
||||
"udpwType":["3"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "udpwMC",
|
||||
"label": "multicast address",
|
||||
"type": "string",
|
||||
"default": "224.0.0.1",
|
||||
"check": "checkMCAddress",
|
||||
"description": "the multicast address we send to 224.0.0.0...239.255.255.255",
|
||||
"category": "UDP writer",
|
||||
"condition":{
|
||||
"udpwType":["4","5","6"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "udpwWriteFilter",
|
||||
|
|
Loading…
Reference in New Issue