VirtualBox

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

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

nits.

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