VirtualBox

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

Last change on this file since 96599 was 96599, checked in by vboxsync, 2 years ago

IPRT/localipc-win.cpp: Eliminated need for ConvertStringSecurityDescriptorToSecurityDescriptorW, making the code work on NT4 and earlier too. bugref:10261

  • 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 96599 2022-09-05 02:05:21Z 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-2022 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 * @returns
570 * @param pThis The server instance.
571 */
572DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis)
573{
574 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
575 Assert(cRefs < UINT32_MAX / 2 && cRefs); NOREF(cRefs);
576}
577
578
579/**
580 * Call when the reference count reaches 0.
581 *
582 * Caller owns the critsect.
583 *
584 * @returns VINF_OBJECT_DESTROYED
585 * @param pThis The instance to destroy.
586 */
587DECL_NO_INLINE(static, int) rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis)
588{
589 Assert(pThis->u32Magic == ~RTLOCALIPCSERVER_MAGIC);
590 pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC;
591
592 BOOL fRc = CloseHandle(pThis->hNmPipe);
593 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
594 pThis->hNmPipe = INVALID_HANDLE_VALUE;
595
596 fRc = CloseHandle(pThis->hEvent);
597 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
598 pThis->hEvent = NULL;
599
600 RTCritSectLeave(&pThis->CritSect);
601 RTCritSectDelete(&pThis->CritSect);
602
603 RTMemFree(pThis);
604 return VINF_OBJECT_DESTROYED;
605}
606
607
608/**
609 * Server instance destructor.
610 *
611 * @returns VINF_OBJECT_DESTROYED
612 * @param pThis The server instance.
613 */
614DECL_NO_INLINE(static, int) rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis)
615{
616 RTCritSectEnter(&pThis->CritSect);
617 return rtLocalIpcServerWinDestroy(pThis);
618}
619
620
621/**
622 * Releases a reference to the server instance.
623 *
624 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
625 * @param pThis The server instance.
626 */
627DECLINLINE(int) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis)
628{
629 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
630 Assert(cRefs < UINT32_MAX / 2);
631 if (!cRefs)
632 return rtLocalIpcServerDtor(pThis);
633 return VINF_SUCCESS;
634}
635
636
637/**
638 * Releases a reference to the server instance and leaves the critsect.
639 *
640 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
641 * @param pThis The server instance.
642 */
643DECLINLINE(int) rtLocalIpcServerReleaseAndUnlock(PRTLOCALIPCSERVERINT pThis)
644{
645 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
646 Assert(cRefs < UINT32_MAX / 2);
647 if (!cRefs)
648 return rtLocalIpcServerWinDestroy(pThis);
649 return RTCritSectLeave(&pThis->CritSect);
650}
651
652
653
654RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
655{
656 /*
657 * Validate input.
658 */
659 if (hServer == NIL_RTLOCALIPCSERVER)
660 return VINF_SUCCESS;
661 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
662 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
663 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
664
665 /*
666 * Cancel any thread currently busy using the server,
667 * leaving the cleanup to it.
668 */
669 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER);
670
671 RTCritSectEnter(&pThis->CritSect);
672
673 /* Cancel everything. */
674 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
675 if (pThis->cRefs > 1)
676 {
677 BOOL fRc = SetEvent(pThis->hEvent);
678 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
679 }
680
681 return rtLocalIpcServerReleaseAndUnlock(pThis);
682}
683
684
685RTDECL(int) RTLocalIpcServerGrantGroupAccess(RTLOCALIPCSERVER hServer, RTGID gid)
686{
687 RT_NOREF_PV(hServer); RT_NOREF(gid);
688 return VERR_NOT_SUPPORTED;
689}
690
691
692RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession)
693{
694 /*
695 * Validate input.
696 */
697 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
698 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
699 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
700 AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
701
702 /*
703 * Enter the critsect before inspecting the object further.
704 */
705 int rc = RTCritSectEnter(&pThis->CritSect);
706 AssertRCReturn(rc, rc);
707
708 rtLocalIpcServerRetain(pThis);
709 if (!pThis->fCancelled)
710 {
711 ResetEvent(pThis->hEvent);
712
713 RTCritSectLeave(&pThis->CritSect);
714
715 /*
716 * Try connect a client. We need to use overlapped I/O here because
717 * of the cancellation done by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
718 */
719 SetLastError(NO_ERROR);
720 BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO);
721 DWORD dwErr = fRc ? NO_ERROR : GetLastError();
722 if ( !fRc
723 && dwErr == ERROR_IO_PENDING)
724 {
725 WaitForSingleObject(pThis->hEvent, INFINITE);
726 DWORD dwIgnored;
727 fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/);
728 dwErr = fRc ? NO_ERROR : GetLastError();
729 }
730
731 RTCritSectEnter(&pThis->CritSect);
732 if ( !pThis->fCancelled /* Event signalled but not cancelled? */
733 && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC)
734 {
735 /*
736 * Still alive, some error or an actual client.
737 *
738 * If it's the latter we'll have to create a new pipe instance that
739 * replaces the current one for the server. The current pipe instance
740 * will be assigned to the client session.
741 */
742 if ( fRc
743 || dwErr == ERROR_PIPE_CONNECTED)
744 {
745 HANDLE hNmPipe;
746 rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->wszName, false /* fFirst */);
747 if (RT_SUCCESS(rc))
748 {
749 HANDLE hNmPipeSession = pThis->hNmPipe; /* consumed */
750 pThis->hNmPipe = hNmPipe;
751 rc = rtLocalIpcWinCreateSession(phClientSession, hNmPipeSession);
752 }
753 else
754 {
755 /*
756 * We failed to create a new instance for the server, disconnect
757 * the client and fail. Don't try service the client here.
758 */
759 fRc = DisconnectNamedPipe(pThis->hNmPipe);
760 AssertMsg(fRc, ("%d\n", GetLastError()));
761 }
762 }
763 else
764 rc = RTErrConvertFromWin32(dwErr);
765 }
766 else
767 {
768 /*
769 * Cancelled.
770 *
771 * Cancel the overlapped io if it didn't complete (must be done
772 * in the this thread) or disconnect the client.
773 */
774 Assert(pThis->fCancelled);
775 if ( fRc
776 || dwErr == ERROR_PIPE_CONNECTED)
777 fRc = DisconnectNamedPipe(pThis->hNmPipe);
778 else if (dwErr == ERROR_IO_PENDING)
779 {
780 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
781 NTSTATUS rcNt = NtCancelIoFile(pThis->hNmPipe, &Ios);
782 fRc = NT_SUCCESS(rcNt);
783 }
784 else
785 fRc = TRUE;
786 AssertMsg(fRc, ("%d\n", GetLastError()));
787 rc = VERR_CANCELLED;
788 }
789 }
790 else
791 {
792 /*pThis->fCancelled = false; - Terrible interface idea. Add API to clear fCancelled if ever required. */
793 rc = VERR_CANCELLED;
794 }
795 rtLocalIpcServerReleaseAndUnlock(pThis);
796 return rc;
797}
798
799
800RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
801{
802 /*
803 * Validate input.
804 */
805 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
806 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
807 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
808
809 /*
810 * Enter the critical section, then set the cancellation flag
811 * and signal the event (to wake up anyone in/at WaitForSingleObject).
812 */
813 rtLocalIpcServerRetain(pThis);
814 int rc = RTCritSectEnter(&pThis->CritSect);
815 if (RT_SUCCESS(rc))
816 {
817 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
818
819 BOOL fRc = SetEvent(pThis->hEvent);
820 if (fRc)
821 rc = VINF_SUCCESS;
822 else
823 {
824 DWORD dwErr = GetLastError();
825 AssertMsgFailed(("dwErr=%u\n", dwErr));
826 rc = RTErrConvertFromWin32(dwErr);
827 }
828
829 rtLocalIpcServerReleaseAndUnlock(pThis);
830 }
831 else
832 rtLocalIpcServerRelease(pThis);
833 return rc;
834}
835
836
837/**
838 * Create a session instance for a new server client or a client connect.
839 *
840 * @returns IPRT status code.
841 *
842 * @param ppSession Where to store the session handle on success.
843 * @param hNmPipeSession The named pipe handle if server calling,
844 * INVALID_HANDLE_VALUE if client connect. This will
845 * be consumed by this session, meaning on failure to
846 * create the session it will be closed.
847 */
848static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession)
849{
850 AssertPtr(ppSession);
851
852 /*
853 * Allocate and initialize the session instance data.
854 */
855 int rc;
856 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis));
857 if (pThis)
858 {
859 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
860 pThis->cRefs = 1; /* our ref */
861 pThis->fCancelled = false;
862 pThis->fZeroByteRead = false;
863 pThis->fServerSide = hNmPipeSession != INVALID_HANDLE_VALUE;
864 pThis->hNmPipe = hNmPipeSession;
865#if 0 /* Non-blocking writes are not yet supported. */
866 pThis->pbBounceBuf = NULL;
867 pThis->cbBounceBufAlloc = 0;
868 pThis->cbBounceBufUsed = 0;
869#endif
870 rc = RTCritSectInit(&pThis->CritSect);
871 if (RT_SUCCESS(rc))
872 {
873 pThis->Read.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
874 FALSE /*bInitialState*/, NULL /*lpName*/);
875 if (pThis->Read.hEvent != NULL)
876 {
877 pThis->Read.OverlappedIO.Internal = STATUS_PENDING;
878 pThis->Read.OverlappedIO.hEvent = pThis->Read.hEvent;
879 pThis->Read.hActiveThread = NIL_RTTHREAD;
880
881 pThis->Write.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
882 FALSE /*bInitialState*/, NULL /*lpName*/);
883 if (pThis->Write.hEvent != NULL)
884 {
885 pThis->Write.OverlappedIO.Internal = STATUS_PENDING;
886 pThis->Write.OverlappedIO.hEvent = pThis->Write.hEvent;
887 pThis->Write.hActiveThread = NIL_RTTHREAD;
888
889 *ppSession = pThis;
890 return VINF_SUCCESS;
891 }
892
893 CloseHandle(pThis->Read.hEvent);
894 }
895
896 /* bail out */
897 rc = RTErrConvertFromWin32(GetLastError());
898 RTCritSectDelete(&pThis->CritSect);
899 }
900 RTMemFree(pThis);
901 }
902 else
903 rc = VERR_NO_MEMORY;
904
905 if (hNmPipeSession != INVALID_HANDLE_VALUE)
906 {
907 BOOL fRc = CloseHandle(hNmPipeSession);
908 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
909 }
910 return rc;
911}
912
913
914RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
915{
916 /*
917 * Validate input.
918 */
919 AssertPtrReturn(phSession, VERR_INVALID_POINTER);
920 AssertReturn(!(fFlags & ~RTLOCALIPC_C_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
921
922 size_t cwcFullName;
923 int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
924 if (RT_SUCCESS(rc))
925 {
926 /*
927 * Create a session (shared with server client session creation).
928 */
929 PRTLOCALIPCSESSIONINT pThis;
930 rc = rtLocalIpcWinCreateSession(&pThis, INVALID_HANDLE_VALUE);
931 if (RT_SUCCESS(rc))
932 {
933 /*
934 * Try open the pipe.
935 */
936 PSECURITY_DESCRIPTOR pSecDesc;
937 rc = rtLocalIpcServerWinAllocSecurityDescriptor(&pSecDesc, false /*fServer*/);
938 if (RT_SUCCESS(rc))
939 {
940 PRTUTF16 pwszFullName = RTUtf16Alloc((cwcFullName + 1) * sizeof(RTUTF16));
941 if (pwszFullName)
942 rc = rtLocalIpcWinConstructName(pszName, pwszFullName, cwcFullName,
943 RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
944 else
945 rc = VERR_NO_UTF16_MEMORY;
946 if (RT_SUCCESS(rc))
947 {
948 SECURITY_ATTRIBUTES SecAttrs;
949 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
950 SecAttrs.lpSecurityDescriptor = pSecDesc;
951 SecAttrs.bInheritHandle = FALSE;
952
953 /* The SECURITY_XXX flags are needed in order to prevent the server from impersonating with
954 this thread's security context (supported at least back to NT 3.51). See @bugref{9773}. */
955 HANDLE hPipe = CreateFileW(pwszFullName,
956 GENERIC_READ | GENERIC_WRITE,
957 0 /*no sharing*/,
958 &SecAttrs,
959 OPEN_EXISTING,
960 FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
961 NULL /*no template handle*/);
962 if (hPipe != INVALID_HANDLE_VALUE)
963 {
964 pThis->hNmPipe = hPipe;
965
966 LocalFree(pSecDesc);
967 RTUtf16Free(pwszFullName);
968
969 /*
970 * We're done!
971 */
972 *phSession = pThis;
973 return VINF_SUCCESS;
974 }
975
976 rc = RTErrConvertFromWin32(GetLastError());
977 }
978
979 RTUtf16Free(pwszFullName);
980 LocalFree(pSecDesc);
981 }
982
983 /* destroy the session handle. */
984 CloseHandle(pThis->Read.hEvent);
985 CloseHandle(pThis->Write.hEvent);
986 RTCritSectDelete(&pThis->CritSect);
987
988 RTMemFree(pThis);
989 }
990 }
991 return rc;
992}
993
994
995/**
996 * Cancells all pending I/O operations, forcing the methods to return with
997 * VERR_CANCELLED (unless they've got actual data to return).
998 *
999 * Used by RTLocalIpcSessionCancel and RTLocalIpcSessionClose.
1000 *
1001 * @returns IPRT status code.
1002 * @param pThis The client session instance.
1003 */
1004static int rtLocalIpcWinCancel(PRTLOCALIPCSESSIONINT pThis)
1005{
1006 ASMAtomicUoWriteBool(&pThis->fCancelled, true);
1007
1008 /*
1009 * Call NtCancelIoFile since this call cancels both read and write
1010 * oriented operations.
1011 */
1012 if ( pThis->fZeroByteRead
1013 || pThis->Read.hActiveThread != NIL_RTTHREAD
1014 || pThis->Write.hActiveThread != NIL_RTTHREAD)
1015 {
1016 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1017 NtCancelIoFile(pThis->hNmPipe, &Ios);
1018 }
1019
1020 /*
1021 * Set both event semaphores.
1022 */
1023 BOOL fRc = SetEvent(pThis->Read.hEvent);
1024 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1025 fRc = SetEvent(pThis->Write.hEvent);
1026 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1027
1028 return VINF_SUCCESS;
1029}
1030
1031
1032/**
1033 * Retains a reference to the session instance.
1034 *
1035 * @param pThis The client session instance.
1036 */
1037DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis)
1038{
1039 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1040 Assert(cRefs < UINT32_MAX / 2 && cRefs); NOREF(cRefs);
1041}
1042
1043
1044RTDECL(uint32_t) RTLocalIpcSessionRetain(RTLOCALIPCSESSION hSession)
1045{
1046 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1047 AssertPtrReturn(pThis, UINT32_MAX);
1048 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
1049
1050 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1051 Assert(cRefs < UINT32_MAX / 2 && cRefs);
1052 return cRefs;
1053}
1054
1055
1056/**
1057 * Call when the reference count reaches 0.
1058 *
1059 * Caller owns the critsect.
1060 *
1061 * @returns VINF_OBJECT_DESTROYED
1062 * @param pThis The instance to destroy.
1063 */
1064DECL_NO_INLINE(static, int) rtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis)
1065{
1066 BOOL fRc = CloseHandle(pThis->hNmPipe);
1067 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
1068 pThis->hNmPipe = INVALID_HANDLE_VALUE;
1069
1070 fRc = CloseHandle(pThis->Write.hEvent);
1071 AssertMsg(fRc, ("%d\n", GetLastError()));
1072 pThis->Write.hEvent = NULL;
1073
1074 fRc = CloseHandle(pThis->Read.hEvent);
1075 AssertMsg(fRc, ("%d\n", GetLastError()));
1076 pThis->Read.hEvent = NULL;
1077
1078 int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2);
1079 RTCritSectDelete(&pThis->CritSect);
1080
1081 RTMemFree(pThis);
1082 return VINF_OBJECT_DESTROYED;
1083}
1084
1085
1086/**
1087 * Releases a reference to the session instance and unlock it.
1088 *
1089 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate.
1090 * @param pThis The session instance.
1091 */
1092DECLINLINE(int) rtLocalIpcSessionReleaseAndUnlock(PRTLOCALIPCSESSIONINT pThis)
1093{
1094 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1095 Assert(cRefs < UINT32_MAX / 2);
1096 if (!cRefs)
1097 return rtLocalIpcSessionWinDestroy(pThis);
1098
1099 int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2);
1100 Log(("rtLocalIpcSessionReleaseAndUnlock: %u refs left\n", cRefs));
1101 return VINF_SUCCESS;
1102}
1103
1104
1105RTDECL(uint32_t) RTLocalIpcSessionRelease(RTLOCALIPCSESSION hSession)
1106{
1107 if (hSession == NIL_RTLOCALIPCSESSION)
1108 return 0;
1109
1110 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1111 AssertPtrReturn(pThis, UINT32_MAX);
1112 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
1113
1114 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1115 Assert(cRefs < UINT32_MAX / 2);
1116 if (cRefs)
1117 Log(("RTLocalIpcSessionRelease: %u refs left\n", cRefs));
1118 else
1119 {
1120 RTCritSectEnter(&pThis->CritSect);
1121 rtLocalIpcSessionWinDestroy(pThis);
1122 }
1123 return cRefs;
1124}
1125
1126
1127RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
1128{
1129 /*
1130 * Validate input.
1131 */
1132 if (hSession == NIL_RTLOCALIPCSESSION)
1133 return VINF_SUCCESS;
1134 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1135 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1136 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1137
1138 /*
1139 * Invalidate the instance, cancel all outstanding I/O and drop our reference.
1140 */
1141 RTCritSectEnter(&pThis->CritSect);
1142 rtLocalIpcWinCancel(pThis);
1143 return rtLocalIpcSessionReleaseAndUnlock(pThis);
1144}
1145
1146
1147/**
1148 * Handles WaitForSingleObject return value when waiting for a zero byte read.
1149 *
1150 * The zero byte read is started by the RTLocalIpcSessionWaitForData method and
1151 * left pending when the function times out. This saves us the problem of
1152 * NtCancelIoFile messing with all active I/O operations and the trouble of
1153 * restarting the zero byte read the next time the method is called. However
1154 * should RTLocalIpcSessionRead be called after a failed
1155 * RTLocalIpcSessionWaitForData call, the zero byte read will still be pending
1156 * and it must wait for it to complete before the OVERLAPPEDIO structure can be
1157 * reused.
1158 *
1159 * Thus, both functions will do WaitForSingleObject and share this routine to
1160 * handle the outcome.
1161 *
1162 * @returns IPRT status code.
1163 * @param pThis The session instance.
1164 * @param rcWait The WaitForSingleObject return code.
1165 */
1166static int rtLocalIpcWinGetZeroReadResult(PRTLOCALIPCSESSIONINT pThis, DWORD rcWait)
1167{
1168 int rc;
1169 DWORD cbRead = 42;
1170 if (rcWait == WAIT_OBJECT_0)
1171 {
1172 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, !pThis->fCancelled /*fWait*/))
1173 {
1174 Assert(cbRead == 0);
1175 rc = VINF_SUCCESS;
1176 pThis->fZeroByteRead = false;
1177 }
1178 else if (pThis->fCancelled)
1179 rc = VERR_CANCELLED;
1180 else
1181 rc = RTErrConvertFromWin32(GetLastError());
1182 }
1183 else
1184 {
1185 /* We try get the result here too, just in case we're lucky, but no waiting. */
1186 DWORD dwErr = GetLastError();
1187 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, FALSE /*fWait*/))
1188 {
1189 Assert(cbRead == 0);
1190 rc = VINF_SUCCESS;
1191 pThis->fZeroByteRead = false;
1192 }
1193 else if (rcWait == WAIT_TIMEOUT)
1194 rc = VERR_TIMEOUT;
1195 else if (rcWait == WAIT_ABANDONED)
1196 rc = VERR_INVALID_HANDLE;
1197 else
1198 rc = RTErrConvertFromWin32(dwErr);
1199 }
1200 return rc;
1201}
1202
1203
1204RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
1205{
1206 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1207 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1208 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1209 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1210 /* pcbRead is optional. */
1211
1212 int rc = RTCritSectEnter(&pThis->CritSect);
1213 if (RT_SUCCESS(rc))
1214 {
1215 rtLocalIpcSessionRetain(pThis);
1216 if (pThis->Read.hActiveThread == NIL_RTTHREAD)
1217 {
1218 pThis->Read.hActiveThread = RTThreadSelf();
1219
1220 size_t cbTotalRead = 0;
1221 while (cbToRead > 0)
1222 {
1223 DWORD cbRead = 0;
1224 if (!pThis->fCancelled)
1225 {
1226 /*
1227 * Wait for pending zero byte read, if necessary.
1228 * Note! It cannot easily be cancelled due to concurrent current writes.
1229 */
1230 if (!pThis->fZeroByteRead)
1231 { /* likely */ }
1232 else
1233 {
1234 RTCritSectLeave(&pThis->CritSect);
1235 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, RT_MS_1MIN);
1236 RTCritSectEnter(&pThis->CritSect);
1237
1238 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
1239 if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT)
1240 continue;
1241 break;
1242 }
1243
1244 /*
1245 * Kick of a an overlapped read. It should return immediately if
1246 * there is bytes in the buffer. If not, we'll cancel it and see
1247 * what we get back.
1248 */
1249 rc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(rc == TRUE);
1250 RTCritSectLeave(&pThis->CritSect);
1251
1252 if (ReadFile(pThis->hNmPipe, pvBuf,
1253 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
1254 &cbRead, &pThis->Read.OverlappedIO))
1255 {
1256 RTCritSectEnter(&pThis->CritSect);
1257 rc = VINF_SUCCESS;
1258 }
1259 else if (GetLastError() == ERROR_IO_PENDING)
1260 {
1261 WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, INFINITE);
1262
1263 RTCritSectEnter(&pThis->CritSect);
1264 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, TRUE /*fWait*/))
1265 rc = VINF_SUCCESS;
1266 else
1267 {
1268 if (pThis->fCancelled)
1269 rc = VERR_CANCELLED;
1270 else
1271 rc = RTErrConvertFromWin32(GetLastError());
1272 break;
1273 }
1274 }
1275 else
1276 {
1277 rc = RTErrConvertFromWin32(GetLastError());
1278 AssertMsgFailedBreak(("%Rrc\n", rc));
1279 }
1280 }
1281 else
1282 {
1283 rc = VERR_CANCELLED;
1284 break;
1285 }
1286
1287 /* Advance. */
1288 cbToRead -= cbRead;
1289 cbTotalRead += cbRead;
1290 pvBuf = (uint8_t *)pvBuf + cbRead;
1291 }
1292
1293 if (pcbRead)
1294 {
1295 *pcbRead = cbTotalRead;
1296 if ( RT_FAILURE(rc)
1297 && cbTotalRead
1298 && rc != VERR_INVALID_POINTER)
1299 rc = VINF_SUCCESS;
1300 }
1301
1302 pThis->Read.hActiveThread = NIL_RTTHREAD;
1303 }
1304 else
1305 rc = VERR_WRONG_ORDER;
1306 rtLocalIpcSessionReleaseAndUnlock(pThis);
1307 }
1308
1309 return rc;
1310}
1311
1312
1313RTDECL(int) RTLocalIpcSessionReadNB(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
1314{
1315 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1316 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1317 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1318 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1319 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
1320 *pcbRead = 0;
1321
1322 int rc = RTCritSectEnter(&pThis->CritSect);
1323 if (RT_SUCCESS(rc))
1324 {
1325 rtLocalIpcSessionRetain(pThis);
1326 if (pThis->Read.hActiveThread == NIL_RTTHREAD)
1327 {
1328 pThis->Read.hActiveThread = RTThreadSelf();
1329
1330 for (;;)
1331 {
1332 DWORD cbRead = 0;
1333 if (!pThis->fCancelled)
1334 {
1335 /*
1336 * Wait for pending zero byte read, if necessary.
1337 * Note! It cannot easily be cancelled due to concurrent current writes.
1338 */
1339 if (!pThis->fZeroByteRead)
1340 { /* likely */ }
1341 else
1342 {
1343 RTCritSectLeave(&pThis->CritSect);
1344 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, 0);
1345 RTCritSectEnter(&pThis->CritSect);
1346
1347 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
1348 if (RT_SUCCESS(rc))
1349 continue;
1350
1351 if (rc == VERR_TIMEOUT)
1352 rc = VINF_TRY_AGAIN;
1353 break;
1354 }
1355
1356 /*
1357 * Figure out how much we can read (cannot try and cancel here
1358 * like in the anonymous pipe code).
1359 */
1360 DWORD cbAvailable;
1361 if (PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL))
1362 {
1363 if (cbAvailable == 0 || cbToRead == 0)
1364 {
1365 *pcbRead = 0;
1366 rc = VINF_TRY_AGAIN;
1367 break;
1368 }
1369 }
1370 else
1371 {
1372 rc = RTErrConvertFromWin32(GetLastError());
1373 break;
1374 }
1375 if (cbAvailable > cbToRead)
1376 cbAvailable = (DWORD)cbToRead;
1377
1378 /*
1379 * Kick of a an overlapped read. It should return immediately, so we
1380 * don't really need to leave the critsect here.
1381 */
1382 rc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(rc == TRUE);
1383 if (ReadFile(pThis->hNmPipe, pvBuf, cbAvailable, &cbRead, &pThis->Read.OverlappedIO))
1384 {
1385 *pcbRead = cbRead;
1386 rc = VINF_SUCCESS;
1387 }
1388 else if (GetLastError() == ERROR_IO_PENDING)
1389 {
1390 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, 0);
1391 if (rcWait == WAIT_TIMEOUT)
1392 {
1393 RTCritSectLeave(&pThis->CritSect);
1394 rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, INFINITE);
1395 RTCritSectEnter(&pThis->CritSect);
1396 }
1397 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, TRUE /*fWait*/))
1398 {
1399 *pcbRead = cbRead;
1400 rc = VINF_SUCCESS;
1401 }
1402 else
1403 {
1404 if (pThis->fCancelled)
1405 rc = VERR_CANCELLED;
1406 else
1407 rc = RTErrConvertFromWin32(GetLastError());
1408 }
1409 }
1410 else
1411 {
1412 rc = RTErrConvertFromWin32(GetLastError());
1413 AssertMsgFailedBreak(("%Rrc\n", rc));
1414 }
1415 }
1416 else
1417 rc = VERR_CANCELLED;
1418 break;
1419 }
1420
1421 pThis->Read.hActiveThread = NIL_RTTHREAD;
1422 }
1423 else
1424 rc = VERR_WRONG_ORDER;
1425 rtLocalIpcSessionReleaseAndUnlock(pThis);
1426 }
1427
1428 return rc;
1429}
1430
1431
1432#if 0 /* Non-blocking writes are not yet supported. */
1433/**
1434 * Common worker for handling I/O completion.
1435 *
1436 * This is used by RTLocalIpcSessionClose and RTLocalIpcSessionWrite.
1437 *
1438 * @returns IPRT status code.
1439 * @param pThis The pipe instance handle.
1440 */
1441static int rtLocalIpcSessionWriteCheckCompletion(PRTLOCALIPCSESSIONINT pThis)
1442{
1443 int rc;
1444 DWORD rcWait = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
1445 if (rcWait == WAIT_OBJECT_0)
1446 {
1447 DWORD cbWritten = 0;
1448 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE))
1449 {
1450 for (;;)
1451 {
1452 if (cbWritten >= pThis->cbBounceBufUsed)
1453 {
1454 pThis->fIOPending = false;
1455 rc = VINF_SUCCESS;
1456 break;
1457 }
1458
1459 /* resubmit the remainder of the buffer - can this actually happen? */
1460 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
1461 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
1462 if (!WriteFile(pThis->hNmPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
1463 &cbWritten, &pThis->OverlappedIO))
1464 {
1465 DWORD dwErr = GetLastError();
1466 if (dwErr == ERROR_IO_PENDING)
1467 rc = VINF_TRY_AGAIN;
1468 else
1469 {
1470 pThis->fIOPending = false;
1471 if (dwErr == ERROR_NO_DATA)
1472 rc = VERR_BROKEN_PIPE;
1473 else
1474 rc = RTErrConvertFromWin32(dwErr);
1475 }
1476 break;
1477 }
1478 Assert(cbWritten > 0);
1479 }
1480 }
1481 else
1482 {
1483 pThis->fIOPending = false;
1484 rc = RTErrConvertFromWin32(GetLastError());
1485 }
1486 }
1487 else if (rcWait == WAIT_TIMEOUT)
1488 rc = VINF_TRY_AGAIN;
1489 else
1490 {
1491 pThis->fIOPending = false;
1492 if (rcWait == WAIT_ABANDONED)
1493 rc = VERR_INVALID_HANDLE;
1494 else
1495 rc = RTErrConvertFromWin32(GetLastError());
1496 }
1497 return rc;
1498}
1499#endif
1500
1501
1502RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuf, size_t cbToWrite)
1503{
1504 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1505 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1506 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1507 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1508 AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);
1509
1510 int rc = RTCritSectEnter(&pThis->CritSect);
1511 if (RT_SUCCESS(rc))
1512 {
1513 rtLocalIpcSessionRetain(pThis);
1514 if (pThis->Write.hActiveThread == NIL_RTTHREAD)
1515 {
1516 pThis->Write.hActiveThread = RTThreadSelf();
1517
1518 /*
1519 * Try write everything. No bounce buffering necessary.
1520 */
1521 size_t cbTotalWritten = 0;
1522 while (cbToWrite > 0)
1523 {
1524 DWORD cbWritten = 0;
1525 if (!pThis->fCancelled)
1526 {
1527 BOOL fRc = ResetEvent(pThis->Write.OverlappedIO.hEvent); Assert(fRc == TRUE);
1528 RTCritSectLeave(&pThis->CritSect);
1529
1530 DWORD const cbToWriteInThisIteration = cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0;
1531 fRc = WriteFile(pThis->hNmPipe, pvBuf, cbToWriteInThisIteration, &cbWritten, &pThis->Write.OverlappedIO);
1532 if (fRc)
1533 rc = VINF_SUCCESS;
1534 else
1535 {
1536 DWORD dwErr = GetLastError();
1537 if (dwErr == ERROR_IO_PENDING)
1538 {
1539 DWORD rcWait = WaitForSingleObject(pThis->Write.OverlappedIO.hEvent, INFINITE);
1540 if (rcWait == WAIT_OBJECT_0)
1541 {
1542 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Write.OverlappedIO, &cbWritten, TRUE /*fWait*/))
1543 rc = VINF_SUCCESS;
1544 else
1545 rc = RTErrConvertFromWin32(GetLastError());
1546 }
1547 else if (rcWait == WAIT_TIMEOUT)
1548 rc = VERR_TIMEOUT;
1549 else if (rcWait == WAIT_ABANDONED)
1550 rc = VERR_INVALID_HANDLE;
1551 else
1552 rc = RTErrConvertFromWin32(GetLastError());
1553 }
1554 else if (dwErr == ERROR_NO_DATA)
1555 rc = VERR_BROKEN_PIPE;
1556 else
1557 rc = RTErrConvertFromWin32(dwErr);
1558 }
1559
1560 if (cbWritten > cbToWriteInThisIteration) /* paranoia^3 */
1561 cbWritten = cbToWriteInThisIteration;
1562
1563 RTCritSectEnter(&pThis->CritSect);
1564 if (RT_FAILURE(rc))
1565 break;
1566 }
1567 else
1568 {
1569 rc = VERR_CANCELLED;
1570 break;
1571 }
1572
1573 /* Advance. */
1574 pvBuf = (char const *)pvBuf + cbWritten;
1575 cbTotalWritten += cbWritten;
1576 cbToWrite -= cbWritten;
1577 }
1578
1579 pThis->Write.hActiveThread = NIL_RTTHREAD;
1580 }
1581 else
1582 rc = VERR_WRONG_ORDER;
1583 rtLocalIpcSessionReleaseAndUnlock(pThis);
1584 }
1585
1586 return rc;
1587}
1588
1589
1590RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
1591{
1592 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1593 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1594 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1595
1596 int rc = RTCritSectEnter(&pThis->CritSect);
1597 if (RT_SUCCESS(rc))
1598 {
1599 if (pThis->Write.hActiveThread == NIL_RTTHREAD)
1600 {
1601 /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
1602 * all data was written (or an error occurred). */
1603 /** @todo r=bird: above comment is misinformed.
1604 * Implement this as soon as we want an explicit asynchronous version of
1605 * RTLocalIpcSessionWrite on Windows. */
1606 rc = VINF_SUCCESS;
1607 }
1608 else
1609 rc = VERR_WRONG_ORDER;
1610 RTCritSectLeave(&pThis->CritSect);
1611 }
1612 return rc;
1613}
1614
1615
1616RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
1617{
1618 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1619 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1620 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1621
1622 uint64_t const msStart = RTTimeMilliTS();
1623
1624 int rc = RTCritSectEnter(&pThis->CritSect);
1625 if (RT_SUCCESS(rc))
1626 {
1627 rtLocalIpcSessionRetain(pThis);
1628 if (pThis->Read.hActiveThread == NIL_RTTHREAD)
1629 {
1630 pThis->Read.hActiveThread = RTThreadSelf();
1631
1632 /*
1633 * Wait loop.
1634 */
1635 for (unsigned iLoop = 0;; iLoop++)
1636 {
1637 /*
1638 * Check for cancellation before we continue.
1639 */
1640 if (!pThis->fCancelled)
1641 { /* likely */ }
1642 else
1643 {
1644 rc = VERR_CANCELLED;
1645 break;
1646 }
1647
1648 /*
1649 * Prep something we can wait on.
1650 */
1651 HANDLE hWait = INVALID_HANDLE_VALUE;
1652 if (pThis->fZeroByteRead)
1653 hWait = pThis->Read.OverlappedIO.hEvent;
1654 else
1655 {
1656 /* Peek at the pipe buffer and see how many bytes it contains. */
1657 DWORD cbAvailable;
1658 if ( PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL)
1659 && cbAvailable)
1660 {
1661 rc = VINF_SUCCESS;
1662 break;
1663 }
1664
1665 /* Start a zero byte read operation that we can wait on. */
1666 if (cMillies == 0)
1667 {
1668 rc = VERR_TIMEOUT;
1669 break;
1670 }
1671 BOOL fRc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(fRc == TRUE); NOREF(fRc);
1672 DWORD cbRead = 0;
1673 if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0 /*cbToRead*/, &cbRead, &pThis->Read.OverlappedIO))
1674 {
1675 rc = VINF_SUCCESS;
1676 if (iLoop > 10)
1677 RTThreadYield();
1678 }
1679 else if (GetLastError() == ERROR_IO_PENDING)
1680 {
1681 pThis->fZeroByteRead = true;
1682 hWait = pThis->Read.OverlappedIO.hEvent;
1683 }
1684 else
1685 rc = RTErrConvertFromWin32(GetLastError());
1686 if (RT_FAILURE(rc))
1687 break;
1688 }
1689
1690 /*
1691 * Check for timeout.
1692 */
1693 DWORD cMsMaxWait = INFINITE; /* (MSC maybe used uninitialized) */
1694 if (cMillies == RT_INDEFINITE_WAIT)
1695 cMsMaxWait = INFINITE;
1696 else if ( hWait != INVALID_HANDLE_VALUE
1697 || iLoop > 10)
1698 {
1699 uint64_t cMsElapsed = RTTimeMilliTS() - msStart;
1700 if (cMsElapsed <= cMillies)
1701 cMsMaxWait = cMillies - (uint32_t)cMsElapsed;
1702 else if (iLoop == 0)
1703 cMsMaxWait = cMillies ? 1 : 0;
1704 else
1705 {
1706 rc = VERR_TIMEOUT;
1707 break;
1708 }
1709 }
1710
1711 /*
1712 * Wait and collect the result.
1713 */
1714 if (hWait != INVALID_HANDLE_VALUE)
1715 {
1716 RTCritSectLeave(&pThis->CritSect);
1717
1718 DWORD rcWait = WaitForSingleObject(hWait, cMsMaxWait);
1719
1720 int rc2 = RTCritSectEnter(&pThis->CritSect);
1721 AssertRC(rc2);
1722
1723 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
1724 break;
1725 }
1726 }
1727
1728 pThis->Read.hActiveThread = NIL_RTTHREAD;
1729 }
1730
1731 rtLocalIpcSessionReleaseAndUnlock(pThis);
1732 }
1733
1734 return rc;
1735}
1736
1737
1738RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
1739{
1740 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
1741 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1742 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
1743
1744 /*
1745 * Enter the critical section, then set the cancellation flag
1746 * and signal the event (to wake up anyone in/at WaitForSingleObject).
1747 */
1748 int rc = RTCritSectEnter(&pThis->CritSect);
1749 if (RT_SUCCESS(rc))
1750 {
1751 rtLocalIpcSessionRetain(pThis);
1752 rc = rtLocalIpcWinCancel(pThis);
1753 rtLocalIpcSessionReleaseAndUnlock(pThis);
1754 }
1755
1756 return rc;
1757}
1758
1759
1760RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
1761{
1762 RT_NOREF_PV(hSession); RT_NOREF_PV(pProcess);
1763 return VERR_NOT_SUPPORTED;
1764}
1765
1766
1767RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid)
1768{
1769 RT_NOREF_PV(hSession); RT_NOREF_PV(pUid);
1770 return VERR_NOT_SUPPORTED;
1771}
1772
1773
1774RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid)
1775{
1776 RT_NOREF_PV(hSession); RT_NOREF_PV(pGid);
1777 return VERR_NOT_SUPPORTED;
1778}
1779
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