VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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