638 lines
20 KiB
C++
638 lines
20 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
Ethernet, UDP/TCP Broadcast/Multicast
|
|
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "piethernet.h"
|
|
|
|
|
|
PIEthernet::PIEthernet(void * data, ReadRetFunc slot): PIIODevice("", ReadWrite) {
|
|
piMonitor.ethernets++;
|
|
setPriority(piHigh);
|
|
type_ = UDP;
|
|
ret_data_ = data;
|
|
ip_ = ip_s = "";
|
|
port_ = port_s = 0;
|
|
sock = sock_s = -1;
|
|
ret_func_ = slot;
|
|
connected_ = false;
|
|
params = PIEthernet::ReuseAddress;
|
|
server_thread_.setData(this);
|
|
setThreadedReadBufferSize(65536);
|
|
if (type_ != UDP) init();
|
|
}
|
|
|
|
|
|
PIEthernet::PIEthernet(PIEthernet::Type type, void * data, ReadRetFunc slot): PIIODevice("", ReadWrite) {
|
|
piMonitor.ethernets++;
|
|
setPriority(piHigh);
|
|
type_ = type;
|
|
ret_data_ = data;
|
|
ip_ = ip_s = "";
|
|
port_ = port_s = 0;
|
|
sock = sock_s = -1;
|
|
ret_func_ = slot;
|
|
connected_ = false;
|
|
params = (type == UDP ? PIEthernet::ReuseAddress : 0);
|
|
server_thread_.setData(this);
|
|
setThreadedReadBufferSize(65536);
|
|
if (type_ != UDP) init();
|
|
}
|
|
|
|
|
|
PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
|
piMonitor.ethernets++;
|
|
setPriority(piHigh);
|
|
type_ = TCP_Client;
|
|
path_ = ip_port;
|
|
parseAddress(ip_port, &ip_s, &port_s);
|
|
sock = sock_;
|
|
sock_s = -1;
|
|
server_thread_.setData(this);
|
|
params = PIEthernet::ReuseAddress;
|
|
init_ = opened_ = connected_ = true;
|
|
setThreadedReadBufferSize(65536);
|
|
}
|
|
|
|
|
|
PIEthernet::~PIEthernet() {
|
|
piMonitor.ethernets--;
|
|
if (server_thread_.isRunning()) server_thread_.terminate();
|
|
stop();
|
|
closeSocket(sock);
|
|
//if (buffer_ != 0) delete buffer_;
|
|
//buffer_ = 0;
|
|
}
|
|
|
|
|
|
bool PIEthernet::init() {
|
|
//cout << "init " << type_ << endl;
|
|
closeSocket(sock);
|
|
int st = 0, pr = 0;;
|
|
#ifdef WINDOWS
|
|
int flags = WSA_FLAG_OVERLAPPED;
|
|
#else
|
|
int so = 1;
|
|
#endif
|
|
if (type_ == UDP) {
|
|
st = SOCK_DGRAM;
|
|
pr = IPPROTO_UDP;
|
|
} else {
|
|
st = SOCK_STREAM;
|
|
pr = IPPROTO_TCP;
|
|
}
|
|
#ifdef WINDOWS
|
|
if (type_ == UDP) flags = WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;
|
|
sock = WSASocket(AF_INET, st, pr, NULL, 0, flags);
|
|
#else
|
|
sock = socket(AF_INET, st, pr);
|
|
#endif
|
|
if (sock == -1) {
|
|
piCoutObj << "[PIEthernet] Can`t create socket, " << ethErrorString();
|
|
return false;
|
|
}
|
|
#ifndef WINDOWS
|
|
if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so, sizeof(so));
|
|
if (params[PIEthernet::Broadcast]) setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so, sizeof(so));
|
|
#else
|
|
BOOL bv = TRUE;
|
|
if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char * )&bv, sizeof(bv));
|
|
#endif
|
|
//cout << "inited " << sock << ": bc = " << params << endl;
|
|
//fcntl(sock, F_SETFL, 0/*O_NONBLOCK*/);
|
|
return true;
|
|
}
|
|
|
|
|
|
void PIEthernet::parseAddress(const PIString & ipp, PIString * ip, int * port) {
|
|
if (ip != 0) *ip = ipp.left(ipp.find(":"));
|
|
if (port != 0) *port = ipp.right(ipp.length() - ipp.find(":") - 1).toInt();
|
|
}
|
|
|
|
|
|
bool PIEthernet::openDevice() {
|
|
if (connected_) return true;
|
|
init();
|
|
if (sock == -1 || path_.isEmpty()) return false;
|
|
parseAddress(path_, &ip_, &port_);
|
|
if (type_ != UDP)
|
|
return true;
|
|
//piCout << "bind to" << (params[PIEthernet::Broadcast] ? "bc" : ip_) << ":" << port_ << " ...";
|
|
memset(&addr_, 0, sizeof(addr_));
|
|
addr_.sin_family = AF_INET;
|
|
addr_.sin_port = htons(port_);
|
|
if (params[PIEthernet::Broadcast]) addr_.sin_addr.s_addr = INADDR_ANY;
|
|
else addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
|
#ifdef QNX
|
|
addr_.sin_len = sizeof(addr_);
|
|
#endif
|
|
int tries = 0;
|
|
while ((bind(sock, (sockaddr * )&addr_, sizeof(addr_)) == -1) && (tries < 10)) {
|
|
init();
|
|
tries++;
|
|
}
|
|
if (tries == 10) {
|
|
piCoutObj << "[PIEthernet] Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
|
return false;
|
|
}
|
|
opened_ = true;
|
|
while (!mcast_queue.isEmpty())
|
|
joinMulticastGroup(mcast_queue.dequeue());
|
|
//cout << "!" << endl;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PIEthernet::closeDevice() {
|
|
//cout << "close\n";
|
|
closeSocket(sock);
|
|
piForeach (PIEthernet * i, clients_)
|
|
delete i;
|
|
clients_.clear();
|
|
if (server_thread_.isRunning()) server_thread_.terminate();
|
|
if (connected_) disconnected(false);
|
|
connected_ = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
void PIEthernet::closeSocket(int & sd) {
|
|
if (sd != -1) {
|
|
#ifdef WINDOWS
|
|
shutdown(sd, SD_BOTH);
|
|
closesocket(sd);
|
|
#else
|
|
shutdown(sock, SHUT_RDWR);
|
|
::close(sd);
|
|
#endif
|
|
}
|
|
sd = -1;
|
|
}
|
|
|
|
|
|
bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
|
if (sock == -1) init();
|
|
if (sock == -1) return false;
|
|
if (type_ != UDP) {
|
|
piCoutObj << "[PIEthernet] Only UDP sockets can join multicast groups";
|
|
return false;
|
|
}
|
|
if (!opened_) {
|
|
if (mcast_queue.has(group))
|
|
return false;
|
|
mcast_queue.enqueue(group);
|
|
return true;
|
|
}
|
|
#ifdef WINDOWS
|
|
parseAddress(path_, &ip_, &port_);
|
|
memset(&addr_, 0, sizeof(addr_));
|
|
addr_.sin_family = AF_INET;
|
|
addr_.sin_addr.s_addr = inet_addr(group.data());
|
|
//int so = 1;
|
|
//setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char * )&so, sizeof(so));
|
|
SOCKET ret = WSAJoinLeaf(sock, (sockaddr *)&addr_, sizeof(addr_), NULL, NULL, NULL, NULL, JL_BOTH);
|
|
if (ret == INVALID_SOCKET) {
|
|
piCoutObj << "[PIEthernet] Can`t join multicast group " << group << ", " << ethErrorString();
|
|
return false;
|
|
}
|
|
if (ret != sock) leafs.insert(group, ret);
|
|
#else
|
|
# ifndef QNX
|
|
if (!params[Broadcast])
|
|
piCoutObj << "[PIEthernet] Warning: \"Broadcast\" parameter not set, \"joinMulticastGroup(\"" << group << "\")\" may be useless!";
|
|
parseAddress(path_, &ip_, &port_);
|
|
struct ip_mreqn mreq;
|
|
memset(&mreq, 0, sizeof(mreq));
|
|
mreq.imr_ifindex = 0;
|
|
if (params[PIEthernet::Broadcast]) mreq.imr_address.s_addr = INADDR_ANY;
|
|
else mreq.imr_address.s_addr = inet_addr(ip_.data());
|
|
PIEthernet::InterfaceList il = interfaces();
|
|
const PIEthernet::Interface * ci = il.getByAddress(ip_);
|
|
if (ci != 0) mreq.imr_ifindex = ci->index;
|
|
//piCout << "join group" << group << "ip" << ip_ << "with index" << mreq.imr_ifindex;
|
|
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
|
|
int so = 1;
|
|
//setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so, sizeof(so));
|
|
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &so, sizeof(so));
|
|
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq));
|
|
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) {
|
|
piCoutObj << "[PIEthernet] Can`t join multicast group " << group << ", " << ethErrorString();
|
|
return false;
|
|
}
|
|
# endif
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PIEthernet::leaveMulticastGroup(const PIString & group) {
|
|
if (sock == -1) init();
|
|
if (sock == -1) return false;
|
|
if (type_ != UDP) {
|
|
piCoutObj << "[PIEthernet] Only UDP sockets can leave multicast groups";
|
|
return false;
|
|
}
|
|
#ifdef WINDOWS
|
|
SOCKET s = leafs[group];
|
|
if (s != SOCKET()) {
|
|
leafs.erase(group);
|
|
closesocket(s);
|
|
}
|
|
#else
|
|
# ifndef QNX
|
|
parseAddress(path_, &ip_, &port_);
|
|
struct ip_mreqn mreq;
|
|
memset(&mreq, 0, sizeof(mreq));
|
|
if (params[PIEthernet::Broadcast]) mreq.imr_address.s_addr = INADDR_ANY;
|
|
else mreq.imr_address.s_addr = inet_addr(ip_.data());
|
|
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
|
|
mreq.imr_ifindex = 0;
|
|
if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
|
|
piCoutObj << "[PIEthernet] Can`t leave multicast group " << group << ", " << ethErrorString();
|
|
return false;
|
|
}
|
|
#endif
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PIEthernet::connect() {
|
|
if (sock == -1) return false;
|
|
memset(&addr_, 0, sizeof(addr_));
|
|
parseAddress(path_, &ip_, &port_);
|
|
addr_.sin_port = htons(port_);
|
|
addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
|
addr_.sin_family = AF_INET;
|
|
#ifdef QNX
|
|
addr_.sin_len = sizeof(addr_);
|
|
#endif
|
|
//piCoutObj << "[PIEthernet] connect to " << ip << ":" << port_;
|
|
connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0);
|
|
if (!connected_)
|
|
piCoutObj << "[PIEthernet] Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
|
opened_ = connected_;
|
|
if (connected_) connected();
|
|
return connected_;
|
|
}
|
|
|
|
|
|
bool PIEthernet::listen() {
|
|
if (sock == -1) init();
|
|
if (sock == -1) return false;
|
|
parseAddress(path_, &ip_, &port_);
|
|
memset(&addr_, 0, sizeof(addr_));
|
|
addr_.sin_port = htons(port_);
|
|
addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
|
addr_.sin_family = AF_INET;
|
|
#ifdef QNX
|
|
addr_.sin_len = sizeof(addr_);
|
|
#endif
|
|
int tries = 0;
|
|
while ((bind(sock, (sockaddr * )&addr_, sizeof(addr_)) == -1) && (tries < 10)) {
|
|
init();
|
|
tries++;
|
|
}
|
|
if (tries == 10) {
|
|
piCoutObj << "[PIEthernet] Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
|
return false;
|
|
}
|
|
if (::listen(sock, 64) == -1) {
|
|
piCoutObj << "[PIEthernet] Can`t listen on "<< ip_ << ":" << port_ << ", " << ethErrorString();
|
|
return false;
|
|
}
|
|
//piCoutObj << "[PIEthernet] listen on " << ip_ << ":" << port_;
|
|
server_thread_.start(server_func);
|
|
return true;
|
|
}
|
|
|
|
|
|
int PIEthernet::read(void * read_to, int max_size) {
|
|
//cout << "read " << sock << endl;
|
|
if (sock == -1) init();
|
|
if (sock == -1 || read_to == 0) return -1;
|
|
int rs = 0, s = 0;
|
|
sockaddr_in client_addr;
|
|
socklen_t slen = sizeof(client_addr);
|
|
//piCoutObj << "[PIEthernet] read from " << ip_ << ":" << port_ << endl;
|
|
switch (type_) {
|
|
case TCP_SingleTCP:
|
|
::listen(sock, 64);
|
|
s = accept(sock, (sockaddr * )&client_addr, &slen);
|
|
if (s == -1) {
|
|
//piCoutObj << "[PIEthernet] Can`t accept new connection, " << ethErrorString();
|
|
msleep(1);
|
|
return -1;
|
|
}
|
|
rs = recv(s, (char * )read_to, max_size, 0);
|
|
closeSocket(s);
|
|
return rs;
|
|
case TCP_Client:
|
|
if (!connected_) return -1;
|
|
case UDP:
|
|
#ifdef WINDOWS
|
|
rs = recv(sock, (char * )read_to, max_size, 0);
|
|
#else
|
|
rs = recv(sock, read_to, max_size, 0);
|
|
#endif
|
|
//piCout << "eth" << path_ << "read return" << rs << errno;
|
|
if (rs <= 0 && type_ == TCP_Client) {
|
|
connected_ = false;
|
|
disconnected(rs < 0);
|
|
//piCoutObj << "eth" << path_ << "disconnected";
|
|
}
|
|
if (rs > 0) received(read_to, rs);
|
|
return rs;
|
|
//return ::read(sock, read_to, max_size);
|
|
default: break;
|
|
//return ::read(sock, (char * )read_to, max_size);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int PIEthernet::write(const void * data, int max_size) {
|
|
if (sock == -1) init();
|
|
if (sock == -1 || !isWriteable()) {
|
|
//piCoutObj << "[PIEthernet] Can`t send to uninitialized socket";
|
|
return -1;
|
|
}
|
|
//piCoutObj << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
|
|
int ret = 0;
|
|
switch (type_) {
|
|
case TCP_SingleTCP:
|
|
memset(&addr_, 0, sizeof(addr_));
|
|
addr_.sin_port = htons(port_s);
|
|
addr_.sin_addr.s_addr = inet_addr(ip_s.data());
|
|
addr_.sin_family = AF_INET;
|
|
#ifdef QNX
|
|
addr_.sin_len = sizeof(addr_);
|
|
#endif
|
|
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
|
|
if (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) != 0) {
|
|
//piCoutObj << "[PIEthernet] Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
|
|
msleep(1);
|
|
return -1;
|
|
}
|
|
//piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
|
|
ret = ::send(sock, (const char *)data, max_size, 0);
|
|
//piCoutObj << "ok, ret" << ret;
|
|
closeSocket(sock);
|
|
init();
|
|
return ret;
|
|
case UDP:
|
|
saddr_.sin_port = htons(port_s);
|
|
/*if (params[PIEthernet::Broadcast]) saddr_.sin_addr.s_addr = INADDR_BROADCAST;
|
|
else*/ saddr_.sin_addr.s_addr = inet_addr(ip_s.data());
|
|
saddr_.sin_family = AF_INET;
|
|
//piCout << "[PIEth] write to" << ip_s << ":" << port_s << max_size << "bytes ...";
|
|
#ifdef WINDOWS
|
|
return sendto(sock, (const char * )data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_));
|
|
#else
|
|
return sendto(sock, data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_));
|
|
#endif
|
|
//piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok";
|
|
case TCP_Client:
|
|
return ::send(sock, (const char *)data, max_size, 0);
|
|
default: break;
|
|
//return ::read(sock, read_to, max_size);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void PIEthernet::server_func(void * eth) {
|
|
PIEthernet * ce = (PIEthernet * )eth;
|
|
sockaddr_in client_addr;
|
|
socklen_t slen = sizeof(client_addr);
|
|
int s = accept(ce->sock, (sockaddr * )&client_addr, &slen);
|
|
if (s == -1) {
|
|
if (ce->debug_) piCout << "[PIEthernet] Can`t accept new connection, " << ethErrorString();
|
|
return;
|
|
}
|
|
PIString ip(inet_ntoa(client_addr.sin_addr));
|
|
ip += ":" + PIString::fromNumber(htons(client_addr.sin_port));
|
|
ce->clients_ << new PIEthernet(s, ip);
|
|
ce->newConnection(ce->clients_.back());
|
|
//cout << "connected " << ip << endl;
|
|
//char d[256];
|
|
//cout << " recv " << recv(s, d, 256, 0) << endl;
|
|
//cout << recv(ce->clients_.back()->sock, d, 256, 0) << endl;
|
|
|
|
}
|
|
|
|
|
|
PIEthernet::InterfaceList PIEthernet::interfaces() {
|
|
#ifdef WINDOWS
|
|
PIEthernet::InterfaceList il;
|
|
Interface ci;
|
|
PIP_ADAPTER_INFO pAdapterInfo, pAdapter = 0;
|
|
int ret = 0;
|
|
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
|
pAdapterInfo = (IP_ADAPTER_INFO * ) HeapAlloc(GetProcessHeap(), 0, (sizeof (IP_ADAPTER_INFO)));
|
|
if (pAdapterInfo == 0) {
|
|
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
|
return il;
|
|
}
|
|
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
|
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
|
pAdapterInfo = (IP_ADAPTER_INFO *) HeapAlloc(GetProcessHeap(), 0, (ulOutBufLen));
|
|
if (pAdapterInfo == 0) {
|
|
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
|
return il;
|
|
}
|
|
}
|
|
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
|
pAdapter = pAdapterInfo;
|
|
while (pAdapter) {
|
|
ci.name = PIString(pAdapter->AdapterName);
|
|
ci.index = pAdapter->Index;
|
|
ci.address = PIString(pAdapter->IpAddressList.IpAddress.String);
|
|
if (ci.address == "0.0.0.0") {
|
|
pAdapter = pAdapter->Next;
|
|
continue;
|
|
}
|
|
ci.mac = macFromBytes(PIByteArray(pAdapter->Address, pAdapter->AddressLength));
|
|
ci.netmask = PIString(pAdapter->IpAddressList.IpMask.String);
|
|
ci.flags = PIEthernet::ifActive | PIEthernet::ifRunning;
|
|
//if (ret->ifa_flags & IFF_BROADCAST) ci.flags |= PIEthernet::ifBroadcast;
|
|
//if (ret->ifa_flags & IFF_MULTICAST) ci.flags |= PIEthernet::ifMulticast;
|
|
if (pAdapter->Type == MIB_IF_TYPE_PPP) ci.flags |= PIEthernet::ifPTP;
|
|
if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
|
|
ci.broadcast.clear();
|
|
ci.ptp.clear();
|
|
/*if (ci.flags[PIEthernet::ifBroadcast])
|
|
ci.broadcast = getSockAddr(ret->ifa_broadaddr);
|
|
if (ci.flags[PIEthernet::ifPTP])
|
|
ci.ptp = getSockAddr(ret->ifa_dstaddr);*/
|
|
il << ci;
|
|
pAdapter = pAdapter->Next;
|
|
}
|
|
} else
|
|
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret;
|
|
if (pAdapterInfo)
|
|
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
|
return il;
|
|
#else
|
|
/*# ifdef QNX
|
|
PIStringList il, sl;
|
|
PIProcess proc;
|
|
proc.setGrabOutput(true);
|
|
proc.exec(ifconfigPath.c_str(), "-l");
|
|
if (!proc.waitForFinish(1000)) return sl;
|
|
PIString out(proc.readOutput());
|
|
il = out.split(" ");
|
|
il.removeAll("");
|
|
piForeachC (PIString & i, il) {
|
|
proc.exec(ifconfigPath.c_str(), i);
|
|
if (!proc.waitForFinish(1000)) return il;
|
|
sl << i.trimmed();
|
|
out = proc.readOutput();
|
|
int al = out.length();
|
|
al = (al - out.replaceAll("alias", "").length()) / 5;
|
|
for (int j = 0; j < al; ++j)
|
|
sl << i.trimmed() + ":" + PIString::fromNumber(j);
|
|
}
|
|
return sl;
|
|
# else
|
|
PIStringList sl;
|
|
PIProcess proc;
|
|
proc.setGrabOutput(true);
|
|
proc.exec(ifconfigPath.c_str(), "-s");
|
|
if (!proc.waitForFinish(1000)) return sl;
|
|
PIString out(proc.readOutput());
|
|
out.cutLeft(out.find('\n') + 1);
|
|
while (!out.isEmpty()) {
|
|
sl << out.left(out.find(' '));
|
|
out.cutLeft(out.find('\n') + 1);
|
|
}
|
|
return sl;
|
|
# endif*/
|
|
PIEthernet::InterfaceList il;
|
|
Interface ci;
|
|
struct ifaddrs * ret;
|
|
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
|
if (getifaddrs(&ret) == 0) {
|
|
while (ret != 0) {
|
|
if (ret->ifa_addr->sa_family != AF_INET) {
|
|
ret = ret->ifa_next;
|
|
continue;
|
|
}
|
|
ci.name = PIString(ret->ifa_name);
|
|
ci.address = getSockAddr(ret->ifa_addr);
|
|
ci.netmask = getSockAddr(ret->ifa_netmask);
|
|
ci.mac.clear();
|
|
#ifdef QNX
|
|
int fd = ::open((PIString("/dev/io-net/") + ci.name).data(), O_RDONLY);
|
|
if (fd != 0) {
|
|
nic_config_t nic;
|
|
devctl(fd, DCMD_IO_NET_GET_CONFIG, &nic, sizeof(nic), 0);
|
|
::close(fd);
|
|
ci.mac = macFromBytes(PIByteArray(nic.permanent_address, 6));
|
|
}
|
|
#else
|
|
if (s != -1) {
|
|
struct ifreq ir;
|
|
strcpy(ir.ifr_name, ret->ifa_name);
|
|
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0)
|
|
ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
|
|
}
|
|
#endif
|
|
ci.flags = 0;
|
|
if (ret->ifa_flags & IFF_UP) ci.flags |= PIEthernet::ifActive;
|
|
if (ret->ifa_flags & IFF_RUNNING) ci.flags |= PIEthernet::ifRunning;
|
|
if (ret->ifa_flags & IFF_BROADCAST) ci.flags |= PIEthernet::ifBroadcast;
|
|
if (ret->ifa_flags & IFF_MULTICAST) ci.flags |= PIEthernet::ifMulticast;
|
|
if (ret->ifa_flags & IFF_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
|
|
if (ret->ifa_flags & IFF_POINTOPOINT) ci.flags |= PIEthernet::ifPTP;
|
|
ci.broadcast.clear();
|
|
ci.ptp.clear();
|
|
if (ci.flags[PIEthernet::ifBroadcast])
|
|
ci.broadcast = getSockAddr(ret->ifa_broadaddr);
|
|
if (ci.flags[PIEthernet::ifPTP])
|
|
ci.ptp = getSockAddr(ret->ifa_dstaddr);
|
|
ci.index = if_nametoindex(ret->ifa_name);
|
|
il << ci;
|
|
ret = ret->ifa_next;
|
|
}
|
|
freeifaddrs(ret);
|
|
} else
|
|
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
|
|
if (s != -1) ::close(s);
|
|
return il;
|
|
#endif
|
|
}
|
|
|
|
|
|
PIString PIEthernet::interfaceAddress(const PIString & interface_) {
|
|
#ifdef WINDOWS
|
|
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" or \"PIEthernet::interfaces\" instead";
|
|
return PIString();
|
|
#else
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strcpy(ifr.ifr_name, interface_.data());
|
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
ioctl(s, SIOCGIFADDR, &ifr);
|
|
::close(s);
|
|
struct sockaddr_in * sa = (struct sockaddr_in * )&ifr.ifr_addr;
|
|
return PIString(inet_ntoa(sa->sin_addr));
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
PIStringList PIEthernet::allAddresses() {
|
|
/*#ifdef WINDOWS
|
|
PIStringList al;
|
|
PIString ca;
|
|
PIP_ADAPTER_INFO pAdapterInfo, pAdapter = 0;
|
|
int ret = 0;
|
|
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
|
pAdapterInfo = (IP_ADAPTER_INFO * ) HeapAlloc(GetProcessHeap(), 0, (sizeof (IP_ADAPTER_INFO)));
|
|
if (pAdapterInfo == 0) {
|
|
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
|
return PIStringList();
|
|
}
|
|
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
|
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
|
pAdapterInfo = (IP_ADAPTER_INFO *) HeapAlloc(GetProcessHeap(), 0, (ulOutBufLen));
|
|
if (pAdapterInfo == 0) {
|
|
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
|
return PIStringList();
|
|
}
|
|
}
|
|
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
|
pAdapter = pAdapterInfo;
|
|
while (pAdapter) {
|
|
ca = PIString(pAdapter->IpAddressList.IpAddress.String);
|
|
if (ca != "0.0.0.0") al << ca;
|
|
pAdapter = pAdapter->Next;
|
|
}
|
|
} else
|
|
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret;
|
|
if (pAdapterInfo)
|
|
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
|
return al;
|
|
#else*/
|
|
PIEthernet::InterfaceList il = interfaces();
|
|
PIStringList al;
|
|
piForeachC (PIEthernet::Interface & i, il)
|
|
al << i.address;
|
|
return al.removeStrings("0.0.0.0");
|
|
//#endif
|
|
}
|