toDel = NULL;
}
+ // FIXME what is this?
if (!videoStack.empty() && videoStack.top().first==toDel) {
videoStack.pop();
if (!videoStack.empty()) display=&videoStack.top().second;
Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);
if (display) Video::getInstance()->setVideoDisplay(*display);
-
if (toDel) delete toDel;
}
-
-
}
int BoxStack::handleCommand(int command)
for (i=numBoxes-1; i>=0; i--)
{
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);
+ // Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);
retVal = boxes[i]->handleCommand(command);
if (retVal == 1)
{
// Wait for connect to complete
fd_set writefds;
- struct timeval tv;
FD_ZERO(&writefds);
FD_SET(sockfd, &writefds);
int maxfd = sockfd;
+ fd_set readfds;
+ FD_ZERO(&readfds);
+
+
#ifdef WIN32
- FD_SET(abortSocket, &writefds);
+ FD_SET(abortSocket, &readfds);
#else
- FD_SET(abortPipe[0], &writefds);
+ FD_SET(abortPipe[0], &readfds);
if (abortPipe[0] > maxfd) maxfd = abortPipe[0];
#endif
- tv.tv_sec = 5; // Allow 5s for a connect
+ struct timeval tv;
+ tv.tv_sec = 20; // Allow 5s for a connect
tv.tv_usec = 0;
- int selectResult = select(maxfd + 1, NULL, &writefds, NULL, &tv);
+ int selectResult = select(maxfd + 1, &readfds, &writefds, NULL, &tv);
+#ifdef WIN32
+ if (FD_ISSET(abortSocket, &readfds))
+#else
+ if (FD_ISSET(abortPipe[0], &readfds))
+#endif
+ {
+ CLOSESOCKET(sockfd);
+ sockfd = -1;
+ logger->log("TCP", Log::INFO, "connect/select aborting");
+ return false;
+ }
if ((selectResult == 1) || FD_ISSET(sockfd, &writefds))
{
freeaddrinfo(aip);
- logger->log("TCP", Log::INFO, "connected");
+ logger->log("TCP", Log::INFO, "Connected");
connected = true;
return true;
}
connected = false;
CLOSESOCKET(sockfd);
sockfd = -1;
+
+ char waste[10];
+#ifdef WIN32
+ while (recv(abortSocket, waste, 10, 0) > 0) ;
+#else
+ while (::read(abortPipe[0], waste, 10) > 0) ;
+#endif
}
bool TCP::status()
#ifdef WIN32
if (FD_ISSET(abortSocket, &readfds)) { logger->log("TCP", Log::DEBUG, "aborting..."); return false; }
#else
- if (FD_ISSET(abortPipe[0], &readfds)) { logger->log("TCP", Log::DEBUG, "aborting..."); return false; }
+
+
+
+ if (FD_ISSET(abortPipe[0], &readfds)) { logger->log("TCP", Log::DEBUG, "B aborting..."); return false; }
#endif
int recvResult = recv(sockfd, pointer, numBytes - totalReceived, 0);
public:
~TCP();
bool init(); // Must call this first, once on any new TCP object
- void shutdown(); // Optional. Closes connection. Can call connect() next
+ void shutdown(); // Optional if this is to be deleted. Closes connection. Can call connect() next
void abortCall(); // causes a read/connect call to immediately abort
bool connect(const std::string& ip, USHORT port);
--- /dev/null
+/*
+ Copyright 2020 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP 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 2 of the License, or
+ (at your option) any later version.
+
+ VOMP 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 VOMP. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#include <time.h>
+#include <iomanip>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "util.h"
+
+void MILLISLEEP(ULONG a)
+{
+#ifndef WIN32
+ struct timespec delayTime;
+ delayTime.tv_sec = a / 1000;
+ delayTime.tv_nsec = (a % 1000) * 1000000;
+ nanosleep(&delayTime, NULL);
+#else
+ Sleep(a);
+#endif
+}
+
+std::string tp2str(const std::chrono::time_point<std::chrono::system_clock>& tp)
+{
+ auto tms = std::chrono::time_point_cast<std::chrono::milliseconds>(tp);
+ std::chrono::milliseconds e = tms.time_since_epoch();
+ long long c = e.count();
+ time_t tt = c / 1000;
+ int ttm = c % 1000;
+ auto stm = std::localtime(&tt);
+ std::stringstream ss;
+ ss << std::put_time(stm, "%T") << "." << std::setfill('0') << std::setw(3) << ttm;
+ return ss.str();
+}
+
+/*
+ULLONG htonll(ULLONG a)
+{
+ return (((ULLONG)htonl((ULONG)((a<<32)>> 32))<<32)
+ |(ULONG)htonl(((ULONG) (a >> 32))));
+}
+
+ULLONG ntohll(ULLONG a)
+{
+ return htonll(a);
+}
+
+ULLONG htonll(ULLONG a)
+{
+ #if BYTE_ORDER == BIG_ENDIAN
+ return a;
+ #else
+ ULLONG b = 0;
+
+ b = ((a << 56) & 0xFF00000000000000ULL)
+ | ((a << 40) & 0x00FF000000000000ULL)
+ | ((a << 24) & 0x0000FF0000000000ULL)
+ | ((a << 8) & 0x000000FF00000000ULL)
+ | ((a >> 8) & 0x00000000FF000000ULL)
+ | ((a >> 24) & 0x0000000000FF0000ULL)
+ | ((a >> 40) & 0x000000000000FF00ULL)
+ | ((a >> 56) & 0x00000000000000FFULL) ;
+
+ return b;
+ #endif
+}
+
+ULLONG ntohll(ULLONG a)
+{
+ return htonll(a);
+}
+
+*/
--- /dev/null
+/*
+ Copyright 2020 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP 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 2 of the License, or
+ (at your option) any later version.
+
+ VOMP 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 VOMP. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <string>
+#include <chrono>
+
+#include "defines.h"
+
+void MILLISLEEP(ULONG a);
+std::string tp2str(const std::chrono::time_point<std::chrono::system_clock>& tp);
+
+
+//ULLONG htonll(ULLONG a);
+//ULLONG ntohll(ULLONG a);
+
+#endif
{
threadMutex.lock();
threadReqQuit = true;
+ vdr->abortConnect(); // If this and vdr are connecting, cancel it
threadCond.notify_one();
threadMutex.unlock();
connectThread.join();
draw();
boxstack->update(this);
+ if (threadReqQuit) return;
success = vdr->connect();
+ if (threadReqQuit) return;
+
if (success)
{
logger->log("VConnect", Log::DEBUG, "Connected ok, doing login");
draw();
boxstack->update(this);
- MILLISLEEP(delay);
+
+ MILLISLEEP(delay); // FIXME wait on cond?
+ if (threadReqQuit) return;
} while(!success);
logger->log("VConnect", Log::INFO, "Send VDR connected message");
serverPort = newPort;
}
+
int VDR::connect()
{
maxChannelNumber = 0;
channelNumberWidth = 1;
- tcp.shutdown();
- if (!tcp.connect(serverIP, serverPort)) return 0;
+ connectStateMutex.lock();
+ if (connecting || connected) return 0;
+ connecting = true;
+ connectStateMutex.unlock(); // now I have connecting
+
+ bool connectResult = tcp.connect(serverIP, serverPort);
- connected = true;
+ connectStateMutex.lock(); // connected = false, connecting = true, babortConnect = ?
+ connecting = false;
- threadStartProtect.lock();
- vdrThread = std::thread( [this]
+ if (babortConnect)
{
+ if (connectResult) tcp.shutdown();
+ babortConnect = false;
+ connectStateMutex.unlock();
+ return 0;
+ }
+
+ if (connectResult)
+ {
+ connected = true;
+
threadStartProtect.lock();
+ vdrThread = std::thread( [this]
+ {
+ threadStartProtect.lock();
+ threadStartProtect.unlock();
+ threadMethod();
+ });
threadStartProtect.unlock();
- threadMethod();
- });
- threadStartProtect.unlock();
- return 1;
+ connectStateMutex.unlock();
+ return 1;
+ }
+ else
+ {
+ connectStateMutex.unlock();
+ return 0;
+ }
+}
+
+void VDR::abortConnect() // If there is one, force a running connect call to abort
+{
+ connectStateMutex.lock();
+
+ if (connecting)
+ {
+ babortConnect = true;
+ tcp.abortCall();
+ }
+
+ connectStateMutex.unlock();
}
void VDR::disconnect()
{
- logger->log("VDR", Log::DEBUG, "Disconnect start");
+ std::lock_guard<std::mutex> lg(connectStateMutex);
+
+ if (!connected) return;
if (vdrThread.joinable())
{
tcp.abortCall();
vdrThread.join();
threadReqStop = false;
- logger->log("VDR", Log::DEBUG, "done thread stop");
}
+ tcp.shutdown();
+
+ disconnecting = false;
connected = false;
logger->log("VDR", Log::DEBUG, "Disconnect");
}
while(1)
{
- if (threadReqStop) return;
-
- timeNow = time(NULL);
-
readSuccess = tcp.read(&channelID, sizeof(ULONG));
-
if (threadReqStop) return;
+ timeNow = time(NULL);
if (!readSuccess)
{
//logger->log("VDR", Log::DEBUG, "Net read timeout");
if (!tcp.status()) { connectionDied(); return; } // return to stop this thread
}
-
- // Error or timeout.
if (!lastKAsent) // have not sent a KA
{
{
// Called from within threadMethod to do cleanup if it decides the connection has died
- connected = false; // though actually it could still be connected until someone calls vdr->disconnect
+ disconnecting = true;
// Need to wake up any waiting channel 1 request-response threads
// Normally this is done by a packet coming in with channelid and requestid
{
//logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
- if (!connected)
+ if (!connected || disconnecting)
{
- logger->log("VDR", Log::DEBUG, "RR when !connected");
+ logger->log("VDR", Log::DEBUG, "RR when !connected || disconnecting");
VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
return vresp; // "no-response" return
}
bool VDR::LogExtern(const char* logString)
{
- if (!connected) return false;
+ if (!connected || disconnecting) return false;
int stringLength = strlen(logString);
int packetLength = stringLength + 8;
char *buffer=new char[packetLength + 1];
if (!tcp.write(buffer, packetLength))
{
- connected = false; // stop the rest of the connection
delete [] buffer;
+ disconnecting = true; // stop the rest of the connection
+ Control::getInstance()->connectionLost();
return false;
}
delete [] buffer;
else
logger->log("VDR", Log::DEBUG, "Shutting down vomp only");
- if(!doVDRShutdown || !connected)
+ if(!doVDRShutdown || !connected || disconnecting)
return;
VDR_RequestPacket vrp;
void setReceiveWindow(size_t size);
int connect();
void disconnect();
+ void abortConnect(); // If there is one, force a running connect call to abort
bool isConnected() { return connected; }
int getChannelNumberWidth() { return channelNumberWidth; }
TCP tcp;
char serverIP[40];
USHORT serverPort;
- bool connected{};
ULONG maxChannelNumber{};
bool doVDRShutdown{};
int channelNumberWidth{1};
VDR_PacketReceiver* TEMP_SINGLE_VDR_PR;
+ std::mutex connectStateMutex; // FIXME improve this
+ bool connecting{};
+ bool disconnecting{};
+ bool babortConnect{};
+ bool connected{};
+
std::mutex threadStartProtect;
std::thread vdrThread;
bool threadReqStop{};