-
Notifications
You must be signed in to change notification settings - Fork 0
/
RemoteFactory.cpp
206 lines (171 loc) · 5.17 KB
/
RemoteFactory.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#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()
*/
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 (fcntl(m_socket.m_socket, F_SETFL, flags) == -1)
{
result = -1;
}
}
}
#endif /* ! WIN32 */
if (result == 0)
{
close();
retVal = openRemote();
}
}
else
{
retVal = openRemote();
}
return retVal;
}