1 /***********************************************************************************************************************************
2 Harness for Protocol Testing
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <stdlib.h>
7 #include <unistd.h>
8
9 #include "common/io/fdRead.h"
10 #include "common/io/fdWrite.h"
11 #include "common/fork.h"
12
13 #include "common/harnessConfig.h"
14 #include "common/harnessDebug.h"
15 #include "common/harnessLog.h"
16 #include "common/harnessProtocol.h"
17
18 /***********************************************************************************************************************************
19 Include shimmed C modules
20 ***********************************************************************************************************************************/
21 {[SHIM_MODULE]}
22
23 /***********************************************************************************************************************************
24 Shim install state
25 ***********************************************************************************************************************************/
26 static struct
27 {
28 // Local process shim
29 bool localShim;
30 const ProtocolServerHandler *localHandlerList;
31 unsigned int localHandlerListSize;
32
33 // Remote process shim
34 bool remoteShim;
35 const ProtocolServerHandler *remoteHandlerList;
36 unsigned int remoteHandlerListSize;
37 } hrnProtocolStatic;
38
39 /***********************************************************************************************************************************
40 Cleanup all clients inherited from the parent process so they cannot be accidentally used to send messages to servers that do not
41 belong to this process. We need to do this carefully so that exit commands are not sent and processes are not terminated, so clear
42 the mem context callback on each object before freeing it.
43 ***********************************************************************************************************************************/
44 static void
hrnProtocolClientCleanup(void)45 hrnProtocolClientCleanup(void)
46 {
47 FUNCTION_LOG_VOID(logLevelDebug);
48
49 if (protocolHelper.memContext != NULL)
50 {
51 // Cleanup remotes
52 for (unsigned int clientIdx = 0; clientIdx < protocolHelper.clientRemoteSize; clientIdx++)
53 {
54 // Cleanup remote client
55 if (protocolHelper.clientRemote[clientIdx].client != NULL)
56 {
57 memContextCallbackClear(((ProtocolClientPub *)protocolHelper.clientRemote[clientIdx].client)->memContext);
58 protocolClientFree(protocolHelper.clientRemote[clientIdx].client);
59 protocolHelper.clientRemote[clientIdx].client = NULL;
60 }
61
62 // Cleanup remote exec
63 if (protocolHelper.clientRemote[clientIdx].exec != NULL)
64 {
65 memContextCallbackClear(((ExecPub *)protocolHelper.clientRemote[clientIdx].exec)->memContext);
66 execFree(protocolHelper.clientRemote[clientIdx].exec);
67 protocolHelper.clientRemote[clientIdx].exec = NULL;
68 }
69 }
70
71 // Cleanup locals
72 for (unsigned int clientIdx = 0; clientIdx < protocolHelper.clientLocalSize; clientIdx++)
73 {
74 // Cleanup local client
75 if (protocolHelper.clientLocal[clientIdx].client != NULL)
76 {
77 memContextCallbackClear(((ProtocolClientPub *)protocolHelper.clientLocal[clientIdx].client)->memContext);
78 protocolClientFree(protocolHelper.clientLocal[clientIdx].client);
79 protocolHelper.clientLocal[clientIdx].client = NULL;
80 }
81
82 // Cleanup local exec
83 if (protocolHelper.clientLocal[clientIdx].exec != NULL)
84 {
85 memContextCallbackClear(((ExecPub *)protocolHelper.clientLocal[clientIdx].exec)->memContext);
86 execFree(protocolHelper.clientLocal[clientIdx].exec);
87 protocolHelper.clientLocal[clientIdx].exec = NULL;
88 }
89 }
90 }
91
92 FUNCTION_LOG_RETURN_VOID();
93 }
94
95 /***********************************************************************************************************************************
96 Shim protocolLocalExec() to provide coverage as detailed in the hrnProtocolLocalShimInstall() documentation.
97 ***********************************************************************************************************************************/
98 static void
protocolLocalExec(ProtocolHelperClient * helper,ProtocolStorageType protocolStorageType,unsigned int hostIdx,unsigned int processId)99 protocolLocalExec(
100 ProtocolHelperClient *helper, ProtocolStorageType protocolStorageType, unsigned int hostIdx, unsigned int processId)
101 {
102 // Call the shim when installed
103 if (hrnProtocolStatic.localShim)
104 {
105 FUNCTION_LOG_BEGIN(logLevelDebug);
106 FUNCTION_LOG_PARAM_P(VOID, helper);
107 FUNCTION_LOG_PARAM(STRING_ID, protocolStorageType);
108 FUNCTION_LOG_PARAM(UINT, hostIdx);
109 FUNCTION_LOG_PARAM(UINT, processId);
110 FUNCTION_LOG_END();
111
112 // Create pipes to communicate with the subprocess. The names of the pipes are from the perspective of the parent process
113 // since the child process will use them only briefly before exec'ing.
114 int pipeRead[2];
115 int pipeWrite[2];
116
117 THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to create read pipe");
118 THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to create write pipe");
119
120 // Exec command in the child process
121 if (forkSafe() == 0)
122 {
123 // Cleanup inherited clients
124 hrnProtocolClientCleanup();
125
126 // Load configuration
127 StringList *const paramList = protocolLocalParam(protocolStorageType, hostIdx, processId);
128 hrnCfgLoadP(cfgCmdNone, paramList, .noStd = true);
129
130 // Change log process id to aid in debugging
131 hrnLogProcessIdSet(processId);
132
133 // Run server with provided handlers
134 String *name = strNewFmt(PROTOCOL_SERVICE_LOCAL "-shim-%u", processId);
135 ProtocolServer *server = protocolServerNew(
136 name, PROTOCOL_SERVICE_LOCAL_STR, ioFdReadNewOpen(name, pipeWrite[0], 5000),
137 ioFdWriteNewOpen(name, pipeRead[1], 5000));
138 protocolServerProcess(server, NULL, hrnProtocolStatic.localHandlerList, hrnProtocolStatic.localHandlerListSize);
139
140 // Exit when done
141 exit(0);
142 }
143
144 // Close the unused file descriptors
145 close(pipeRead[1]);
146 close(pipeWrite[0]);
147
148 // Create protocol object
149 helper->client = protocolClientNew(
150 strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u shim protocol", processId), PROTOCOL_SERVICE_LOCAL_STR,
151 ioFdReadNewOpen(strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u shim protocol read", processId), pipeRead[0], 5000),
152 ioFdWriteNewOpen(strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u shim protocol write", processId), pipeWrite[1], 5000));
153
154 FUNCTION_LOG_RETURN_VOID();
155 }
156 // Else call the base function
157 else
158 protocolLocalExec_SHIMMED(helper, protocolStorageType, hostIdx, processId);
159 }
160
161 /**********************************************************************************************************************************/
162 void
hrnProtocolLocalShimInstall(const ProtocolServerHandler * const handlerList,const unsigned int handlerListSize)163 hrnProtocolLocalShimInstall(const ProtocolServerHandler *const handlerList, const unsigned int handlerListSize)
164 {
165 FUNCTION_HARNESS_BEGIN();
166 FUNCTION_HARNESS_PARAM_P(VOID, handlerList);
167 FUNCTION_HARNESS_PARAM(UINT, handlerListSize);
168 FUNCTION_HARNESS_END();
169
170 hrnProtocolStatic.localShim = true;
171 hrnProtocolStatic.localHandlerList = handlerList;
172 hrnProtocolStatic.localHandlerListSize = handlerListSize;
173
174 FUNCTION_HARNESS_RETURN_VOID();
175 }
176
177 /**********************************************************************************************************************************/
178 void
hrnProtocolLocalShimUninstall(void)179 hrnProtocolLocalShimUninstall(void)
180 {
181 FUNCTION_HARNESS_VOID();
182
183 hrnProtocolStatic.localShim = false;
184
185 FUNCTION_HARNESS_RETURN_VOID();
186 }
187
188 /***********************************************************************************************************************************
189 Shim protocolRemoteExec() to provide coverage as detailed in the hrnProtocolRemoteShimInstall() documentation.
190 ***********************************************************************************************************************************/
191 static void
protocolRemoteExec(ProtocolHelperClient * helper,ProtocolStorageType protocolStorageType,unsigned int hostIdx,unsigned int processId)192 protocolRemoteExec(
193 ProtocolHelperClient *helper, ProtocolStorageType protocolStorageType, unsigned int hostIdx, unsigned int processId)
194 {
195 // Call the shim when installed
196 if (hrnProtocolStatic.remoteShim)
197 {
198 FUNCTION_LOG_BEGIN(logLevelDebug);
199 FUNCTION_LOG_PARAM_P(VOID, helper);
200 FUNCTION_LOG_PARAM(STRING_ID, protocolStorageType);
201 FUNCTION_LOG_PARAM(UINT, hostIdx);
202 FUNCTION_LOG_PARAM(UINT, processId);
203 FUNCTION_LOG_END();
204
205 // Create pipes to communicate with the subprocess. The names of the pipes are from the perspective of the parent process
206 // since the child process will use them only briefly before exec'ing.
207 int pipeRead[2];
208 int pipeWrite[2];
209
210 THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to create read pipe");
211 THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to create write pipe");
212
213 // Exec command in the child process
214 if (forkSafe() == 0)
215 {
216 // Cleanup inherited clients
217 hrnProtocolClientCleanup();
218
219 // Load configuration
220 StringList *const paramList = protocolRemoteParam(protocolStorageType, hostIdx);
221 hrnCfgLoadP(cfgCmdNone, paramList, .noStd = true);
222
223 // Change log process id to aid in debugging
224 hrnLogProcessIdSet(processId);
225
226 // Run server with provided handlers
227 String *name = strNewFmt(PROTOCOL_SERVICE_REMOTE "-shim-%u", processId);
228 ProtocolServer *server = protocolServerNew(
229 name, PROTOCOL_SERVICE_REMOTE_STR, ioFdReadNewOpen(name, pipeWrite[0], 5000),
230 ioFdWriteNewOpen(name, pipeRead[1], 5000));
231 protocolServerProcess(server, NULL, hrnProtocolStatic.remoteHandlerList, hrnProtocolStatic.remoteHandlerListSize);
232
233 // Put an end message here to sync with the client to ensure that coverage data is written before exiting
234 protocolServerDataEndPut(server);
235
236 // Exit when done
237 exit(0);
238 }
239
240 // Close the unused file descriptors
241 close(pipeRead[1]);
242 close(pipeWrite[0]);
243
244 // Create protocol object
245 helper->client = protocolClientNew(
246 strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u shim protocol", processId), PROTOCOL_SERVICE_REMOTE_STR,
247 ioFdReadNewOpen(strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u shim protocol read", processId), pipeRead[0], 5000),
248 ioFdWriteNewOpen(strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u shim protocol write", processId), pipeWrite[1], 5000));
249
250 FUNCTION_LOG_RETURN_VOID();
251 }
252 // Else call the base function
253 else
254 protocolRemoteExec_SHIMMED(helper, protocolStorageType, hostIdx, processId);
255 }
256
257 /**********************************************************************************************************************************/
258 void
hrnProtocolRemoteShimInstall(const ProtocolServerHandler * const handlerList,const unsigned int handlerListSize)259 hrnProtocolRemoteShimInstall(const ProtocolServerHandler *const handlerList, const unsigned int handlerListSize)
260 {
261 FUNCTION_HARNESS_BEGIN();
262 FUNCTION_HARNESS_PARAM_P(VOID, handlerList);
263 FUNCTION_HARNESS_PARAM(UINT, handlerListSize);
264 FUNCTION_HARNESS_END();
265
266 hrnProtocolStatic.remoteShim = true;
267 hrnProtocolStatic.remoteHandlerList = handlerList;
268 hrnProtocolStatic.remoteHandlerListSize = handlerListSize;
269
270 FUNCTION_HARNESS_RETURN_VOID();
271 }
272
273 /**********************************************************************************************************************************/
274 void
hrnProtocolRemoteShimUninstall(void)275 hrnProtocolRemoteShimUninstall(void)
276 {
277 FUNCTION_HARNESS_VOID();
278
279 hrnProtocolStatic.remoteShim = false;
280
281 FUNCTION_HARNESS_RETURN_VOID();
282 }
283