VirtualBox

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

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

localipc.h: Correct read/write parameter names.

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

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