VirtualBox

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

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

localipc-posix.cpp: rtSocketListen should be done when creating the server, not in the misnamed RTLocalIpcServerListen method.

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