VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/localipc-posix.cpp@ 58305

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

RTLocalIpcServerCreate: Dropped the RTLOCALIPC_FLAGS_MULTI_SESSION as it's not easy to implement single session servers on windows and especially linux.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.4 KB
Line 
1/* $Id: localipc-posix.cpp 58305 2015-10-18 23:41:37Z vboxsync $ */
2/** @file
3 * IPRT - Local IPC Server & Client, Posix.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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#define LOG_GROUP RTLOGGROUP_LOCALIPC
32#include "internal/iprt.h"
33#include <iprt/localipc.h>
34
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38#include <iprt/critsect.h>
39#include <iprt/mem.h>
40#include <iprt/log.h>
41#include <iprt/poll.h>
42#include <iprt/socket.h>
43#include <iprt/string.h>
44#include <iprt/time.h>
45
46#include <sys/types.h>
47#include <sys/socket.h>
48#include <sys/un.h>
49#ifndef RT_OS_OS2
50# include <sys/poll.h>
51# include <errno.h>
52#endif
53#include <fcntl.h>
54#include <unistd.h>
55
56#include "internal/magics.h"
57#include "internal/path.h"
58#include "internal/socket.h"
59
60
61/*******************************************************************************
62* Structures and Typedefs *
63*******************************************************************************/
64/**
65 * Local IPC service instance, POSIX.
66 */
67typedef struct RTLOCALIPCSERVERINT
68{
69 /** The magic (RTLOCALIPCSERVER_MAGIC). */
70 uint32_t u32Magic;
71 /** The creation flags. */
72 uint32_t fFlags;
73 /** Critical section protecting the structure. */
74 RTCRITSECT CritSect;
75 /** The number of references to the instance. */
76 uint32_t volatile cRefs;
77 /** Indicates that there is a pending cancel request. */
78 bool volatile fCancelled;
79 /** The server socket. */
80 RTSOCKET hSocket;
81 /** Thread currently listening for clients. */
82 RTTHREAD hListenThread;
83 /** The name we bound the server to (native charset encoding). */
84 struct sockaddr_un Name;
85} RTLOCALIPCSERVERINT;
86/** Pointer to a local IPC server instance (POSIX). */
87typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT;
88
89
90/**
91 * Local IPC session instance, POSIX.
92 */
93typedef struct RTLOCALIPCSESSIONINT
94{
95 /** The magic (RTLOCALIPCSESSION_MAGIC). */
96 uint32_t u32Magic;
97 /** Critical section protecting the structure. */
98 RTCRITSECT CritSect;
99 /** The number of references to the instance. */
100 uint32_t volatile cRefs;
101 /** Indicates that there is a pending cancel request. */
102 bool volatile fCancelled;
103 /** Set if this is the server side, clear if the client. */
104 bool fServerSide;
105 /** The client socket. */
106 RTSOCKET hSocket;
107 /** Thread currently doing read related activites. */
108 RTTHREAD hWriteThread;
109 /** Thread currently doing write related activies. */
110 RTTHREAD hReadThread;
111} RTLOCALIPCSESSIONINT;
112/** Pointer to a local IPC session instance (Windows). */
113typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
114
115
116/** Local IPC name prefix for portable names. */
117#define RTLOCALIPC_POSIX_NAME_PREFIX "/tmp/.iprt-localipc-"
118
119
120/**
121 * Validates the user specified name.
122 *
123 * @returns IPRT status code.
124 * @param pszName The name to validate.
125 * @param fNative Whether it's a native name or a portable name.
126 */
127static int rtLocalIpcPosixValidateName(const char *pszName, bool fNative)
128{
129 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
130 AssertReturn(*pszName, VERR_INVALID_NAME);
131
132 if (!fNative)
133 {
134 for (;;)
135 {
136 char ch = *pszName++;
137 if (!ch)
138 break;
139 AssertReturn(!RT_C_IS_CNTRL(ch), VERR_INVALID_NAME);
140 AssertReturn((unsigned)ch < 0x80, VERR_INVALID_NAME);
141 AssertReturn(ch != '\\', VERR_INVALID_NAME);
142 AssertReturn(ch != '/', VERR_INVALID_NAME);
143 }
144 }
145 else
146 {
147 int rc = RTStrValidateEncoding(pszName);
148 AssertRCReturn(rc, rc);
149 }
150
151 return VINF_SUCCESS;
152}
153
154
155/**
156 * Constructs a local (unix) domain socket name.
157 *
158 * @returns IPRT status code.
159 * @param pAddr The address structure to construct the name in.
160 * @param pcbAddr Where to return the address size.
161 * @param pszName The user specified name (valid).
162 * @param fNative Whether it's a native name or a portable name.
163 */
164static int rtLocalIpcPosixConstructName(struct sockaddr_un *pAddr, uint8_t *pcbAddr, const char *pszName, bool fNative)
165{
166 const char *pszNativeName;
167 int rc = rtPathToNative(&pszNativeName, pszName, NULL /*pszBasePath not support*/);
168 if (RT_SUCCESS(rc))
169 {
170 size_t cchNativeName = strlen(pszNativeName);
171 size_t cbFull = !fNative ? cchNativeName + sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) : cchNativeName + 1;
172 if (cbFull <= sizeof(pAddr->sun_path))
173 {
174 RT_ZERO(*pAddr);
175#ifdef RT_OS_OS2 /* Size must be exactly right on OS/2. */
176 *pcbAddr = sizeof(*pAddr);
177#else
178 *pcbAddr = RT_OFFSETOF(struct sockaddr_un, sun_path) + (uint8_t)cbFull;
179#endif
180#ifdef HAVE_SUN_LEN_MEMBER
181 pAddr->sun_len = *pcbAddr;
182#endif
183 pAddr->sun_family = AF_LOCAL;
184
185 if (!fNative)
186 {
187 memcpy(pAddr->sun_path, RTLOCALIPC_POSIX_NAME_PREFIX, sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) - 1);
188 memcpy(&pAddr->sun_path[sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) - 1], pszNativeName, cchNativeName + 1);
189 }
190 else
191 memcpy(pAddr->sun_path, pszNativeName, cchNativeName + 1);
192 }
193 else
194 rc = VERR_FILENAME_TOO_LONG;
195 rtPathFreeNative(pszNativeName, pszName);
196 }
197 return rc;
198}
199
200
201
202RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags)
203{
204 /*
205 * Parameter validation.
206 */
207 AssertPtrReturn(phServer, VERR_INVALID_POINTER);
208 *phServer = NIL_RTLOCALIPCSERVER;
209 AssertReturn(!(fFlags & ~RTLOCALIPC_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
210 int rc = rtLocalIpcPosixValidateName(pszName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
211 if (RT_SUCCESS(rc))
212 {
213 /*
214 * Allocate memory for the instance and initialize it.
215 */
216 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocZ(sizeof(*pThis));
217 if (pThis)
218 {
219 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC;
220 pThis->fFlags = fFlags;
221 pThis->cRefs = 1;
222 pThis->fCancelled = false;
223 pThis->hListenThread = NIL_RTTHREAD;
224 rc = RTCritSectInit(&pThis->CritSect);
225 if (RT_SUCCESS(rc))
226 {
227 /*
228 * Create the local (unix) socket and bind to it.
229 */
230 rc = rtSocketCreate(&pThis->hSocket, AF_LOCAL, SOCK_STREAM, 0 /*iProtocol*/);
231 if (RT_SUCCESS(rc))
232 {
233 RTSocketSetInheritance(pThis->hSocket, false /*fInheritable*/);
234
235 uint8_t cbAddr;
236 rc = rtLocalIpcPosixConstructName(&pThis->Name, &cbAddr, pszName,
237 RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
238 if (RT_SUCCESS(rc))
239 {
240 rc = rtSocketBindRawAddr(pThis->hSocket, &pThis->Name, cbAddr);
241 if (rc == VERR_NET_ADDRESS_IN_USE)
242 {
243 unlink(pThis->Name.sun_path);
244 rc = rtSocketBindRawAddr(pThis->hSocket, &pThis->Name, cbAddr);
245 }
246 if (RT_SUCCESS(rc))
247 {
248 rc = rtSocketListen(pThis->hSocket, 16);
249 if (RT_SUCCESS(rc))
250 {
251 LogFlow(("RTLocalIpcServerCreate: Created %p (%s)\n", pThis, pThis->Name.sun_path));
252 *phServer = pThis;
253 return VINF_SUCCESS;
254 }
255 unlink(pThis->Name.sun_path);
256 }
257 }
258 RTSocketRelease(pThis->hSocket);
259 }
260 RTCritSectDelete(&pThis->CritSect);
261 }
262 RTMemFree(pThis);
263 }
264 else
265 rc = VERR_NO_MEMORY;
266 }
267 Log(("RTLocalIpcServerCreate: failed, rc=%Rrc\n", rc));
268 return rc;
269}
270
271
272/**
273 * Retains a reference to the server instance.
274 *
275 * @returns
276 * @param pThis The server instance.
277 */
278DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis)
279{
280 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
281 Assert(cRefs < UINT32_MAX / 2 && cRefs);
282}
283
284
285/**
286 * Server instance destructor.
287 *
288 * @returns VINF_OBJECT_DESTROYED
289 * @param pThis The server instance.
290 */
291static int rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis)
292{
293 pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC;
294 if (RTSocketRelease(pThis->hSocket) == 0)
295 Log(("rtLocalIpcServerDtor: Released socket\n"));
296 else
297 Log(("rtLocalIpcServerDtor: Socket still has references (impossible?)\n"));
298 RTCritSectDelete(&pThis->CritSect);
299 unlink(pThis->Name.sun_path);
300 RTMemFree(pThis);
301 return VINF_OBJECT_DESTROYED;
302}
303
304
305/**
306 * Releases a reference to the server instance.
307 *
308 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
309 * @param pThis The server instance.
310 */
311DECLINLINE(int) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis)
312{
313 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
314 Assert(cRefs < UINT32_MAX / 2);
315 if (!cRefs)
316 return rtLocalIpcServerDtor(pThis);
317 return VINF_SUCCESS;
318}
319
320
321/**
322 * The core of RTLocalIpcServerCancel, used by both the destroy and cancel APIs.
323 *
324 * @returns IPRT status code
325 * @param pThis The server instance.
326 */
327static int rtLocalIpcServerCancel(PRTLOCALIPCSERVERINT pThis)
328{
329 RTCritSectEnter(&pThis->CritSect);
330 pThis->fCancelled = true;
331 Log(("rtLocalIpcServerCancel:\n"));
332 if (pThis->hListenThread != NIL_RTTHREAD)
333 RTThreadPoke(pThis->hListenThread);
334 RTCritSectLeave(&pThis->CritSect);
335 return VINF_SUCCESS;
336}
337
338
339
340RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
341{
342 /*
343 * Validate input.
344 */
345 if (hServer == NIL_RTLOCALIPCSERVER)
346 return VINF_SUCCESS;
347 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
348 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
349 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
350
351 /*
352 * Invalidate the server, releasing the caller's reference to the instance
353 * data and making sure any other thread in the listen API will wake up.
354 */
355 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER);
356
357 rtLocalIpcServerCancel(pThis);
358 return rtLocalIpcServerRelease(pThis);
359}
360
361
362RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
363{
364 /*
365 * Validate input.
366 */
367 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
368 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
369 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
370
371 /*
372 * Do the job.
373 */
374 rtLocalIpcServerRetain(pThis);
375 rtLocalIpcServerCancel(pThis);
376 rtLocalIpcServerRelease(pThis);
377 return VINF_SUCCESS;
378}
379
380
381RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession)
382{
383 /*
384 * Validate input.
385 */
386 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
387 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
388 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
389
390 /*
391 * Begin listening.
392 */
393 rtLocalIpcServerRetain(pThis);
394 int rc = RTCritSectEnter(&pThis->CritSect);
395 if (RT_SUCCESS(rc))
396 {
397 if (pThis->hListenThread == NIL_RTTHREAD)
398 {
399 pThis->hListenThread = RTThreadSelf();
400
401 /*
402 * The listening retry loop.
403 */
404 for (;;)
405 {
406 if (!pThis->fCancelled)
407 {
408 rc = RTCritSectLeave(&pThis->CritSect);
409 AssertRCBreak(rc);
410
411 struct sockaddr_un Addr;
412 size_t cbAddr = sizeof(Addr);
413 RTSOCKET hClient;
414 Log(("RTLocalIpcServerListen: Calling rtSocketAccept...\n"));
415 rc = rtSocketAccept(pThis->hSocket, &hClient, (struct sockaddr *)&Addr, &cbAddr);
416 Log(("RTLocalIpcServerListen: rtSocketAccept returns %Rrc.\n", rc));
417
418 int rc2 = RTCritSectEnter(&pThis->CritSect);
419 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
420
421 if (RT_SUCCESS(rc))
422 {
423 /*
424 * Create a client session.
425 */
426 PRTLOCALIPCSESSIONINT pSession = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pSession));
427 if (pSession)
428 {
429 pSession->u32Magic = RTLOCALIPCSESSION_MAGIC;
430 pSession->cRefs = 1;
431 pSession->fCancelled = false;
432 pSession->fServerSide = true;
433 pSession->hSocket = hClient;
434 pSession->hReadThread = NIL_RTTHREAD;
435 pSession->hWriteThread = NIL_RTTHREAD;
436 rc = RTCritSectInit(&pSession->CritSect);
437 if (RT_SUCCESS(rc))
438 {
439 Log(("RTLocalIpcServerListen: Returning new client session: %p\n", pSession));
440 *phClientSession = pSession;
441 break;
442 }
443
444 RTMemFree(pSession);
445 }
446 else
447 rc = VERR_NO_MEMORY;
448 }
449 else if ( rc != VERR_INTERRUPTED
450 && rc != VERR_TRY_AGAIN)
451 break;
452 }
453 else
454 {
455 rc = VERR_CANCELLED;
456 break;
457 }
458 }
459
460 pThis->hListenThread = NIL_RTTHREAD;
461 }
462 else
463 {
464 AssertFailed();
465 rc = VERR_RESOURCE_BUSY;
466 }
467 int rc2 = RTCritSectLeave(&pThis->CritSect);
468 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
469 }
470 rtLocalIpcServerRelease(pThis);
471
472 Log(("RTLocalIpcServerListen: returns %Rrc\n", rc));
473 return rc;
474}
475
476
477RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
478{
479 /*
480 * Parameter validation.
481 */
482 AssertPtrReturn(phSession, VERR_INVALID_POINTER);
483 *phSession = NIL_RTLOCALIPCSESSION;
484
485 AssertReturn(!(fFlags & ~RTLOCALIPC_C_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
486
487 int rc = rtLocalIpcPosixValidateName(pszName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
488 if (RT_SUCCESS(rc))
489 {
490 /*
491 * Allocate memory for the instance and initialize it.
492 */
493 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis));
494 if (pThis)
495 {
496 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
497 pThis->cRefs = 1;
498 pThis->fCancelled = false;
499 pThis->fServerSide = false;
500 pThis->hSocket = NIL_RTSOCKET;
501 pThis->hReadThread = NIL_RTTHREAD;
502 pThis->hWriteThread = NIL_RTTHREAD;
503 rc = RTCritSectInit(&pThis->CritSect);
504 if (RT_SUCCESS(rc))
505 {
506 /*
507 * Create the local (unix) socket and try connect to the server.
508 */
509 rc = rtSocketCreate(&pThis->hSocket, AF_LOCAL, SOCK_STREAM, 0 /*iProtocol*/);
510 if (RT_SUCCESS(rc))
511 {
512 RTSocketSetInheritance(pThis->hSocket, false /*fInheritable*/);
513
514 struct sockaddr_un Addr;
515 uint8_t cbAddr;
516 rc = rtLocalIpcPosixConstructName(&Addr, &cbAddr, pszName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
517 if (RT_SUCCESS(rc))
518 {
519 rc = rtSocketConnectRaw(pThis->hSocket, &Addr, cbAddr);
520 if (RT_SUCCESS(rc))
521 {
522 *phSession = pThis;
523 Log(("RTLocalIpcSessionConnect: Returns new session %p\n", pThis));
524 return VINF_SUCCESS;
525 }
526 }
527 RTCritSectDelete(&pThis->CritSect);
528 }
529 }
530 RTMemFree(pThis);
531 }
532 else
533 rc = VERR_NO_MEMORY;
534 }
535 Log(("RTLocalIpcSessionConnect: returns %Rrc\n", rc));
536 return rc;
537}
538
539
540/**
541 * Retains a reference to the session instance.
542 *
543 * @param pThis The server instance.
544 */
545DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis)
546{
547 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
548 Assert(cRefs < UINT32_MAX / 2 && cRefs);
549}
550
551
552RTDECL(uint32_t) RTLocalIpcSessionRetain(RTLOCALIPCSESSION hSession)
553{
554 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
555 AssertPtrReturn(pThis, UINT32_MAX);
556 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
557
558 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
559 Assert(cRefs < UINT32_MAX / 2 && cRefs);
560 return cRefs;
561}
562
563
564/**
565 * Session instance destructor.
566 *
567 * @returns VINF_OBJECT_DESTROYED
568 * @param pThis The server instance.
569 */
570static int rtLocalIpcSessionDtor(PRTLOCALIPCSESSIONINT pThis)
571{
572 pThis->u32Magic = ~RTLOCALIPCSESSION_MAGIC;
573 if (RTSocketRelease(pThis->hSocket) == 0)
574 Log(("rtLocalIpcSessionDtor: Released socket\n"));
575 else
576 Log(("rtLocalIpcSessionDtor: Socket still has references (impossible?)\n"));
577 RTCritSectDelete(&pThis->CritSect);
578 RTMemFree(pThis);
579 return VINF_OBJECT_DESTROYED;
580}
581
582
583/**
584 * Releases a reference to the session instance.
585 *
586 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate.
587 * @param pThis The session instance.
588 */
589DECLINLINE(int) rtLocalIpcSessionRelease(PRTLOCALIPCSESSIONINT pThis)
590{
591 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
592 Assert(cRefs < UINT32_MAX / 2);
593 if (!cRefs)
594 return rtLocalIpcSessionDtor(pThis);
595 Log(("rtLocalIpcSessionRelease: %u refs left\n", cRefs));
596 return VINF_SUCCESS;
597}
598
599
600RTDECL(uint32_t) RTLocalIpcSessionRelease(RTLOCALIPCSESSION hSession)
601{
602 if (hSession == NIL_RTLOCALIPCSESSION)
603 return 0;
604
605 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
606 AssertPtrReturn(pThis, UINT32_MAX);
607 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
608
609 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
610 Assert(cRefs < UINT32_MAX / 2);
611 if (cRefs)
612 Log(("RTLocalIpcSessionRelease: %u refs left\n", cRefs));
613 else
614 rtLocalIpcSessionDtor(pThis);
615 return cRefs;
616}
617
618
619/**
620 * The core of RTLocalIpcSessionCancel, used by both the destroy and cancel APIs.
621 *
622 * @returns IPRT status code
623 * @param pThis The session instance.
624 */
625static int rtLocalIpcSessionCancel(PRTLOCALIPCSESSIONINT pThis)
626{
627 RTCritSectEnter(&pThis->CritSect);
628 pThis->fCancelled = true;
629 Log(("rtLocalIpcSessionCancel:\n"));
630 if (pThis->hReadThread != NIL_RTTHREAD)
631 RTThreadPoke(pThis->hReadThread);
632 if (pThis->hWriteThread != NIL_RTTHREAD)
633 RTThreadPoke(pThis->hWriteThread);
634 RTCritSectLeave(&pThis->CritSect);
635 return VINF_SUCCESS;
636}
637
638
639RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
640{
641 /*
642 * Validate input.
643 */
644 if (hSession == NIL_RTLOCALIPCSESSION)
645 return VINF_SUCCESS;
646 PRTLOCALIPCSESSIONINT pThis = hSession;
647 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
648 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
649
650 /*
651 * Invalidate the session, releasing the caller's reference to the instance
652 * data and making sure any other thread in the listen API will wake up.
653 */
654 Log(("RTLocalIpcSessionClose:\n"));
655
656 rtLocalIpcSessionCancel(pThis);
657 return rtLocalIpcSessionRelease(pThis);
658}
659
660
661RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
662{
663 /*
664 * Validate input.
665 */
666 PRTLOCALIPCSESSIONINT pThis = hSession;
667 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
668 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
669
670 /*
671 * Do the job.
672 */
673 rtLocalIpcSessionRetain(pThis);
674 rtLocalIpcSessionCancel(pThis);
675 rtLocalIpcSessionRelease(pThis);
676 return VINF_SUCCESS;
677}
678
679
680/**
681 * Checks if the socket has has a HUP condition.
682 *
683 * @returns true if HUP, false if no.
684 * @param pThis The IPC session handle.
685 */
686static bool rtLocalIpcPosixHasHup(PRTLOCALIPCSESSIONINT pThis)
687{
688#ifndef RT_OS_OS2
689 struct pollfd PollFd;
690 RT_ZERO(PollFd);
691 PollFd.fd = RTSocketToNative(pThis->hSocket);
692 PollFd.events = POLLHUP;
693 return poll(&PollFd, 1, 0) >= 1
694 && (PollFd.revents & POLLHUP);
695
696#else /* RT_OS_OS2: */
697 return true;
698#endif
699}
700
701
702RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
703{
704 /*
705 * Validate input.
706 */
707 PRTLOCALIPCSESSIONINT pThis = hSession;
708 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
709 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
710
711 /*
712 * Do the job.
713 */
714 rtLocalIpcSessionRetain(pThis);
715
716 int rc = RTCritSectEnter(&pThis->CritSect);
717 if (RT_SUCCESS(rc))
718 {
719 if (pThis->hReadThread == NIL_RTTHREAD)
720 {
721 pThis->hReadThread = RTThreadSelf();
722
723 for (;;)
724 {
725 if (!pThis->fCancelled)
726 {
727 rc = RTCritSectLeave(&pThis->CritSect);
728 AssertRCBreak(rc);
729
730 rc = RTSocketRead(pThis->hSocket, pvBuf, cbToRead, pcbRead);
731
732 /* Detect broken pipe. */
733 if (rc == VINF_SUCCESS)
734 {
735 if (!pcbRead || *pcbRead)
736 { /* likely */ }
737 else if (rtLocalIpcPosixHasHup(pThis))
738 rc = VERR_BROKEN_PIPE;
739 }
740 else if (rc == VERR_NET_CONNECTION_RESET_BY_PEER || rc == VERR_NET_SHUTDOWN)
741 rc = VERR_BROKEN_PIPE;
742
743 int rc2 = RTCritSectEnter(&pThis->CritSect);
744 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
745
746 if ( rc == VERR_INTERRUPTED
747 || rc == VERR_TRY_AGAIN)
748 continue;
749 }
750 else
751 rc = VERR_CANCELLED;
752 break;
753 }
754
755 pThis->hReadThread = NIL_RTTHREAD;
756 }
757 int rc2 = RTCritSectLeave(&pThis->CritSect);
758 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
759 }
760
761 rtLocalIpcSessionRelease(pThis);
762 return rc;
763}
764
765
766RTDECL(int) RTLocalIpcSessionReadNB(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
767{
768 /*
769 * Validate input.
770 */
771 PRTLOCALIPCSESSIONINT pThis = hSession;
772 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
773 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
774
775 /*
776 * Do the job.
777 */
778 rtLocalIpcSessionRetain(pThis);
779
780 int rc = RTCritSectEnter(&pThis->CritSect);
781 if (RT_SUCCESS(rc))
782 {
783 if (pThis->hReadThread == NIL_RTTHREAD)
784 {
785 pThis->hReadThread = RTThreadSelf(); /* not really required, but whatever. */
786
787 for (;;)
788 {
789 if (!pThis->fCancelled)
790 {
791 rc = RTSocketReadNB(pThis->hSocket, pvBuf, cbToRead, pcbRead);
792
793 /* Detect broken pipe. */
794 if (rc == VINF_SUCCESS)
795 {
796 if (!pcbRead || *pcbRead)
797 { /* likely */ }
798 else if (rtLocalIpcPosixHasHup(pThis))
799 rc = VERR_BROKEN_PIPE;
800 }
801 else if (rc == VERR_NET_CONNECTION_RESET_BY_PEER || rc == VERR_NET_SHUTDOWN)
802 rc = VERR_BROKEN_PIPE;
803
804 if (rc == VERR_INTERRUPTED)
805 continue;
806 }
807 else
808 rc = VERR_CANCELLED;
809 break;
810 }
811
812 pThis->hReadThread = NIL_RTTHREAD;
813 }
814 int rc2 = RTCritSectLeave(&pThis->CritSect);
815 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
816 }
817
818 rtLocalIpcSessionRelease(pThis);
819 return rc;
820}
821
822
823RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuf, size_t cbToWrite)
824{
825 /*
826 * Validate input.
827 */
828 PRTLOCALIPCSESSIONINT pThis = hSession;
829 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
830 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
831
832 /*
833 * Do the job.
834 */
835 rtLocalIpcSessionRetain(pThis);
836
837 int rc = RTCritSectEnter(&pThis->CritSect);
838 if (RT_SUCCESS(rc))
839 {
840 if (pThis->hWriteThread == NIL_RTTHREAD)
841 {
842 pThis->hWriteThread = RTThreadSelf();
843
844 for (;;)
845 {
846 if (!pThis->fCancelled)
847 {
848 rc = RTCritSectLeave(&pThis->CritSect);
849 AssertRCBreak(rc);
850
851 rc = RTSocketWrite(pThis->hSocket, pvBuf, cbToWrite);
852
853 int rc2 = RTCritSectEnter(&pThis->CritSect);
854 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
855
856 if ( rc == VERR_INTERRUPTED
857 || rc == VERR_TRY_AGAIN)
858 continue;
859 }
860 else
861 rc = VERR_CANCELLED;
862 break;
863 }
864
865 pThis->hWriteThread = NIL_RTTHREAD;
866 }
867 int rc2 = RTCritSectLeave(&pThis->CritSect);
868 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
869 }
870
871 rtLocalIpcSessionRelease(pThis);
872 return rc;
873}
874
875
876RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
877{
878 /*
879 * Validate input.
880 */
881 PRTLOCALIPCSESSIONINT pThis = hSession;
882 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
883 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
884
885 /*
886 * This is a no-op because apparently write doesn't return until the
887 * result is read. At least that's what the reply to a 2003-04-08 LKML
888 * posting title "fsync() on unix domain sockets?" indicates.
889 *
890 * For conformity, make sure there isn't any active writes concurrent to this call.
891 */
892 rtLocalIpcSessionRetain(pThis);
893
894 int rc = RTCritSectEnter(&pThis->CritSect);
895 if (RT_SUCCESS(rc))
896 {
897 if (pThis->hWriteThread == NIL_RTTHREAD)
898 rc = RTCritSectLeave(&pThis->CritSect);
899 else
900 {
901 rc = RTCritSectLeave(&pThis->CritSect);
902 if (RT_SUCCESS(rc))
903 rc = VERR_RESOURCE_BUSY;
904 }
905 }
906
907 rtLocalIpcSessionRelease(pThis);
908 return rc;
909}
910
911
912RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
913{
914 /*
915 * Validate input.
916 */
917 PRTLOCALIPCSESSIONINT pThis = hSession;
918 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
919 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
920
921 /*
922 * Do the job.
923 */
924 rtLocalIpcSessionRetain(pThis);
925
926 int rc = RTCritSectEnter(&pThis->CritSect);
927 if (RT_SUCCESS(rc))
928 {
929 if (pThis->hReadThread == NIL_RTTHREAD)
930 {
931 pThis->hReadThread = RTThreadSelf();
932 uint64_t const msStart = RTTimeMilliTS();
933 RTMSINTERVAL const cMsOriginalTimeout = cMillies;
934
935 for (;;)
936 {
937 if (!pThis->fCancelled)
938 {
939 rc = RTCritSectLeave(&pThis->CritSect);
940 AssertRCBreak(rc);
941
942 uint32_t fEvents = 0;
943#ifdef RT_OS_OS2
944 /* This doesn't give us any error condition on hangup. */
945 Log(("RTLocalIpcSessionWaitForData: Calling RTSocketSelectOneEx...\n"));
946 rc = RTSocketSelectOneEx(pThis->hSocket, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, &fEvents, cMillies);
947 Log(("RTLocalIpcSessionWaitForData: RTSocketSelectOneEx returns %Rrc, fEvents=%#x\n", rc, fEvents));
948#else
949/** @todo RTSocketPoll */
950 /* POLLHUP will be set on hangup. */
951 struct pollfd PollFd;
952 RT_ZERO(PollFd);
953 PollFd.fd = RTSocketToNative(pThis->hSocket);
954 PollFd.events = POLLHUP | POLLERR | POLLIN;
955 Log(("RTLocalIpcSessionWaitForData: Calling poll...\n"));
956 int cFds = poll(&PollFd, 1, cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies);
957 if (cFds >= 1)
958 {
959 fEvents = PollFd.revents & (POLLHUP | POLLERR) ? RTPOLL_EVT_ERROR : RTPOLL_EVT_READ;
960 rc = VINF_SUCCESS;
961 }
962 else if (rc == 0)
963 rc = VERR_TIMEOUT;
964 else
965 rc = RTErrConvertFromErrno(errno);
966 Log(("RTLocalIpcSessionWaitForData: poll returns %u (rc=%%d), revents=%#x\n", cFds, rc, PollFd.revents));
967#endif
968
969 int rc2 = RTCritSectEnter(&pThis->CritSect);
970 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
971
972 if (RT_SUCCESS(rc))
973 {
974 if (pThis->fCancelled)
975 rc = VERR_CANCELLED;
976 else if (fEvents & RTPOLL_EVT_ERROR)
977 rc = VERR_BROKEN_PIPE;
978 }
979 else if ( rc == VERR_INTERRUPTED
980 || rc == VERR_TRY_AGAIN)
981 {
982 /* Recalc cMillies. */
983 if (cMsOriginalTimeout != RT_INDEFINITE_WAIT)
984 {
985 uint64_t cMsElapsed = RTTimeMilliTS() - msStart;
986 cMillies = cMsElapsed >= cMsOriginalTimeout ? 0 : cMsOriginalTimeout - (RTMSINTERVAL)cMsElapsed;
987 }
988 continue;
989 }
990 }
991 else
992 rc = VERR_CANCELLED;
993 break;
994 }
995
996 pThis->hReadThread = NIL_RTTHREAD;
997 }
998 int rc2 = RTCritSectLeave(&pThis->CritSect);
999 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
1000 }
1001
1002 rtLocalIpcSessionRelease(pThis);
1003 return rc;
1004}
1005
1006
1007RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
1008{
1009 return VERR_NOT_SUPPORTED;
1010}
1011
1012
1013RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid)
1014{
1015 return VERR_NOT_SUPPORTED;
1016}
1017
1018
1019RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid)
1020{
1021 return VERR_NOT_SUPPORTED;
1022}
1023
1024
1025
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette