4.06.2013 - Version 0.3.4 - PIOBJECT() macro, ethernet improvement, documentation based on Doxygen
This commit is contained in:
117
piethernet.cpp
117
piethernet.cpp
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP
|
||||
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
|
||||
@@ -47,7 +47,7 @@ PIEthernet::PIEthernet(PIEthernet::Type type, void * data, ReadRetFunc slot): PI
|
||||
sock = sock_s = -1;
|
||||
ret_func_ = slot;
|
||||
connected_ = false;
|
||||
params = PIEthernet::ReuseAddress;
|
||||
params = (type == UDP ? PIEthernet::ReuseAddress : 0);
|
||||
server_thread_.setData(this);
|
||||
setThreadedReadBufferSize(65536);
|
||||
if (type_ != UDP) init();
|
||||
@@ -58,6 +58,7 @@ 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;
|
||||
@@ -80,22 +81,28 @@ PIEthernet::~PIEthernet() {
|
||||
bool PIEthernet::init() {
|
||||
//cout << "init " << type_ << endl;
|
||||
closeSocket(sock);
|
||||
int st = 0;
|
||||
int st = 0, pr = 0;;
|
||||
#ifdef WINDOWS
|
||||
int flags = WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;
|
||||
int flags = 0;
|
||||
#else
|
||||
int so = 1;
|
||||
#endif
|
||||
if (type_ == UDP) st = SOCK_DGRAM;
|
||||
else st = SOCK_STREAM;
|
||||
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;
|
||||
if (params[ReuseAddress]) flags |= WSA_FLAG_OVERLAPPED;
|
||||
sock = WSASocket(AF_INET, st, type_ == UDP ? IPPROTO_UDP : IPPROTO_TCP, NULL, 0, flags);
|
||||
sock = WSASocket(AF_INET, st, pr, NULL, 0, flags);
|
||||
#else
|
||||
sock = socket(AF_INET, st, type_ == UDP ? IPPROTO_UDP : IPPROTO_TCP);
|
||||
sock = socket(AF_INET, st, pr);
|
||||
#endif
|
||||
if (sock == -1) {
|
||||
piCout << "[PIEthernet] Cant`t create socket, " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t create socket, " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
#ifndef WINDOWS
|
||||
@@ -116,9 +123,11 @@ void PIEthernet::parseAddress(const PIString & ipp, PIString * ip, int * port) {
|
||||
|
||||
bool PIEthernet::openDevice() {
|
||||
if (connected_) return true;
|
||||
if (sock == -1) init();
|
||||
init();
|
||||
if (sock == -1 || path_.isEmpty()) return false;
|
||||
parseAddress(path_, &ip_, &port_);
|
||||
if (type_ != UDP)
|
||||
return true;
|
||||
//cout << " bind to " << sock << ": " << (params[PIEthernet::Broadcast] ? "0.0.0.0" : path_) << ": " << port_ << " ..." <<endl;
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
addr_.sin_family = AF_INET;
|
||||
@@ -134,9 +143,12 @@ bool PIEthernet::openDevice() {
|
||||
tries++;
|
||||
}
|
||||
if (tries == 10) {
|
||||
piCout << "[PIEthernet] Cant`t bind to " << ip_ << ":" << port_ << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
opened_ = true;
|
||||
while (!mcast_queue.isEmpty())
|
||||
joinMulticastGroup(mcast_queue.dequeue());
|
||||
//cout << "!" << endl;
|
||||
return true;
|
||||
}
|
||||
@@ -150,6 +162,7 @@ bool PIEthernet::closeDevice() {
|
||||
delete i;
|
||||
clients_.clear();
|
||||
if (server_thread_.isRunning()) server_thread_.terminate();
|
||||
if (connected_) disconnected(false);
|
||||
connected_ = false;
|
||||
return true;
|
||||
}
|
||||
@@ -159,9 +172,15 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1) return false;
|
||||
if (type_ != UDP) {
|
||||
piCout << "[PIEthernet] Only UDP sockets can join multicast groups" << endl;
|
||||
piCout << "[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_));
|
||||
@@ -170,23 +189,23 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
||||
addr_.sin_addr.s_addr = inet_addr(group.data());
|
||||
SOCKET ret = WSAJoinLeaf(sock, (sockaddr *)&addr_, sizeof(addr_), NULL, NULL, NULL, NULL, JL_BOTH);
|
||||
if (ret == INVALID_SOCKET) {
|
||||
piCout << "[PIEthernet] Cant`t join multicast group " << group << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t join multicast group " << group << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
leafs.insert(group, ret);
|
||||
#else
|
||||
# ifndef QNX
|
||||
if (!params[Broadcast])
|
||||
piCout << "[PIEthernet] Warning: \"Broadcast\" parameter not set, \"joinMulticastGroup(\"" << group << "\")\" may be useless!" << endl;
|
||||
piCout << "[PIEthernet] Warning: \"Broadcast\" parameter not set, \"joinMulticastGroup(\"" << group << "\")\" may be useless!";
|
||||
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());
|
||||
/*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_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
|
||||
piCout << "[PIEthernet] Cant`t join multicast group " << group << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t join multicast group " << group << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
@@ -199,7 +218,7 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1) return false;
|
||||
if (type_ != UDP) {
|
||||
piCout << "[PIEthernet] Only UDP sockets can leave multicast groups" << endl;
|
||||
piCout << "[PIEthernet] Only UDP sockets can leave multicast groups";
|
||||
return false;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
@@ -218,7 +237,7 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
|
||||
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) {
|
||||
piCout << "[PIEthernet] Cant`t leave multicast group " << group << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t leave multicast group " << group << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -227,20 +246,22 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::connect(const PIString & ip, int port) {
|
||||
bool PIEthernet::connect() {
|
||||
if (sock == -1) return false;
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
addr_.sin_port = htons(port);
|
||||
addr_.sin_addr.s_addr = inet_addr(ip.data());
|
||||
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
|
||||
//piCout << "[PIEthernet] connect to " << ip << ":" << port << endl;
|
||||
//piCout << "[PIEthernet] connect to " << ip << ":" << port_;
|
||||
connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0);
|
||||
if (!connected_)
|
||||
piCout << "[PIEthernet] Cant`t connect to " << ip << ":" << port << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
opened_ = connected_;
|
||||
if (connected_) connected();
|
||||
return connected_;
|
||||
}
|
||||
|
||||
@@ -262,14 +283,14 @@ bool PIEthernet::listen() {
|
||||
tries++;
|
||||
}
|
||||
if (tries == 10) {
|
||||
piCout << "[PIEthernet] Cant`t bind to " << ip_ << ":" << port_ << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
if (::listen(sock, 64) == -1) {
|
||||
piCout << "[PIEthernet] Can`t listen on "<< ip_ << ":" << port_ << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Can`t listen on "<< ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
//piCout << "[PIEthernet] listen on " << ip_ << ":" << port_ << endl;
|
||||
//piCout << "[PIEthernet] listen on " << ip_ << ":" << port_;
|
||||
server_thread_.start(server_func);
|
||||
return true;
|
||||
}
|
||||
@@ -288,19 +309,27 @@ int PIEthernet::read(void * read_to, int max_size) {
|
||||
::listen(sock, 64);
|
||||
s = accept(sock, (sockaddr * )&client_addr, &slen);
|
||||
if (s == -1) {
|
||||
piCout << "[PIEthernet] Cant`t accept new connection, " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t accept new connection, " << ethErrorString();
|
||||
return -1;
|
||||
}
|
||||
rs = recv(s, (char * )read_to, max_size, 0);
|
||||
closeSocket(s);
|
||||
return rs;
|
||||
case UDP: case TCP_Client:
|
||||
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
|
||||
if (rs >= 0) received(read_to, rs);
|
||||
piCout << "eth" << path_ << "read return" << rs << errno;
|
||||
if (rs <= 0) {
|
||||
connected_ = false;
|
||||
disconnected(rs < 0);
|
||||
piCout << "eth" << path_ << "disconnected";
|
||||
}
|
||||
if (rs > 0) received(read_to, rs);
|
||||
return rs;
|
||||
//return ::read(sock, read_to, max_size);
|
||||
default: break;
|
||||
@@ -313,10 +342,10 @@ int PIEthernet::read(void * read_to, int max_size) {
|
||||
int PIEthernet::write(const void * data, int max_size) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1 || !isWriteable()) {
|
||||
//piCout << "[PIEthernet] Can`t send to uninitialized socket" << endl;
|
||||
//piCout << "[PIEthernet] Can`t send to uninitialized socket";
|
||||
return -1;
|
||||
}
|
||||
//piCout << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes" << endl;
|
||||
//piCout << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
|
||||
int ret = 0;
|
||||
switch (type_) {
|
||||
case TCP_SingleTCP:
|
||||
@@ -327,11 +356,14 @@ int PIEthernet::write(const void * data, int max_size) {
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
//piCout << "connect SingleTCP" << ip_s << ":" << port_s << "...";
|
||||
if (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) != 0) {
|
||||
piCout << "[PIEthernet] Cant`t connect to " << ip_s << ":" << port_s << ", " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
|
||||
return -1;
|
||||
}
|
||||
ret = ::write(sock, data, max_size);
|
||||
//piCout << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
|
||||
ret = ::send(sock, (const char *)data, max_size, 0);
|
||||
//piCout << "ok, ret" << ret;
|
||||
closeSocket(sock);
|
||||
init();
|
||||
return ret;
|
||||
@@ -346,7 +378,7 @@ int PIEthernet::write(const void * data, int max_size) {
|
||||
return sendto(sock, data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_));
|
||||
#endif
|
||||
case TCP_Client:
|
||||
return ::write(sock, data, max_size);
|
||||
return ::send(sock, (const char *)data, max_size, 0);
|
||||
default: break;
|
||||
//return ::read(sock, read_to, max_size);
|
||||
}
|
||||
@@ -359,12 +391,13 @@ void PIEthernet::server_func(void * eth) {
|
||||
socklen_t slen = sizeof(client_addr);
|
||||
int s = accept(ce->sock, (sockaddr * )&client_addr, &slen);
|
||||
if (s == -1) {
|
||||
piCout << "[PIEthernet] Cant`t accept new connection, " << EthErrorString() << endl;
|
||||
piCout << "[PIEthernet] Cant`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;
|
||||
@@ -375,7 +408,7 @@ void PIEthernet::server_func(void * eth) {
|
||||
|
||||
PIStringList PIEthernet::interfaces() {
|
||||
#ifdef WINDOWS
|
||||
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead" << endl;
|
||||
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead";
|
||||
return PIStringList();
|
||||
#else
|
||||
# ifdef QNX
|
||||
@@ -434,7 +467,7 @@ PIStringList PIEthernet::interfaces() {
|
||||
|
||||
PIString PIEthernet::interfaceAddress(const PIString & interface_) {
|
||||
#ifdef WINDOWS
|
||||
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead" << endl;
|
||||
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead";
|
||||
return PIString();
|
||||
#else
|
||||
struct ifreq ifr;
|
||||
@@ -459,14 +492,14 @@ PIStringList PIEthernet::allAddresses() {
|
||||
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" << endl;
|
||||
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" << endl;
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
||||
return PIStringList();
|
||||
}
|
||||
}
|
||||
@@ -482,7 +515,7 @@ PIStringList PIEthernet::allAddresses() {
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
} else
|
||||
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret << endl;
|
||||
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret;
|
||||
if (pAdapterInfo)
|
||||
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
||||
return al;
|
||||
@@ -490,6 +523,6 @@ PIStringList PIEthernet::allAddresses() {
|
||||
PIStringList il = interfaces(), al;
|
||||
piForeachC (PIString & i, il)
|
||||
al << interfaceAddress(i);
|
||||
return al;
|
||||
return al.removeStrings("0.0.0.0");
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user