VirtualBox

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

Last change on this file was 107600, checked in by vboxsync, 7 days ago

src/VBox/Runtime/r3/win/localipc-win.cpp: Fixed warnings found by Parfait (unused variable). jiraref:VBP-1424

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.5 KB
Line 
1/* $Id: localipc-win.cpp 107600 2025-01-09 16:52:56Z vboxsync $ */
2/** @file
3 * IPRT - Local IPC, Windows Implementation Using Named Pipes.
4 *
5 * @note This code only works on W2K because of the dependency on
6 * ConvertStringSecurityDescriptorToSecurityDescriptor.
7 */
8
9/*
10 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * The contents of this file may alternatively be used under the terms
29 * of the Common Development and Distribution License Version 1.0
30 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31 * in the VirtualBox distribution, in which case the provisions of the
32 * CDDL are applicable instead of those of the GPL.
33 *
34 * You may elect to license modified versions of this file under the
35 * terms and conditions of either the GPL or the CDDL or both.
36 *
37 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38 */
39
40
41/*********************************************************************************************************************************
42* Header Files *
43*********************************************************************************************************************************/
44#define LOG_GROUP RTLOGGROUP_LOCALIPC
45#include <iprt/nt/nt-and-windows.h> /* Need NtCancelIoFile and a few Rtl functions. */
46#include <sddl.h>
47#include <aclapi.h>
48
49#include "internal/iprt.h"
50#include <iprt/localipc.h>
51
52#include <iprt/asm.h>
53#include <iprt/assert.h>
54#include <iprt/critsect.h>
55#include <iprt/ctype.h>
56#include <iprt/err.h>
57#include <iprt/ldr.h>
58#include <iprt/log.h>
59#include <iprt/mem.h>
60#include <iprt/param.h>
61#include <iprt/string.h>
62#include <iprt/thread.h>
63#include <iprt/time.h>
64#include <iprt/utf16.h>
65
66#include "internal/magics.h"
67#include "internal-r3-win.h"
68
69
70
71/*********************************************************************************************************************************
72* Defined Constants And Macros *
73*********************************************************************************************************************************/
74/** Pipe prefix string. */
75#define RTLOCALIPC_WIN_PREFIX L"\\\\.\\pipe\\IPRT-"
76
77
78/*********************************************************************************************************************************
79* Structures and Typedefs *
80*********************************************************************************************************************************/
81/**
82 * Local IPC service instance, Windows.
83 */
84typedef struct RTLOCALIPCSERVERINT
85{
86 /** The magic (RTLOCALIPCSERVER_MAGIC). */
87 uint32_t u32Magic;
88 /** The creation flags. */
89 uint32_t fFlags;
90 /** Critical section protecting the structure. */
91 RTCRITSECT CritSect;
92 /** The number of references to the instance.
93 * @remarks The reference counting isn't race proof. */
94 uint32_t volatile cRefs;
95 /** Indicates that there is a pending cancel request. */
96 bool volatile fCancelled;
97 /** The named pipe handle. */
98 HANDLE hNmPipe;
99 /** The handle to the event object we're using for overlapped I/O. */
100 HANDLE hEvent;
101 /** The overlapped I/O structure. */
102 OVERLAPPED OverlappedIO;
103 /** The full pipe name (variable length). */
104 RTUTF16 wszName[1];
105} RTLOCALIPCSERVERINT;
106/** Pointer to a local IPC server instance (Windows). */
107typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT;
108
109
110/**
111 * Local IPC session instance, Windows.
112 *
113 * This is a named pipe and we should probably merge the pipe code with this to
114 * save work and code duplication.
115 */
116typedef struct RTLOCALIPCSESSIONINT
117{
118 /** The magic (RTLOCALIPCSESSION_MAGIC). */
119 uint32_t u32Magic;
120 /** Critical section protecting the structure. */
121 RTCRITSECT CritSect;
122 /** The number of references to the instance.
123 * @remarks The reference counting isn't race proof. */
124 uint32_t volatile cRefs;
125 /** Set if the zero byte read that the poll code using is pending. */
126 bool fZeroByteRead;
127 /** Indicates that there is a pending cancel request. */
128 bool volatile fCancelled;
129 /** Set if this is the server side, clear if the client. */
130 bool fServerSide;
131 /** The named pipe handle. */
132 HANDLE hNmPipe;
133 struct
134 {
135 RTTHREAD hActiveThread;
136 /** The handle to the event object we're using for overlapped I/O. */
137 HANDLE hEvent;
138 /** The overlapped I/O structure. */
139 OVERLAPPED OverlappedIO;
140 }
141 /** Overlapped reads. */
142 Read,
143 /** Overlapped writes. */
144 Write;
145#if 0 /* Non-blocking writes are not yet supported. */
146 /** Bounce buffer for writes. */
147 uint8_t *pbBounceBuf;
148 /** Amount of used buffer space. */
149 size_t cbBounceBufUsed;
150 /** Amount of allocated buffer space. */
151 size_t cbBounceBufAlloc;
152#endif
153 /** Buffer for the zero byte read.
154 * Used in RTLocalIpcSessionWaitForData(). */
155 uint8_t abBuf[8];
156} RTLOCALIPCSESSIONINT;
157/** Pointer to a local IPC session instance (Windows). */
158typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
159
160
161/*********************************************************************************************************************************
162* Internal Functions *
163*********************************************************************************************************************************/
164static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession);
165
166
167/**
168 * DACL for block all network access and local users other than the creator/owner.
169 *
170 * ACE format: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
171 *
172 * Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes
173 * the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded
174 * value 0x0012019b in the client ACE. The server-side still needs
175 * setting FILE_CREATE_PIPE_INSTANCE although.
176 * It expands to:
177 * 0x00000001 - FILE_READ_DATA
178 * 0x00000008 - FILE_READ_EA
179 * 0x00000080 - FILE_READ_ATTRIBUTES
180 * 0x00020000 - READ_CONTROL
181 * 0x00100000 - SYNCHRONIZE
182 * 0x00000002 - FILE_WRITE_DATA
183 * 0x00000010 - FILE_WRITE_EA
184 * 0x00000100 - FILE_WRITE_ATTRIBUTES
185 * = 0x0012019b (client)
186 * + (only for server):
187 * 0x00000004 - FILE_CREATE_PIPE_INSTANCE
188 * = 0x0012019f
189 *
190 * @todo Triple check this!
191 * @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate?
192 * @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking
193 * it just to get progress - the service runs as local system.
194 * The CREATOR OWNER and PERSONAL SELF works (the former is only involved in inheriting
195 * it seems, which is why it won't work. The latter I've no idea about. Perhaps the solution
196 * is to go the annoying route of OpenProcessToken, QueryTokenInformation,
197 * ConvertSidToStringSid and then use the result... Suggestions are very welcome
198 */
199#define RTLOCALIPC_WIN_SDDL_BASE \
200 SDDL_DACL SDDL_DELIMINATOR \
201 SDDL_ACE_BEGIN SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK SDDL_ACE_END \
202 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
203#define RTLOCALIPC_WIN_SDDL_SERVER \
204 RTLOCALIPC_WIN_SDDL_BASE \
205 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019f" L";;;" SDDL_EVERYONE SDDL_ACE_END
206#define RTLOCALIPC_WIN_SDDL_CLIENT \
207 RTLOCALIPC_WIN_SDDL_BASE \
208 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b" L";;;" SDDL_EVERYONE SDDL_ACE_END
209static NTSTATUS rtLocalIpcBuildDacl(PACL pDacl, bool fServer)
210{
211 static SID_IDENTIFIER_AUTHORITY s_NtAuth = SECURITY_NT_AUTHORITY;
212 union
213 {
214 SID Sid;
215 uint8_t abPadding[SECURITY_MAX_SID_SIZE];
216 } Network, LocalSystem, Everyone;
217
218
219 /* 1. SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK */
220 NTSTATUS rcNt = RtlInitializeSid(&Network.Sid, &s_NtAuth, 1);
221 AssertReturn(NT_SUCCESS(rcNt), rcNt);
222 *RtlSubAuthoritySid(&Network.Sid, 0) = SECURITY_NETWORK_RID;
223
224 rcNt = RtlAddAccessDeniedAce(pDacl, ACL_REVISION, GENERIC_ALL, &Network.Sid);
225 AssertReturn(NT_SUCCESS(rcNt), rcNt);
226
227 /* 2. SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL L";;;" SDDL_LOCAL_SYSTEM */
228 rcNt = RtlInitializeSid(&LocalSystem.Sid, &s_NtAuth, 1);
229 AssertReturn(NT_SUCCESS(rcNt), rcNt);
230 *RtlSubAuthoritySid(&LocalSystem.Sid, 0) = SECURITY_LOCAL_SYSTEM_RID;
231
232 rcNt = RtlAddAccessAllowedAce(pDacl, ACL_REVISION, FILE_ALL_ACCESS, &Network.Sid);
233 AssertReturn(NT_SUCCESS(rcNt), rcNt);
234
235
236 /* 3. server: SDDL_ACCESS_ALLOWED L";;" L"0x0012019f" L";;;" SDDL_EVERYONE
237 client: SDDL_ACCESS_ALLOWED L";;" L"0x0012019b" L";;;" SDDL_EVERYONE */
238 rcNt = RtlInitializeSid(&Everyone.Sid, &s_NtAuth, 1);
239 AssertReturn(NT_SUCCESS(rcNt), rcNt);
240 *RtlSubAuthoritySid(&Everyone.Sid, 0) = SECURITY_WORLD_RID;
241
242 DWORD const fAccess = FILE_READ_DATA /* 0x00000001 */
243 | FILE_WRITE_DATA /* 0x00000002 */
244 | FILE_CREATE_PIPE_INSTANCE * fServer /* 0x00000004 */
245 | FILE_READ_EA /* 0x00000008 */
246 | FILE_WRITE_EA /* 0x00000010 */
247 | FILE_READ_ATTRIBUTES /* 0x00000080 */
248 | FILE_WRITE_ATTRIBUTES /* 0x00000100 */
249 | READ_CONTROL /* 0x00020000 */
250 | SYNCHRONIZE; /* 0x00100000*/
251 Assert(fAccess == (fServer ? 0x0012019fU : 0x0012019bU));
252
253 rcNt = RtlAddAccessAllowedAce(pDacl, ACL_REVISION, fAccess, &Network.Sid);
254 AssertReturn(NT_SUCCESS(rcNt), rcNt);
255
256 return true;
257}
258
259
260/**
261 * Builds and allocates the security descriptor required for securing the local pipe.
262 *
263 * @return IPRT status code.
264 * @param ppDesc Where to store the allocated security descriptor on success.
265 * Must be free'd using LocalFree().
266 * @param fServer Whether it's for a server or client instance.
267 */
268static int rtLocalIpcServerWinAllocSecurityDescriptor(PSECURITY_DESCRIPTOR *ppDesc, bool fServer)
269{
270 int rc;
271 PSECURITY_DESCRIPTOR pSecDesc = NULL;
272
273#if 0
274 /*
275 * Resolve the API the first time around.
276 */
277 static bool volatile s_fResolvedApis = false;
278 /** advapi32.dll API ConvertStringSecurityDescriptorToSecurityDescriptorW. */
279 static decltype(ConvertStringSecurityDescriptorToSecurityDescriptorW) *s_pfnSSDLToSecDescW = NULL;
280
281 if (!s_fResolvedApis)
282 {
283 s_pfnSSDLToSecDescW
284 = (decltype(s_pfnSSDLToSecDescW))RTLdrGetSystemSymbol("advapi32.dll",
285 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
286 ASMCompilerBarrier();
287 s_fResolvedApis = true;
288 }
289 if (s_pfnSSDLToSecDescW)
290 {
291 /*
292 * We'll create a security descriptor from a SDDL that denies
293 * access to network clients (this is local IPC after all), it
294 * makes some further restrictions to prevent non-authenticated
295 * users from screwing around.
296 */
297 PCRTUTF16 pwszSDDL = fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT;
298 ULONG cbSecDesc = 0;
299 SetLastError(0);
300 if (s_pfnSSDLToSecDescW(pwszSDDL, SDDL_REVISION_1, &pSecDesc, &cbSecDesc))
301 {
302 DWORD dwErr = GetLastError(); RT_NOREF(dwErr);
303 AssertPtr(pSecDesc);
304 *ppDesc = pSecDesc;
305 return VINF_SUCCESS;
306 }
307
308 rc = RTErrConvertFromWin32(GetLastError());
309 }
310 else
311#endif
312 {
313 /*
314 * Manually construct the descriptor.
315 *
316 * This is a bit crude. The 8KB is probably 50+ times more than what we need.
317 */
318 uint32_t const cbAlloc = SECURITY_DESCRIPTOR_MIN_LENGTH * 2 + _8K;
319 pSecDesc = LocalAlloc(LMEM_FIXED, cbAlloc);
320 if (!pSecDesc)
321 return VERR_NO_MEMORY;
322 RT_BZERO(pSecDesc, cbAlloc);
323
324 uint32_t const cbDacl = cbAlloc - SECURITY_DESCRIPTOR_MIN_LENGTH * 2;
325 PACL const pDacl = (PACL)((uint8_t *)pSecDesc + SECURITY_DESCRIPTOR_MIN_LENGTH * 2);
326
327 if ( InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)
328 && InitializeAcl(pDacl, cbDacl, ACL_REVISION))
329 {
330 if (rtLocalIpcBuildDacl(pDacl, fServer))
331 {
332 *ppDesc = pSecDesc;
333 return VINF_SUCCESS;
334 }
335 rc = VERR_GENERAL_FAILURE;
336 }
337 else
338 rc = RTErrConvertFromWin32(GetLastError());
339 LocalFree(pSecDesc);
340 }
341 return rc;
342}
343
344
345/**
346 * Creates a named pipe instance.
347 *
348 * This is used by both RTLocalIpcServerCreate and RTLocalIpcServerListen.
349 *
350 * @return IPRT status code.
351 * @param phNmPipe Where to store the named pipe handle on success.
352 * This will be set to INVALID_HANDLE_VALUE on failure.
353 * @param pwszPipeName The named pipe name, full, UTF-16 encoded.
354 * @param fFirst Set on the first call (from RTLocalIpcServerCreate),
355 * otherwise clear. Governs the
356 * FILE_FLAG_FIRST_PIPE_INSTANCE flag.
357 */
358static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, PCRTUTF16 pwszPipeName, bool fFirst)
359{
360 *phNmPipe = INVALID_HANDLE_VALUE;
361
362 /*
363 * Create a security descriptor blocking access to the pipe via network.
364 */
365 PSECURITY_DESCRIPTOR pSecDesc;
366 int rc = rtLocalIpcServerWinAllocSecurityDescriptor(&pSecDesc, fFirst /* Server? */);
367 if (RT_SUCCESS(rc))
368 {
369#if 0
370 { /* Just for checking the security descriptor out in the debugger (!sd <addr> doesn't work): */
371 DWORD dwRet = LookupSecurityDescriptorPartsW(NULL, NULL, NULL, NULL, NULL, NULL, pSecDesc);
372 __debugbreak(); RT_NOREF(dwRet);
373
374 PTRUSTEE_W pOwner = NULL;
375 PTRUSTEE_W pGroup = NULL;
376 ULONG cAces = 0;
377 PEXPLICIT_ACCESS_W paAces = NULL;
378 ULONG cAuditEntries = 0;
379 PEXPLICIT_ACCESS_W paAuditEntries = NULL;
380 dwRet = LookupSecurityDescriptorPartsW(&pOwner, NULL, NULL, NULL, NULL, NULL, pSecDesc);
381 dwRet = LookupSecurityDescriptorPartsW(NULL, &pGroup, NULL, NULL, NULL, NULL, pSecDesc);
382 dwRet = LookupSecurityDescriptorPartsW(NULL, NULL, &cAces, &paAces, NULL, NULL, pSecDesc);
383 dwRet = LookupSecurityDescriptorPartsW(NULL, NULL, NULL, NULL, &cAuditEntries, &paAuditEntries, pSecDesc);
384 __debugbreak(); RT_NOREF(dwRet);
385 }
386#endif
387
388 /*
389 * Now, create the pipe.
390 */
391 SECURITY_ATTRIBUTES SecAttrs;
392 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
393 SecAttrs.lpSecurityDescriptor = pSecDesc;
394 SecAttrs.bInheritHandle = FALSE;
395
396 DWORD fOpenMode = PIPE_ACCESS_DUPLEX
397 | PIPE_WAIT
398 | FILE_FLAG_OVERLAPPED;
399 if ( fFirst
400 && ( g_enmWinVer >= kRTWinOSType_XP
401 || ( g_enmWinVer == kRTWinOSType_2K
402 && g_WinOsInfoEx.wServicePackMajor >= 2) ) )
403 fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; /* Introduced with W2K SP2 */
404
405 HANDLE hNmPipe = CreateNamedPipeW(pwszPipeName, /* lpName */
406 fOpenMode, /* dwOpenMode */
407 PIPE_TYPE_BYTE, /* dwPipeMode */
408 PIPE_UNLIMITED_INSTANCES, /* nMaxInstances */
409 PAGE_SIZE, /* nOutBufferSize (advisory) */
410 PAGE_SIZE, /* nInBufferSize (ditto) */
411 30*1000, /* nDefaultTimeOut = 30 sec */
412 &SecAttrs); /* lpSecurityAttributes */
413 if (hNmPipe != INVALID_HANDLE_VALUE)
414 {
415#if 0 /* For checking access control stuff in windbg (doesn't work): */
416 PSECURITY_DESCRIPTOR pSecDesc2 = NULL;
417 PACL pDacl = NULL;
418 DWORD dwRet;
419 dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &pSecDesc2);
420 PACL pSacl = NULL;
421 dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, SACL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecDesc2);
422 dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, &pSacl, &pSecDesc2);
423 PSID pSidOwner = NULL;
424 dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pSidOwner, NULL, NULL, NULL, &pSecDesc2);
425 PSID pSidGroup = NULL;
426 dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, NULL, &pSidGroup, NULL, NULL, &pSecDesc2);
427 __debugbreak();
428 RT_NOREF(dwRet);
429#endif
430 *phNmPipe = hNmPipe;
431 rc = VINF_SUCCESS;
432 }
433 else
434 rc = RTErrConvertFromWin32(GetLastError());
435 LocalFree(pSecDesc);
436 }
437 return rc;
438}
439
440
441/**
442 * Validates the user specified name.
443 *
444 * @returns IPRT status code.
445 * @param pszName The name to validate.
446 * @param pcwcFullName Where to return the UTF-16 length of the full name.
447 * @param fNative Whether it's a native name or a portable name.
448 */
449static int rtLocalIpcWinValidateName(const char *pszName, size_t *pcwcFullName, bool fNative)
450{
451 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
452 AssertReturn(*pszName, VERR_INVALID_NAME);
453
454 if (!fNative)
455 {
456 size_t cwcName = RT_ELEMENTS(RTLOCALIPC_WIN_PREFIX) - 1;
457 for (;;)
458 {
459 char ch = *pszName++;
460 if (!ch)
461 break;
462 AssertReturn(!RT_C_IS_CNTRL(ch), VERR_INVALID_NAME);
463 AssertReturn((unsigned)ch < 0x80, VERR_INVALID_NAME);
464 AssertReturn(ch != '\\', VERR_INVALID_NAME);
465 AssertReturn(ch != '/', VERR_INVALID_NAME);
466 cwcName++;
467 }
468 *pcwcFullName = cwcName;
469 }
470 else
471 {
472 int rc = RTStrCalcUtf16LenEx(pszName, RTSTR_MAX, pcwcFullName);
473 AssertRCReturn(rc, rc);
474 }
475
476 return VINF_SUCCESS;
477}
478
479
480/**
481 * Constructs the full pipe name as UTF-16.
482 *
483 * @returns IPRT status code.
484 * @param pszName The user supplied name. ASSUMES reasonable length
485 * for now, so no long path prefixing needed.
486 * @param pwszFullName The output buffer.
487 * @param cwcFullName The output buffer size excluding the terminator.
488 * @param fNative Whether the user supplied name is a native or
489 * portable one.
490 */
491static int rtLocalIpcWinConstructName(const char *pszName, PRTUTF16 pwszFullName, size_t cwcFullName, bool fNative)
492{
493 if (!fNative)
494 {
495 static RTUTF16 const s_wszPrefix[] = RTLOCALIPC_WIN_PREFIX;
496 Assert(cwcFullName * sizeof(RTUTF16) > sizeof(s_wszPrefix));
497 memcpy(pwszFullName, s_wszPrefix, sizeof(s_wszPrefix));
498 cwcFullName -= RT_ELEMENTS(s_wszPrefix) - 1;
499 pwszFullName += RT_ELEMENTS(s_wszPrefix) - 1;
500 }
501 return RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszFullName, cwcFullName + 1, NULL);
502}
503
504
505RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags)
506{
507 /*
508 * Validate parameters.
509 */
510 AssertPtrReturn(phServer, VERR_INVALID_POINTER);
511 *phServer = NIL_RTLOCALIPCSERVER;
512 AssertReturn(!(fFlags & ~RTLOCALIPC_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
513 size_t cwcFullName;
514 int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
515 if (RT_SUCCESS(rc))
516 {
517 /*
518 * Allocate and initialize the instance data.
519 */
520 size_t cbThis = RT_UOFFSETOF_DYN(RTLOCALIPCSERVERINT, wszName[cwcFullName + 1]);
521 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocVar(cbThis);
522 AssertReturn(pThis, VERR_NO_MEMORY);
523
524 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC;
525 pThis->cRefs = 1; /* the one we return */
526 pThis->fCancelled = false;
527
528 rc = rtLocalIpcWinConstructName(pszName, pThis->wszName, cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
529 if (RT_SUCCESS(rc))
530 {
531 rc = RTCritSectInit(&pThis->CritSect);
532 if (RT_SUCCESS(rc))
533 {
534 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
535 FALSE /*bInitialState*/, NULL /*lpName*/);
536 if (pThis->hEvent != NULL)
537 {
538 RT_ZERO(pThis->OverlappedIO);
539 pThis->OverlappedIO.Internal = STATUS_PENDING;
540 pThis->OverlappedIO.hEvent = pThis->hEvent;
541
542 rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, pThis->wszName, true /* fFirst */);
543 if (RT_SUCCESS(rc))
544 {
545 *phServer = pThis;
546 return VINF_SUCCESS;
547 }
548
549 BOOL fRc = CloseHandle(pThis->hEvent);
550 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
551 }
552 else
553 rc = RTErrConvertFromWin32(GetLastError());
554
555 int rc2 = RTCritSectDelete(&pThis->CritSect);
556 AssertRC(rc2);
557 }
558 }
559 RTMemFree(pThis);
560 }
561 return rc;
562}
563
564
565/**
566 * Retains a reference to the server instance.
567 *
568 * @param pThis The server instance.
569 */
570DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis)
571{
572 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
573 Assert(cRefs < UINT32_MAX / 2 && cRefs); NOREF(cRefs);
574}
575
576
577/**
578 * Call when the reference count reaches 0.
579 *
580 * Caller owns the critsect.
581 *
582 * @returns VINF_OBJECT_DESTROYED
583 * @param pThis The instance to destroy.
584 */
585DECL_NO_INLINE(static, int) rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis)
586{
587 Assert(pThis->u32Magic == ~RTLOCALIPCSERVER_MAGIC);
588 pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC;
589
590 BOOL fRc = CloseHandle(pThis->hNmPipe);
591 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
592 pThis->hNmPipe = INVALID_HANDLE_VALUE;
593
594 fRc = CloseHandle(pThis->hEvent);
595 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
596 pThis->hEvent = NULL;
597
598 RTCritSectLeave(&pThis->CritSect);
599 RTCritSectDelete(&pThis->CritSect);
600
601 RTMemFree(pThis);
602 return VINF_OBJECT_DESTROYED;
603}
604
605
606/**
607 * Server instance destructor.
608 *
609 * @returns VINF_OBJECT_DESTROYED
610 * @param pThis The server instance.
611 */
612DECL_NO_INLINE(static, int) rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis)
613{
614 RTCritSectEnter(&pThis->CritSect);
615 return rtLocalIpcServerWinDestroy(pThis);
616}
617
618
619/**
620 * Releases a reference to the server instance.
621 *
622 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
623 * @param pThis The server instance.
624 */
625DECLINLINE(int) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis)
626{
627 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
628 Assert(cRefs < UINT32_MAX / 2);
629 if (!cRefs)
630 return rtLocalIpcServerDtor(pThis);
631 return VINF_SUCCESS;
632}
633
634
635/**
636 * Releases a reference to the server instance and leaves the critsect.
637 *
638 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
639 * @param pThis The server instance.
640 */
641DECLINLINE(int) rtLocalIpcServerReleaseAndUnlock(PRTLOCALIPCSERVERINT pThis)
642{
643 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
644 Assert(cRefs < UINT32_MAX / 2);
645 if (!cRefs)
646 return rtLocalIpcServerWinDestroy(pThis);
647 return RTCritSectLeave(&pThis->CritSect);
648}
649
650
651
652RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
653{
654 /*
655 * Validate input.
656 */
657 if (hServer == NIL_RTLOCALIPCSERVER)
658 return VINF_SUCCESS;
659 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
660 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
661 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
662
663 /*
664 * Cancel any thread currently busy using the server,
665 * leaving the cleanup to it.
666 */
667 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER);
668
669 RTCritSectEnter(&pThis->CritSect);
670
671 /* Cancel everything. */
672 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
673 if (pThis->cRefs > 1)
674 {
675 BOOL fRc = SetEvent(pThis->hEvent);
676 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
677 }
678
679 return rtLocalIpcServerReleaseAndUnlock(pThis);
680}
681
682
683RTDECL(int) RTLocalIpcServerGrantGroupAccess(RTLOCALIPCSERVER hServer, RTGID gid)
684{
685 RT_NOREF_PV(hServer); RT_NOREF(gid);
686 return VERR_NOT_SUPPORTED;
687}
688
689
690RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession)
691{
692 /*
693 * Validate input.
694 */
695 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
696 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
697 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
698 AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
699
700 /*
701 * Enter the critsect before inspecting the object further.
702 */
703 int rc = RTCritSectEnter(&pThis->CritSect);
704 AssertRCReturn(rc, rc);
705
706 rtLocalIpcServerRetain(pThis);
707 if (!pThis->fCancelled)
708 {
709 ResetEvent(pThis->hEvent);
710
711 RTCritSectLeave(&pThis->CritSect);
712
713 /*
714 * Try connect a client. We need to use overlapped I/O here because
715 * of the cancellation done by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
716 */
717 SetLastError(NO_ERROR);
718 BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO);
719 DWORD dwErr = fRc ? NO_ERROR : GetLastError();
720 if ( !fRc
721 && dwErr == ERROR_IO_PENDING)
722 {
723 WaitForSingleObject(pThis->hEvent, INFINITE);
724 DWORD dwIgnored;
725 fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/);
726 dwErr = fRc ? NO_ERROR : GetLastError();
727 }
728
729 RTCritSectEnter(&pThis->CritSect);
730 if ( !pThis->fCancelled /* Event signalled but not cancelled? */
731 && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC)
732 {
733 /*
734 * Still alive, some error or an actual client.
735 *
736 * If it's the latter we'll have to create a new pipe instance that
737 * replaces the current one for the server. The current pipe instance
738 * will be assigned to the client session.
739 */
740 if ( fRc
741 || dwErr == ERROR_PIPE_CONNECTED)
742 {
743 HANDLE hNmPipe;
744 rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->wszName, false /* fFirst */);
745 if (RT_SUCCESS(rc))
746 {
747 HANDLE hNmPipeSession = pThis->hNmPipe; /* consumed */
748 pThis->hNmPipe = hNmPipe;
749 rc = rtLocalIpcWinCreateSession(phClientSession, hNmPipeSession);
750 }
751 else
752 {
753 /*
754 * We failed to create a new instance for the server, disconnect
755 * the client and fail. Don't try service the client here.
756 */
757 fRc = DisconnectNamedPipe(pThis->hNmPipe);
758 AssertMsg(fRc, ("%d\n", GetLastError()));
759 }
760 }
761 else
762 rc = RTErrConvertFromWin32(dwErr);
763 }
764 else
765 {
766 /*
767 * Cancelled.
768 *
769 * Cancel the overlapped io if it didn't complete (must be done
770 * in the this thread) or disconnect the client.
771 */
772 Assert(pThis->fCancelled);
773 if ( fRc
774 || dwErr == ERROR_PIPE_CONNECTED)
775 fRc = DisconnectNamedPipe(pThis->hNmPipe);
776 else if (dwErr == ERROR_IO_PENDING)
777 {
778 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
779 NTSTATUS rcNt = NtCancelIoFile(pThis->hNmPipe, &Ios);
780 fRc = NT_SUCCESS(rcNt);
781 }
782 else
783 fRc = TRUE;
784 AssertMsg(fRc, ("%d\n", GetLastError()));
785 rc = VERR_CANCELLED;
786 }
787 }
788 else
789 {
790 /*pThis->fCancelled = false; - Terrible interface idea. Add API to clear fCancelled if ever required. */
791 rc = VERR_CANCELLED;
792 }
793 rtLocalIpcServerReleaseAndUnlock(pThis);
794 return rc;
795}
796
797
798RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
799{
800 /*
801 * Validate input.
802 */
803 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
804 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
805 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
806
807 /*
808 * Enter the critical section, then set the cancellation flag
809 * and signal the event (to wake up anyone in/at WaitForSingleObject).
810 */
811 rtLocalIpcServerRetain(pThis);
812 int rc = RTCritSectEnter(&pThis->CritSect);
813 if (RT_SUCCESS(rc))
814 {
815 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
816
817 BOOL fRc = SetEvent(pThis->hEvent);
818 if (fRc)
819 rc = VINF_SUCCESS;
820 else
821 {
822 DWORD dwErr = GetLastError();
823 AssertMsgFailed(("dwErr=%u\n", dwErr));
824 rc = RTErrConvertFromWin32(dwErr);
825 }
826
827 rtLocalIpcServerReleaseAndUnlock(pThis);
828 }
829 else
830 rtLocalIpcServerRelease(pThis);
831 return rc;
832}
833
834
835/**
836 * Create a session instance for a new server client or a client connect.
837 *
838 * @returns IPRT status code.
839 *
840 * @param ppSession Where to store the session handle on success.
841 * @param hNmPipeSession The named pipe handle if server calling,
842 * INVALID_HANDLE_VALUE if client connect. This will
843 * be consumed by this session, meaning on failure to
844 * create the session it will be closed.
845 */
846static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession)
847{
848 AssertPtr(ppSession);
849
850 /*
851 * Allocate and initialize the session instance data.
852 */
853 int rc;
854 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis));
855 if (pThis)
856 {
857 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
858 pThis->cRefs = 1; /* our ref */
859 pThis->fCancelled = false;
860 pThis->fZeroByteRead = false;
861 pThis->fServerSide = hNmPipeSession != INVALID_HANDLE_VALUE;
862 pThis->hNmPipe = hNmPipeSession;
863#if 0 /* Non-blocking writes are not yet supported. */
864 pThis->pbBounceBuf = NULL;
865 pThis->cbBounceBufAlloc = 0;
866 pThis->cbBounceBufUsed = 0;
867#endif
868 rc = RTCritSectInit(&pThis->CritSect);
869 if (RT_SUCCESS(rc))
870 {
871 pThis->Read.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
872 FALSE /*bInitialState*/, NULL /*lpName*/);
873 if (pThis->Read.hEvent != NULL)
874 {
875 pThis->Read.OverlappedIO.Internal = STATUS_PENDING;
876 pThis->Read.OverlappedIO.hEvent = pThis->Read.hEvent;
877 pThis->Read.hActiveThread = NIL_RTTHREAD;
878
879 pThis->Write.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
880 FALSE /*bInitialState*/, NULL /*lpName*/);
881 if (pThis->Write.hEvent != NULL)
882 {
883 pThis->Write.OverlappedIO.Internal = STATUS_PENDING;
884 pThis->Write.OverlappedIO.hEvent = pThis->Write.hEvent;
885 pThis->Write.hActiveThread = NIL_RTTHREAD;
886
887 *ppSession = pThis;
888 return VINF_SUCCESS;
889 }
890
891 CloseHandle(pThis->Read.hEvent);
892 }
893
894 /* bail out */
895 rc = RTErrConvertFromWin32(GetLastError());
896 RTCritSectDelete(&pThis->CritSect);
897 }
898 RTMemFree(pThis);
899 }
900 else
901 rc = VERR_NO_MEMORY;
902
903 if (hNmPipeSession != INVALID_HANDLE_VALUE)
904 {
905 BOOL fRc = CloseHandle(hNmPipeSession);
906 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
907 }
908 return rc;
909}
910
911
912RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
913{
914 /*
915 * Validate input.
916 */
917 AssertPtrReturn(phSession, VERR_INVALID_POINTER);
918 AssertReturn(!(fFlags & ~RTLOCALIPC_C_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
919
920 size_t cwcFullName;
921 int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
922 if (RT_SUCCESS(rc))
923 {
924 /*
925 * Create a session (shared with server client session creation).
926 */
927 PRTLOCALIPCSESSIONINT pThis;
928 rc = rtLocalIpcWinCreateSession(&pThis, INVALID_HANDLE_VALUE);
929 if (RT_SUCCESS(rc))
930 {
931 /*
932 * Try open the pipe.
933 */
934 PSECURITY_DESCRIPTOR pSecDesc;
935 rc = rtLocalIpcServerWinAllocSecurityDescriptor(&pSecDesc, false /*fServer*/);
936 if (RT_SUCCESS(rc))
937 {
938 PRTUTF16 pwszFullName = RTUtf16Alloc((cwcFullName + 1) * sizeof(RTUTF16));
939 if (pwszFullName)
940 rc = rtLocalIpcWinConstructName(pszName, pwszFullName, cwcFullName,
941 RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
942 else
943 rc = VERR_NO_UTF16_MEMORY;
944 if (RT_SUCCESS(rc))
945 {
946 SECURITY_ATTRIBUTES SecAttrs;
947 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
948 SecAttrs.lpSecurityDescriptor = pSecDesc;
949 SecAttrs.bInheritHandle = FALSE;
950
951 /* The SECURITY_XXX flags are needed in order to prevent the server from impersonating with
952 this thread's security context (supported at least back to NT 3.51). See @bugref{9773}. */
953 HANDLE hPipe = CreateFileW(pwszFullName,
954 GENERIC_READ | GENERIC_WRITE,
955 0 /*no sharing*/,
956 &SecAttrs,
957 OPEN_EXISTING,
958 FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
959 NULL /*no template handle*/);
960 if (hPipe != INVALID_HANDLE_VALUE)
961 {
962 pThis->hNmPipe = hPipe;
963
964 LocalFree(pSecDesc);
965 RTUtf16Free(pwszFullName);
966
967 /*
968 * We're done!
969 */
970 *phSession = pThis;
971 return VINF_SUCCESS;
972 }
973
974 rc = RTErrConvertFromWin32(GetLastError());
975 }
976
977 RTUtf16Free(pwszFullName);
978 LocalFree(pSecDesc);
979 }
980
981 /* destroy the session handle. */
982 CloseHandle(pThis->Read.hEvent);
983 CloseHandle(pThis->Write.hEvent);
984 RTCritSectDelete(&pThis->CritSect);
985
986 RTMemFree(pThis);
987 }
988 }
989 return rc;
990}
991
992
993/**
994 * Cancells all pending I/O operations, forcing the methods to return with
995 * VERR_CANCELLED (unless they've got actual data to return).
996 *
997 * Used by RTLocalIpcSessionCancel and RTLocalIpcSessionClose.
998 *
999 * @returns IPRT status code.
1000 * @param pThis The client session instance.
1001 */
1002static int rtLocalIpcWinCancel(PRTLOCALIPCSESSIONINT pThis)
1003{
1004 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
1005
1006 /*
1007 * Call NtCancelIoFile since this call cancels both read and write
1008 * oriented operations.
1009 */
1010 if ( pThis->fZeroByteRead
1011 || pThis->Read.hActiveThread != NIL_RTTHREAD
1012 || pThis->Write.hActiveThread != NIL_RTTHREAD)
1013 {
1014 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1015 NtCancelIoFile(pThis->hNmPipe, &Ios);
1016 }
1017
1018 /*
1019 * Set both event semaphores.
1020 */
1021 BOOL fRc = SetEvent(pThis->Read.hEvent);
1022 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1023 fRc = SetEvent(pThis->Write.hEvent);
1024 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1025
1026 return VINF_SUCCESS;
1027}
1028
1029
1030/**
1031 * Retains a reference to the session instance.
1032 *
1033 * @param pThis The client session instance.
1034 */
1035DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis)
1036{
1037 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1038 Assert(cRefs < UINT32_MAX / 2 && cRefs); NOREF(cRefs);
1039}
1040
1041
1042RTDECL(uint32_t) RTLocalIpcSessionRetain(RTLOCALIPCSESSION hSession)
1043{
1044 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1045 AssertPtrReturn(pThis, UINT32_MAX);
1046 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
1047
1048 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1049 Assert(cRefs < UINT32_MAX / 2 && cRefs);
1050 return cRefs;
1051}
1052
1053
1054/**
1055 * Call when the reference count reaches 0.
1056 *
1057 * Caller owns the critsect.
1058 *
1059 * @returns VINF_OBJECT_DESTROYED
1060 * @param pThis The instance to destroy.
1061 */
1062DECL_NO_INLINE(static, int) rtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis)
1063{
1064 BOOL fRc = CloseHandle(pThis->hNmPipe);
1065 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1066 pThis->hNmPipe = INVALID_HANDLE_VALUE;
1067
1068 fRc = CloseHandle(pThis->Write.hEvent);
1069 AssertMsg(fRc, ("%d\n", GetLastError()));
1070 pThis->Write.hEvent = NULL;
1071
1072 fRc = CloseHandle(pThis->Read.hEvent);
1073 AssertMsg(fRc, ("%d\n", GetLastError()));
1074 pThis->Read.hEvent = NULL;
1075
1076 int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2);
1077 RTCritSectDelete(&pThis->CritSect);
1078
1079 RTMemFree(pThis);
1080 return VINF_OBJECT_DESTROYED;
1081}
1082
1083
1084/**
1085 * Releases a reference to the session instance and unlock it.
1086 *
1087 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate.
1088 * @param pThis The session instance.
1089 */
1090DECLINLINE(int) rtLocalIpcSessionReleaseAndUnlock(PRTLOCALIPCSESSIONINT pThis)
1091{
1092 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1093 Assert(cRefs < UINT32_MAX / 2);
1094 if (!cRefs)
1095 return rtLocalIpcSessionWinDestroy(pThis);
1096
1097 int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2);
1098 Log(("rtLocalIpcSessionReleaseAndUnlock: %u refs left\n", cRefs));
1099 return VINF_SUCCESS;
1100}
1101
1102
1103RTDECL(uint32_t) RTLocalIpcSessionRelease(RTLOCALIPCSESSION hSession)
1104{
1105 if (hSession == NIL_RTLOCALIPCSESSION)
1106 return 0;
1107
1108 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1109 AssertPtrReturn(pThis, UINT32_MAX);
1110 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
1111
1112 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1113 Assert(cRefs < UINT32_MAX / 2);
1114 if (cRefs)
1115 Log(("RTLocalIpcSessionRelease: %u refs left\n", cRefs));
1116 else
1117 {
1118 RTCritSectEnter(&pThis->CritSect);
1119 rtLocalIpcSessionWinDestroy(pThis);
1120 }
1121 return cRefs;
1122}
1123
1124
1125RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
1126{
1127 /*
1128 * Validate input.
1129 */
1130 if (hSession == NIL_RTLOCALIPCSESSION)
1131 return VINF_SUCCESS;
1132 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1133 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1134 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1135
1136 /*
1137 * Invalidate the instance, cancel all outstanding I/O and drop our reference.
1138 */
1139 RTCritSectEnter(&pThis->CritSect);
1140 rtLocalIpcWinCancel(pThis);
1141 return rtLocalIpcSessionReleaseAndUnlock(pThis);
1142}
1143
1144
1145/**
1146 * Handles WaitForSingleObject return value when waiting for a zero byte read.
1147 *
1148 * The zero byte read is started by the RTLocalIpcSessionWaitForData method and
1149 * left pending when the function times out. This saves us the problem of
1150 * NtCancelIoFile messing with all active I/O operations and the trouble of
1151 * restarting the zero byte read the next time the method is called. However
1152 * should RTLocalIpcSessionRead be called after a failed
1153 * RTLocalIpcSessionWaitForData call, the zero byte read will still be pending
1154 * and it must wait for it to complete before the OVERLAPPEDIO structure can be
1155 * reused.
1156 *
1157 * Thus, both functions will do WaitForSingleObject and share this routine to
1158 * handle the outcome.
1159 *
1160 * @returns IPRT status code.
1161 * @param pThis The session instance.
1162 * @param rcWait The WaitForSingleObject return code.
1163 */
1164static int rtLocalIpcWinGetZeroReadResult(PRTLOCALIPCSESSIONINT pThis, DWORD rcWait)
1165{
1166 int rc;
1167 DWORD cbRead = 42;
1168 if (rcWait == WAIT_OBJECT_0)
1169 {
1170 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, !pThis->fCancelled /*fWait*/))
1171 {
1172 Assert(cbRead == 0);
1173 rc = VINF_SUCCESS;
1174 pThis->fZeroByteRead = false;
1175 }
1176 else if (pThis->fCancelled)
1177 rc = VERR_CANCELLED;
1178 else
1179 rc = RTErrConvertFromWin32(GetLastError());
1180 }
1181 else
1182 {
1183 /* We try get the result here too, just in case we're lucky, but no waiting. */
1184 DWORD dwErr = GetLastError();
1185 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, FALSE /*fWait*/))
1186 {
1187 Assert(cbRead == 0);
1188 rc = VINF_SUCCESS;
1189 pThis->fZeroByteRead = false;
1190 }
1191 else if (rcWait == WAIT_TIMEOUT)
1192 rc = VERR_TIMEOUT;
1193 else if (rcWait == WAIT_ABANDONED)
1194 rc = VERR_INVALID_HANDLE;
1195 else
1196 rc = RTErrConvertFromWin32(dwErr);
1197 }
1198 return rc;
1199}
1200
1201
1202RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
1203{
1204 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1205 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1206 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1207 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1208 /* pcbRead is optional. */
1209
1210 int rc = RTCritSectEnter(&pThis->CritSect);
1211 if (RT_SUCCESS(rc))
1212 {
1213 rtLocalIpcSessionRetain(pThis);
1214 if (pThis->Read.hActiveThread == NIL_RTTHREAD)
1215 {
1216 pThis->Read.hActiveThread = RTThreadSelf();
1217
1218 size_t cbTotalRead = 0;
1219 while (cbToRead > 0)
1220 {
1221 DWORD cbRead = 0;
1222 if (!pThis->fCancelled)
1223 {
1224 /*
1225 * Wait for pending zero byte read, if necessary.
1226 * Note! It cannot easily be cancelled due to concurrent current writes.
1227 */
1228 if (!pThis->fZeroByteRead)
1229 { /* likely */ }
1230 else
1231 {
1232 RTCritSectLeave(&pThis->CritSect);
1233 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, RT_MS_1MIN);
1234 RTCritSectEnter(&pThis->CritSect);
1235
1236 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
1237 if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT)
1238 continue;
1239 break;
1240 }
1241
1242 /*
1243 * Kick of a an overlapped read. It should return immediately if
1244 * there is bytes in the buffer. If not, we'll cancel it and see
1245 * what we get back.
1246 */
1247 rc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(rc == TRUE);
1248 RTCritSectLeave(&pThis->CritSect);
1249
1250 if (ReadFile(pThis->hNmPipe, pvBuf,
1251 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
1252 &cbRead, &pThis->Read.OverlappedIO))
1253 {
1254 RTCritSectEnter(&pThis->CritSect);
1255 rc = VINF_SUCCESS;
1256 }
1257 else if (GetLastError() == ERROR_IO_PENDING)
1258 {
1259 WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, INFINITE);
1260
1261 RTCritSectEnter(&pThis->CritSect);
1262 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, TRUE /*fWait*/))
1263 rc = VINF_SUCCESS;
1264 else
1265 {
1266 if (pThis->fCancelled)
1267 rc = VERR_CANCELLED;
1268 else
1269 rc = RTErrConvertFromWin32(GetLastError());
1270 break;
1271 }
1272 }
1273 else
1274 {
1275 rc = RTErrConvertFromWin32(GetLastError());
1276 AssertMsgFailedBreak(("%Rrc\n", rc));
1277 }
1278 }
1279 else
1280 {
1281 rc = VERR_CANCELLED;
1282 break;
1283 }
1284
1285 /* Advance. */
1286 cbToRead -= cbRead;
1287 cbTotalRead += cbRead;
1288 pvBuf = (uint8_t *)pvBuf + cbRead;
1289 }
1290
1291 if (pcbRead)
1292 {
1293 *pcbRead = cbTotalRead;
1294 if ( RT_FAILURE(rc)
1295 && cbTotalRead
1296 && rc != VERR_INVALID_POINTER)
1297 rc = VINF_SUCCESS;
1298 }
1299
1300 pThis->Read.hActiveThread = NIL_RTTHREAD;
1301 }
1302 else
1303 rc = VERR_WRONG_ORDER;
1304 rtLocalIpcSessionReleaseAndUnlock(pThis);
1305 }
1306
1307 return rc;
1308}
1309
1310
1311RTDECL(int) RTLocalIpcSessionReadNB(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
1312{
1313 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1314 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1315 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1316 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1317 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
1318 *pcbRead = 0;
1319
1320 int rc = RTCritSectEnter(&pThis->CritSect);
1321 if (RT_SUCCESS(rc))
1322 {
1323 rtLocalIpcSessionRetain(pThis);
1324 if (pThis->Read.hActiveThread == NIL_RTTHREAD)
1325 {
1326 pThis->Read.hActiveThread = RTThreadSelf();
1327
1328 for (;;)
1329 {
1330 DWORD cbRead = 0;
1331 if (!pThis->fCancelled)
1332 {
1333 /*
1334 * Wait for pending zero byte read, if necessary.
1335 * Note! It cannot easily be cancelled due to concurrent current writes.
1336 */
1337 if (!pThis->fZeroByteRead)
1338 { /* likely */ }
1339 else
1340 {
1341 RTCritSectLeave(&pThis->CritSect);
1342 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, 0);
1343 RTCritSectEnter(&pThis->CritSect);
1344
1345 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
1346 if (RT_SUCCESS(rc))
1347 continue;
1348
1349 if (rc == VERR_TIMEOUT)
1350 rc = VINF_TRY_AGAIN;
1351 break;
1352 }
1353
1354 /*
1355 * Figure out how much we can read (cannot try and cancel here
1356 * like in the anonymous pipe code).
1357 */
1358 DWORD cbAvailable;
1359 if (PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL))
1360 {
1361 if (cbAvailable == 0 || cbToRead == 0)
1362 {
1363 *pcbRead = 0;
1364 rc = VINF_TRY_AGAIN;
1365 break;
1366 }
1367 }
1368 else
1369 {
1370 rc = RTErrConvertFromWin32(GetLastError());
1371 break;
1372 }
1373 if (cbAvailable > cbToRead)
1374 cbAvailable = (DWORD)cbToRead;
1375
1376 /*
1377 * Kick of a an overlapped read. It should return immediately, so we
1378 * don't really need to leave the critsect here.
1379 */
1380 rc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(rc == TRUE);
1381 if (ReadFile(pThis->hNmPipe, pvBuf, cbAvailable, &cbRead, &pThis->Read.OverlappedIO))
1382 {
1383 *pcbRead = cbRead;
1384 rc = VINF_SUCCESS;
1385 }
1386 else if (GetLastError() == ERROR_IO_PENDING)
1387 {
1388 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, 0);
1389 if (rcWait == WAIT_TIMEOUT)
1390 {
1391 RTCritSectLeave(&pThis->CritSect);
1392 rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, INFINITE);
1393 RTCritSectEnter(&pThis->CritSect);
1394 }
1395 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, TRUE /*fWait*/))
1396 {
1397 *pcbRead = cbRead;
1398 rc = VINF_SUCCESS;
1399 }
1400 else
1401 {
1402 if (pThis->fCancelled)
1403 rc = VERR_CANCELLED;
1404 else
1405 rc = RTErrConvertFromWin32(GetLastError());
1406 }
1407 }
1408 else
1409 {
1410 rc = RTErrConvertFromWin32(GetLastError());
1411 AssertMsgFailedBreak(("%Rrc\n", rc));
1412 }
1413 }
1414 else
1415 rc = VERR_CANCELLED;
1416 break;
1417 }
1418
1419 pThis->Read.hActiveThread = NIL_RTTHREAD;
1420 }
1421 else
1422 rc = VERR_WRONG_ORDER;
1423 rtLocalIpcSessionReleaseAndUnlock(pThis);
1424 }
1425
1426 return rc;
1427}
1428
1429
1430#if 0 /* Non-blocking writes are not yet supported. */
1431/**
1432 * Common worker for handling I/O completion.
1433 *
1434 * This is used by RTLocalIpcSessionClose and RTLocalIpcSessionWrite.
1435 *
1436 * @returns IPRT status code.
1437 * @param pThis The pipe instance handle.
1438 */
1439static int rtLocalIpcSessionWriteCheckCompletion(PRTLOCALIPCSESSIONINT pThis)
1440{
1441 int rc;
1442 DWORD rcWait = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
1443 if (rcWait == WAIT_OBJECT_0)
1444 {
1445 DWORD cbWritten = 0;
1446 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE))
1447 {
1448 for (;;)
1449 {
1450 if (cbWritten >= pThis->cbBounceBufUsed)
1451 {
1452 pThis->fIOPending = false;
1453 rc = VINF_SUCCESS;
1454 break;
1455 }
1456
1457 /* resubmit the remainder of the buffer - can this actually happen? */
1458 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
1459 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
1460 if (!WriteFile(pThis->hNmPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
1461 &cbWritten, &pThis->OverlappedIO))
1462 {
1463 DWORD dwErr = GetLastError();
1464 if (dwErr == ERROR_IO_PENDING)
1465 rc = VINF_TRY_AGAIN;
1466 else
1467 {
1468 pThis->fIOPending = false;
1469 if (dwErr == ERROR_NO_DATA)
1470 rc = VERR_BROKEN_PIPE;
1471 else
1472 rc = RTErrConvertFromWin32(dwErr);
1473 }
1474 break;
1475 }
1476 Assert(cbWritten > 0);
1477 }
1478 }
1479 else
1480 {
1481 pThis->fIOPending = false;
1482 rc = RTErrConvertFromWin32(GetLastError());
1483 }
1484 }
1485 else if (rcWait == WAIT_TIMEOUT)
1486 rc = VINF_TRY_AGAIN;
1487 else
1488 {
1489 pThis->fIOPending = false;
1490 if (rcWait == WAIT_ABANDONED)
1491 rc = VERR_INVALID_HANDLE;
1492 else
1493 rc = RTErrConvertFromWin32(GetLastError());
1494 }
1495 return rc;
1496}
1497#endif
1498
1499
1500RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuf, size_t cbToWrite)
1501{
1502 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1503 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1504 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1505 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1506 AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);
1507
1508 int rc = RTCritSectEnter(&pThis->CritSect);
1509 if (RT_SUCCESS(rc))
1510 {
1511 rtLocalIpcSessionRetain(pThis);
1512 if (pThis->Write.hActiveThread == NIL_RTTHREAD)
1513 {
1514 pThis->Write.hActiveThread = RTThreadSelf();
1515
1516 /*
1517 * Try write everything. No bounce buffering necessary.
1518 */
1519 size_t cbTotalWritten = 0;
1520 while (cbToWrite > 0)
1521 {
1522 DWORD cbWritten = 0;
1523 if (!pThis->fCancelled)
1524 {
1525 BOOL fRc = ResetEvent(pThis->Write.OverlappedIO.hEvent); Assert(fRc == TRUE);
1526 RTCritSectLeave(&pThis->CritSect);
1527
1528 DWORD const cbToWriteInThisIteration = cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0;
1529 fRc = WriteFile(pThis->hNmPipe, pvBuf, cbToWriteInThisIteration, &cbWritten, &pThis->Write.OverlappedIO);
1530 if (fRc)
1531 rc = VINF_SUCCESS;
1532 else
1533 {
1534 DWORD dwErr = GetLastError();
1535 if (dwErr == ERROR_IO_PENDING)
1536 {
1537 DWORD rcWait = WaitForSingleObject(pThis->Write.OverlappedIO.hEvent, INFINITE);
1538 if (rcWait == WAIT_OBJECT_0)
1539 {
1540 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Write.OverlappedIO, &cbWritten, TRUE /*fWait*/))
1541 rc = VINF_SUCCESS;
1542 else
1543 rc = RTErrConvertFromWin32(GetLastError());
1544 }
1545 else if (rcWait == WAIT_TIMEOUT)
1546 rc = VERR_TIMEOUT;
1547 else if (rcWait == WAIT_ABANDONED)
1548 rc = VERR_INVALID_HANDLE;
1549 else
1550 rc = RTErrConvertFromWin32(GetLastError());
1551 }
1552 else if (dwErr == ERROR_NO_DATA)
1553 rc = VERR_BROKEN_PIPE;
1554 else
1555 rc = RTErrConvertFromWin32(dwErr);
1556 }
1557
1558 if (cbWritten > cbToWriteInThisIteration) /* paranoia^3 */
1559 cbWritten = cbToWriteInThisIteration;
1560
1561 RTCritSectEnter(&pThis->CritSect);
1562 if (RT_FAILURE(rc))
1563 break;
1564 }
1565 else
1566 {
1567 rc = VERR_CANCELLED;
1568 break;
1569 }
1570
1571 /* Advance. */
1572 pvBuf = (char const *)pvBuf + cbWritten;
1573 cbTotalWritten += cbWritten;
1574 cbToWrite -= cbWritten;
1575 }
1576
1577 pThis->Write.hActiveThread = NIL_RTTHREAD;
1578 }
1579 else
1580 rc = VERR_WRONG_ORDER;
1581 rtLocalIpcSessionReleaseAndUnlock(pThis);
1582 }
1583
1584 return rc;
1585}
1586
1587
1588RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
1589{
1590 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1591 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1592 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1593
1594 int rc = RTCritSectEnter(&pThis->CritSect);
1595 if (RT_SUCCESS(rc))
1596 {
1597 if (pThis->Write.hActiveThread == NIL_RTTHREAD)
1598 {
1599 /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
1600 * all data was written (or an error occurred). */
1601 /** @todo r=bird: above comment is misinformed.
1602 * Implement this as soon as we want an explicit asynchronous version of
1603 * RTLocalIpcSessionWrite on Windows. */
1604 rc = VINF_SUCCESS;
1605 }
1606 else
1607 rc = VERR_WRONG_ORDER;
1608 RTCritSectLeave(&pThis->CritSect);
1609 }
1610 return rc;
1611}
1612
1613
1614RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
1615{
1616 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1617 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1618 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1619
1620 uint64_t const msStart = RTTimeMilliTS();
1621
1622 int rc = RTCritSectEnter(&pThis->CritSect);
1623 if (RT_SUCCESS(rc))
1624 {
1625 rtLocalIpcSessionRetain(pThis);
1626 if (pThis->Read.hActiveThread == NIL_RTTHREAD)
1627 {
1628 pThis->Read.hActiveThread = RTThreadSelf();
1629
1630 /*
1631 * Wait loop.
1632 */
1633 for (unsigned iLoop = 0;; iLoop++)
1634 {
1635 /*
1636 * Check for cancellation before we continue.
1637 */
1638 if (!pThis->fCancelled)
1639 { /* likely */ }
1640 else
1641 {
1642 rc = VERR_CANCELLED;
1643 break;
1644 }
1645
1646 /*
1647 * Prep something we can wait on.
1648 */
1649 HANDLE hWait = INVALID_HANDLE_VALUE;
1650 if (pThis->fZeroByteRead)
1651 hWait = pThis->Read.OverlappedIO.hEvent;
1652 else
1653 {
1654 /* Peek at the pipe buffer and see how many bytes it contains. */
1655 DWORD cbAvailable;
1656 if ( PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL)
1657 && cbAvailable)
1658 {
1659 rc = VINF_SUCCESS;
1660 break;
1661 }
1662
1663 /* Start a zero byte read operation that we can wait on. */
1664 if (cMillies == 0)
1665 {
1666 rc = VERR_TIMEOUT;
1667 break;
1668 }
1669 BOOL fRc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(fRc == TRUE); NOREF(fRc);
1670 DWORD cbRead = 0;
1671 if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0 /*cbToRead*/, &cbRead, &pThis->Read.OverlappedIO))
1672 {
1673 rc = VINF_SUCCESS;
1674 if (iLoop > 10)
1675 RTThreadYield();
1676 }
1677 else if (GetLastError() == ERROR_IO_PENDING)
1678 {
1679 pThis->fZeroByteRead = true;
1680 hWait = pThis->Read.OverlappedIO.hEvent;
1681 }
1682 else
1683 rc = RTErrConvertFromWin32(GetLastError());
1684 if (RT_FAILURE(rc))
1685 break;
1686 }
1687
1688 /*
1689 * Check for timeout.
1690 */
1691 DWORD cMsMaxWait = INFINITE; /* (MSC maybe used uninitialized) */
1692 if (cMillies == RT_INDEFINITE_WAIT)
1693 cMsMaxWait = INFINITE;
1694 else if ( hWait != INVALID_HANDLE_VALUE
1695 || iLoop > 10)
1696 {
1697 uint64_t cMsElapsed = RTTimeMilliTS() - msStart;
1698 if (cMsElapsed <= cMillies)
1699 cMsMaxWait = cMillies - (uint32_t)cMsElapsed;
1700 else if (iLoop == 0)
1701 cMsMaxWait = cMillies ? 1 : 0;
1702 else
1703 {
1704 rc = VERR_TIMEOUT;
1705 break;
1706 }
1707 }
1708
1709 /*
1710 * Wait and collect the result.
1711 */
1712 if (hWait != INVALID_HANDLE_VALUE)
1713 {
1714 RTCritSectLeave(&pThis->CritSect);
1715
1716 DWORD rcWait = WaitForSingleObject(hWait, cMsMaxWait);
1717
1718 int rc2 = RTCritSectEnter(&pThis->CritSect);
1719 AssertRC(rc2);
1720
1721 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
1722 break;
1723 }
1724 }
1725
1726 pThis->Read.hActiveThread = NIL_RTTHREAD;
1727 }
1728
1729 rtLocalIpcSessionReleaseAndUnlock(pThis);
1730 }
1731
1732 return rc;
1733}
1734
1735
1736RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
1737{
1738 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1739 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1740 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1741
1742 /*
1743 * Enter the critical section, then set the cancellation flag
1744 * and signal the event (to wake up anyone in/at WaitForSingleObject).
1745 */
1746 int rc = RTCritSectEnter(&pThis->CritSect);
1747 if (RT_SUCCESS(rc))
1748 {
1749 rtLocalIpcSessionRetain(pThis);
1750 rc = rtLocalIpcWinCancel(pThis);
1751 rtLocalIpcSessionReleaseAndUnlock(pThis);
1752 }
1753
1754 return rc;
1755}
1756
1757
1758RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
1759{
1760 RT_NOREF_PV(hSession); RT_NOREF_PV(pProcess);
1761 return VERR_NOT_SUPPORTED;
1762}
1763
1764
1765RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid)
1766{
1767 RT_NOREF_PV(hSession); RT_NOREF_PV(pUid);
1768 return VERR_NOT_SUPPORTED;
1769}
1770
1771
1772RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid)
1773{
1774 RT_NOREF_PV(hSession); RT_NOREF_PV(pGid);
1775 return VERR_NOT_SUPPORTED;
1776}
1777
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