|
|
|
|
@@ -212,6 +212,18 @@ PRIVATE_DEFINITION_START(PIEthernet)
|
|
|
|
|
sockaddr_in addr_;
|
|
|
|
|
sockaddr_in saddr_;
|
|
|
|
|
sockaddr_in raddr_;
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
WSAEVENT read_event = nullptr;
|
|
|
|
|
void createEvent() {
|
|
|
|
|
closeEvent();
|
|
|
|
|
read_event = WSACreateEvent();
|
|
|
|
|
}
|
|
|
|
|
void closeEvent() {
|
|
|
|
|
if (!read_event) return;
|
|
|
|
|
WSACloseEvent(read_event);
|
|
|
|
|
read_event = nullptr;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
PRIVATE_DEFINITION_END(PIEthernet)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -240,6 +252,11 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
|
|
|
|
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop);
|
|
|
|
|
setType(TCP_Client, false);
|
|
|
|
|
setPath(ip_port);
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
u_long mode = 1;
|
|
|
|
|
ioctlsocket(sock, FIONBIO, &mode);
|
|
|
|
|
PRIVATE->createEvent();
|
|
|
|
|
#endif
|
|
|
|
|
//piCoutObj << "new tcp client" << sock_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -248,6 +265,9 @@ PIEthernet::~PIEthernet() {
|
|
|
|
|
//piCout << "~PIEthernet" << uint(this);
|
|
|
|
|
stop();
|
|
|
|
|
close();
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
PRIVATE->closeEvent();
|
|
|
|
|
#endif
|
|
|
|
|
//piCoutObj << "~PIEthernet done";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -277,6 +297,9 @@ bool PIEthernet::init() {
|
|
|
|
|
//cout << "init " << type_ << endl;
|
|
|
|
|
if (sock_s == sock)
|
|
|
|
|
sock_s = -1;
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
PRIVATE->closeEvent();
|
|
|
|
|
#endif
|
|
|
|
|
closeSocket(sock);
|
|
|
|
|
closeSocket(sock_s);
|
|
|
|
|
int st = 0, pr = 0;
|
|
|
|
|
@@ -289,6 +312,14 @@ bool PIEthernet::init() {
|
|
|
|
|
}
|
|
|
|
|
PIFlags<Parameters> params = parameters();
|
|
|
|
|
sock = ::socket(AF_INET, st, pr);
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
if (type() != TCP_Server) {
|
|
|
|
|
// non-blocking socket
|
|
|
|
|
u_long mode = 1;
|
|
|
|
|
ioctlsocket(sock, FIONBIO, &mode);
|
|
|
|
|
}
|
|
|
|
|
PRIVATE->createEvent();
|
|
|
|
|
#endif
|
|
|
|
|
if (params[SeparateSockets])
|
|
|
|
|
sock_s = ::socket(AF_INET, st, pr);
|
|
|
|
|
else
|
|
|
|
|
@@ -395,13 +426,17 @@ bool PIEthernet::closeDevice() {
|
|
|
|
|
//cout << "close\n";
|
|
|
|
|
if (server_thread_.isRunning()) {
|
|
|
|
|
server_thread_.stop();
|
|
|
|
|
if (!server_thread_.waitForFinish(100))
|
|
|
|
|
server_thread_.interrupt();
|
|
|
|
|
if (!server_thread_.waitForFinish(1000))
|
|
|
|
|
server_thread_.terminate();
|
|
|
|
|
}
|
|
|
|
|
if (sock_s == sock)
|
|
|
|
|
sock_s = -1;
|
|
|
|
|
closeSocket(sock);
|
|
|
|
|
closeSocket(sock_s);
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
if (PRIVATE->read_event) WSASetEvent(PRIVATE->read_event);
|
|
|
|
|
#endif
|
|
|
|
|
while (!clients_.isEmpty())
|
|
|
|
|
delete clients_.back();
|
|
|
|
|
bool ned = connected_;
|
|
|
|
|
@@ -566,7 +601,7 @@ bool PIEthernet::connect(bool threaded) {
|
|
|
|
|
#ifdef QNX
|
|
|
|
|
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
|
|
|
|
#endif
|
|
|
|
|
connected_ = (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == 0);
|
|
|
|
|
connected_ = connectTCP();
|
|
|
|
|
if (!connected_) {
|
|
|
|
|
piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
|
|
|
|
}
|
|
|
|
|
@@ -618,7 +653,7 @@ bool PIEthernet::listen(bool threaded) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
opened_ = server_bounded = true;
|
|
|
|
|
//piCoutObj << "listen on " << ip_ << ":" << port_;
|
|
|
|
|
piCoutObj << "listen on" << path();
|
|
|
|
|
server_thread_.start(server_func);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@@ -718,9 +753,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
|
|
|
|
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
|
|
|
|
#endif
|
|
|
|
|
//piCout << "connect to " << path() << "...";
|
|
|
|
|
reading_now = true;
|
|
|
|
|
connected_ = (::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)) == 0);
|
|
|
|
|
reading_now = false;
|
|
|
|
|
connected_ = connectTCP();
|
|
|
|
|
//piCout << "connect to " << path() << connected_;
|
|
|
|
|
if (!connected_)
|
|
|
|
|
piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
|
|
|
|
@@ -734,9 +767,24 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
|
|
|
|
}
|
|
|
|
|
if (!connected_) return -1;
|
|
|
|
|
errorClear();
|
|
|
|
|
reading_now = true;
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
{
|
|
|
|
|
long wr = waitForEvent(FD_READ | FD_CLOSE);
|
|
|
|
|
switch (wr) {
|
|
|
|
|
case FD_READ:
|
|
|
|
|
piCout << "fd_read ...";
|
|
|
|
|
rs = ethRecv(sock, read_to, max_size);
|
|
|
|
|
break;
|
|
|
|
|
case FD_CLOSE:
|
|
|
|
|
piCout << "fd_close ...";
|
|
|
|
|
rs = -1;
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
rs = ethRecv(sock, read_to, max_size);
|
|
|
|
|
reading_now = false;
|
|
|
|
|
#endif
|
|
|
|
|
//piCoutObj << "readed" << rs;
|
|
|
|
|
if (rs <= 0) {
|
|
|
|
|
lerr = ethErrorCore();
|
|
|
|
|
@@ -763,11 +811,26 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
|
|
|
|
}
|
|
|
|
|
if (rs > 0) received(read_to, rs);
|
|
|
|
|
return rs;
|
|
|
|
|
case UDP:
|
|
|
|
|
case UDP: {
|
|
|
|
|
memset(&PRIVATE->raddr_, 0, sizeof(PRIVATE->raddr_));
|
|
|
|
|
reading_now = true;
|
|
|
|
|
piCoutObj << "read from" << path() << "...";
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
long wr = waitForEvent(FD_READ | FD_CLOSE);
|
|
|
|
|
switch (wr) {
|
|
|
|
|
case FD_READ:
|
|
|
|
|
piCout << "fd_read ...";
|
|
|
|
|
rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_);
|
|
|
|
|
break;
|
|
|
|
|
case FD_CLOSE:
|
|
|
|
|
piCout << "fd_close ...";
|
|
|
|
|
rs = -1;
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_);
|
|
|
|
|
reading_now = false;
|
|
|
|
|
#endif
|
|
|
|
|
piCoutObj << "read from" << path() << rs << "bytes";
|
|
|
|
|
if (rs > 0) {
|
|
|
|
|
addr_lr.set(uint(PRIVATE->raddr_.sin_addr.s_addr), ntohs(PRIVATE->raddr_.sin_port));
|
|
|
|
|
//piCoutObj << "read from" << ip_r << ":" << port_r << rs << "bytes";
|
|
|
|
|
@@ -775,6 +838,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
|
|
|
|
}
|
|
|
|
|
//else piCoutObj << "read returt" << rs << ", error" << ethErrorString();
|
|
|
|
|
return rs;
|
|
|
|
|
}
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
@@ -799,7 +863,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
|
|
|
|
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
|
|
|
|
#endif
|
|
|
|
|
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
|
|
|
|
|
if (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) != 0) {
|
|
|
|
|
if (!connectTCP()) {
|
|
|
|
|
//piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
|
|
|
|
|
piMinSleep();
|
|
|
|
|
return -1;
|
|
|
|
|
@@ -834,7 +898,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
|
|
|
|
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
|
|
|
|
#endif
|
|
|
|
|
//piCoutObj << "connect to " << ip << ":" << port_;
|
|
|
|
|
connected_ = (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == 0);
|
|
|
|
|
connected_ = connectTCP();
|
|
|
|
|
if (!connected_)
|
|
|
|
|
piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
|
|
|
|
opened_ = connected_;
|
|
|
|
|
@@ -890,7 +954,15 @@ void PIEthernet::server_func(void * eth) {
|
|
|
|
|
}
|
|
|
|
|
sockaddr_in client_addr;
|
|
|
|
|
socklen_t slen = sizeof(client_addr);
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
long wr = ce->waitForEvent(FD_ACCEPT | FD_CLOSE);
|
|
|
|
|
if (wr != FD_ACCEPT) {
|
|
|
|
|
piMSleep(10);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
int s = accept(ce->sock, (sockaddr * )&client_addr, &slen);
|
|
|
|
|
piCout << ethErrorString();
|
|
|
|
|
if (s == -1) {
|
|
|
|
|
int lerr = ethErrorCore();
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
@@ -930,6 +1002,50 @@ void PIEthernet::setType(Type t, bool reopen) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PIEthernet::connectTCP() {
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_));
|
|
|
|
|
long wr = waitForEvent(FD_CONNECT | FD_CLOSE);
|
|
|
|
|
switch (wr) {
|
|
|
|
|
case FD_CONNECT: {
|
|
|
|
|
//piCout << "fd_connect ...";
|
|
|
|
|
timeval timeout;
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
fd_set fd_test;
|
|
|
|
|
FD_ZERO(&fd_test);
|
|
|
|
|
FD_SET(sock, &fd_test);
|
|
|
|
|
::select(0, nullptr, &fd_test, nullptr, &timeout);
|
|
|
|
|
return FD_ISSET(sock, &fd_test);
|
|
|
|
|
} break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return ::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)) == 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
long PIEthernet::waitForEvent(long mask) {
|
|
|
|
|
if (!PRIVATE->read_event || sock < 0) return 0;
|
|
|
|
|
WSAEventSelect(sock, PRIVATE->read_event, mask);
|
|
|
|
|
DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE);
|
|
|
|
|
piCout << "wait result" << wr;
|
|
|
|
|
if (wr == WSA_WAIT_EVENT_0) {
|
|
|
|
|
WSANETWORKEVENTS events;
|
|
|
|
|
memset(&events, 0, sizeof(events));
|
|
|
|
|
WSAEnumNetworkEvents(sock, PRIVATE->read_event, &events);
|
|
|
|
|
WSAResetEvent(PRIVATE->read_event);
|
|
|
|
|
return events.lNetworkEvents;
|
|
|
|
|
}
|
|
|
|
|
WSAResetEvent(PRIVATE->read_event);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|