VirtualBox

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

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

localipc-posix.cpp: Partly debugged code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.2 KB
Line 
1/* $Id: localipc-posix.cpp 58282 2015-10-16 14:51:40Z 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#include "internal/iprt.h"
32#include <iprt/localipc.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/critsect.h>
38#include <iprt/mem.h>
39#include <iprt/poll.h>
40#include <iprt/socket.h>
41#include <iprt/string.h>
42
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <sys/un.h>
46#include <fcntl.h>
47#include <unistd.h>
48
49#include "internal/magics.h"
50#include "internal/socket.h"
51
52
53/*******************************************************************************
54* Structures and Typedefs *
55*******************************************************************************/
56/**
57 * Local IPC service instance, POSIX.
58 */
59typedef struct RTLOCALIPCSERVERINT
60{
61 /** The magic (RTLOCALIPCSERVER_MAGIC). */
62 uint32_t u32Magic;
63 /** The creation flags. */
64 uint32_t fFlags;
65 /** Critical section protecting the structure. */
66 RTCRITSECT CritSect;
67 /** The number of references to the instance. */
68 uint32_t volatile cRefs;
69 /** Indicates that there is a pending cancel request. */
70 bool volatile fCancelled;
71 /** The server socket. */
72 RTSOCKET hSocket;
73 /** Thread currently listening for clients. */
74 RTTHREAD hListenThread;
75 /** The name we bound the server to (native charset encoding). */
76 struct sockaddr_un Name;
77} RTLOCALIPCSERVERINT;
78/** Pointer to a local IPC server instance (POSIX). */
79typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT;
80
81
82/**
83 * Local IPC session instance, POSIX.
84 */
85typedef struct RTLOCALIPCSESSIONINT
86{
87 /** The magic (RTLOCALIPCSESSION_MAGIC). */
88 uint32_t u32Magic;
89 /** Critical section protecting the structure. */
90 RTCRITSECT CritSect;
91 /** The number of references to the instance. */
92 uint32_t volatile cRefs;
93 /** Indicates that there is a pending cancel request. */
94 bool volatile fCancelled;
95 /** Set if this is the server side, clear if the client. */
96 bool fServerSide;
97 /** The client socket. */
98 RTSOCKET hSocket;
99 /** Thread currently doing read related activites. */
100 RTTHREAD hWriteThread;
101 /** Thread currently doing write related activies. */
102 RTTHREAD hReadThread;
103} RTLOCALIPCSESSIONINT;
104/** Pointer to a local IPC session instance (Windows). */
105typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
106
107
108/** Local IPC name prefix. */
109#define RTLOCALIPC_POSIX_NAME_PREFIX "/tmp/.iprt-localipc-"
110
111
112/**
113 * Validates the user specified name.
114 *
115 * @returns IPRT status code.
116 * @param pszName The name to validate.
117 * @param pcchName Where to return the length.
118 */
119static int rtLocalIpcPosixValidateName(const char *pszName, size_t *pcchName)
120{
121 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
122
123 uint32_t cchName = 0;
124 for (;;)
125 {
126 char ch = pszName[cchName];
127 if (!ch)
128 break;
129 AssertReturn(!RT_C_IS_CNTRL(ch), VERR_INVALID_NAME);
130 AssertReturn((unsigned)ch < 0x80, VERR_INVALID_NAME);
131 AssertReturn(ch != '\\', VERR_INVALID_NAME);
132 AssertReturn(ch != '/', VERR_INVALID_NAME);
133 cchName++;
134 }
135
136 *pcchName = cchName;
137 AssertReturn(sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) + cchName <= RT_SIZEOFMEMB(struct sockaddr_un, sun_path),
138 VERR_FILENAME_TOO_LONG);
139 AssertReturn(cchName, VERR_INVALID_NAME);
140
141 return VINF_SUCCESS;
142}
143
144
145/**
146 * Constructs a local (unix) domain socket name.
147 *
148 * @returns IPRT status code.
149 * @param pAddr The address structure to construct the name in.
150 * @param pcbAddr Where to return the address size.
151 * @param pszName The user specified name (valid).
152 * @param cchName The user specified name length.
153 */
154static int rtLocalIpcPosixConstructName(struct sockaddr_un *pAddr, uint8_t *pcbAddr, const char *pszName, size_t cchName)
155{
156 AssertMsgReturn(cchName + sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) <= sizeof(pAddr->sun_path),
157 ("cchName=%zu sizeof(sun_path)=%zu\n", cchName, sizeof(pAddr->sun_path)),
158 VERR_FILENAME_TOO_LONG);
159
160/** @todo Bother converting to local codeset/encoding?? */
161
162 RT_ZERO(*pAddr);
163#ifdef RT_OS_OS2 /* Size must be exactly right on OS/2. */
164 *pcbAddr = sizeof(*pAddr);
165#else
166 *pcbAddr = RT_OFFSETOF(struct sockaddr_un, sun_path) + (uint8_t)cchName + sizeof(RTLOCALIPC_POSIX_NAME_PREFIX);
167#endif
168#ifdef HAVE_SUN_LEN_MEMBER
169 pAddr->sun_len = *pcbAddr;
170#endif
171 pAddr->sun_family = AF_LOCAL;
172 memcpy(pAddr->sun_path, RTLOCALIPC_POSIX_NAME_PREFIX, sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) - 1);
173 memcpy(&pAddr->sun_path[sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) - 1], pszName, cchName + 1);
174
175 return VINF_SUCCESS;
176}
177
178
179
180RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags)
181{
182 /*
183 * Parameter validation.
184 */
185 AssertPtrReturn(phServer, VERR_INVALID_POINTER);
186 *phServer = NIL_RTLOCALIPCSERVER;
187
188 AssertReturn(!(fFlags & ~RTLOCALIPC_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
189
190 size_t cchName;
191 int rc = rtLocalIpcPosixValidateName(pszName, &cchName);
192 if (RT_SUCCESS(rc))
193 {
194 /*
195 * Allocate memory for the instance and initialize it.
196 */
197 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocZ(sizeof(*pThis));
198 if (pThis)
199 {
200 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC;
201 pThis->fFlags = fFlags;
202 pThis->cRefs = 1;
203 pThis->fCancelled = false;
204 pThis->hListenThread = NIL_RTTHREAD;
205 rc = RTCritSectInit(&pThis->CritSect);
206 if (RT_SUCCESS(rc))
207 {
208 /*
209 * Create the local (unix) socket and bind to it.
210 */
211 rc = rtSocketCreate(&pThis->hSocket, AF_LOCAL, SOCK_STREAM, 0 /*iProtocol*/);
212 if (RT_SUCCESS(rc))
213 {
214 RTSocketSetInheritance(pThis->hSocket, false /*fInheritable*/);
215
216 uint8_t cbAddr;
217 rc = rtLocalIpcPosixConstructName(&pThis->Name, &cbAddr, pszName, cchName);
218 if (RT_SUCCESS(rc))
219 {
220 rc = rtSocketBindRawAddr(pThis->hSocket, &pThis->Name, cbAddr);
221 if (rc == VERR_NET_ADDRESS_IN_USE)
222 {
223 unlink(pThis->Name.sun_path);
224 rc = rtSocketBindRawAddr(pThis->hSocket, &pThis->Name, cbAddr);
225 }
226 if (RT_SUCCESS(rc))
227 {
228 *phServer = pThis;
229 return VINF_SUCCESS;
230 }
231 }
232 RTSocketRelease(pThis->hSocket);
233 }
234 RTCritSectDelete(&pThis->CritSect);
235 }
236 RTMemFree(pThis);
237 }
238 else
239 rc = VERR_NO_MEMORY;
240 }
241 return rc;
242}
243
244
245/**
246 * Retains a reference to the server instance.
247 *
248 * @returns
249 * @param pThis The server instance.
250 */
251DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis)
252{
253 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
254 Assert(cRefs < UINT32_MAX / 2 && cRefs);
255}
256
257
258/**
259 * Server instance destructor.
260 * @param pThis The server instance.
261 */
262static void rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis)
263{
264 pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC;
265 RTSocketRelease(pThis->hSocket);
266 RTCritSectDelete(&pThis->CritSect);
267 unlink(pThis->Name.sun_path);
268 RTMemFree(pThis);
269}
270
271
272/**
273 * Releases a reference to the server instance.
274 *
275 * @param pThis The server instance.
276 */
277DECLINLINE(void) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis)
278{
279 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
280 Assert(cRefs < UINT32_MAX / 2);
281 if (!cRefs)
282 rtLocalIpcServerDtor(pThis);
283}
284
285
286/**
287 * The core of RTLocalIpcServerCancel, used by both the destroy and cancel APIs.
288 *
289 * @returns IPRT status code
290 * @param pThis The server instance.
291 */
292static int rtLocalIpcServerCancel(PRTLOCALIPCSERVERINT pThis)
293{
294 RTCritSectEnter(&pThis->CritSect);
295 pThis->fCancelled = true;
296 if (pThis->hListenThread != NIL_RTTHREAD)
297 RTThreadPoke(pThis->hListenThread);
298 RTCritSectLeave(&pThis->CritSect);
299 return VINF_SUCCESS;
300}
301
302
303
304RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer)
305{
306 /*
307 * Validate input.
308 */
309 if (hServer == NIL_RTLOCALIPCSERVER)
310 return VINF_SUCCESS;
311 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
312 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
313 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
314
315 /*
316 * Invalidate the server, releasing the caller's reference to the instance
317 * data and making sure any other thread in the listen API will wake up.
318 */
319 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER);
320
321 rtLocalIpcServerCancel(pThis);
322 rtLocalIpcServerRelease(pThis);
323
324 return VINF_SUCCESS;
325}
326
327
328RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer)
329{
330 /*
331 * Validate input.
332 */
333 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
334 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
335 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
336
337 /*
338 * Do the job.
339 */
340 rtLocalIpcServerRetain(pThis);
341 rtLocalIpcServerCancel(pThis);
342 rtLocalIpcServerRelease(pThis);
343 return VINF_SUCCESS;
344}
345
346
347RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession)
348{
349 /*
350 * Validate input.
351 */
352 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)hServer;
353 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
354 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
355
356 /*
357 * Begin listening.
358 */
359 rtLocalIpcServerRetain(pThis);
360 int rc = RTCritSectEnter(&pThis->CritSect);
361 if (RT_SUCCESS(rc))
362 {
363 if (pThis->hListenThread == NIL_RTTHREAD)
364 {
365 pThis->hListenThread = RTThreadSelf();
366
367 /*
368 * The listening retry loop.
369 */
370 for (;;)
371 {
372 if (pThis->fCancelled)
373 {
374 rc = VERR_CANCELLED;
375 break;
376 }
377
378 rc = RTCritSectLeave(&pThis->CritSect);
379 AssertRCBreak(rc);
380
381 rc = rtSocketListen(pThis->hSocket, pThis->fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION ? 10 : 0);
382 if (RT_SUCCESS(rc))
383 {
384 struct sockaddr_un Addr;
385 size_t cbAddr = sizeof(Addr);
386 RTSOCKET hClient;
387 rc = rtSocketAccept(pThis->hSocket, &hClient, (struct sockaddr *)&Addr, &cbAddr);
388
389 int rc2 = RTCritSectEnter(&pThis->CritSect);
390 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
391
392 if (RT_SUCCESS(rc))
393 {
394 /*
395 * Create a client session.
396 */
397 PRTLOCALIPCSESSIONINT pSession = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pSession));
398 if (pSession)
399 {
400 pSession->u32Magic = RTLOCALIPCSESSION_MAGIC;
401 pSession->cRefs = 1;
402 pSession->fCancelled = false;
403 pSession->fServerSide = true;
404 pSession->hSocket = hClient;
405 pSession->hReadThread = NIL_RTTHREAD;
406 pSession->hWriteThread = NIL_RTTHREAD;
407 rc = RTCritSectInit(&pSession->CritSect);
408 if (RT_SUCCESS(rc))
409 *phClientSession = pSession;
410 else
411 RTMemFree(pSession);
412 }
413 else
414 rc = VERR_NO_MEMORY;
415 }
416 else if ( rc != VERR_INTERRUPTED
417 && rc != VERR_TRY_AGAIN)
418 break;
419 }
420 else
421 {
422 int rc2 = RTCritSectEnter(&pThis->CritSect);
423 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
424 if ( rc != VERR_INTERRUPTED
425 && rc != VERR_TRY_AGAIN)
426 break;
427 }
428 }
429
430 pThis->hListenThread = NIL_RTTHREAD;
431 }
432 else
433 {
434 AssertFailed();
435 rc = VERR_RESOURCE_BUSY;
436 }
437 int rc2 = RTCritSectLeave(&pThis->CritSect);
438 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
439 }
440 rtLocalIpcServerRelease(pThis);
441
442 return rc;
443}
444
445
446RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
447{
448 /*
449 * Parameter validation.
450 */
451 AssertPtrReturn(phSession, VERR_INVALID_POINTER);
452 *phSession = NIL_RTLOCALIPCSESSION;
453
454 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
455
456 size_t cchName;
457 int rc = rtLocalIpcPosixValidateName(pszName, &cchName);
458 if (RT_SUCCESS(rc))
459 {
460 /*
461 * Allocate memory for the instance and initialize it.
462 */
463 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis));
464 if (pThis)
465 {
466 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
467 pThis->cRefs = 1;
468 pThis->fCancelled = false;
469 pThis->fServerSide = false;
470 pThis->hSocket = NIL_RTSOCKET;
471 pThis->hReadThread = NIL_RTTHREAD;
472 pThis->hWriteThread = NIL_RTTHREAD;
473 rc = RTCritSectInit(&pThis->CritSect);
474 if (RT_SUCCESS(rc))
475 {
476 /*
477 * Create the local (unix) socket and try connect to the server.
478 */
479 rc = rtSocketCreate(&pThis->hSocket, AF_LOCAL, SOCK_STREAM, 0 /*iProtocol*/);
480 if (RT_SUCCESS(rc))
481 {
482 RTSocketSetInheritance(pThis->hSocket, false /*fInheritable*/);
483
484 struct sockaddr_un Addr;
485 uint8_t cbAddr;
486 rc = rtLocalIpcPosixConstructName(&Addr, &cbAddr, pszName, cchName);
487 if (RT_SUCCESS(rc))
488 {
489 rc = rtSocketConnectRaw(pThis->hSocket, &Addr, cbAddr);
490 if (RT_SUCCESS(rc))
491 {
492 *phSession = pThis;
493 return VINF_SUCCESS;
494 }
495 }
496 RTCritSectDelete(&pThis->CritSect);
497 }
498 }
499 RTMemFree(pThis);
500 }
501 else
502 rc = VERR_NO_MEMORY;
503 }
504 return rc;
505}
506
507
508/**
509 * Retains a reference to the session instance.
510 *
511 * @param pThis The server instance.
512 */
513DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis)
514{
515 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
516 Assert(cRefs < UINT32_MAX / 2 && cRefs);
517}
518
519
520/**
521 * Session instance destructor.
522 * @param pThis The server instance.
523 */
524static void rtLocalIpcSessionDtor(PRTLOCALIPCSESSIONINT pThis)
525{
526 pThis->u32Magic = ~RTLOCALIPCSESSION_MAGIC;
527 if (RTSocketRelease(pThis->hSocket) == 0)
528 pThis->hSocket = NIL_RTSOCKET;
529 RTCritSectDelete(&pThis->CritSect);
530 RTMemFree(pThis);
531}
532
533
534/**
535 * Releases a reference to the session instance.
536 *
537 * @param pThis The session instance.
538 */
539DECLINLINE(void) rtLocalIpcSessionRelease(PRTLOCALIPCSESSIONINT pThis)
540{
541 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
542 Assert(cRefs < UINT32_MAX / 2);
543 if (!cRefs)
544 rtLocalIpcSessionDtor(pThis);
545}
546
547
548/**
549 * The core of RTLocalIpcSessionCancel, used by both the destroy and cancel APIs.
550 *
551 * @returns IPRT status code
552 * @param pThis The session instance.
553 */
554static int rtLocalIpcSessionCancel(PRTLOCALIPCSESSIONINT pThis)
555{
556 RTCritSectEnter(&pThis->CritSect);
557 pThis->fCancelled = true;
558 if (pThis->hReadThread != NIL_RTTHREAD)
559 RTThreadPoke(pThis->hReadThread);
560 if (pThis->hWriteThread != NIL_RTTHREAD)
561 RTThreadPoke(pThis->hWriteThread);
562 RTCritSectLeave(&pThis->CritSect);
563 return VINF_SUCCESS;
564}
565
566
567RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession)
568{
569 /*
570 * Validate input.
571 */
572 if (hSession == NIL_RTLOCALIPCSESSION)
573 return VINF_SUCCESS;
574 PRTLOCALIPCSESSIONINT pThis = hSession;
575 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
576 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
577
578 /*
579 * Invalidate the session, releasing the caller's reference to the instance
580 * data and making sure any other thread in the listen API will wake up.
581 */
582 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSESSION_MAGIC, RTLOCALIPCSESSION_MAGIC), VERR_WRONG_ORDER);
583
584 rtLocalIpcSessionCancel(pThis);
585 rtLocalIpcSessionRelease(pThis);
586
587 return VINF_SUCCESS;
588}
589
590
591RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
592{
593 /*
594 * Validate input.
595 */
596 PRTLOCALIPCSESSIONINT pThis = hSession;
597 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
598 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
599
600 /*
601 * Do the job.
602 */
603 rtLocalIpcSessionRetain(pThis);
604 rtLocalIpcSessionCancel(pThis);
605 rtLocalIpcSessionRelease(pThis);
606 return VINF_SUCCESS;
607}
608
609
610RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
611{
612 /*
613 * Validate input.
614 */
615 PRTLOCALIPCSESSIONINT pThis = hSession;
616 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
617 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
618
619 /*
620 * Do the job.
621 */
622 rtLocalIpcSessionRetain(pThis);
623
624 int rc = RTCritSectEnter(&pThis->CritSect);
625 if (RT_SUCCESS(rc))
626 {
627 if (pThis->hReadThread == NIL_RTTHREAD)
628 {
629 pThis->hReadThread = RTThreadSelf();
630
631 for (;;)
632 {
633 if (!pThis->fCancelled)
634 {
635 rc = RTCritSectLeave(&pThis->CritSect);
636 AssertRCBreak(rc);
637
638 rc = RTSocketRead(pThis->hSocket, pvBuffer, cbBuffer, pcbRead);
639
640 int rc2 = RTCritSectEnter(&pThis->CritSect);
641 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
642
643 if ( rc == VERR_INTERRUPTED
644 || rc == VERR_TRY_AGAIN)
645 continue;
646 }
647 else
648 rc = VERR_CANCELLED;
649 break;
650 }
651
652 pThis->hReadThread = NIL_RTTHREAD;
653 }
654 int rc2 = RTCritSectLeave(&pThis->CritSect);
655 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
656 }
657
658 rtLocalIpcSessionRelease(pThis);
659 return rc;
660}
661
662
663RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer)
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
677 int rc = RTCritSectEnter(&pThis->CritSect);
678 if (RT_SUCCESS(rc))
679 {
680 if (pThis->hWriteThread == NIL_RTTHREAD)
681 {
682 pThis->hWriteThread = RTThreadSelf();
683
684 for (;;)
685 {
686 if (!pThis->fCancelled)
687 {
688 rc = RTCritSectLeave(&pThis->CritSect);
689 AssertRCBreak(rc);
690
691 rc = RTSocketWrite(pThis->hSocket, pvBuffer, cbBuffer);
692
693 int rc2 = RTCritSectEnter(&pThis->CritSect);
694 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
695
696 if ( rc == VERR_INTERRUPTED
697 || rc == VERR_TRY_AGAIN)
698 continue;
699 }
700 else
701 rc = VERR_CANCELLED;
702 break;
703 }
704
705 pThis->hWriteThread = NIL_RTTHREAD;
706 }
707 int rc2 = RTCritSectLeave(&pThis->CritSect);
708 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
709 }
710
711 rtLocalIpcSessionRelease(pThis);
712 return rc;
713}
714
715
716RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
717{
718 /*
719 * Validate input.
720 */
721 PRTLOCALIPCSESSIONINT pThis = hSession;
722 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
723 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
724
725 /*
726 * This is a no-op because apparently write doesn't return until the
727 * result is read. At least that's what the reply to a 2003-04-08 LKML
728 * posting title "fsync() on unix domain sockets?" indicates.
729 *
730 * For conformity, make sure there isn't any active writes concurrent to this call.
731 */
732 rtLocalIpcSessionRetain(pThis);
733
734 int rc = RTCritSectEnter(&pThis->CritSect);
735 if (RT_SUCCESS(rc))
736 {
737 if (pThis->hWriteThread == NIL_RTTHREAD)
738 rc = RTCritSectLeave(&pThis->CritSect);
739 else
740 {
741 rc = RTCritSectLeave(&pThis->CritSect);
742 if (RT_SUCCESS(rc))
743 rc = VERR_RESOURCE_BUSY;
744 }
745 }
746
747 rtLocalIpcSessionRelease(pThis);
748 return rc;
749}
750
751
752RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
753{
754 /*
755 * Validate input.
756 */
757 PRTLOCALIPCSESSIONINT pThis = hSession;
758 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
759 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
760
761 /*
762 * Do the job.
763 */
764 rtLocalIpcSessionRetain(pThis);
765
766 int rc = RTCritSectEnter(&pThis->CritSect);
767 if (RT_SUCCESS(rc))
768 {
769 if (pThis->hReadThread == NIL_RTTHREAD)
770 {
771 pThis->hReadThread = RTThreadSelf();
772
773 for (;;)
774 {
775 if (!pThis->fCancelled)
776 {
777 rc = RTCritSectLeave(&pThis->CritSect);
778 AssertRCBreak(rc);
779
780 uint32_t fEvents = 0;
781 rc = RTSocketSelectOneEx(pThis->hSocket, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, &fEvents, cMillies);
782
783 int rc2 = RTCritSectEnter(&pThis->CritSect);
784 AssertRCBreakStmt(rc2, rc = RT_SUCCESS(rc) ? rc2 : rc);
785
786 if (RT_SUCCESS(rc))
787 {
788 if (pThis->fCancelled)
789 rc = VERR_CANCELLED;
790 else if (fEvents & RTPOLL_EVT_ERROR)
791 rc = VERR_BROKEN_PIPE;
792 }
793 else if ( rc == VERR_INTERRUPTED
794 || rc == VERR_TRY_AGAIN)
795 continue;
796 }
797 else
798 rc = VERR_CANCELLED;
799 break;
800 }
801
802 pThis->hReadThread = NIL_RTTHREAD;
803 }
804 int rc2 = RTCritSectLeave(&pThis->CritSect);
805 AssertStmt(RT_SUCCESS(rc2), rc = RT_SUCCESS(rc) ? rc2 : rc);
806 }
807
808 rtLocalIpcSessionRelease(pThis);
809 return rc;
810}
811
812
813RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
814{
815 return VERR_NOT_SUPPORTED;
816}
817
818
819RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid)
820{
821 return VERR_NOT_SUPPORTED;
822}
823
824
825RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid)
826{
827 return VERR_NOT_SUPPORTED;
828}
829
830
831
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