VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/localipc-win.cpp@ 47122

Last change on this file since 47122 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: 41.5 KB
Line 
1/* $Id: localipc-win.cpp 47122 2013-07-12 14:34:26Z vboxsync $ */
2/** @file
3 * IPRT - Local IPC, Windows Implementation Using Named Pipes.
4 */
5
6/*
7 * Copyright (C) 2008-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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* Header Files *
29*******************************************************************************/
30/*
31 * We have to force NT 5.0 here because of
32 * ConvertStringSecurityDescriptorToSecurityDescriptor. Note that because of
33 * FILE_FLAG_FIRST_PIPE_INSTANCE this code actually requires W2K SP2+.
34 */
35#ifndef _WIN32_WINNT
36# define _WIN32_WINNT 0x0500 /* for ConvertStringSecurityDescriptorToSecurityDescriptor */
37#elif _WIN32_WINNT < 0x0500
38# undef _WIN32_WINNT
39# define _WIN32_WINNT 0x0500
40#endif
41#include <Windows.h>
42#include <sddl.h>
43
44#include <iprt/alloc.h>
45#include <iprt/asm.h>
46#include <iprt/assert.h>
47#include <iprt/critsect.h>
48#include <iprt/err.h>
49#include <iprt/ldr.h>
50#include <iprt/localipc.h>
51#include <iprt/param.h>
52#include <iprt/string.h>
53#include <iprt/thread.h>
54#include <iprt/time.h>
55
56#include "internal/magics.h"
57
58
59/*******************************************************************************
60* Defined Constants And Macros *
61*******************************************************************************/
62/** Pipe prefix string. */
63#define RTLOCALIPC_WIN_PREFIX "\\\\.\\pipe\\IPRT-"
64
65/** DACL for block all network access and local users other than the creator/owner.
66 *
67 * ACE format: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
68 *
69 * Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes
70 * the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded
71 * value 0x0012019b in the 2nd ACE. It expands to:
72 * 0x00000001 - FILE_READ_DATA
73 * 0x00000008 - FILE_READ_EA
74 * 0x00000080 - FILE_READ_ATTRIBUTES
75 * 0x00020000 - READ_CONTROL
76 * 0x00100000 - SYNCHRONIZE
77 * 0x00000002 - FILE_WRITE_DATA
78 * 0x00000010 - FILE_WRITE_EA
79 * 0x00000100 - FILE_WRITE_ATTRIBUTES
80 * 0x0012019b
81 * or FILE_GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_CREATE_PIPE_INSTANCE)
82 *
83 * @todo Double check this!
84 * @todo Drop the EA rights too? Since they doesn't mean anything to PIPS according to the docs.
85 * @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate?
86 * @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking
87 * it just to get progress - the service runs as local system.
88 * The CREATOR OWNER and PERSONAL SELF works (the former is only involved in inheriting
89 * it seems, which is why it won't work. The latter I've no idea about. Perhaps the solution
90 * is to go the annoying route of OpenProcessToken, QueryTokenInformation,
91 * ConvertSidToStringSid and then use the result... Suggestions are very welcome
92 */
93#define RTLOCALIPC_WIN_SDDL \
94 SDDL_DACL SDDL_DELIMINATOR \
95 SDDL_ACE_BEGIN SDDL_ACCESS_DENIED ";;" SDDL_GENERIC_ALL ";;;" SDDL_NETWORK SDDL_ACE_END \
96 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END \
97 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
98
99// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \
100// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";CIOI;" SDDL_GENERIC_ALL ";;;" SDDL_CREATOR_OWNER SDDL_ACE_END
101// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END
102// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
103
104
105/*******************************************************************************
106* Structures and Typedefs *
107*******************************************************************************/
108/**
109 * Local IPC service instance, Windows.
110 */
111typedef struct RTLOCALIPCSERVERINT
112{
113 /** The magic (RTLOCALIPCSERVER_MAGIC). */
114 uint32_t u32Magic;
115 /** The creation flags. */
116 uint32_t fFlags;
117 /** Critical section protecting the structure. */
118 RTCRITSECT CritSect;
119 /** The number of references to the instance.
120 * @remarks The reference counting isn't race proof. */
121 uint32_t volatile cRefs;
122 /** Indicates that there is a pending cancel request. */
123 bool volatile fCancelled;
124 /** The name pipe handle. */
125 HANDLE hNmPipe;
126 /** The handle to the event object we're using for overlapped I/O. */
127 HANDLE hEvent;
128 /** The overlapped I/O structure. */
129 OVERLAPPED OverlappedIO;
130 /** The pipe name. */
131 char szName[1];
132} RTLOCALIPCSERVERINT;
133/** Pointer to a local IPC server instance (Windows). */
134typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT;
135
136
137/**
138 * Local IPC session instance, Windows.
139 */
140typedef struct RTLOCALIPCSESSIONINT
141{
142 /** The magic (RTLOCALIPCSESSION_MAGIC). */
143 uint32_t u32Magic;
144 /** Critical section protecting the structure. */
145 RTCRITSECT CritSect;
146 /** The number of references to the instance.
147 * @remarks The reference counting isn't race proof. */
148 uint32_t volatile cRefs;
149 /** Set if there is already pending I/O. */
150 bool fIOPending;
151 /** Set if the zero byte read that the poll code using is pending. */
152 bool fZeroByteRead;
153 /** Indicates that there is a pending cancel request. */
154 bool volatile fCancelled;
155 /** The name pipe handle. */
156 HANDLE hNmPipe;
157 /** The handle to the event object we're using for overlapped I/O. */
158 HANDLE hEvent;
159 /** The overlapped I/O structure. */
160 OVERLAPPED OverlappedIO;
161 /** Bounce buffer for writes. */
162 uint8_t *pbBounceBuf;
163 /** Amount of used buffer space. */
164 size_t cbBounceBufUsed;
165 /** Amount of allocated buffer space. */
166 size_t cbBounceBufAlloc;
167 /** Buffer for the zero byte read.
168 * Used in RTLocalIpcSessionWaitForData(). */
169 uint8_t abBuf[8];
170} RTLOCALIPCSESSIONINT;
171/** Pointer to a local IPC session instance (Windows). */
172typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
173
174typedef BOOL WINAPI FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR(LPCTSTR, DWORD, PSECURITY_DESCRIPTOR, PULONG);
175typedef FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
176 *PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR; /* No, nobody fell on the keyboard, really! */
177
178
179/*******************************************************************************
180* Internal Functions *
181*******************************************************************************/
182static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession);
183
184
185/**
186 * Builds and allocates the security descriptor required for securing the local pipe.
187 *
188 * @return IPRT status code.
189 * @param ppDesc Where to store the allocated security descriptor on success.
190 * Must be free'd using LocalFree().
191 */
192static int rtLocalIpcServerWinAllocSecurityDescriptior(PSECURITY_DESCRIPTOR *ppDesc)
193{
194 /** @todo Stuff this into RTInitOnce? Later. */
195 PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
196 pfnConvertStringSecurityDescriptorToSecurityDescriptor = NULL;
197
198 RTLDRMOD hAdvApi32 = NIL_RTLDRMOD;
199 int rc = RTLdrLoadSystem("Advapi32.dll", true /*fNoUnload*/, &hAdvApi32);
200 if (RT_SUCCESS(rc))
201 rc = RTLdrGetSymbol(hAdvApi32, "ConvertStringSecurityDescriptorToSecurityDescriptorW",
202 (void**)&pfnConvertStringSecurityDescriptorToSecurityDescriptor);
203
204 PSECURITY_DESCRIPTOR pSecDesc = NULL;
205 if (RT_SUCCESS(rc))
206 {
207 AssertPtr(pfnConvertStringSecurityDescriptorToSecurityDescriptor);
208
209 /*
210 * We'll create a security descriptor from a SDDL that denies
211 * access to network clients (this is local IPC after all), it
212 * makes some further restrictions to prevent non-authenticated
213 * users from screwing around.
214 */
215 PRTUTF16 pwszSDDL;
216 rc = RTStrToUtf16(RTLOCALIPC_WIN_SDDL, &pwszSDDL);
217 if (RT_SUCCESS(rc))
218 {
219 if (!pfnConvertStringSecurityDescriptorToSecurityDescriptor((LPCTSTR)pwszSDDL,
220 SDDL_REVISION_1,
221 &pSecDesc,
222 NULL))
223 {
224 rc = RTErrConvertFromWin32(GetLastError());
225 }
226
227 RTUtf16Free(pwszSDDL);
228 }
229 }
230 else
231 {
232 /* Windows OSes < W2K SP2 not supported for now, bail out. */
233 /** @todo Implement me! */
234 rc = VERR_NOT_SUPPORTED;
235 }
236
237 if (hAdvApi32 != NIL_RTLDRMOD)
238 RTLdrClose(hAdvApi32);
239
240 if (RT_SUCCESS(rc))
241 {
242 AssertPtr(pSecDesc);
243 *ppDesc = pSecDesc;
244 }
245
246 return rc;
247}
248
249/**
250 * Creates a named pipe instance.
251 *
252 * This is used by both RTLocalIpcServerCreate and RTLocalIpcServerListen.
253 *
254 * @return IPRT status code.
255 * @param phNmPipe Where to store the named pipe handle on success. This
256 * will be set to INVALID_HANDLE_VALUE on failure.
257 * @param pszFullPipeName The full named pipe name.
258 * @param fFirst Set on the first call (from RTLocalIpcServerCreate), otherwise clear.
259 * Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag.
260 */
261static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
262{
263 *phNmPipe = INVALID_HANDLE_VALUE;
264
265 PSECURITY_DESCRIPTOR pSecDesc;
266 int rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc);
267 if (RT_SUCCESS(rc))
268 {
269 SECURITY_ATTRIBUTES SecAttrs;
270 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
271 SecAttrs.lpSecurityDescriptor = pSecDesc;
272 SecAttrs.bInheritHandle = FALSE;
273
274 DWORD fOpenMode = PIPE_ACCESS_DUPLEX
275 | PIPE_WAIT
276 | FILE_FLAG_OVERLAPPED;
277
278 bool fSupportsFirstInstance = false;
279
280 OSVERSIONINFOEX OSInfoEx;
281 RT_ZERO(OSInfoEx);
282 OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
283 if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
284 && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT)
285 {
286 if ( /* Vista+. */
287 OSInfoEx.dwMajorVersion >= 6
288 /* Windows XP+. */
289 || ( OSInfoEx.dwMajorVersion == 5
290 && OSInfoEx.dwMinorVersion > 0)
291 /* Windows 2000. */
292 || ( OSInfoEx.dwMajorVersion == 5
293 && OSInfoEx.dwMinorVersion == 0
294 && OSInfoEx.wServicePackMajor >= 2))
295 {
296 /* Requires at least W2K (5.0) SP2+. This is non-fatal. */
297 fSupportsFirstInstance = true;
298 }
299 }
300
301 if (fFirst && fSupportsFirstInstance)
302 fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
303
304 HANDLE hNmPipe = CreateNamedPipe(pszFullPipeName, /* lpName */
305 fOpenMode, /* dwOpenMode */
306 PIPE_TYPE_BYTE, /* dwPipeMode */
307 PIPE_UNLIMITED_INSTANCES, /* nMaxInstances */
308 PAGE_SIZE, /* nOutBufferSize (advisory) */
309 PAGE_SIZE, /* nInBufferSize (ditto) */
310 30*1000, /* nDefaultTimeOut = 30 sec */
311 NULL /** @todo !!! Fix this !!! &SecAttrs */); /* lpSecurityAttributes */
312 LocalFree(pSecDesc);
313 if (hNmPipe != INVALID_HANDLE_VALUE)
314 {
315 *phNmPipe = hNmPipe;
316 }
317 else
318 rc = RTErrConvertFromWin32(GetLastError());
319 }
320
321 return rc;
322}
323
324
325RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags)
326{
327 /*
328 * Basic parameter validation.
329 */
330 AssertPtrReturn(phServer, VERR_INVALID_POINTER);
331 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
332 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
333 AssertReturn(!(fFlags & ~(RTLOCALIPC_FLAGS_VALID_MASK)), VERR_INVALID_PARAMETER);
334 AssertReturn((fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION), VERR_INVALID_PARAMETER); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */
335
336 /*
337 * Allocate and initialize the instance data.
338 */
339 size_t cchName = strlen(pszName);
340 size_t cch = RT_OFFSETOF(RTLOCALIPCSERVERINT, szName[cchName + sizeof(RTLOCALIPC_WIN_PREFIX)]);
341 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAlloc(cch);
342 if (!pThis)
343 return VERR_NO_MEMORY;
344 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC;
345 pThis->cRefs = 1; /* the one we return */
346 pThis->fCancelled = false;
347 memcpy(pThis->szName, RTLOCALIPC_WIN_PREFIX, sizeof(RTLOCALIPC_WIN_PREFIX) - 1);
348 memcpy(&pThis->szName[sizeof(RTLOCALIPC_WIN_PREFIX) - 1], pszName, cchName + 1);
349 int rc = RTCritSectInit(&pThis->CritSect);
350 if (RT_SUCCESS(rc))
351 {
352 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
353 FALSE /*bInitialState*/, NULL /*lpName*/);
354 if (pThis->hEvent != NULL)
355 {
356 RT_ZERO(pThis->OverlappedIO);
357 pThis->OverlappedIO.Internal = STATUS_PENDING;
358 pThis->OverlappedIO.hEvent = pThis->hEvent;
359
360 rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe,
361 pThis->szName, true /* fFirst */);
362 if (RT_SUCCESS(rc))
363 {
364 *phServer = pThis;
365 return VINF_SUCCESS;
366 }
367
368 BOOL fRc = CloseHandle(pThis->hEvent);
369 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
370 }
371 else
372 rc = RTErrConvertFromWin32(GetLastError());
373
374 int rc2 = RTCritSectDelete(&pThis->CritSect);
375 AssertRC(rc2);
376 }
377 RTMemFree(pThis);
378 return rc;
379}
380
381
382/**
383 * Call when the reference count reaches 0.
384 * Caller owns the critsect.
385 * @param pThis The instance to destroy.
386 */
387static void rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis)
388{
389 BOOL fRc = CloseHandle(pThis->hNmPipe);
390 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
391 pThis->hNmPipe = INVALID_HANDLE_VALUE;
392
393 fRc = CloseHandle(pThis->hEvent);
394 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
395 pThis->hEvent = NULL;
396
397 RTCritSectLeave(&pThis->CritSect);
398 RTCritSectDelete(&pThis->CritSect);
399
400 RTMemFree(pThis);
401}
402
403
404RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
405{
406 /*
407 * Validate input.
408 */
409 if (hServer == NIL_RTLOCALIPCSERVER)
410 return VINF_SUCCESS;
411 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
412 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
413 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_MAGIC);
414
415 /*
416 * Cancel any thread currently busy using the server,
417 * leaving the cleanup to it.
418 */
419 RTCritSectEnter(&pThis->CritSect);
420 ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC);
421 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
422 Assert(pThis->cRefs);
423 pThis->cRefs--;
424
425 if (pThis->cRefs)
426 {
427 BOOL fRc = SetEvent(pThis->hEvent);
428 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
429
430 RTCritSectLeave(&pThis->CritSect);
431 }
432 else
433 rtLocalIpcServerWinDestroy(pThis);
434
435 return VINF_SUCCESS;
436}
437
438
439RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession)
440{
441 /*
442 * Validate input.
443 */
444 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
445 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
446 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_MAGIC);
447
448 /*
449 * Enter the critsect before inspecting the object further.
450 */
451 int rc;
452 RTCritSectEnter(&pThis->CritSect);
453 if (pThis->fCancelled)
454 {
455 pThis->fCancelled = false;
456 rc = VERR_CANCELLED;
457 RTCritSectLeave(&pThis->CritSect);
458 }
459 else
460 {
461 pThis->cRefs++;
462 ResetEvent(pThis->hEvent);
463 RTCritSectLeave(&pThis->CritSect);
464
465 /*
466 * Try connect a client. We need to use overlapped I/O here because
467 * of the cancellation done by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
468 */
469 SetLastError(NO_ERROR);
470 BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO);
471 DWORD dwErr = fRc ? NO_ERROR : GetLastError();
472 if ( !fRc
473 && dwErr == ERROR_IO_PENDING)
474 {
475 WaitForSingleObject(pThis->hEvent, INFINITE);
476 DWORD dwIgnored;
477 fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/);
478 dwErr = fRc ? NO_ERROR : GetLastError();
479 }
480
481 RTCritSectEnter(&pThis->CritSect);
482 if ( !pThis->fCancelled /* Event signalled but not cancelled? */
483 && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC)
484 {
485 /*
486 * Still alive, some error or an actual client.
487 *
488 * If it's the latter we'll have to create a new pipe instance that
489 * replaces the current one for the server. The current pipe instance
490 * will be assigned to the client session.
491 */
492 if ( fRc
493 || dwErr == ERROR_PIPE_CONNECTED)
494 {
495 HANDLE hNmPipe;
496 rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->szName, false /* fFirst */);
497 if (RT_SUCCESS(rc))
498 {
499 HANDLE hNmPipeSession = pThis->hNmPipe; /* consumed */
500 pThis->hNmPipe = hNmPipe;
501 rc = rtLocalIpcWinCreateSession(phClientSession, hNmPipeSession);
502 }
503 else
504 {
505 /*
506 * We failed to create a new instance for the server, disconnect
507 * the client and fail. Don't try service the client here.
508 */
509 fRc = DisconnectNamedPipe(pThis->hNmPipe);
510 AssertMsg(fRc, ("%d\n", GetLastError()));
511 }
512 }
513 else
514 rc = RTErrConvertFromWin32(dwErr);
515 }
516 else
517 {
518 /*
519 * Cancelled or destroyed.
520 *
521 * Cancel the overlapped io if it didn't complete (must be done
522 * in the this thread) or disconnect the client.
523 */
524 if ( fRc
525 || dwErr == ERROR_PIPE_CONNECTED)
526 fRc = DisconnectNamedPipe(pThis->hNmPipe);
527 else if (dwErr == ERROR_IO_PENDING)
528 fRc = CancelIo(pThis->hNmPipe);
529 else
530 fRc = TRUE;
531 AssertMsg(fRc, ("%d\n", GetLastError()));
532 rc = VERR_CANCELLED;
533 }
534
535 pThis->cRefs--;
536 if (pThis->cRefs)
537 RTCritSectLeave(&pThis->CritSect);
538 else
539 rtLocalIpcServerWinDestroy(pThis);
540 }
541
542 return rc;
543}
544
545
546RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
547{
548 /*
549 * Validate input.
550 */
551 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
552 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
553 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_MAGIC);
554
555 /*
556 * Enter the critical section, then set the cancellation flag
557 * and signal the event (to wake up anyone in/at WaitForSingleObject).
558 */
559 int rc = RTCritSectEnter(&pThis->CritSect);
560 if (RT_SUCCESS(rc))
561 {
562 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
563 BOOL fRc = SetEvent(pThis->hEvent);
564 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
565
566 rc = RTCritSectLeave(&pThis->CritSect);
567 }
568
569 return rc;
570}
571
572
573/**
574 * Create a session instance.
575 *
576 * @returns IPRT status code.
577 *
578 * @param phClientSession Where to store the session handle on success.
579 * @param hNmPipeSession The named pipe handle. This will be consumed by this session, meaning on failure
580 * to create the session it will be closed.
581 */
582static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession)
583{
584 AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
585 AssertReturn(hNmPipeSession != INVALID_HANDLE_VALUE, VERR_INVALID_HANDLE);
586
587 int rc;
588
589 /*
590 * Allocate and initialize the session instance data.
591 */
592 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis));
593 if (pThis)
594 {
595 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
596 pThis->cRefs = 1; /* our ref */
597 pThis->fCancelled = false;
598 pThis->hNmPipe = hNmPipeSession;
599
600 rc = RTCritSectInit(&pThis->CritSect);
601 if (RT_SUCCESS(rc))
602 {
603 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
604 FALSE /*bInitialState*/, NULL /*lpName*/);
605 if (pThis->hEvent != NULL)
606 {
607 RT_ZERO(pThis->OverlappedIO);
608 pThis->OverlappedIO.Internal = STATUS_PENDING;
609 pThis->OverlappedIO.hEvent = pThis->hEvent;
610
611 *phClientSession = pThis;
612 return VINF_SUCCESS;
613 }
614
615 /* bail out */
616 rc = RTErrConvertFromWin32(GetLastError());
617 RTCritSectDelete(&pThis->CritSect);
618 }
619 RTMemFree(pThis);
620 }
621 else
622 rc = VERR_NO_MEMORY;
623
624 BOOL fRc = CloseHandle(hNmPipeSession);
625 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
626 return rc;
627}
628
629RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
630{
631 AssertPtrReturn(phSession, VERR_INVALID_POINTER);
632 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
633 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
634 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* Flags currently unused, must be 0. */
635
636 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis));
637 if (!pThis)
638 return VERR_NO_MEMORY;
639
640 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
641 pThis->cRefs = 1; /* The one we return. */
642 pThis->fIOPending = false;
643 pThis->fZeroByteRead = false;
644 pThis->fCancelled = false;
645 pThis->pbBounceBuf = NULL;
646 pThis->cbBounceBufAlloc = 0;
647 pThis->cbBounceBufUsed = 0;
648
649 int rc = RTCritSectInit(&pThis->CritSect);
650 if (RT_SUCCESS(rc))
651 {
652 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
653 FALSE /*bInitialState*/, NULL /*lpName*/);
654 if (pThis->hEvent != NULL)
655 {
656 RT_ZERO(pThis->OverlappedIO);
657 pThis->OverlappedIO.Internal = STATUS_PENDING;
658 pThis->OverlappedIO.hEvent = pThis->hEvent;
659
660 char *pszPipe;
661 if (RTStrAPrintf(&pszPipe, "%s%s", RTLOCALIPC_WIN_PREFIX, pszName))
662 {
663 PSECURITY_DESCRIPTOR pSecDesc;
664 rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc);
665 if (RT_SUCCESS(rc))
666 {
667 SECURITY_ATTRIBUTES SecAttrs;
668 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
669 SecAttrs.lpSecurityDescriptor = pSecDesc;
670 SecAttrs.bInheritHandle = FALSE;
671
672 HANDLE hPipe = CreateFile(pszPipe, /* pipe name */
673 GENERIC_READ | /* read and write access */
674 GENERIC_WRITE,
675 0, /* no sharing */
676 &SecAttrs, /* default security attributes */
677 OPEN_EXISTING, /* opens existing pipe */
678 FILE_FLAG_OVERLAPPED, /* default attributes */
679 NULL); /* no template file */
680 LocalFree(pSecDesc);
681 RTStrFree(pszPipe);
682
683 if (hPipe != INVALID_HANDLE_VALUE)
684 {
685 pThis->hNmPipe = hPipe;
686 *phSession = pThis;
687 return VINF_SUCCESS;
688 }
689 else
690 rc = RTErrConvertFromWin32(GetLastError());
691 }
692 }
693 else
694 rc = VERR_NO_MEMORY;
695
696 BOOL fRc = CloseHandle(pThis->hEvent);
697 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
698 }
699 else
700 rc = RTErrConvertFromWin32(GetLastError());
701
702 int rc2 = RTCritSectDelete(&pThis->CritSect);
703 AssertRC(rc2);
704 }
705
706 RTMemFree(pThis);
707 return rc;
708}
709
710
711/**
712 * Call when the reference count reaches 0.
713 * Caller owns the critsect.
714 * @param pThis The instance to destroy.
715 */
716static void rtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis)
717{
718 BOOL fRc = CloseHandle(pThis->hNmPipe);
719 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
720 pThis->hNmPipe = INVALID_HANDLE_VALUE;
721
722 fRc = CloseHandle(pThis->hEvent);
723 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
724 pThis->hEvent = NULL;
725
726 RTCritSectLeave(&pThis->CritSect);
727 RTCritSectDelete(&pThis->CritSect);
728
729 RTMemFree(pThis);
730}
731
732
733RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
734{
735 /*
736 * Validate input.
737 */
738 if (hSession == NIL_RTLOCALIPCSESSION)
739 return VINF_SUCCESS;
740 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
741 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
742 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_MAGIC);
743
744 /*
745 * Cancel any thread currently busy using the session,
746 * leaving the cleanup to it.
747 */
748 RTCritSectEnter(&pThis->CritSect);
749 ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSESSION_MAGIC);
750 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
751 pThis->cRefs--;
752
753 if (pThis->cRefs > 0)
754 {
755 BOOL fRc = SetEvent(pThis->hEvent);
756 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
757
758 RTCritSectLeave(&pThis->CritSect);
759 }
760 else
761 rtLocalIpcSessionWinDestroy(pThis);
762
763 return VINF_SUCCESS;
764}
765
766
767RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
768{
769 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
770 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
771 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
772 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
773 /* pcbRead is optional. */
774
775 int rc = RTCritSectEnter(&pThis->CritSect);
776 if (RT_SUCCESS(rc))
777 {
778 /* No concurrent readers, sorry. */
779 if (pThis->cRefs == 1)
780 {
781 pThis->cRefs++;
782
783 /*
784 * If pcbRead is non-NULL this indicates the maximum number of bytes to read.
785 * If pcbRead is NULL the this is the exact number of bytes to read.
786 */
787 size_t cbToRead = pcbRead ? *pcbRead : cbBuffer;
788 size_t cbTotalRead = 0;
789 while (cbToRead > 0)
790 {
791 /*
792 * Kick of a an overlapped read. It should return immediately if
793 * there is bytes in the buffer. If not, we'll cancel it and see
794 * what we get back.
795 */
796 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
797 DWORD cbRead = 0;
798 pThis->fIOPending = true;
799 RTCritSectLeave(&pThis->CritSect);
800
801 if (ReadFile(pThis->hNmPipe, pvBuffer,
802 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
803 &cbRead, &pThis->OverlappedIO))
804 rc = VINF_SUCCESS;
805 else if (GetLastError() == ERROR_IO_PENDING)
806 {
807 WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
808 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO,
809 &cbRead, TRUE /*fWait*/))
810 rc = VINF_SUCCESS;
811 else
812 rc = RTErrConvertFromWin32(GetLastError());
813 }
814 else
815 rc = RTErrConvertFromWin32(GetLastError());
816
817 RTCritSectEnter(&pThis->CritSect);
818 pThis->fIOPending = false;
819 if (RT_FAILURE(rc))
820 break;
821
822 /* Advance. */
823 cbToRead -= cbRead;
824 cbTotalRead += cbRead;
825 pvBuffer = (uint8_t *)pvBuffer + cbRead;
826 }
827
828 if (pcbRead)
829 {
830 *pcbRead = cbTotalRead;
831 if ( RT_FAILURE(rc)
832 && cbTotalRead
833 && rc != VERR_INVALID_POINTER)
834 rc = VINF_SUCCESS;
835 }
836
837 pThis->cRefs--;
838 }
839 else
840 rc = VERR_WRONG_ORDER;
841 RTCritSectLeave(&pThis->CritSect);
842 }
843
844 return rc;
845}
846
847
848/**
849 * Common worker for handling I/O completion.
850 *
851 * This is used by RTLocalIpcSessionClose and RTLocalIpcSessionWrite.
852 *
853 * @returns IPRT status code.
854 * @param pThis The pipe instance handle.
855 */
856static int rtLocalIpcSessionWriteCheckCompletion(PRTLOCALIPCSESSIONINT pThis)
857{
858 int rc;
859 DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
860 if (dwRc == WAIT_OBJECT_0)
861 {
862 DWORD cbWritten = 0;
863 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE))
864 {
865 for (;;)
866 {
867 if (cbWritten >= pThis->cbBounceBufUsed)
868 {
869 pThis->fIOPending = false;
870 rc = VINF_SUCCESS;
871 break;
872 }
873
874 /* resubmit the remainder of the buffer - can this actually happen? */
875 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
876 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
877 if (!WriteFile(pThis->hNmPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
878 &cbWritten, &pThis->OverlappedIO))
879 {
880 if (GetLastError() == ERROR_IO_PENDING)
881 rc = VINF_TRY_AGAIN;
882 else
883 {
884 pThis->fIOPending = false;
885 if (GetLastError() == ERROR_NO_DATA)
886 rc = VERR_BROKEN_PIPE;
887 else
888 rc = RTErrConvertFromWin32(GetLastError());
889 }
890 break;
891 }
892 Assert(cbWritten > 0);
893 }
894 }
895 else
896 {
897 pThis->fIOPending = false;
898 rc = RTErrConvertFromWin32(GetLastError());
899 }
900 }
901 else if (dwRc == WAIT_TIMEOUT)
902 rc = VINF_TRY_AGAIN;
903 else
904 {
905 pThis->fIOPending = false;
906 if (dwRc == WAIT_ABANDONED)
907 rc = VERR_INVALID_HANDLE;
908 else
909 rc = RTErrConvertFromWin32(GetLastError());
910 }
911 return rc;
912}
913
914
915RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer)
916{
917 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
918 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
919 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
920 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
921 AssertReturn(cbBuffer, VERR_INVALID_PARAMETER);
922
923 int rc = RTCritSectEnter(&pThis->CritSect);
924 if (RT_SUCCESS(rc))
925 {
926 /* No concurrent writers, sorry. */
927 if (pThis->cRefs == 1)
928 {
929 pThis->cRefs++;
930
931 /*
932 * If I/O is pending, wait for it to complete.
933 */
934 if (pThis->fIOPending)
935 {
936 rc = rtLocalIpcSessionWriteCheckCompletion(pThis);
937 while (rc == VINF_TRY_AGAIN)
938 {
939 Assert(pThis->fIOPending);
940 HANDLE hEvent = pThis->OverlappedIO.hEvent;
941 RTCritSectLeave(&pThis->CritSect);
942 WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
943 RTCritSectEnter(&pThis->CritSect);
944 }
945 }
946 if (RT_SUCCESS(rc))
947 {
948 Assert(!pThis->fIOPending);
949
950 /*
951 * Try write everything.
952 * No bounce buffering, cUsers protects us.
953 */
954 size_t cbTotalWritten = 0;
955 while (cbBuffer > 0)
956 {
957 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
958 pThis->fIOPending = true;
959 RTCritSectLeave(&pThis->CritSect);
960
961 DWORD cbWritten = 0;
962 if (WriteFile(pThis->hNmPipe, pvBuffer,
963 cbBuffer <= ~(DWORD)0 ? (DWORD)cbBuffer : ~(DWORD)0,
964 &cbWritten, &pThis->OverlappedIO))
965 rc = VINF_SUCCESS;
966 else if (GetLastError() == ERROR_IO_PENDING)
967 {
968 WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
969 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE /*fWait*/))
970 rc = VINF_SUCCESS;
971 else
972 rc = RTErrConvertFromWin32(GetLastError());
973 }
974 else if (GetLastError() == ERROR_NO_DATA)
975 rc = VERR_BROKEN_PIPE;
976 else
977 rc = RTErrConvertFromWin32(GetLastError());
978
979 RTCritSectEnter(&pThis->CritSect);
980 pThis->fIOPending = false;
981 if (RT_FAILURE(rc))
982 break;
983
984 /* Advance. */
985 pvBuffer = (char const *)pvBuffer + cbWritten;
986 cbTotalWritten += cbWritten;
987 cbBuffer -= cbWritten;
988 }
989 }
990
991 pThis->cRefs--;
992 }
993 else
994 rc = VERR_WRONG_ORDER;
995 RTCritSectLeave(&pThis->CritSect);
996 }
997
998 return rc;
999}
1000
1001
1002RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
1003{
1004 /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
1005 * all data was written (or an error occurred). */
1006 /** @todo Implement this as soon as we want an explicit asynchronous version of
1007 * RTLocalIpcSessionWrite on Windows. */
1008 return VINF_SUCCESS;
1009}
1010
1011
1012RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
1013{
1014 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1015 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1016 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1017
1018 uint64_t const StartMsTS = RTTimeMilliTS();
1019
1020 int rc = RTCritSectEnter(&pThis->CritSect);
1021 if (RT_FAILURE(rc))
1022 return rc;
1023 for (unsigned iLoop = 0;; iLoop++)
1024 {
1025 HANDLE hWait = INVALID_HANDLE_VALUE;
1026
1027 if (pThis->fIOPending)
1028 hWait = pThis->OverlappedIO.hEvent;
1029 else
1030 {
1031 /* Peek at the pipe buffer and see how many bytes it contains. */
1032 DWORD cbAvailable;
1033 BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL);
1034 if ( fRc
1035 && cbAvailable)
1036 {
1037 rc = VINF_SUCCESS;
1038 break;
1039 }
1040 else if (!fRc)
1041 {
1042 rc = RTErrConvertFromWin32(GetLastError());
1043 break;
1044 }
1045
1046 /* Start a zero byte read operation that we can wait on. */
1047 if (cMillies == 0)
1048 {
1049 rc = VERR_TIMEOUT;
1050 break;
1051 }
1052 AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER);
1053 fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
1054 DWORD cbRead = 0;
1055 if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO))
1056 {
1057 rc = VINF_SUCCESS;
1058 if (iLoop > 10)
1059 RTThreadYield();
1060 }
1061 else if (GetLastError() == ERROR_IO_PENDING)
1062 {
1063 pThis->cRefs++;
1064 pThis->fIOPending = true;
1065 pThis->fZeroByteRead = true;
1066 hWait = pThis->OverlappedIO.hEvent;
1067 }
1068 else
1069 rc = RTErrConvertFromWin32(GetLastError());
1070 }
1071
1072 if (RT_FAILURE(rc))
1073 break;
1074
1075 /*
1076 * Check for timeout.
1077 */
1078 DWORD cMsMaxWait = INFINITE;
1079 if ( cMillies != RT_INDEFINITE_WAIT
1080 && ( hWait != INVALID_HANDLE_VALUE
1081 || iLoop > 10)
1082 )
1083 {
1084 uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
1085 if (cElapsed >= cMillies)
1086 {
1087 rc = VERR_TIMEOUT;
1088 break;
1089 }
1090 cMsMaxWait = cMillies - (uint32_t)cElapsed;
1091 }
1092
1093 /*
1094 * Wait.
1095 */
1096 if (hWait != INVALID_HANDLE_VALUE)
1097 {
1098 RTCritSectLeave(&pThis->CritSect);
1099
1100 DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
1101 if (dwRc == WAIT_OBJECT_0)
1102 rc = VINF_SUCCESS;
1103 else if (dwRc == WAIT_TIMEOUT)
1104 rc = VERR_TIMEOUT;
1105 else if (dwRc == WAIT_ABANDONED)
1106 rc = VERR_INVALID_HANDLE;
1107 else
1108 rc = RTErrConvertFromWin32(GetLastError());
1109
1110 if ( RT_FAILURE(rc)
1111 && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC)
1112 return rc;
1113
1114 int rc2 = RTCritSectEnter(&pThis->CritSect);
1115 AssertRC(rc2);
1116 if (pThis->fZeroByteRead)
1117 {
1118 Assert(pThis->cRefs);
1119 pThis->cRefs--;
1120 pThis->fIOPending = false;
1121
1122 if (rc != VINF_SUCCESS)
1123 {
1124 BOOL fRc = CancelIo(pThis->hNmPipe);
1125 Assert(fRc == TRUE);
1126 }
1127
1128 DWORD cbRead = 0;
1129 BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/);
1130 if ( !fRc
1131 && RT_SUCCESS(rc))
1132 {
1133 DWORD dwRc = GetLastError();
1134 if (dwRc == ERROR_OPERATION_ABORTED)
1135 rc = VERR_CANCELLED;
1136 else
1137 rc = RTErrConvertFromWin32(dwRc);
1138 }
1139 }
1140
1141 if (RT_FAILURE(rc))
1142 break;
1143 }
1144 }
1145
1146 int rc2 = RTCritSectLeave(&pThis->CritSect);
1147 if (RT_SUCCESS(rc))
1148 rc = rc2;
1149
1150 return rc;
1151}
1152
1153
1154RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
1155{
1156 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1157 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1158 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1159
1160 /*
1161 * Enter the critical section, then set the cancellation flag
1162 * and signal the event (to wake up anyone in/at WaitForSingleObject).
1163 */
1164 int rc = RTCritSectEnter(&pThis->CritSect);
1165 if (RT_SUCCESS(rc))
1166 {
1167 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
1168 BOOL fRc = SetEvent(pThis->hEvent);
1169 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1170
1171 RTCritSectLeave(&pThis->CritSect);
1172 }
1173
1174 return rc;
1175}
1176
1177
1178RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
1179{
1180 return VERR_NOT_SUPPORTED;
1181}
1182
1183
1184RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid)
1185{
1186 return VERR_NOT_SUPPORTED;
1187}
1188
1189
1190RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTUID pUid)
1191{
1192 return VERR_NOT_SUPPORTED;
1193}
1194
Note: See TracBrowser for help on using the repository browser.

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