hlswmaster-ng/multisock.cpp

188 lines
3.6 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "logging.h"
#include "multisock.h"
#define DEFAULT_PORT 7130
#define DEVFILE "/proc/net/dev"
#define BUFSIZE 256
MultiSock::Socket::Socket()
{
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
LogSystem::log(LOG_CRIT, "Socket: socket()");
}
MultiSock::Socket::~Socket()
{
close(fd);
}
bool MultiSock::Socket::bindToDevice(const char* name)
{
strncpy(devname, name, sizeof(devname));
int ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, devname, sizeof(devname));
if (ret < 0) {
LogSystem::log(LOG_WARNING, "Socket: setsockopt(SO_BINDTODEVICE) %s", devname);
return false;
}
return true;
}
bool MultiSock::Socket::bindToPort(int port)
{
struct ifreq ifr;
strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFADDR, &ifr) != 0) {
LogSystem::log(LOG_WARNING, "Socket: ioctl(SIOCGIFADDR) %s", devname);
return false;
}
memcpy(&addr, &ifr.ifr_addr, sizeof(addr));
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LogSystem::log(LOG_WARNING, "Socket: bind() %s", devname);
return false;
}
int bcast = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) {
LogSystem::log(LOG_WARNING, "Socket: setsockopt(SO_BROADCAST) %s", devname);
return false;
}
return true;
}
int MultiSock::Socket::show(char* buf, int size)
{
return snprintf(buf, size, "%s (%s:%d) ", devname,
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
}
MultiSock::Socket* MultiSock::Socket::createSocket(const char* name, int port)
{
Socket* sock = new Socket();
if (sock->fd < 0) {
delete sock;
return NULL;
}
struct ifreq ifr;
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(sock->fd, SIOCGIFFLAGS, &ifr) != 0) {
LogSystem::log(LOG_WARNING, "Socket: ioctl(SIOCGIFFLAGS) %s", name);
delete sock;
return NULL;
}
if (!(ifr.ifr_flags & IFF_UP) || (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
delete sock;
return NULL;
}
sock->bindToDevice(name);
if (!sock->bindToPort(port)) {
delete sock;
return NULL;
}
return sock;
}
MultiSock::MultiSock(Config& conf)
{
char* buf = (char*)malloc(BUFSIZE);
if (buf == NULL) {
LogSystem::log(LOG_CRIT, "MultiSock(): out of memory");
return;
}
FILE* fp = fopen(DEVFILE, "r");
if (fp == NULL) {
LogSystem::log(LOG_CRIT, "MultiSock(): can not open " DEVFILE);
free(buf);
return;
}
fgets(buf, BUFSIZE, fp);
fgets(buf, BUFSIZE, fp);
int port = conf.getInteger("global", "scan_port", DEFAULT_PORT);
FD_ZERO(&fdsel);
while (fgets(buf, BUFSIZE, fp) != NULL) {
char* tok = strtok(buf, " :");
// TODO: check against config list
Socket* sock = Socket::createSocket(tok, port);
if (sock) {
FD_SET(sock->getFD(), &fdsel);
sock->show(buf, BUFSIZE);
LogSystem::log(LOG_NOTICE, "adding Interface %s", buf);
ifaceList.add(sock);
}
}
fclose(fp);
free(buf);
}
MultiSock::~MultiSock()
{
while (!ifaceList.isEmpty())
delete ifaceList.get();
}
int MultiSock::getRecvSocket()
{
fd_set fdcpy;
while (1) {
memcpy(&fdcpy, &fdsel, sizeof(fdcpy));
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL);
Iterator<Socket>* it = ifaceList.createIterator();
while (it->hasNext()) {
Socket* sock = it->next();
if (FD_ISSET(sock->getFD(), &fdcpy)) {
delete it;
return sock->getFD();
}
}
delete it;
LogSystem::log(LOG_ERROR, "getRecvSocket(): select()");
}
return -1;
}