VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp@ 47136

Last change on this file since 47136 was 47122, checked in by vboxsync, 12 years ago

IPRT/localipc-win.cpp: Update (waiting on data now is properly getting interrupted on server destruction), more testcases (work in progress).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: tstRTLocalIpc.cpp 47122 2013-07-12 14:34:26Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTLocalIpc.
4 */
5
6/*
7 * Copyright (C) 2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/env.h>
32#include <iprt/localipc.h>
33#include <iprt/path.h>
34#include <iprt/process.h>
35#include <iprt/string.h>
36#include <iprt/test.h>
37#include <iprt/thread.h>
38#include <iprt/time.h>
39
40
41typedef struct LOCALIPCTHREADCTX
42{
43 /** The IPC server handle. */
44 RTLOCALIPCSERVER hServer;
45 /** The test handle. */
46 RTTEST hTest;
47} LOCALIPCTHREADCTX, *PLOCALIPCTHREADCTX;
48
49static int testServerListenAndCancel2(const char *pszExecPath)
50{
51 const char *apszArgs[4] = { pszExecPath, "child", "testServerListenAndCancel", NULL };
52 RTPROCESS hProc;
53 int rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc);
54
55 return rc;
56}
57
58static DECLCALLBACK(int) testServerListenAndCancelThread(RTTHREAD hSelf, void *pvUser)
59{
60 PRTLOCALIPCSERVER pServer = (PRTLOCALIPCSERVER)pvUser;
61 AssertPtr(pServer);
62
63 RTThreadSleep(5000); /* Wait a bit to simulate waiting in main thread. */
64
65 int rc = RTLocalIpcServerCancel(*pServer);
66 AssertRC(rc);
67
68 return 0;
69}
70
71static int testServerListenAndCancel(RTTEST hTest, const char *pszExecPath)
72{
73 RTTestSub(hTest, "testServerListenAndCancel");
74
75 RTLOCALIPCSERVER ipcServer;
76 int rc = RTLocalIpcServerCreate(&ipcServer, "testServerListenAndCancel",
77 RTLOCALIPC_FLAGS_MULTI_SESSION);
78 if (RT_SUCCESS(rc))
79 {
80 /* Spawn a simple worker thread and let it listen for incoming connections.
81 * In the meanwhile we try to cancel the server and see what happens. */
82 RTTHREAD hThread;
83 rc = RTThreadCreate(&hThread, testServerListenAndCancelThread,
84 &ipcServer, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc1");
85 if (RT_SUCCESS(rc))
86 {
87 do
88 {
89 RTTestPrintf(hTest, RTTESTLVL_INFO, "Listening for incoming connections ...\n");
90 RTLOCALIPCSESSION ipcSession;
91 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerListen(ipcServer, &ipcSession), VERR_CANCELLED);
92 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
93 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
94
95 RTTestPrintf(hTest, RTTESTLVL_INFO, "Waiting for thread to exit ...\n");
96 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
97 30 * 1000 /* 30s timeout */, NULL), VINF_SUCCESS);
98 } while (0);
99 }
100 else
101 RTTestIFailed("Unable to create thread for cancelling server, rc=%Rrc\n", rc);
102 }
103 else
104 RTTestIFailed("Unable to create IPC server, rc=%Rrc\n", rc);
105
106 return VINF_SUCCESS;
107}
108
109static DECLCALLBACK(int) testSessionConnectionThread(RTTHREAD hSelf, void *pvUser)
110{
111 PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
112 AssertPtr(pCtx);
113
114 int rc;
115 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Listening for incoming connections ...\n");
116 for (;;)
117 {
118 RTLOCALIPCSESSION ipcSession;
119 rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession);
120 RTTestPrintf(pCtx->hTest, RTTESTLVL_DEBUG, "testSessionConnectionThread: Listening returned with rc=%Rrc\n", rc);
121 if (RT_SUCCESS(rc))
122 {
123 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Got new client connection\n");
124 }
125 else
126 break;
127 }
128
129 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Ended with rc=%Rrc\n", rc);
130 return rc;
131}
132
133static RTEXITCODE testSessionConnectionChild(int argc, char **argv, RTTEST hTest)
134{
135 do
136 {
137 RTThreadSleep(2000); /* Fudge */
138 RTLOCALIPCSESSION clientSession;
139 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionConnection",
140 0 /* Flags */), VINF_SUCCESS);
141 RTThreadSleep(5000); /* Fudge */
142 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS);
143
144 } while (0);
145
146 return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
147}
148
149static int testSessionConnection(RTTEST hTest, const char *pszExecPath)
150{
151 RTTestSub(hTest, "testSessionConnection");
152
153 RTLOCALIPCSERVER ipcServer;
154 int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionConnection",
155 RTLOCALIPC_FLAGS_MULTI_SESSION);
156 if (RT_SUCCESS(rc))
157 {
158#ifndef VBOX_TESTCASES_WITH_NO_THREADING
159 LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
160
161 /* Spawn a simple worker thread and let it listen for incoming connections.
162 * In the meanwhile we try to cancel the server and see what happens. */
163 RTTHREAD hThread;
164 rc = RTThreadCreate(&hThread, testSessionConnectionThread,
165 &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc2");
166 if (RT_SUCCESS(rc))
167 {
168 do
169 {
170 RTPROCESS hProc;
171 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionFork", NULL };
172 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
173 RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
174 RTPROCSTATUS stsChild;
175 RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
176 RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated, waiting for server thread ...\n");
177 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
178 int threadRc;
179 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
180 30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
181 RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED);
182 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
183 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
184 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
185 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
186 }
187 while (0);
188 }
189 else
190 RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
191#else
192 do
193 {
194 RTPROCESS hProc;
195 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionFork", NULL };
196 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
197 RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
198 RTLOCALIPCSESSION ipcSession;
199 rc = RTLocalIpcServerListen(ipcServer, &ipcSession);
200 if (RT_SUCCESS(rc))
201 {
202 RTTestPrintf(hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Got new client connection\n");
203 }
204 else
205 RTTestFailed(hTest, "Error while listening, rc=%Rrc\n", rc);
206
207 } while (0);
208#endif
209 }
210 else
211 RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
212
213 return VINF_SUCCESS;
214}
215
216static DECLCALLBACK(int) testSessionWaitThread(RTTHREAD hSelf, void *pvUser)
217{
218 PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
219 AssertPtr(pCtx);
220
221 int rc;
222 for (;;)
223 {
224 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening for incoming connections ...\n");
225 RTLOCALIPCSESSION ipcSession;
226 rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession);
227 if (RT_SUCCESS(rc))
228 {
229 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Got new client connection, waiting a bit ...\n");
230 RTThreadSleep(2000);
231 rc = RTLocalIpcSessionClose(ipcSession);
232 }
233 else
234 {
235 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening ended with rc=%Rrc\n", rc);
236 break;
237 }
238 }
239
240 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Ended with rc=%Rrc\n", rc);
241 return rc;
242}
243
244static RTEXITCODE testSessionWaitChild(int argc, char **argv, RTTEST hTest)
245{
246 do
247 {
248 RTThreadSleep(2000); /* Fudge. */
249 RTLOCALIPCSESSION clientSession;
250 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionWait",
251 0 /* Flags */), VINF_SUCCESS);
252 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 100 /* 100ms timeout */),
253 VERR_TIMEOUT);
254 /* Next, try 60s timeout. Should be returning way earlier because the server closed the
255 * connection after the first client connected. */
256 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 60 * 1000),
257 VERR_BROKEN_PIPE);
258 /* Last try, also should fail because the server should be not around anymore. */
259 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 5 * 1000),
260 VERR_BROKEN_PIPE);
261 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS);
262
263 } while (0);
264
265 return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
266}
267
268static int testSessionWait(RTTEST hTest, const char *pszExecPath)
269{
270 RTTestSub(hTest, "testSessionWait");
271
272 RTLOCALIPCSERVER ipcServer;
273 int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionWait",
274 RTLOCALIPC_FLAGS_MULTI_SESSION);
275 if (RT_SUCCESS(rc))
276 {
277 LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
278
279 /* Spawn a simple worker thread and let it listen for incoming connections.
280 * In the meanwhile we try to cancel the server and see what happens. */
281 RTTHREAD hThread;
282 rc = RTThreadCreate(&hThread, testSessionWaitThread,
283 &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc3");
284 if (RT_SUCCESS(rc))
285 {
286 do
287 {
288 RTPROCESS hProc;
289 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitFork", NULL };
290 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
291 RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
292 RTThreadSleep(5000); /* Let the server run for some time ... */
293 RTTestPrintf(hTest, RTTESTLVL_INFO, "Cancelling server listening\n");
294 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
295 /* Wait for the server thread to terminate. */
296 int threadRc;
297 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
298 30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
299 RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED);
300 RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
301 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
302 /* Check if the child ran successfully. */
303 RTPROCSTATUS stsChild;
304 RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
305 RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
306 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
307 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
308 }
309 while (0);
310 }
311 else
312 RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
313 }
314 else
315 RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
316
317 return VINF_SUCCESS;
318}
319
320static RTEXITCODE mainChild(int argc, char **argv)
321{
322 if (argc < 3) /* Safety first. */
323 return RTEXITCODE_FAILURE;
324 /* Note: We assume argv[2] always contains the actual test type to perform. */
325 RTTEST hTest;
326 RTEXITCODE rcExit = RTTestInitAndCreate(argv[2], &hTest);
327 if (rcExit)
328 return rcExit;
329 RTTestBanner(hTest);
330
331 RTAssertSetMayPanic(false);
332#ifdef DEBUG_andy
333 RTAssertSetQuiet(true);
334#endif
335
336 if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionConnectionFork"))
337 rcExit = testSessionConnectionChild(argc, argv, hTest);
338 else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionWaitFork"))
339 rcExit = testSessionWaitChild(argc, argv, hTest);
340
341 return RTTestSummaryAndDestroy(hTest);
342}
343
344int main(int argc, char **argv)
345{
346 if ( argc > 2
347 && !RTStrICmp(argv[1], "child"))
348 return mainChild(argc, argv);
349
350 RTTEST hTest;
351 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTLocalIpc", &hTest);
352 if (rcExit)
353 return rcExit;
354 RTTestBanner(hTest);
355
356 char szExecPath[RTPATH_MAX];
357 if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
358 RTStrCopy(szExecPath, sizeof(szExecPath), argv[0]);
359
360 RTTestISub("Basics");
361
362 RTAssertSetMayPanic(false);
363#ifdef DEBUG_andy
364 RTAssertSetQuiet(true);
365#endif
366
367 /* Server-side. */
368 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(NULL, NULL, 0), VERR_INVALID_POINTER, 1);
369 RTLOCALIPCSERVER ipcServer;
370 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, NULL, 0), VERR_INVALID_POINTER, 1);
371 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "", 0), VERR_INVALID_PARAMETER, 1);
372 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "BasicTest", 0 /* Invalid flags */), VERR_INVALID_PARAMETER, 1);
373 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "BasicTest", 1234 /* Invalid flags */), VERR_INVALID_PARAMETER, 1);
374 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCancel(NULL), VERR_INVALID_HANDLE, 1);
375 RTTESTI_CHECK_RC_RET(RTLocalIpcServerDestroy(NULL), VINF_SUCCESS, 1);
376 /* Basic server creation / destruction. */
377 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCreate(&ipcServer, "BasicTest", RTLOCALIPC_FLAGS_MULTI_SESSION), VINF_SUCCESS, 1);
378 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS, 1);
379 RTTESTI_CHECK_RC_RET(RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS, 1);
380
381 /* Client-side (per session). */
382 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(NULL, NULL, 0), VERR_INVALID_POINTER, 1);
383 RTLOCALIPCSESSION ipcSession;
384 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, NULL, 0), VERR_INVALID_POINTER, 1);
385 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, "", 0), VERR_INVALID_PARAMETER, 1);
386 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, "BasicTest", 1234 /* Invalid flags */), VERR_INVALID_PARAMETER, 1);
387 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionCancel(NULL), VERR_INVALID_HANDLE, 1);
388 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionClose(NULL), VINF_SUCCESS, 1);
389 /* Basic client creation / destruction. */
390 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&ipcSession, "BasicTest", 0), VERR_FILE_NOT_FOUND, 1);
391 RTTESTI_CHECK_RC_RET(RTLocalIpcServerCancel(ipcServer), VERR_INVALID_MAGIC, 1);
392 RTTESTI_CHECK_RC_RET(RTLocalIpcServerDestroy(ipcServer), VERR_INVALID_MAGIC, 1);
393
394 if (RTTestErrorCount(hTest) == 0)
395 {
396 RTTESTI_CHECK_RC_RET(testServerListenAndCancel(hTest, szExecPath), VINF_SUCCESS, 1);
397 RTTESTI_CHECK_RC_RET(testSessionConnection(hTest, szExecPath), VINF_SUCCESS, 1);
398 RTTESTI_CHECK_RC_RET(testSessionWait(hTest, szExecPath), VINF_SUCCESS, 1);
399 }
400
401 /*
402 * Summary.
403 */
404 return RTTestSummaryAndDestroy(hTest);
405}
406
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette