VirtualBox

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

Last change on this file since 58029 was 57974, checked in by vboxsync, 9 years ago

IPRT: Some more doxygen fixes.

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