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