VirtualBox

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

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

RTLocalIpc: Added RTLocalIpcSessionRetain and RTLocalIpcSessionRelease.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 KB
Line 
1/* $Id: localipc-posix.cpp 58301 2015-10-18 19:52:38Z 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
210 AssertReturn(!(fFlags & ~RTLOCALIPC_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
211
212 int rc = rtLocalIpcPosixValidateName(pszName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
213 if (RT_SUCCESS(rc))
214 {
215 /*
216 * Allocate memory for the instance and initialize it.
217 */
218 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocZ(sizeof(*pThis));
219 if (pThis)
220 {
221 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC;
222 pThis->fFlags = fFlags;
223 pThis->cRefs = 1;
224 pThis->fCancelled = false;
225 pThis->hListenThread = NIL_RTTHREAD;
226 rc = RTCritSectInit(&pThis->CritSect);
227 if (RT_SUCCESS(rc))
228 {
229 /*
230 * Create the local (unix) socket and bind to it.
231 */
232 rc = rtSocketCreate(&pThis->hSocket, AF_LOCAL, SOCK_STREAM, 0 /*iProtocol*/);
233 if (RT_SUCCESS(rc))
234 {
235 RTSocketSetInheritance(pThis->hSocket, false /*fInheritable*/);
236
237 uint8_t cbAddr;
238 rc = rtLocalIpcPosixConstructName(&pThis->Name, &cbAddr, pszName,
239 RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
240 if (RT_SUCCESS(rc))
241 {
242 rc = rtSocketBindRawAddr(pThis->hSocket, &pThis->Name, cbAddr);
243 if (rc == VERR_NET_ADDRESS_IN_USE)
244 {
245 unlink(pThis->Name.sun_path);
246 rc = rtSocketBindRawAddr(pThis->hSocket, &pThis->Name, cbAddr);
247 }
248 if (RT_SUCCESS(rc))
249 {
250 LogFlow(("RTLocalIpcServerCreate: Created %p (%s)\n", pThis, pThis->Name.sun_path));
251 *phServer = pThis;
252 return VINF_SUCCESS;
253 }
254 }
255 RTSocketRelease(pThis->hSocket);
256 }
257 RTCritSectDelete(&pThis->CritSect);
258 }
259 RTMemFree(pThis);
260 }
261 else
262 rc = VERR_NO_MEMORY;
263 }
264 Log(("RTLocalIpcServerCreate: failed, rc=%Rrc\n", rc));
265 return rc;
266}
267
268
269/**
270 * Retains a reference to the server instance.
271 *
272 * @returns
273 * @param pThis The server instance.
274 */
275DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis)
276{
277 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
278 Assert(cRefs < UINT32_MAX / 2 && cRefs);
279}
280
281
282/**
283 * Server instance destructor.
284 *
285 * @returns VINF_OBJECT_DESTROYED
286 * @param pThis The server instance.
287 */
288static int rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis)
289{
290 pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC;
291 if (RTSocketRelease(pThis->hSocket) == 0)
292 Log(("rtLocalIpcServerDtor: Released socket\n"));
293 else
294 Log(("rtLocalIpcServerDtor: Socket still has references (impossible?)\n"));
295 RTCritSectDelete(&pThis->CritSect);
296 unlink(pThis->Name.sun_path);
297 RTMemFree(pThis);
298 return VINF_OBJECT_DESTROYED;
299}
300
301
302/**
303 * Releases a reference to the server instance.
304 *
305 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
306 * @param pThis The server instance.
307 */
308DECLINLINE(int) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis)
309{
310 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
311 Assert(cRefs < UINT32_MAX / 2);
312 if (!cRefs)
313 return rtLocalIpcServerDtor(pThis);
314 return VINF_SUCCESS;
315}
316
317
318/**
319 * The core of RTLocalIpcServerCancel, used by both the destroy and cancel APIs.
320 *
321 * @returns IPRT status code
322 * @param pThis The server instance.
323 */
324static int rtLocalIpcServerCancel(PRTLOCALIPCSERVERINT pThis)
325{
326 RTCritSectEnter(&pThis->CritSect);
327 pThis->fCancelled = true;
328 Log(("rtLocalIpcServerCancel:\n"));
329 if (pThis->hListenThread != NIL_RTTHREAD)
330 RTThreadPoke(pThis->hListenThread);
331 RTCritSectLeave(&pThis->CritSect);
332 return VINF_SUCCESS;
333}
334
335
336
337RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
338{
339 /*
340 * Validate input.
341 */
342 if (hServer == NIL_RTLOCALIPCSERVER)
343 return VINF_SUCCESS;
344 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
345 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
346 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
347
348 /*
349 * Invalidate the server, releasing the caller's reference to the instance
350 * data and making sure any other thread in the listen API will wake up.
351 */
352 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER);
353
354 rtLocalIpcServerCancel(pThis);
355 return rtLocalIpcServerRelease(pThis);
356}
357
358
359RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
360{
361 /*
362 * Validate input.
363 */
364 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
365 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
366 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
367
368 /*
369 * Do the job.
370 */
371 rtLocalIpcServerRetain(pThis);
372 rtLocalIpcServerCancel(pThis);
373 rtLocalIpcServerRelease(pThis);
374 return VINF_SUCCESS;
375}
376
377
378RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession)
379{
380 /*
381 * Validate input.
382 */
383 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
384 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
385 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
386
387 /*
388 * Begin listening.
389 */
390 rtLocalIpcServerRetain(pThis);
391 int rc = RTCritSectEnter(&pThis->CritSect);
392 if (RT_SUCCESS(rc))
393 {
394 if (pThis->hListenThread == NIL_RTTHREAD)
395 {
396 pThis->hListenThread = RTThreadSelf();
397
398 /*
399 * The listening retry loop.
400 */
401 for (;;)
402 {
403 if (pThis->fCancelled)
404 {
405 rc = VERR_CANCELLED;
406 break;
407 }
408
409 rc = RTCritSectLeave(&pThis->CritSect);
410 AssertRCBreak(rc);
411
412 rc = rtSocketListen(pThis->hSocket, pThis->fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION ? 10 : 0);
413 if (RT_SUCCESS(rc))
414 {
415 struct sockaddr_un Addr;
416 size_t cbAddr = sizeof(Addr);
417 RTSOCKET hClient;
418 Log(("RTLocalIpcServerListen: Calling rtSocketAccept...\n"));
419 rc = rtSocketAccept(pThis->hSocket, &hClient, (struct sockaddr *)&Addr, &cbAddr);
420 Log(("RTLocalIpcServerListen: rtSocketAccept returns %Rrc.\n", rc));
421
422 int rc2 = RTCritSectEnter(&pThis->CritSect);
423 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
424
425 if (RT_SUCCESS(rc))
426 {
427 /*
428 * Create a client session.
429 */
430 PRTLOCALIPCSESSIONINT pSession = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pSession));
431 if (pSession)
432 {
433 pSession->u32Magic = RTLOCALIPCSESSION_MAGIC;
434 pSession->cRefs = 1;
435 pSession->fCancelled = false;
436 pSession->fServerSide = true;
437 pSession->hSocket = hClient;
438 pSession->hReadThread = NIL_RTTHREAD;
439 pSession->hWriteThread = NIL_RTTHREAD;
440 rc = RTCritSectInit(&pSession->CritSect);
441 if (RT_SUCCESS(rc))
442 {
443 Log(("RTLocalIpcServerListen: Returning new client session: %p\n", pSession));
444 *phClientSession = pSession;
445 break;
446 }
447
448 RTMemFree(pSession);
449 }
450 else
451 rc = VERR_NO_MEMORY;
452 }
453 else if ( rc != VERR_INTERRUPTED
454 && rc != VERR_TRY_AGAIN)
455 break;
456 }
457 else
458 {
459 int rc2 = RTCritSectEnter(&pThis->CritSect);
460 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
461 if ( rc != VERR_INTERRUPTED
462 && rc != VERR_TRY_AGAIN)
463 break;
464 }
465 }
466
467 pThis->hListenThread = NIL_RTTHREAD;
468 }
469 else
470 {
471 AssertFailed();
472 rc = VERR_RESOURCE_BUSY;
473 }
474 int rc2 = RTCritSectLeave(&pThis->CritSect);
475 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
476 }
477 rtLocalIpcServerRelease(pThis);
478
479 Log(("RTLocalIpcServerListen: returns %Rrc\n", rc));
480 return rc;
481}
482
483
484RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
485{
486 /*
487 * Parameter validation.
488 */
489 AssertPtrReturn(phSession, VERR_INVALID_POINTER);
490 *phSession = NIL_RTLOCALIPCSESSION;
491
492 AssertReturn(!(fFlags & ~RTLOCALIPC_C_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
493
494 int rc = rtLocalIpcPosixValidateName(pszName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
495 if (RT_SUCCESS(rc))
496 {
497 /*
498 * Allocate memory for the instance and initialize it.
499 */
500 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis));
501 if (pThis)
502 {
503 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
504 pThis->cRefs = 1;
505 pThis->fCancelled = false;
506 pThis->fServerSide = false;
507 pThis->hSocket = NIL_RTSOCKET;
508 pThis->hReadThread = NIL_RTTHREAD;
509 pThis->hWriteThread = NIL_RTTHREAD;
510 rc = RTCritSectInit(&pThis->CritSect);
511 if (RT_SUCCESS(rc))
512 {
513 /*
514 * Create the local (unix) socket and try connect to the server.
515 */
516 rc = rtSocketCreate(&pThis->hSocket, AF_LOCAL, SOCK_STREAM, 0 /*iProtocol*/);
517 if (RT_SUCCESS(rc))
518 {
519 RTSocketSetInheritance(pThis->hSocket, false /*fInheritable*/);
520
521 struct sockaddr_un Addr;
522 uint8_t cbAddr;
523 rc = rtLocalIpcPosixConstructName(&Addr, &cbAddr, pszName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
524 if (RT_SUCCESS(rc))
525 {
526 rc = rtSocketConnectRaw(pThis->hSocket, &Addr, cbAddr);
527 if (RT_SUCCESS(rc))
528 {
529 *phSession = pThis;
530 Log(("RTLocalIpcSessionConnect: Returns new session %p\n", pThis));
531 return VINF_SUCCESS;
532 }
533 }
534 RTCritSectDelete(&pThis->CritSect);
535 }
536 }
537 RTMemFree(pThis);
538 }
539 else
540 rc = VERR_NO_MEMORY;
541 }
542 Log(("RTLocalIpcSessionConnect: returns %Rrc\n", rc));
543 return rc;
544}
545
546
547/**
548 * Retains a reference to the session instance.
549 *
550 * @param pThis The server instance.
551 */
552DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis)
553{
554 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
555 Assert(cRefs < UINT32_MAX / 2 && cRefs);
556}
557
558
559RTDECL(uint32_t) RTLocalIpcSessionRetain(RTLOCALIPCSESSION hSession)
560{
561 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
562 AssertPtrReturn(pThis, UINT32_MAX);
563 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
564
565 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
566 Assert(cRefs < UINT32_MAX / 2 && cRefs);
567 return cRefs;
568}
569
570
571/**
572 * Session instance destructor.
573 *
574 * @returns VINF_OBJECT_DESTROYED
575 * @param pThis The server instance.
576 */
577static int rtLocalIpcSessionDtor(PRTLOCALIPCSESSIONINT pThis)
578{
579 pThis->u32Magic = ~RTLOCALIPCSESSION_MAGIC;
580 if (RTSocketRelease(pThis->hSocket) == 0)
581 Log(("rtLocalIpcSessionDtor: Released socket\n"));
582 else
583 Log(("rtLocalIpcSessionDtor: Socket still has references (impossible?)\n"));
584 RTCritSectDelete(&pThis->CritSect);
585 RTMemFree(pThis);
586 return VINF_OBJECT_DESTROYED;
587}
588
589
590/**
591 * Releases a reference to the session instance.
592 *
593 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate.
594 * @param pThis The session instance.
595 */
596DECLINLINE(int) rtLocalIpcSessionRelease(PRTLOCALIPCSESSIONINT pThis)
597{
598 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
599 Assert(cRefs < UINT32_MAX / 2);
600 if (!cRefs)
601 return rtLocalIpcSessionDtor(pThis);
602 Log(("rtLocalIpcSessionRelease: %u refs left\n", cRefs));
603 return VINF_SUCCESS;
604}
605
606
607RTDECL(uint32_t) RTLocalIpcSessionRelease(RTLOCALIPCSESSION hSession)
608{
609 if (hSession == NIL_RTLOCALIPCSESSION)
610 return 0;
611
612 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
613 AssertPtrReturn(pThis, UINT32_MAX);
614 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, UINT32_MAX);
615
616 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
617 Assert(cRefs < UINT32_MAX / 2);
618 if (cRefs)
619 Log(("RTLocalIpcSessionRelease: %u refs left\n", cRefs));
620 else
621 rtLocalIpcSessionDtor(pThis);
622 return cRefs;
623}
624
625
626/**
627 * The core of RTLocalIpcSessionCancel, used by both the destroy and cancel APIs.
628 *
629 * @returns IPRT status code
630 * @param pThis The session instance.
631 */
632static int rtLocalIpcSessionCancel(PRTLOCALIPCSESSIONINT pThis)
633{
634 RTCritSectEnter(&pThis->CritSect);
635 pThis->fCancelled = true;
636 Log(("rtLocalIpcSessionCancel:\n"));
637 if (pThis->hReadThread != NIL_RTTHREAD)
638 RTThreadPoke(pThis->hReadThread);
639 if (pThis->hWriteThread != NIL_RTTHREAD)
640 RTThreadPoke(pThis->hWriteThread);
641 RTCritSectLeave(&pThis->CritSect);
642 return VINF_SUCCESS;
643}
644
645
646RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
647{
648 /*
649 * Validate input.
650 */
651 if (hSession == NIL_RTLOCALIPCSESSION)
652 return VINF_SUCCESS;
653 PRTLOCALIPCSESSIONINT pThis = hSession;
654 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
655 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
656
657 /*
658 * Invalidate the session, releasing the caller's reference to the instance
659 * data and making sure any other thread in the listen API will wake up.
660 */
661 Log(("RTLocalIpcSessionClose:\n"));
662
663 rtLocalIpcSessionCancel(pThis);
664 return rtLocalIpcSessionRelease(pThis);
665}
666
667
668RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
669{
670 /*
671 * Validate input.
672 */
673 PRTLOCALIPCSESSIONINT pThis = hSession;
674 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
675 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
676
677 /*
678 * Do the job.
679 */
680 rtLocalIpcSessionRetain(pThis);
681 rtLocalIpcSessionCancel(pThis);
682 rtLocalIpcSessionRelease(pThis);
683 return VINF_SUCCESS;
684}
685
686
687/**
688 * Checks if the socket has has a HUP condition.
689 *
690 * @returns true if HUP, false if no.
691 * @param pThis The IPC session handle.
692 */
693static bool rtLocalIpcPosixHasHup(PRTLOCALIPCSESSIONINT pThis)
694{
695#ifndef RT_OS_OS2
696 struct pollfd PollFd;
697 RT_ZERO(PollFd);
698 PollFd.fd = RTSocketToNative(pThis->hSocket);
699 PollFd.events = POLLHUP;
700 return poll(&PollFd, 1, 0) >= 1
701 && (PollFd.revents & POLLHUP);
702
703#else /* RT_OS_OS2: */
704 return true;
705#endif
706}
707
708
709RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
710{
711 /*
712 * Validate input.
713 */
714 PRTLOCALIPCSESSIONINT pThis = hSession;
715 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
716 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
717
718 /*
719 * Do the job.
720 */
721 rtLocalIpcSessionRetain(pThis);
722
723 int rc = RTCritSectEnter(&pThis->CritSect);
724 if (RT_SUCCESS(rc))
725 {
726 if (pThis->hReadThread == NIL_RTTHREAD)
727 {
728 pThis->hReadThread = RTThreadSelf();
729
730 for (;;)
731 {
732 if (!pThis->fCancelled)
733 {
734 rc = RTCritSectLeave(&pThis->CritSect);
735 AssertRCBreak(rc);
736
737 rc = RTSocketRead(pThis->hSocket, pvBuf, cbToRead, pcbRead);
738
739 /* Detect broken pipe. */
740 if (rc == VINF_SUCCESS)
741 {
742 if (!pcbRead || *pcbRead)
743 { /* likely */ }
744 else if (rtLocalIpcPosixHasHup(pThis))
745 rc = VERR_BROKEN_PIPE;
746 }
747 else if (rc == VERR_NET_CONNECTION_RESET_BY_PEER || rc == VERR_NET_SHUTDOWN)
748 rc = VERR_BROKEN_PIPE;
749
750 int rc2 = RTCritSectEnter(&pThis->CritSect);
751 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
752
753 if ( rc == VERR_INTERRUPTED
754 || rc == VERR_TRY_AGAIN)
755 continue;
756 }
757 else
758 rc = VERR_CANCELLED;
759 break;
760 }
761
762 pThis->hReadThread = NIL_RTTHREAD;
763 }
764 int rc2 = RTCritSectLeave(&pThis->CritSect);
765 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
766 }
767
768 rtLocalIpcSessionRelease(pThis);
769 return rc;
770}
771
772
773RTDECL(int) RTLocalIpcSessionReadNB(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead)
774{
775 /*
776 * Validate input.
777 */
778 PRTLOCALIPCSESSIONINT pThis = hSession;
779 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
780 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
781
782 /*
783 * Do the job.
784 */
785 rtLocalIpcSessionRetain(pThis);
786
787 int rc = RTCritSectEnter(&pThis->CritSect);
788 if (RT_SUCCESS(rc))
789 {
790 if (pThis->hReadThread == NIL_RTTHREAD)
791 {
792 pThis->hReadThread = RTThreadSelf(); /* not really required, but whatever. */
793
794 for (;;)
795 {
796 if (!pThis->fCancelled)
797 {
798 rc = RTSocketReadNB(pThis->hSocket, pvBuf, cbToRead, pcbRead);
799
800 /* Detect broken pipe. */
801 if (rc == VINF_SUCCESS)
802 {
803 if (!pcbRead || *pcbRead)
804 { /* likely */ }
805 else if (rtLocalIpcPosixHasHup(pThis))
806 rc = VERR_BROKEN_PIPE;
807 }
808 else if (rc == VERR_NET_CONNECTION_RESET_BY_PEER || rc == VERR_NET_SHUTDOWN)
809 rc = VERR_BROKEN_PIPE;
810
811 if (rc == VERR_INTERRUPTED)
812 continue;
813 }
814 else
815 rc = VERR_CANCELLED;
816 break;
817 }
818
819 pThis->hReadThread = NIL_RTTHREAD;
820 }
821 int rc2 = RTCritSectLeave(&pThis->CritSect);
822 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
823 }
824
825 rtLocalIpcSessionRelease(pThis);
826 return rc;
827}
828
829
830RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuf, size_t cbToWrite)
831{
832 /*
833 * Validate input.
834 */
835 PRTLOCALIPCSESSIONINT pThis = hSession;
836 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
837 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
838
839 /*
840 * Do the job.
841 */
842 rtLocalIpcSessionRetain(pThis);
843
844 int rc = RTCritSectEnter(&pThis->CritSect);
845 if (RT_SUCCESS(rc))
846 {
847 if (pThis->hWriteThread == NIL_RTTHREAD)
848 {
849 pThis->hWriteThread = RTThreadSelf();
850
851 for (;;)
852 {
853 if (!pThis->fCancelled)
854 {
855 rc = RTCritSectLeave(&pThis->CritSect);
856 AssertRCBreak(rc);
857
858 rc = RTSocketWrite(pThis->hSocket, pvBuf, cbToWrite);
859
860 int rc2 = RTCritSectEnter(&pThis->CritSect);
861 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
862
863 if ( rc == VERR_INTERRUPTED
864 || rc == VERR_TRY_AGAIN)
865 continue;
866 }
867 else
868 rc = VERR_CANCELLED;
869 break;
870 }
871
872 pThis->hWriteThread = NIL_RTTHREAD;
873 }
874 int rc2 = RTCritSectLeave(&pThis->CritSect);
875 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
876 }
877
878 rtLocalIpcSessionRelease(pThis);
879 return rc;
880}
881
882
883RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
884{
885 /*
886 * Validate input.
887 */
888 PRTLOCALIPCSESSIONINT pThis = hSession;
889 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
890 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
891
892 /*
893 * This is a no-op because apparently write doesn't return until the
894 * result is read. At least that's what the reply to a 2003-04-08 LKML
895 * posting title "fsync() on unix domain sockets?" indicates.
896 *
897 * For conformity, make sure there isn't any active writes concurrent to this call.
898 */
899 rtLocalIpcSessionRetain(pThis);
900
901 int rc = RTCritSectEnter(&pThis->CritSect);
902 if (RT_SUCCESS(rc))
903 {
904 if (pThis->hWriteThread == NIL_RTTHREAD)
905 rc = RTCritSectLeave(&pThis->CritSect);
906 else
907 {
908 rc = RTCritSectLeave(&pThis->CritSect);
909 if (RT_SUCCESS(rc))
910 rc = VERR_RESOURCE_BUSY;
911 }
912 }
913
914 rtLocalIpcSessionRelease(pThis);
915 return rc;
916}
917
918
919RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
920{
921 /*
922 * Validate input.
923 */
924 PRTLOCALIPCSESSIONINT pThis = hSession;
925 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
926 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
927
928 /*
929 * Do the job.
930 */
931 rtLocalIpcSessionRetain(pThis);
932
933 int rc = RTCritSectEnter(&pThis->CritSect);
934 if (RT_SUCCESS(rc))
935 {
936 if (pThis->hReadThread == NIL_RTTHREAD)
937 {
938 pThis->hReadThread = RTThreadSelf();
939 uint64_t const msStart = RTTimeMilliTS();
940 RTMSINTERVAL const cMsOriginalTimeout = cMillies;
941
942 for (;;)
943 {
944 if (!pThis->fCancelled)
945 {
946 rc = RTCritSectLeave(&pThis->CritSect);
947 AssertRCBreak(rc);
948
949 uint32_t fEvents = 0;
950#ifdef RT_OS_OS2
951 /* This doesn't give us any error condition on hangup. */
952 Log(("RTLocalIpcSessionWaitForData: Calling RTSocketSelectOneEx...\n"));
953 rc = RTSocketSelectOneEx(pThis->hSocket, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, &fEvents, cMillies);
954 Log(("RTLocalIpcSessionWaitForData: RTSocketSelectOneEx returns %Rrc, fEvents=%#x\n", rc, fEvents));
955#else
956/** @todo RTSocketPoll */
957 /* POLLHUP will be set on hangup. */
958 struct pollfd PollFd;
959 RT_ZERO(PollFd);
960 PollFd.fd = RTSocketToNative(pThis->hSocket);
961 PollFd.events = POLLHUP | POLLERR | POLLIN;
962 Log(("RTLocalIpcSessionWaitForData: Calling poll...\n"));
963 int cFds = poll(&PollFd, 1, cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies);
964 if (cFds >= 1)
965 {
966 fEvents = PollFd.revents & (POLLHUP | POLLERR) ? RTPOLL_EVT_ERROR : RTPOLL_EVT_READ;
967 rc = VINF_SUCCESS;
968 }
969 else if (rc == 0)
970 rc = VERR_TIMEOUT;
971 else
972 rc = RTErrConvertFromErrno(errno);
973 Log(("RTLocalIpcSessionWaitForData: poll returns %u (rc=%%d), revents=%#x\n", cFds, rc, PollFd.revents));
974#endif
975
976 int rc2 = RTCritSectEnter(&pThis->CritSect);
977 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
978
979 if (RT_SUCCESS(rc))
980 {
981 if (pThis->fCancelled)
982 rc = VERR_CANCELLED;
983 else if (fEvents & RTPOLL_EVT_ERROR)
984 rc = VERR_BROKEN_PIPE;
985 }
986 else if ( rc == VERR_INTERRUPTED
987 || rc == VERR_TRY_AGAIN)
988 {
989 /* Recalc cMillies. */
990 if (cMsOriginalTimeout != RT_INDEFINITE_WAIT)
991 {
992 uint64_t cMsElapsed = RTTimeMilliTS() - msStart;
993 cMillies = cMsElapsed >= cMsOriginalTimeout ? 0 : cMsOriginalTimeout - (RTMSINTERVAL)cMsElapsed;
994 }
995 continue;
996 }
997 }
998 else
999 rc = VERR_CANCELLED;
1000 break;
1001 }
1002
1003 pThis->hReadThread = NIL_RTTHREAD;
1004 }
1005 int rc2 = RTCritSectLeave(&pThis->CritSect);
1006 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
1007 }
1008
1009 rtLocalIpcSessionRelease(pThis);
1010 return rc;
1011}
1012
1013
1014RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
1015{
1016 return VERR_NOT_SUPPORTED;
1017}
1018
1019
1020RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid)
1021{
1022 return VERR_NOT_SUPPORTED;
1023}
1024
1025
1026RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid)
1027{
1028 return VERR_NOT_SUPPORTED;
1029}
1030
1031
1032
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