VirtualBox

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

Last change on this file since 55563 was 55563, checked in by vboxsync, 10 years ago

localipc-win.cpp: electric fence fix.

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