Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use persistent connection to server #73

Merged
merged 1 commit into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ if(${Qt6_FOUND} EQUAL 1)

set(SourceFiles ${SourceFiles} "StdApplication.cpp")
set(SourceFiles ${SourceFiles} "RemoteDir.cpp")
set(SourceFiles ${SourceFiles} "RemoteFactory.cpp")
set(SourceFiles ${SourceFiles} "RemoteFile.cpp")
set(SourceFiles ${SourceFiles} "RemoteFileUtils.cpp")
set(SourceFiles ${SourceFiles} "StdCharConverter.cpp")
Expand Down
15 changes: 7 additions & 8 deletions RemoteDir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,15 @@ int RRemoteDir::open(const char *a_pattern)
{
(void) a_pattern;

RSocket socket;
int retVal = socket.open(m_remoteFactory->getServer().c_str(), m_remoteFactory->getPort());
int retVal = KErrNone;

if (retVal == KErrNone)
if (m_socket->isOpen())
{
CDir *handler = nullptr;

try
{
socket.write(g_signature, SIGNATURE_SIZE);

handler = new CDir(&socket, a_pattern);
handler = new CDir(m_socket, a_pattern);
handler->sendRequest();

if (handler->getResponse()->m_result == KErrNone)
Expand Down Expand Up @@ -110,11 +107,13 @@ int RRemoteDir::open(const char *a_pattern)
}

delete handler;
socket.close();
}
else
{
Utils::info("RRemoteDir::open() => Cannot connect to %s (%d)", m_remoteFactory->getServer().c_str(), retVal);
Utils::info("RRemoteDir::open() => Connection to server \"%s:%d\" is not open", m_remoteFactory->getServer().c_str(),
m_remoteFactory->getPort());

retVal = KErrNotOpen;
}

return retVal;
Expand Down
9 changes: 7 additions & 2 deletions RemoteDir.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,21 @@ class RRemoteFactory;
class RRemoteDir : public RDirObject
{
RRemoteFactory *m_remoteFactory; /**< Pointer to the remote factory that owns this instance */
RSocket *m_socket; /**< Socket for communicating with remote RADRunner */

public:

RRemoteDir() : m_remoteFactory(nullptr) { }
RRemoteDir() : m_remoteFactory(nullptr), m_socket(nullptr) { }

int open(const char *a_pattern);

int read(TEntryArray *&a_entries, enum TDirSortOrder a_sortOrder = EDirSortNone);

void setFactory(RRemoteFactory *a_remoteFactory) { m_remoteFactory = a_remoteFactory; }
void setFactory(RRemoteFactory *a_remoteFactory, RSocket *a_socket)
{
m_remoteFactory = a_remoteFactory;
m_socket = a_socket;
}
};

#endif /* ! REMOTEDIR_H */
210 changes: 210 additions & 0 deletions RemoteFactory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@

#include "StdFuncs.h"
#include "RemoteFactory.h"

#if defined(__unix__) || defined(__amigaos__)

#include <fcntl.h>
#include <sys/socket.h>

#else /* ! defined(__unix__) || defined(__amigaos__) */

#include <ws2tcpip.h>

#endif /* ! defined(__unix__) || defined(__amigaos__) */

/**
* Gets an object for directory manipulation.
* Returns an instance of a class derived from RDirObject which can be used to manipulate directories, either
* locally or remotely, depending on how the factory was configured.
*
* @date Saturday 25-May-2024 8:27 am, Code HQ Tokyo Tsukuda
* @return A reference to an RDirObject derived object
*/

RDirObject &RRemoteFactory::getDirObject()
{
if (isRemote())
{
checkConnection();
m_remoteDir.setFactory(this, &m_socket);
return m_remoteDir;
}
else
{
return m_dir;
}
}

/**
* Gets an object for file manipulation.
* Returns an instance of a class derived from RFileObject which can be used to manipulate files, either
* locally or remotely, depending on how the factory was configured.
*
* @date Saturday 25-May-2024 8:27 am, Code HQ Tokyo Tsukuda
* @return A reference to an RFileObject derived object
*/

RFileObject &RRemoteFactory::getFileObject()
{
if (isRemote())
{
checkConnection();
m_remoteFile.setFactory(this, &m_socket);
return m_remoteFile;
}
else
{
return m_file;
}
}

/**
* Gets an object for file system manipulation.
* Returns an instance of a class derived from RFileUtilsObject which can be used to manipulate file system
* objects, either locally or remotely, depending on how the factory was configured.
*
* @date Saturday 25-May-2024 8:27 am, Code HQ Tokyo Tsukuda
* @return A reference to an RFileUtilsObject derived object
*/

RFileUtilsObject &RRemoteFactory::getFileUtilsObject()
{
if (isRemote())
{
checkConnection();
m_remoteFileUtils.setFactory(this, &m_socket);
return m_remoteFileUtils;
}
else
{
return m_fileUtils;
}
}

/**
* Open a connection to a remote RADRunner instance.
* This function can be called any time a connection to RADRunner needs to be made. It can be called either
* by client code at startup, or The Framework will do it automatically if a file request is made and it is
* detected that the connection has been lost.
*
* @pre Server and port must have already been set
*
* @date Saturday 11-May-2024 9:14 am, Enoshima holiday apartment
* @return KErrNone if successful, otherwise one of the errors returned by RSocket::open()
*/

int RRemoteFactory::openRemote()
{
int retVal = m_socket.open(getServer().c_str(), getPort());

if (retVal == KErrNone)
{
try
{
m_socket.write(g_signature, SIGNATURE_SIZE);
}
catch (RSocket::Error &a_exception)
{
Utils::info("RRemoteFactory::openRemote() => Unable to perform I/O on socket (Error = %d)", a_exception.m_result);
}
}

return retVal;
}

/**
* Close the remote factory.
* Closing the remote factory will also close any connected sockets.
*
* @date Saturday 11-May-2024 9:16 am, Enoshima holiday apartment
*/

void RRemoteFactory::close()
{
m_socket.close();
}

/**
* Check connection and reopen if necessary.
* This method is a part of the self-healing functionality of The Framework's socket system. It can be called at
* any time, whether the socket has been connected previously or not. If the socket is closed, it will be opened.
* If the socket is open, it will be checked to see if it is still connected. If it is not, it will be reconnected.
*
* @pre Server and port must have already been set
*
* @date Tuesday 14-May-2024 6:02 am, Code HQ Tokyo Tsukuda
* @return KErrNone if successful, otherwise one of the errors returned by RRemoteFactory::openRemote()
*/

// TODO: CAW - Move this stuff into RSocket?
int RRemoteFactory::checkConnection()
{
int retVal = KErrNone;

/* If the socket is open, it could be that the connection has been lost, so we'll check that by setting */
/* the socket to non-blocking and trying to read a byte. If it fails, it means the connection is closed. */
/* This trick depends on the remote server not sending data without being requested to */
if (m_socket.isOpen())
{
int result = 0;

/* Error handling is difficult here, as it is unlikely to fail unless an invalid socket is used, and if */
/* it does fail, there is not much we can do as this is supposed to be a transparent self-healing routine. */
/* So we'll check for errors and handle but not report them, and if the final call to set the socket back */
/* to blocking mode fails, all hell will break loose, but so be it */

#ifdef WIN32

u_long blocking = 1;

if (ioctlsocket(m_socket.m_socket, FIONBIO, &blocking) == 0)
{
char buffer[1];
result = recv(m_socket.m_socket, buffer, 1, 0);

blocking = 0;

if (ioctlsocket(m_socket.m_socket, FIONBIO, &blocking) != 0)
{
result = -1;
}
}

#else /* ! WIN32 */

int flags = fcntl(m_socket.m_socket, F_GETFL, 0);

if (flags != -1)
{
if (fcntl(m_socket.m_socket, F_SETFL, flags | O_NONBLOCK) != -1)
{
char buffer[1];
result = recv(m_socket.m_socket, buffer, 1, 0);

if (result != -1)
{
if (fcntl(m_socket.m_socket, F_SETFL, flags) == -1)
{
result = -1;
}
}
}
}

#endif /* ! WIN32 */

if (result == 0)
{
close();

retVal = openRemote();
}
}
else
{
retVal = openRemote();
}

return retVal;
}
50 changes: 14 additions & 36 deletions RemoteFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "RemoteDir.h"
#include "RemoteFile.h"
#include "RemoteFileUtils.h"
#include "Yggdrasil/Commands.h"

/**
* A class for management of file system related objects.
Expand All @@ -26,51 +27,25 @@ class RRemoteFactory
RRemoteFile m_remoteFile; /**< Class for remote file access */
RFileUtils m_fileUtils; /**< Class for local file system manipulation */
RRemoteFileUtils m_remoteFileUtils; /**< Class for remote file system manipulation */
RSocket m_socket; /**< Socket for communicating with remote RADRunner */
std::string m_serverName; /**< The host name of the instance of RADRunner to use */
unsigned short m_serverPort; /**< The port on which RADRunner is listening */

public:

RRemoteFactory() : m_useLocal(false) { }

RDirObject &getDirObject()
{
if (isRemote())
{
m_remoteDir.setFactory(this);
return m_remoteDir;
}
else
{
return m_dir;
}
}
int openRemote();

RFileObject &getFileObject()
{
if (isRemote())
{
m_remoteFile.setFactory(this);
return m_remoteFile;
}
else
{
return m_file;
}
}
void close();

RFileUtilsObject &getFileUtilsObject()
{
if (isRemote())
{
m_remoteFileUtils.setFactory(this);
return m_remoteFileUtils;
}
else
{
return m_fileUtils;
}
}
int checkConnection();

RDirObject &getDirObject();

RFileObject &getFileObject();

RFileUtilsObject &getFileUtilsObject();

bool isRemote()
{
Expand All @@ -87,6 +62,9 @@ class RRemoteFactory
m_serverPort = a_port;
}

/**< Set this to true when the RRemoteFactory instance is configured to be used for remote
* access, but there is a need to temporarily access the local file system
*/
void useLocal(bool a_useLocal)
{
m_useLocal = a_useLocal;
Expand Down
Loading
Loading