VirtualBox

Changeset 102060 in vbox for trunk/src/libs/xpcom18a4/ipc


Ignore:
Timestamp:
Nov 10, 2023 9:47:46 AM (15 months ago)
Author:
vboxsync
Message:

libs/xpcom/ipc/ipcd/client: Rewrite the IPC client connection code to move away from NSPR and use IPRT, bugref:10545

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp

    r101890 r102060  
    1 /* vim:set ts=2 sw=2 et cindent: */
    21/* ***** BEGIN LICENSE BLOCK *****
    32 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
     
    3534 *
    3635 * ***** END LICENSE BLOCK ***** */
    37 
    38 #include "private/pprio.h"
    39 #include "prerror.h"
    40 #include "prio.h"
     36#define LOG_GROUP LOG_GROUP_IPC
     37#include <iprt/assert.h>
     38#include <iprt/critsect.h>
     39#include <iprt/err.h>
     40#include <iprt/env.h>
     41#include <iprt/mem.h>
     42#include <iprt/pipe.h>
     43#include <iprt/poll.h>
     44#include <iprt/socket.h>
     45#include <iprt/string.h>
     46#include <iprt/thread.h>
     47
     48#include <VBox/log.h>
     49
     50#include <unistd.h>
     51#include <errno.h>
     52#include <sys/types.h>
     53#include <sys/socket.h>
     54#include <sys/un.h>
     55#include <sys/stat.h>
     56#include <stdio.h> /* fprintf below */
    4157
    4258#include "ipcConnection.h"
    4359#include "ipcMessageQ.h"
    4460#include "ipcConfig.h"
    45 #include "ipcLog.h"
    46 
    47 #ifdef VBOX
    48 # include <iprt/assert.h>
    49 # include <iprt/critsect.h>
    50 # include <iprt/err.h>
    51 # include <iprt/env.h>
    52 # include <iprt/log.h>
    53 # include <iprt/mem.h>
    54 # include <iprt/pipe.h>
    55 # include <iprt/string.h>
    56 # include <iprt/thread.h>
    57 
    58 # include <stdio.h>
    59 #endif
    60 
    61 
    62 //-----------------------------------------------------------------------------
    63 // NOTE: this code does not need to link with anything but NSPR.  that is by
    64 //       design, so it can be easily reused in other projects that want to
    65 //       talk with mozilla's IPC daemon, but don't want to depend on xpcom.
    66 //       we depend at most on some xpcom header files, but no xpcom runtime
    67 //       symbols are used.
    68 //-----------------------------------------------------------------------------
    69 
    70 
    71 #include <unistd.h>
    72 #include <sys/stat.h>
     61
    7362
    7463static PRStatus
    75 DoSecurityCheck(PRFileDesc *fd, const char *path)
     64DoSecurityCheck(int fd, const char *path)
    7665{
    7766    //
     
    8473    // if these conditions aren't met then bail.
    8574    //
    86     int unix_fd = PR_FileDesc2NativeHandle(fd); 
    87 
    8875    struct stat st;
    89     if (fstat(unix_fd, &st) == -1) {
    90         LOG(("stat failed"));
     76    if (fstat(fd, &st) == -1)
     77    {
     78        LogFlowFunc(("stat failed"));
    9179        return PR_FAILURE;
    9280    }
    9381
    94     if (st.st_uid != getuid() && st.st_uid != geteuid()) {
     82    if (st.st_uid != getuid() && st.st_uid != geteuid())
     83    {
    9584        //
    9685        // on OSX 10.1.5, |fstat| has a bug when passed a file descriptor to
     
    10190        //
    10291        if (st.st_uid != 0) {
    103             LOG(("userid check failed"));
     92            LogFlowFunc(("userid check failed"));
    10493            return PR_FAILURE;
    10594        }
    10695        if (stat(path, &st) == -1) {
    107             LOG(("stat failed"));
     96            LogFlowFunc(("stat failed"));
    10897            return PR_FAILURE;
    10998        }
    11099        if (st.st_uid != getuid() && st.st_uid != geteuid()) {
    111             LOG(("userid check failed"));
     100            LogFlowFunc(("userid check failed"));
    112101            return PR_FAILURE;
    113102        }
     
    124113struct ipcCallback : public ipcListNode<ipcCallback>
    125114{
    126   ipcCallbackFunc  func;
    127   void            *arg;
     115    ipcCallbackFunc  func;
     116    void            *arg;
    128117};
    129118
     
    134123struct ipcConnectionState
    135124{
    136   RTCRITSECT   CritSect;
    137   RTPIPE       hWakeupPipeW;
    138   PRPollDesc   fds[2];
    139   ipcCallbackQ callback_queue;
    140   ipcMessageQ  send_queue;
    141   PRUint32     send_offset; // amount of send_queue.First() already written.
    142   ipcMessage  *in_msg;
    143   PRBool       shutdown;
     125    RTCRITSECT   CritSect;
     126    RTPIPE       hWakeupPipeW;
     127    RTPIPE       hWakeupPipeR;
     128    RTSOCKET     hSockConn;
     129    RTPOLLSET    hPollSet;
     130    ipcCallbackQ callback_queue;
     131    ipcMessageQ  send_queue;
     132    PRUint32     send_offset; // amount of send_queue.First() already written.
     133    ipcMessage  *in_msg;
     134    bool         fShutdown;
    144135};
    145136
     
    149140static void ConnDestroy(ipcConnectionState *s)
    150141{
    151   if (RTCritSectIsInitialized(&s->CritSect))
    152142    RTCritSectDelete(&s->CritSect);
    153 
    154   if (s->fds[SOCK].fd)
    155     PR_Close(s->fds[SOCK].fd);
    156 
    157   if (s->fds[POLL].fd)
    158     PR_Close(s->fds[POLL].fd);
    159 
    160   if (s->in_msg)
    161     delete s->in_msg;
    162 
    163   s->send_queue.DeleteAll();
    164   RTMemFree(s);
    165 }
    166 
    167 static ipcConnectionState *ConnCreate(PRFileDesc *fd)
     143    RTPollSetDestroy(s->hPollSet);
     144    RTPipeClose(s->hWakeupPipeR);
     145    RTPipeClose(s->hWakeupPipeW);
     146    RTSocketClose(s->hSockConn);
     147
     148    if (s->in_msg)
     149        delete s->in_msg;
     150
     151    s->send_queue.DeleteAll();
     152    RTMemFree(s);
     153}
     154
     155static ipcConnectionState *ConnCreate(RTSOCKET hSockConn)
    168156{
    169157    ipcConnectionState *s = (ipcConnectionState *)RTMemAllocZ(sizeof(*s));
     
    171159      return NULL;
    172160
     161    s->send_offset = 0;
     162    s->in_msg = NULL;
     163    s->fShutdown = false;
     164
    173165    int vrc = RTCritSectInit(&s->CritSect);
    174166    if (RT_SUCCESS(vrc))
    175167    {
    176         RTPIPE hPipeR;
    177 
    178         vrc = RTPipeCreate(&hPipeR, &s->hWakeupPipeW, 0 /*fFlags*/);
     168        vrc = RTPollSetCreate(&s->hPollSet);
    179169        if (RT_SUCCESS(vrc))
    180170        {
    181             s->fds[SOCK].fd = NULL;
    182             s->fds[POLL].fd = PR_AllocFileDesc((PRInt32)RTPipeToNative(hPipeR), PR_GetPipeMethods());
    183             s->send_offset = 0;
    184             s->in_msg = NULL;
    185             s->shutdown = PR_FALSE;
    186 
    187             if (s->fds[POLL].fd)
    188             {
    189                 /* NSPR has taken over the pipe. */
    190                 vrc = RTPipeCloseEx(hPipeR, true /*fLeaveOpen*/); AssertRC(vrc);
    191 
    192                 // disable inheritance of the IPC socket by children started
    193                 // using non-NSPR process API
    194                 PRStatus status = PR_SetFDInheritable(fd, PR_FALSE);
    195                 if (status == PR_SUCCESS)
     171            RTPIPE hPipeR;
     172
     173            vrc = RTPipeCreate(&s->hWakeupPipeR, &s->hWakeupPipeW, 0 /*fFlags*/);
     174            if (RT_SUCCESS(vrc))
     175            {
     176                vrc = RTPollSetAddSocket(s->hPollSet, hSockConn, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, SOCK);
     177                if (RT_SUCCESS(vrc))
    196178                {
    197                     // store this only if we are going to succeed.
    198                     s->fds[SOCK].fd = fd;
    199 
    200                     return s;
     179                    vrc = RTPollSetAddPipe(s->hPollSet, s->hWakeupPipeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, POLL);
     180                    if (RT_SUCCESS(vrc))
     181                    {
     182                        vrc = RTSocketSetInheritance(hSockConn, false /*fInheritable*/);
     183                        if (RT_SUCCESS(vrc))
     184                        {
     185                            s->hSockConn = hSockConn;
     186                            return s;
     187                        }
     188
     189                        LogFlowFunc(("coudn't make IPC socket non-inheritable [err=%Rrc]\n", vrc));
     190                        vrc = RTPollSetRemove(s->hPollSet, POLL); AssertRC(vrc);
     191                    }
     192
     193                    vrc = RTPollSetRemove(s->hPollSet, SOCK); AssertRC(vrc);
    201194                }
    202195
    203                 PR_Close(s->fds[POLL].fd);
    204                 s->fds[POLL].fd = NULL;
    205                 LOG(("coudn't make IPC socket non-inheritable [err=%d]\n", PR_GetError()));
    206             }
    207 
    208             vrc = RTPipeClose(hPipeR);          AssertRC(vrc);
    209             vrc = RTPipeClose(s->hWakeupPipeW); AssertRC(vrc);
    210         }
    211 
    212         ConnDestroy(s);
     196                vrc = RTPipeClose(s->hWakeupPipeR); AssertRC(vrc);
     197                vrc = RTPipeClose(s->hWakeupPipeW); AssertRC(vrc);
     198            }
     199
     200            vrc = RTPollSetDestroy(s->hPollSet); AssertRC(vrc);
     201        }
     202
     203        RTCritSectDelete(&s->CritSect);
    213204    }
    214205
     
    216207}
    217208
    218 static nsresult
    219 ConnRead(ipcConnectionState *s)
    220 {
    221   char buf[1024];
    222   nsresult rv = NS_OK;
    223   PRInt32 n;
    224 
    225   do
    226   {
    227     n = PR_Read(s->fds[SOCK].fd, buf, sizeof(buf));
    228     if (n < 0)
    229     {
    230       PRErrorCode err = PR_GetError();
    231       if (err == PR_WOULD_BLOCK_ERROR)
    232       {
    233         // socket is empty... we need to go back to polling.
    234         break;
    235       }
    236       LOG(("PR_Read returned failure [err=%d]\n", err));
    237       rv = NS_ERROR_UNEXPECTED;
    238     }
    239     else if (n == 0)
    240     {
    241       LOG(("PR_Read returned EOF\n"));
    242       rv = NS_ERROR_UNEXPECTED;
    243     }
    244     else
    245     {
    246       const char *pdata = buf;
    247       while (n)
    248       {
    249         PRUint32 bytesRead;
    250         PRBool complete;
    251 
    252         if (!s->in_msg)
    253         {
    254           s->in_msg = new ipcMessage;
    255           if (!s->in_msg)
    256           {
    257             rv = NS_ERROR_OUT_OF_MEMORY;
     209static nsresult ConnRead(ipcConnectionState *s)
     210{
     211    nsresult rv = NS_OK;
     212
     213    /* Read as much as possible. */
     214    for (;;)
     215    {
     216        char buf[_1K];
     217        size_t cbRead = 0;
     218        int vrc = RTSocketReadNB(s->hSockConn, &buf[0], sizeof(buf), &cbRead);
     219        if (RT_SUCCESS(vrc) && cbRead > 0)
     220        { /* likely */ }
     221        else if (vrc == VINF_TRY_AGAIN)
     222            break; /* Socket is empty, go back to polling. */
     223        else if (RT_FAILURE(vrc))
     224        {
     225            rv = NS_ERROR_UNEXPECTED;
    258226            break;
    259           }
    260         }
    261 
    262         if (s->in_msg->ReadFrom(pdata, n, &bytesRead, &complete) != PR_SUCCESS)
    263         {
    264           LOG(("error reading IPC message\n"));
    265           rv = NS_ERROR_UNEXPECTED;
    266           break;
    267         }
    268 
    269         Assert(PRUint32(n) >= bytesRead);
    270         n -= bytesRead;
    271         pdata += bytesRead;
    272 
    273         if (complete)
    274         {
    275           // protect against weird re-entrancy cases...
    276           ipcMessage *m = s->in_msg;
    277           s->in_msg = NULL;
    278 
    279           IPC_OnMessageAvailable(m);
    280         }
    281       }
    282     }
    283   }
    284   while (NS_SUCCEEDED(rv));
    285 
    286   return rv;
    287 }
    288 
    289 static nsresult
    290 ConnWrite(ipcConnectionState *s)
    291 {
    292   nsresult rv = NS_OK;
    293 
    294   RTCritSectEnter(&s->CritSect);
    295 
    296   // write one message and then return.
    297   if (s->send_queue.First())
    298   {
    299     PRInt32 n = PR_Write(s->fds[SOCK].fd,
    300                          s->send_queue.First()->MsgBuf() + s->send_offset,
    301                          s->send_queue.First()->MsgLen() - s->send_offset);
    302     if (n <= 0)
    303     {
    304       PRErrorCode err = PR_GetError();
    305       if (err == PR_WOULD_BLOCK_ERROR)
    306       {
    307         // socket is full... we need to go back to polling.
    308       }
    309       else
    310       {
    311         LOG(("error writing to socket [err=%d]\n", err));
    312         rv = NS_ERROR_UNEXPECTED;
    313       }
    314     }
    315     else
    316     {
    317       s->send_offset += n;
    318       if (s->send_offset == s->send_queue.First()->MsgLen())
    319       {
    320         s->send_queue.DeleteFirst();
    321         s->send_offset = 0;
    322 
    323         // if the send queue is empty, then we need to stop trying to write.
    324         if (s->send_queue.IsEmpty())
    325           s->fds[SOCK].in_flags &= ~PR_POLL_WRITE;
    326       }
    327     }
    328   }
    329 
    330   RTCritSectLeave(&s->CritSect);
    331   return rv;
     227        }
     228        else if (cbRead == 0)
     229        {
     230            LogFlowFunc(("RTSocketReadNB() returned EOF\n"));
     231            rv = NS_ERROR_UNEXPECTED;
     232            break;
     233        }
     234
     235        const char *pdata = buf;
     236        while (cbRead)
     237        {
     238            PRUint32 bytesRead;
     239            PRBool fComplete = PR_FALSE;
     240
     241            /* No message frame available? Allocate a new one. */
     242            if (!s->in_msg)
     243            {
     244                s->in_msg = new ipcMessage;
     245                if (RT_UNLIKELY(!s->in_msg))
     246                {
     247                    rv = NS_ERROR_OUT_OF_MEMORY;
     248                    break;
     249                }
     250            }
     251
     252            if (s->in_msg->ReadFrom(pdata, cbRead, &bytesRead, &fComplete) != PR_SUCCESS)
     253            {
     254                LogFlowFunc(("error reading IPC message\n"));
     255                rv = NS_ERROR_UNEXPECTED;
     256                break;
     257            }
     258
     259            Assert(cbRead >= bytesRead);
     260            cbRead -= bytesRead;
     261            pdata  += bytesRead;
     262
     263            if (fComplete)
     264            {
     265                // protect against weird re-entrancy cases...
     266                ipcMessage *m = s->in_msg;
     267                s->in_msg = NULL;
     268
     269                IPC_OnMessageAvailable(m);
     270            }
     271        }
     272    }
     273
     274    return rv;
     275}
     276
     277static nsresult ConnWrite(ipcConnectionState *s)
     278{
     279    nsresult rv = NS_OK;
     280
     281    RTCritSectEnter(&s->CritSect);
     282
     283    // write one message and then return.
     284    if (s->send_queue.First())
     285    {
     286        size_t cbWritten = 0;
     287        int vrc = RTSocketWriteNB(s->hSockConn,
     288                                  s->send_queue.First()->MsgBuf() + s->send_offset,
     289                                  s->send_queue.First()->MsgLen() - s->send_offset,
     290                                  &cbWritten);
     291        if (vrc == VINF_SUCCESS && cbWritten)
     292        {
     293            s->send_offset += cbWritten;
     294            if (s->send_offset == s->send_queue.First()->MsgLen())
     295            {
     296                s->send_queue.DeleteFirst();
     297                s->send_offset = 0;
     298
     299                /* if the send queue is empty, then we need to stop trying to write. */
     300                if (s->send_queue.IsEmpty())
     301                {
     302                    vrc = RTPollSetEventsChange(s->hPollSet, SOCK, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR);
     303                    AssertRC(vrc);
     304                }
     305            }
     306        }
     307        else if (vrc != VINF_TRY_AGAIN)
     308        {
     309            Assert(RT_FAILURE(vrc));
     310            LogFlowFunc(("error writing to socket [err=%Rrc]\n", vrc));
     311            rv = NS_ERROR_UNEXPECTED;
     312        }
     313    }
     314
     315    RTCritSectLeave(&s->CritSect);
     316    return rv;
    332317}
    333318
    334319static DECLCALLBACK(int) ipcConnThread(RTTHREAD hSelf, void *pvArg)
    335320{
    336   RT_NOREF(hSelf);
    337 
    338   PRInt32 num;
    339   nsresult rv = NS_OK;
    340 
    341   ipcConnectionState *s = (ipcConnectionState *)pvArg;
    342 
    343   // we monitor two file descriptors in this thread.  the first (at index 0) is
    344   // the socket connection with the IPC daemon.  the second (at index 1) is the
    345   // pollable event we monitor in order to know when to send messages to the
    346   // IPC daemon.
    347 
    348   s->fds[SOCK].in_flags = PR_POLL_READ;
    349   s->fds[POLL].in_flags = PR_POLL_READ;
    350 
    351   while (NS_SUCCEEDED(rv))
    352   {
    353     s->fds[SOCK].out_flags = 0;
    354     s->fds[POLL].out_flags = 0;
    355 
    356     //
    357     // poll on the IPC socket and NSPR pollable event
    358     //
    359     num = PR_Poll(s->fds, 2, PR_INTERVAL_NO_TIMEOUT);
    360     if (num > 0)
    361     {
    362       ipcCallbackQ cbs_to_run;
    363 
    364       // check if something has been added to the send queue.  if so, then
    365       // acknowledge pollable event (wait should not block), and configure
    366       // poll flags to find out when we can write.
    367 
    368       if (s->fds[POLL].out_flags & PR_POLL_READ)
    369       {
    370         /* Drain wakeup pipe. */
    371         uint8_t buf[32];
     321    RT_NOREF(hSelf);
     322
     323    nsresult rv = NS_OK;
     324    ipcConnectionState *s = (ipcConnectionState *)pvArg;
     325
     326    // we monitor two file descriptors in this thread.  the first (at index 0) is
     327    // the socket connection with the IPC daemon.  the second (at index 1) is the
     328    // pollable event we monitor in order to know when to send messages to the
     329    // IPC daemon.
     330
     331    while (NS_SUCCEEDED(rv))
     332    {
     333        //
     334        // poll on the IPC socket and NSPR pollable event
     335        //
     336        uint32_t fEvents;
     337        uint32_t idPoll;
     338        int vrc = RTPoll(s->hPollSet, RT_INDEFINITE_WAIT, &fEvents, &idPoll);
     339        if (RT_SUCCESS(vrc))
     340        {
     341            if (idPoll == SOCK)
     342            {
     343                /* check if we can read... */
     344                if (fEvents & RTPOLL_EVT_READ)
     345                    rv = ConnRead(s);
     346
     347                /* check if we can write... */
     348                if (fEvents & RTPOLL_EVT_WRITE)
     349                    rv = ConnWrite(s);
     350            }
     351            else
     352            {
     353                Assert(   idPoll == POLL
     354                       && (fEvents & RTPOLL_EVT_READ)
     355                       && !(fEvents & (RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR)));
     356
     357                uint8_t buf[32];
     358                ipcCallbackQ cbs_to_run;
     359
     360                // check if something has been added to the send queue.  if so, then
     361                // acknowledge pollable event (wait should not block), and configure
     362                // poll flags to find out when we can write.
     363
     364                /* Drain wakeup pipe. */
     365                size_t cbRead = 0;
     366                vrc = RTPipeRead(s->hWakeupPipeR, &buf[0], sizeof(buf), &cbRead);
     367                Assert(RT_SUCCESS(vrc) && cbRead > 0);
     368
    372369#ifdef DEBUG
    373         PRIntn i;
     370                /* Make sure this is not written with something else. */
     371                for (uint32_t i = 0; i < cbRead; i++)
     372                    Assert(buf[i] == magicChar);
    374373#endif
    375         PRInt32 nBytes = PR_Read(s->fds[POLL].fd, buf, sizeof(buf));
    376         Assert(nBytes > 0);
    377 
    378 #ifdef DEBUG
    379         /* Make sure this is not written with something else. */
    380         for (i = 0; i < nBytes; i++) {
    381             Assert(buf[i] == magicChar);
    382         }
    383 #endif
    384 
    385         RTCritSectEnter(&s->CritSect);
    386 
    387         if (!s->send_queue.IsEmpty())
    388           s->fds[SOCK].in_flags |= PR_POLL_WRITE;
    389 
    390         if (!s->callback_queue.IsEmpty())
    391           s->callback_queue.MoveTo(cbs_to_run);
    392 
    393         RTCritSectLeave(&s->CritSect);
    394       }
    395 
    396       // check if we can read...
    397       if (s->fds[SOCK].out_flags & PR_POLL_READ)
    398         rv = ConnRead(s);
    399 
    400       // check if we can write...
    401       if (s->fds[SOCK].out_flags & PR_POLL_WRITE)
    402         rv = ConnWrite(s);
    403 
    404       // check if we have callbacks to run
    405       while (!cbs_to_run.IsEmpty())
    406       {
    407         ipcCallback *cb = cbs_to_run.First();
    408         (cb->func)(cb->arg);
    409         cbs_to_run.DeleteFirst();
    410       }
    411 
    412       // check if we should exit this thread.  delay processing a shutdown
    413       // request until after all queued up messages have been sent and until
    414       // after all queued up callbacks have been run.
    415       RTCritSectEnter(&s->CritSect);
    416       if (s->shutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty())
    417         rv = NS_ERROR_ABORT;
    418       RTCritSectLeave(&s->CritSect);
    419     }
    420     else
    421     {
    422       LOG(("PR_Poll returned error %d (%s), os error %d\n", PR_GetError(),
    423            PR_ErrorToName(PR_GetError()), PR_GetOSError()));
    424       rv = NS_ERROR_UNEXPECTED;
    425     }
    426   }
    427 
    428   // notify termination of the IPC connection
    429   if (rv == NS_ERROR_ABORT)
    430     rv = NS_OK;
    431   IPC_OnConnectionEnd(rv);
    432 
    433   LOG(("IPC thread exiting\n"));
    434   return VINF_SUCCESS;
     374
     375                RTCritSectEnter(&s->CritSect);
     376
     377                if (!s->send_queue.IsEmpty())
     378                {
     379                    vrc = RTPollSetEventsChange(s->hPollSet, SOCK, RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR);
     380                    AssertRC(vrc);
     381                }
     382
     383                if (!s->callback_queue.IsEmpty())
     384                    s->callback_queue.MoveTo(cbs_to_run);
     385
     386                // check if we should exit this thread.  delay processing a shutdown
     387                // request until after all queued up messages have been sent and until
     388                // after all queued up callbacks have been run.
     389                if (s->fShutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty())
     390                    rv = NS_ERROR_ABORT;
     391
     392                RTCritSectLeave(&s->CritSect);
     393
     394                // check if we have callbacks to run
     395                while (!cbs_to_run.IsEmpty())
     396                {
     397                    ipcCallback *cb = cbs_to_run.First();
     398                    (cb->func)(cb->arg);
     399                    cbs_to_run.DeleteFirst();
     400                }
     401            }
     402        }
     403        else
     404        {
     405            LogFlowFunc(("RTPoll returned error %Rrc\n", vrc));
     406            rv = NS_ERROR_UNEXPECTED;
     407        }
     408    }
     409
     410    // notify termination of the IPC connection
     411    if (rv == NS_ERROR_ABORT)
     412        rv = NS_OK;
     413    IPC_OnConnectionEnd(rv);
     414
     415    LogFlowFunc(("IPC thread exiting\n"));
     416    return VINF_SUCCESS;
    435417}
    436418
     
    446428#endif
    447429
    448 static nsresult
    449 TryConnect(PRFileDesc **result)
    450 {
    451   PRFileDesc *fd;
    452   PRNetAddr addr;
    453   PRSocketOptionData opt;
    454   // don't use NS_ERROR_FAILURE as we want to detect these kind of errors
    455   // in the frontend
    456   nsresult rv = NS_ERROR_SOCKET_FAIL;
    457 
    458   fd = PR_OpenTCPSocket(PR_AF_LOCAL);
    459   if (!fd)
    460     goto end;
    461 
    462   addr.local.family = PR_AF_LOCAL;
    463   IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path));
    464 
    465   // blocking connect... will fail if no one is listening.
    466   if (PR_Connect(fd, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE)
    467     goto end;
    468 
    469 #ifdef VBOX
    470   if (RTEnvExist("TESTBOX_UUID"))
    471     fprintf(stderr, "IPC socket path: %s\n", addr.local.path);
    472   LogRel(("IPC socket path: %s\n", addr.local.path));
     430static nsresult TryConnect(RTSOCKET *phSocket)
     431{
     432    struct sockaddr_un addr;
     433    memset(&addr, 0, sizeof(addr));
     434    addr.sun_family = AF_UNIX;
     435    IPC_GetDefaultSocketPath(addr.sun_path, sizeof(addr.sun_path) - 1);
     436
     437    // don't use NS_ERROR_FAILURE as we want to detect these kind of errors
     438    // in the frontend
     439    nsresult rv = NS_ERROR_SOCKET_FAIL;
     440
     441    int fdSock = socket(PF_UNIX, SOCK_STREAM, 0);
     442    if (fdSock != -1)
     443    {
     444        /* Connect to the local socket. */
     445        if (connect(fdSock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
     446        {
     447            if (RTEnvExist("TESTBOX_UUID"))
     448                fprintf(stderr, "IPC socket path: %s\n", addr.sun_path);
     449            LogRel(("IPC socket path: %s\n", addr.sun_path));
     450
     451            // do some security checks on connection socket...
     452            if (DoSecurityCheck(fdSock, addr.sun_path) == PR_SUCCESS)
     453            {
     454                int vrc = RTSocketFromNative(phSocket, fdSock);
     455                if (RT_SUCCESS(vrc))
     456                    return NS_OK;
     457            }
     458        }
     459
     460        close(fdSock);
     461    }
     462
     463    return rv;
     464}
     465
     466nsresult IPC_Connect(const char *daemonPath)
     467{
     468  // synchronous connect, spawn daemon if necessary.
     469    nsresult rv = NS_ERROR_FAILURE;
     470
     471    if (gConnState)
     472        return NS_ERROR_ALREADY_INITIALIZED;
     473
     474    //
     475    // here's the connection algorithm:  try to connect to an existing daemon.
     476    // if the connection fails, then spawn the daemon (wait for it to be ready),
     477    // and then retry the connection.  it is critical that the socket used to
     478    // connect to the daemon not be inherited (this causes problems on RH9 at
     479    // least).
     480    //
     481
     482    RTSOCKET hSockConn = NIL_RTSOCKET;
     483    rv = TryConnect(&hSockConn);
     484    if (NS_FAILED(rv))
     485    {
     486        nsresult rv1 = IPC_SpawnDaemon(daemonPath);
     487        if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL)
     488          rv = rv1;
     489        if (NS_SUCCEEDED(rv))
     490          rv = TryConnect(&hSockConn);
     491    }
     492
     493    if (NS_SUCCEEDED(rv))
     494    {
     495        //
     496        // ok, we have a connection to the daemon!
     497        //
     498
     499      // build connection state object
     500        gConnState = ConnCreate(hSockConn);
     501        if (RT_LIKELY(gConnState))
     502        {
     503            hSockConn = NIL_RTSOCKET; // connection state now owns the socket
     504
     505            int vrc = RTThreadCreate(&gConnThread, ipcConnThread, gConnState, 0 /*cbStack*/,
     506                                     RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Ipc-Conn");
     507            if (RT_SUCCESS(vrc))
     508            {
     509#ifdef DEBUG
     510                gMainThread = RTThreadSelf();
    473511#endif
    474 
    475   // make socket non-blocking
    476   opt.option = PR_SockOpt_Nonblocking;
    477   opt.value.non_blocking = PR_TRUE;
    478   PR_SetSocketOption(fd, &opt);
    479 
    480   // do some security checks on connection socket...
    481   if (DoSecurityCheck(fd, addr.local.path) != PR_SUCCESS)
    482     goto end;
    483  
    484   *result = fd;
    485   return NS_OK;
    486 
    487 end:
    488   if (fd)
    489     PR_Close(fd);
    490 
    491   return rv;
    492 }
    493 
    494 nsresult
    495 IPC_Connect(const char *daemonPath)
    496 {
    497   // synchronous connect, spawn daemon if necessary.
    498 
    499   PRFileDesc *fd = NULL;
    500   nsresult rv = NS_ERROR_FAILURE;
    501   int vrc = VINF_SUCCESS;
    502 
    503   if (gConnState)
    504     return NS_ERROR_ALREADY_INITIALIZED;
    505 
    506   //
    507   // here's the connection algorithm:  try to connect to an existing daemon.
    508   // if the connection fails, then spawn the daemon (wait for it to be ready),
    509   // and then retry the connection.  it is critical that the socket used to
    510   // connect to the daemon not be inherited (this causes problems on RH9 at
    511   // least).
    512   //
    513 
    514   rv = TryConnect(&fd);
    515   if (NS_FAILED(rv))
    516   {
    517     nsresult rv1 = IPC_SpawnDaemon(daemonPath);
    518     if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL)
    519       rv = rv1;
    520     if (NS_SUCCEEDED(rv))
    521       rv = TryConnect(&fd);
    522   }
    523 
    524   if (NS_FAILED(rv))
    525     goto end;
    526 
    527   //
    528   // ok, we have a connection to the daemon!
    529   //
    530 
    531   // build connection state object
    532   gConnState = ConnCreate(fd);
    533   if (!gConnState)
    534   {
    535     rv = NS_ERROR_OUT_OF_MEMORY;
    536     goto end;
    537   }
    538   fd = NULL; // connection state now owns the socket
    539 
    540   vrc = RTThreadCreate(&gConnThread, ipcConnThread, gConnState, 0 /*cbStack*/,
    541                        RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Ipc-Conn");
    542   if (RT_FAILURE(vrc))
    543   {
    544     rv = NS_ERROR_OUT_OF_MEMORY;
    545     goto end;
    546   }
    547 
    548 #ifdef DEBUG
    549   gMainThread = RTThreadSelf();
    550 #endif
    551   return NS_OK;
    552 
    553 end:
    554   if (gConnState)
    555   {
    556     ConnDestroy(gConnState);
    557     gConnState = NULL;
    558   }
    559   if (fd)
    560     PR_Close(fd);
    561   return rv;
    562 }
    563 
    564 nsresult
    565 IPC_Disconnect()
     512                return NS_OK;
     513            }
     514            else
     515                rv = NS_ERROR_OUT_OF_MEMORY;
     516        }
     517        else
     518          rv = NS_ERROR_OUT_OF_MEMORY;
     519    }
     520
     521    if (gConnState)
     522    {
     523        ConnDestroy(gConnState);
     524        gConnState = NULL;
     525    }
     526
     527    if (hSockConn != NIL_RTSOCKET)
     528        RTSocketClose(hSockConn);
     529
     530    return rv;
     531}
     532
     533nsresult IPC_Disconnect()
    566534{
    567535    // Must disconnect on same thread used to connect!
     
    574542
    575543    RTCritSectEnter(&gConnState->CritSect);
    576     gConnState->shutdown = PR_TRUE;
     544    gConnState->fShutdown = true;
    577545    size_t cbWrittenIgn = 0;
    578546    int vrc = RTPipeWrite(gConnState->hWakeupPipeW, &magicChar, sizeof(magicChar), &cbWrittenIgn);
     
    591559}
    592560
    593 nsresult
    594 IPC_SendMsg(ipcMessage *msg)
     561nsresult IPC_SendMsg(ipcMessage *msg)
    595562{
    596563    if (!gConnState || !gConnThread)
     
    607574}
    608575
    609 nsresult
    610 IPC_DoCallback(ipcCallbackFunc func, void *arg)
     576nsresult IPC_DoCallback(ipcCallbackFunc func, void *arg)
    611577{
    612578    if (!gConnState || !gConnThread)
Note: See TracChangeset for help on using the changeset viewer.

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