/* PIP - Platform Independent Primitives Ethernet, UDP/TCP Broadcast/Multicast Copyright (C) 2014 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 . */ #include "piethernet.h" #include "piconfig.h" #ifdef QNX # include # include # include #endif /** \class PIEthernet * \brief Ethernet device * \details * \section PIEthernet_sec0 Synopsis * %PIEthernet designed to work with IPv4 network by two protocols: * UDP and TCP. This class allow you send and receive packets to/from * another computer through network. * * \section PIEthernet_sec1 IPv4 * * * \section PIEthernet_sec2 UDP * User Datagram Protocol * * \section PIEthernet_sec3 TCP * Transmission Control Protocol * * */ REGISTER_DEVICE(PIEthernet); PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) { piMonitor.ethernets++; ip_ = ip_s = ""; port_ = port_s = 0; sock = sock_s = -1; connected_ = connecting_ = false; server_thread_.setData(this); setThreadedReadBufferSize(65536); setPriority(piHigh); setType(UDP); setParameters(PIEthernet::ReuseAddress); //if (type_ != UDP) init(); } PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const PIFlags params_): PIIODevice(ip_port, ReadWrite) { piMonitor.ethernets++; parseAddress(ip_port, &ip_, &port_); ip_s = ""; port_s = 0; sock = sock_s = -1; connected_ = connecting_ = false; server_thread_.setData(this); setThreadedReadBufferSize(65536); setPriority(piHigh); setType(type_); setParameters(params_); if (type_ != UDP) init(); } PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) { piMonitor.ethernets++; parseAddress(ip_port, &ip_s, &port_s); sock = sock_; sock_s = -1; init_ = opened_ = connected_ = true; connecting_ = false; server_thread_.setData(this); setParameters(PIEthernet::ReuseAddress); setThreadedReadBufferSize(65536); setPriority(piHigh); setType(TCP_Client, false); setPath(ip_port); } PIEthernet::~PIEthernet() { piMonitor.ethernets--; if (server_thread_.isRunning()) server_thread_.terminate(); stop(); closeSocket(sock); closeSocket(sock_s); //if (buffer_ != 0) delete buffer_; //buffer_ = 0; } bool PIEthernet::init() { //cout << "init " << type_ << endl; closeSocket(sock); closeSocket(sock_s); 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); sock_s = WSASocket(AF_INET, st, pr, NULL, 0, WSA_FLAG_OVERLAPPED); #else sock = socket(AF_INET, st, pr); sock_s = socket(AF_INET, st, pr); #endif if (sock == -1 || sock_s == -1) { piCoutObj << "Can`t create socket, " << ethErrorString(); return false; } PIFlags params = parameters(); #ifndef WINDOWS timeval to; to.tv_sec = 10; to.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to)); 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 && mode() == PIIODevice::WriteOnly) 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_); PIFlags params = parameters(); 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 << "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); closeSocket(sock_s); 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(sd, SHUT_RDWR); ::close(sd); #endif } sd = -1; } void PIEthernet::setParameter(PIEthernet::Parameters parameter, bool on) { PIFlags cp = (PIFlags)(property("parameters").toInt()); cp.setFlag(parameter, on); setParameters(cp); } bool PIEthernet::joinMulticastGroup(const PIString & group) { if (sock == -1) init(); if (sock == -1) return false; if (type() != UDP) { piCoutObj << "Only UDP sockets can join multicast groups"; return false; } if (!opened_) { if (mcast_queue.contains(group)) return false; mcast_queue.enqueue(group); if (!mcast_groups.contains(group)) mcast_groups << group; return true; } PIFlags params = parameters(); #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 << "Can`t join multicast group " << group << ", " << ethErrorString(); return false; } if (ret != sock) { leafs.insert(group, ret); if (!mcast_groups.contains(group)) mcast_groups << group; } #else # ifndef QNX if (!params[Broadcast]) piCoutObj << "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 << "Can`t join multicast group " << group << ", " << ethErrorString(); return false; } if (!mcast_groups.contains(group)) mcast_groups << group; # endif #endif return true; } bool PIEthernet::leaveMulticastGroup(const PIString & group) { if (sock == -1) init(); if (sock == -1) return false; if (type() != UDP) { piCoutObj << "Only UDP sockets can leave multicast groups"; return false; } PIFlags params = parameters(); #ifdef WINDOWS SOCKET s = leafs[group]; if (s != SOCKET()) { leafs.erase(group); closesocket(s); mcast_groups.removeAll(group); } #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 << "Can`t leave multicast group " << group << ", " << ethErrorString(); return false; } mcast_groups.removeAll(group); #endif #endif return true; } bool PIEthernet::connect() { connecting_ = true; return true; /*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 << "connect to " << ip << ":" << port_; connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0); if (!connected_) piCoutObj << "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 opened_ = false; int tries = 0; while ((bind(sock, (sockaddr * )&addr_, sizeof(addr_)) == -1) && (tries < 10)) { init(); tries++; } if (tries == 10) { piCoutObj << "Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString(); return false; } if (::listen(sock, 64) == -1) { piCoutObj << "Can`t listen on "<< ip_ << ":" << port_ << ", " << ethErrorString(); return false; } opened_ = true; //piCoutObj << "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, lerr = 0; sockaddr_in client_addr; socklen_t slen = sizeof(client_addr); //piCoutObj << "read from " << ip_ << ":" << port_ << endl; switch (type()) { case TCP_SingleTCP: ::listen(sock, 64); s = accept(sock, (sockaddr * )&client_addr, &slen); if (s == -1) { //piCoutObj << "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 (connecting_) { 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 << "connect to " << ip << ":" << port_; connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0); if (!connected_) piCoutObj << "Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString(); opened_ = connected_; if (connected_) { connecting_ = false; connected(); } } if (!connected_) return -1; #ifdef WINDOWS rs = recv(sock, (char * )read_to, max_size, 0); #else rs = recv(sock, read_to, max_size, MSG_DONTWAIT); #endif if (rs <= 0) { #ifdef WINDOWS lerr = WSAGetLastError(); if (lerr == WSAEWOULDBLOCK) { piMSleep(1); return -1; } #else lerr = errno; if (lerr == EAGAIN || lerr == EWOULDBLOCK) { piMSleep(1); return -1; } #endif if (connected_) disconnected(rs < 0); connected_ = false; //piCoutObj << "eth" << path_ << "disconnected"; } if (rs > 0) received(read_to, rs); return rs; 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) 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 << "Can`t send to uninitialized socket"; return -1; } //piCoutObj << "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 << "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_s, (const char * )data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_)); #else return sendto(sock_s, data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_)); #endif //piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok"; case TCP_Client: if (connecting_) { 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 << "connect to " << ip << ":" << port_; connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0); if (!connected_) piCoutObj << "Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString(); opened_ = connected_; if (connected_) { connecting_ = false; connected(); } } if (!connected_) return -1; 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; } bool PIEthernet::configureDevice(const void * e_main, const void * e_parent) { PIConfig::Entry * em = (PIConfig::Entry * )e_main; PIConfig::Entry * ep = (PIConfig::Entry * )e_parent; setReadIP(readDeviceSetting("ip", readIP(), em, ep)); setReadPort(readDeviceSetting("port", readPort(), em, ep)); setParameter(PIEthernet::Broadcast, readDeviceSetting("broadcast", isParameterSet(PIEthernet::Broadcast), em, ep)); setParameter(PIEthernet::ReuseAddress, readDeviceSetting("reuseAddress", isParameterSet(PIEthernet::ReuseAddress), em, ep)); return true; } PIString PIEthernet::constructFullPath() const { PIString ret(fullPathPrefix() + "://"); ret << (type() == PIEthernet::UDP ? "UDP" : "TCP") << ":" << readIP() << ":" << readPort(); if (type() == PIEthernet::UDP) { piForeachC (PIString & m, multicastGroups()) ret << ":mcast:" << m; } return ret; } void PIEthernet::configureFromFullPath(const PIString & full_path) { PIStringList pl = full_path.split(":"); bool mcast = false; for (int i = 0; i < pl.size_s(); ++i) { PIString p(pl[i]); switch (i) { case 0: p = p.toLowerCase(); if (p == "udp") setType(UDP); if (p == "tcp") setType(TCP_Client); break; case 1: setReadIP(p); setSendIP(p); break; case 2: setReadPort(p.toInt()); setSendPort(p.toInt()); break; } if (i <= 2) continue; if (i % 2 == 1) {if (p.toLowerCase() == "mcast") mcast = true;} else {if (mcast) {joinMulticastGroup(p); mcast = false;}} } } PIEthernet::InterfaceList PIEthernet::interfaces() { PIEthernet::InterfaceList il; Interface ci; #ifdef WINDOWS 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)); #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*/ # ifdef ANDROID struct ifconf ifc; int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); ifc.ifc_len = 256; ifc.ifc_buf = new char[ifc.ifc_len]; if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { piCout << "[PIEthernet] Can`t get interfaces:" << errorString(); delete ifc.ifc_buf; return il; } int icnt = ifc.ifc_len / sizeof(ifreq); PIStringList inl; struct ifreq ir; for (int i = 0; i < icnt; ++i) { PIString in(ifc.ifc_req[i].ifr_name); if (in.isEmpty()) continue; ci.name = in; strcpy(ir.ifr_name, in.data()); if (ioctl(s, SIOCGIFHWADDR, &ir) == 0) ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6)); if (ioctl(s, SIOCGIFADDR, &ir) >= 0) ci.address = getSockAddr(&ir.ifr_addr); if (ioctl(s, SIOCGIFNETMASK, &ir) >= 0) ci.netmask = getSockAddr(&ir.ifr_addr); il << ci; } delete ifc.ifc_buf; # else 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 # ifdef MAC_OS PIString req = PIString(ifconfigPath) + " " + ci.name + " | grep ether"; FILE * fp = popen(req.data(), "r"); if (fp != 0) { char in[256]; if (fgets(in, 256, fp) != 0) { req = PIString(in).trim(); ci.mac = req.cutLeft(req.find(" ") + 1).trim().toUpperCase(); } pclose(fp); } # 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 # 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); # endif #endif return il; } 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 }