/** * Initializes the object (called right after construction). * * @returns S_OK on success and non-fatal failures, some COM error otherwise. */ int USBProxyBackendUsbIp::init(void) { int rc = VINF_SUCCESS; m = new Data; /** @todo: Pass in some config like host and port to connect to. */ /* Setup wakeup pipe and poll set first. */ rc = RTSemFastMutexCreate(&m->hMtxDevices); if (RT_SUCCESS(rc)) { rc = RTPipeCreate(&m->hWakeupPipeR, &m->hWakeupPipeW, 0); if (RT_SUCCESS(rc)) { rc = RTPollSetCreate(&m->hPollSet); if (RT_SUCCESS(rc)) { rc = RTPollSetAddPipe(m->hPollSet, m->hWakeupPipeR, RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE); if (RT_SUCCESS(rc)) { /* Connect to the USB/IP host. */ rc = reconnect(); if (RT_SUCCESS(rc)) rc = start(); /* Start service thread. */ } if (RT_FAILURE(rc)) { RTPollSetRemove(m->hPollSet, USBIP_POLL_ID_PIPE); int rc2 = RTPollSetDestroy(m->hPollSet); AssertRC(rc2); } } if (RT_FAILURE(rc)) { int rc2 = RTPipeClose(m->hWakeupPipeR); AssertRC(rc2); rc2 = RTPipeClose(m->hWakeupPipeW); AssertRC(rc2); } } if (RT_FAILURE(rc)) RTSemFastMutexDestroy(m->hMtxDevices); } return rc; }
static void tstRTPoll2(void) { RTTestISub("Negative"); /* * Bad set pointer and handle values. */ RTTESTI_CHECK_RC(RTPollSetCreate(NULL), VERR_INVALID_POINTER); RTPOLLSET hSetInvl = (RTPOLLSET)(intptr_t)-3; RTTESTI_CHECK_RC(RTPollSetDestroy(hSetInvl), VERR_INVALID_HANDLE); RTHANDLE Handle; Handle.enmType = RTHANDLETYPE_PIPE; Handle.u.hPipe = NIL_RTPIPE; RTTESTI_CHECK_RC(RTPollSetAdd(hSetInvl, &Handle, RTPOLL_EVT_ERROR, 1), VERR_INVALID_HANDLE); RTTESTI_CHECK_RC(RTPollSetRemove(hSetInvl, 1), VERR_INVALID_HANDLE); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSetInvl, 1, NULL), VERR_INVALID_HANDLE); RTTESTI_CHECK(RTPollSetGetCount(hSetInvl) == UINT32_MAX); RTTESTI_CHECK_RC(RTPoll(hSetInvl, 0, NULL, NULL), VERR_INVALID_HANDLE); RTTESTI_CHECK_RC(RTPollNoResume(hSetInvl, 0, NULL, NULL), VERR_INVALID_HANDLE); /* * Invalid arguments and other stuff. */ RTPOLLSET hSet = NIL_RTPOLLSET; RTTESTI_CHECK_RC_RETV(RTPollSetCreate(&hSet), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPoll(hSet, RT_INDEFINITE_WAIT, NULL, NULL), VERR_DEADLOCK); RTTESTI_CHECK_RC(RTPollNoResume(hSet, RT_INDEFINITE_WAIT, NULL, NULL), VERR_DEADLOCK); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, UINT32_MAX), VERR_INVALID_PARAMETER); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 1, NULL), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 1), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RC(RTPollSetAdd(hSet, NULL, RTPOLL_EVT_ERROR, 1), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPollSetAdd(hSet, &Handle, RTPOLL_EVT_ERROR, UINT32_MAX), VERR_INVALID_PARAMETER); RTTESTI_CHECK_RC(RTPollSetAdd(hSet, &Handle, UINT32_MAX, 3), VERR_INVALID_PARAMETER); Handle.enmType = RTHANDLETYPE_INVALID; RTTESTI_CHECK_RC(RTPollSetAdd(hSet, &Handle, RTPOLL_EVT_ERROR, 3), VERR_INVALID_PARAMETER); RTTESTI_CHECK_RC(RTPollSetAdd(hSet, NULL, RTPOLL_EVT_ERROR, UINT32_MAX), VERR_INVALID_PARAMETER); /* duplicate id */ RTPIPE hPipeR; RTPIPE hPipeW; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0/*fFlags*/), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_ERROR, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_ERROR, 0), VERR_POLL_HANDLE_ID_EXISTS); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 0), VINF_SUCCESS); RTPipeClose(hPipeR); RTPipeClose(hPipeW); /* non-pollable handle */ RTFILE hBitBucket; RTTESTI_CHECK_RC_RETV(RTFileOpenBitBucket(&hBitBucket, RTFILE_O_WRITE), VINF_SUCCESS); Handle.enmType = RTHANDLETYPE_FILE; Handle.u.hFile = hBitBucket; RTTESTI_CHECK_RC(RTPollSetAdd(hSet, &Handle, RTPOLL_EVT_WRITE, 10), VERR_POLL_HANDLE_NOT_POLLABLE); RTFileClose(hBitBucket); RTTESTI_CHECK_RC_RETV(RTPollSetDestroy(hSet), VINF_SUCCESS); }
static void tstRTPoll1(void) { RTTestISub("Basics"); /* create and destroy. */ RTPOLLSET hSet = NIL_RTPOLLSET; RTTESTI_CHECK_RC_RETV(RTPollSetCreate(&hSet), VINF_SUCCESS); RTTESTI_CHECK_RETV(hSet != NIL_RTPOLLSET); RTTESTI_CHECK_RC(RTPollSetDestroy(hSet), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPollSetDestroy(NIL_RTPOLLSET), VINF_SUCCESS); /* empty set, adding a NIL handle. */ hSet = NIL_RTPOLLSET; RTTESTI_CHECK_RC_RETV(RTPollSetCreate(&hSet), VINF_SUCCESS); RTTESTI_CHECK_RETV(hSet != NIL_RTPOLLSET); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 0); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 0, NULL), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RC(RTPollSetAddPipe(hSet, NIL_RTPIPE, RTPOLL_EVT_READ, 1 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 0); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 1 /*id*/, NULL), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 0), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 0); RTTESTI_CHECK_RC(RTPollSetDestroy(hSet), VINF_SUCCESS); /* * Set with pipes */ RTPIPE hPipeR; RTPIPE hPipeW; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0/*fFlags*/), VINF_SUCCESS); hSet = NIL_RTPOLLSET; RTTESTI_CHECK_RC_RETV(RTPollSetCreate(&hSet), VINF_SUCCESS); RTTESTI_CHECK_RETV(hSet != NIL_RTPOLLSET); /* add the read pipe */ RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_READ, 1 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 1); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 1 /*id*/, NULL), VINF_SUCCESS); RTHANDLE Handle; RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 1 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeR); /* poll on the set, should time out. */ RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL, NULL), VERR_TIMEOUT); RTTESTI_CHECK_RC(RTPoll(hSet, 1, NULL, NULL), VERR_TIMEOUT); /* add the write pipe with error detection only, check that poll still times out. remove it again. */ RTTESTI_CHECK_RC(RTPollSetAddPipe(hSet, hPipeW, RTPOLL_EVT_ERROR, 11 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 2); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 11 /*id*/, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL, NULL), VERR_TIMEOUT); RTTESTI_CHECK_RC(RTPoll(hSet, 1, NULL, NULL), VERR_TIMEOUT); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 11), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 1); /* add the write pipe */ RTTESTI_CHECK_RC(RTPollSetAddPipe(hSet, hPipeW, RTPOLL_EVT_WRITE, 10 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 2); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 10 /*id*/, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 10 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeW); RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 1 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeR); /* poll on the set again, now it should indicate hPipeW is ready. */ int rc; RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(rc = RTPoll(hSet, 100, NULL, NULL), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTESTI_CHECK_RC(RTPoll(hSet, RT_INDEFINITE_WAIT, NULL, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(rc = RTPollNoResume(hSet, 0, NULL, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(rc = RTPollNoResume(hSet, 100, NULL, NULL), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTESTI_CHECK_RC(rc = RTPollNoResume(hSet, RT_INDEFINITE_WAIT, NULL, NULL), VINF_SUCCESS); uint32_t fEvents = UINT32_MAX; uint32_t id = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 0, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(rc = RTPoll(hSet, 250, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); if (RT_SUCCESS(rc)) { fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, RT_INDEFINITE_WAIT, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); } fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPollNoResume(hSet, 0, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(rc = RTPollNoResume(hSet, 100, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); if (RT_SUCCESS(rc)) { fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPollNoResume(hSet, RT_INDEFINITE_WAIT, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); } /* Write to the pipe. Currently ASSUMING we'll get the read ready now... Good idea? */ RTTESTI_CHECK_RC(rc = RTPipeWriteBlocking(hPipeW, "hello", 5, NULL), VINF_SUCCESS); if (RT_SUCCESS(rc)) { fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 0, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(rc = RTPoll(hSet, 256, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); if (RT_SUCCESS(rc)) { fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, RT_INDEFINITE_WAIT, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); } fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPollNoResume(hSet, 0, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(rc = RTPollNoResume(hSet, 383, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); if (RT_SUCCESS(rc)) { fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPollNoResume(hSet, RT_INDEFINITE_WAIT, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); } } /* Remove the read pipe, do a quick poll check. */ RTTESTI_CHECK_RC_RETV(RTPollSetRemove(hSet, 1), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 1); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 1 /*id*/, NULL), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 10 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeW); RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL, NULL), VINF_SUCCESS); /* Add it back and check that we now get the write handle when polling. (Is this FIFOing a good idea?) */ RTTESTI_CHECK_RC_RETV(RTPoll(hSet, 0, NULL, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_READ, 1 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 2); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 1 /*id*/, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 1 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeR); RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 10 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeW); fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(rc = RTPollNoResume(hSet, 555, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); /* Remove it again and break the pipe by closing the read end. */ RTTESTI_CHECK_RC_RETV(RTPollSetRemove(hSet, 1), VINF_SUCCESS); RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 1); RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 1 /*id*/, NULL), VERR_POLL_HANDLE_ID_NOT_FOUND); RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 10 /*id*/, &Handle), VINF_SUCCESS); RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE); RTTESTI_CHECK(Handle.u.hPipe == hPipeW); RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); fEvents = UINT32_MAX; id = UINT32_MAX; RTTESTI_CHECK_RC(RTPollNoResume(hSet, 0, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 10); RTTESTI_CHECK_MSG( fEvents == RTPOLL_EVT_ERROR \ || fEvents == (RTPOLL_EVT_ERROR | RTPOLL_EVT_WRITE), ("%#x\n", fEvents)); RTTESTI_CHECK_RC(RTPollSetDestroy(hSet), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); /* * Check FIFO order when removing and adding. * * Note! FIFO order is not guaranteed when a handle has more than one entry * in the set. */ RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0/*fFlags*/), VINF_SUCCESS); RTPIPE hPipeR2, hPipeW2; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR2, &hPipeW2, 0/*fFlags*/), VINF_SUCCESS); RTPIPE hPipeR3, hPipeW3; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR3, &hPipeW3, 0/*fFlags*/), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetCreate(&hSet), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_READ, 1 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeW, RTPOLL_EVT_WRITE, 2 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR2, RTPOLL_EVT_READ, 3 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeW2, RTPOLL_EVT_WRITE, 4 /*id*/), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR3, RTPOLL_EVT_READ, 5 /*id*/), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 2); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); RTTESTI_CHECK_RC(RTPipeWriteBlocking(hPipeW, "hello", 5, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeWriteBlocking(hPipeW2, "hello", 5, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeWriteBlocking(hPipeW3, "hello", 5, NULL), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 1); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 1), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 2); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 2), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 3); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 3), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 4); RTTESTI_CHECK(fEvents == RTPOLL_EVT_WRITE); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 4), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VINF_SUCCESS); RTTESTI_CHECK(id == 5); RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ); RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 5), VINF_SUCCESS); id = UINT32_MAX; fEvents = UINT32_MAX; RTTESTI_CHECK_RC(RTPoll(hSet, 5, &fEvents, &id), VERR_TIMEOUT); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeW2), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeR2), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeW3), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeR3), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPollSetDestroy(hSet), VINF_SUCCESS); }
/** * Runs a process, collecting the standard output and/or standard error. * * * @returns IPRT status code * @retval VERR_NO_TRANSLATION if the output of the program isn't valid UTF-8 * or contains a nul character. * @retval VERR_TOO_MUCH_DATA if the process produced too much data. * * @param pszExec Executable image to use to create the child process. * @param papszArgs Pointer to an array of arguments to the child. The * array terminated by an entry containing NULL. * @param hEnv Handle to the environment block for the child. * @param fFlags A combination of RTPROCEXEC_FLAGS_XXX. The @a * ppszStdOut and @a ppszStdErr parameters takes precedence * over redirection flags. * @param pStatus Where to return the status on success. * @param ppszStdOut Where to return the text written to standard output. If * NULL then standard output will not be collected and go * to the standard output handle of the process. * Free with RTStrFree, regardless of return status. * @param ppszStdErr Where to return the text written to standard error. If * NULL then standard output will not be collected and go * to the standard error handle of the process. * Free with RTStrFree, regardless of return status. */ int RTProcExecToString(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, PRTPROCSTATUS pStatus, char **ppszStdOut, char **ppszStdErr) { int rc2; /* * Clear output arguments (no returning failure here, simply crash!). */ AssertPtr(pStatus); pStatus->enmReason = RTPROCEXITREASON_ABEND; pStatus->iStatus = RTEXITCODE_FAILURE; AssertPtrNull(ppszStdOut); if (ppszStdOut) *ppszStdOut = NULL; AssertPtrNull(ppszStdOut); if (ppszStdErr) *ppszStdErr = NULL; /* * Check input arguments. */ AssertReturn(!(fFlags & ~RTPROCEXEC_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); /* * Do we need a standard input bitbucket? */ int rc = VINF_SUCCESS; PRTHANDLE phChildStdIn = NULL; RTHANDLE hChildStdIn; hChildStdIn.enmType = RTHANDLETYPE_FILE; hChildStdIn.u.hFile = NIL_RTFILE; if ((fFlags & RTPROCEXEC_FLAGS_STDIN_NULL) && RT_SUCCESS(rc)) { phChildStdIn = &hChildStdIn; rc = RTFileOpenBitBucket(&hChildStdIn.u.hFile, RTFILE_O_READ); } /* * Create the output pipes / bitbuckets. */ RTPIPE hPipeStdOutR = NIL_RTPIPE; PRTHANDLE phChildStdOut = NULL; RTHANDLE hChildStdOut; hChildStdOut.enmType = RTHANDLETYPE_PIPE; hChildStdOut.u.hPipe = NIL_RTPIPE; if (ppszStdOut && RT_SUCCESS(rc)) { phChildStdOut = &hChildStdOut; rc = RTPipeCreate(&hPipeStdOutR, &hChildStdOut.u.hPipe, 0 /*fFlags*/); } else if ((fFlags & RTPROCEXEC_FLAGS_STDOUT_NULL) && RT_SUCCESS(rc)) { phChildStdOut = &hChildStdOut; hChildStdOut.enmType = RTHANDLETYPE_FILE; hChildStdOut.u.hFile = NIL_RTFILE; rc = RTFileOpenBitBucket(&hChildStdOut.u.hFile, RTFILE_O_WRITE); } RTPIPE hPipeStdErrR = NIL_RTPIPE; PRTHANDLE phChildStdErr = NULL; RTHANDLE hChildStdErr; hChildStdErr.enmType = RTHANDLETYPE_PIPE; hChildStdErr.u.hPipe = NIL_RTPIPE; if (ppszStdErr && RT_SUCCESS(rc)) { phChildStdErr = &hChildStdErr; rc = RTPipeCreate(&hPipeStdErrR, &hChildStdErr.u.hPipe, 0 /*fFlags*/); } else if ((fFlags & RTPROCEXEC_FLAGS_STDERR_NULL) && RT_SUCCESS(rc)) { phChildStdErr = &hChildStdErr; hChildStdErr.enmType = RTHANDLETYPE_FILE; hChildStdErr.u.hFile = NIL_RTFILE; rc = RTFileOpenBitBucket(&hChildStdErr.u.hFile, RTFILE_O_WRITE); } if (RT_SUCCESS(rc)) { RTPOLLSET hPollSet; rc = RTPollSetCreate(&hPollSet); if (RT_SUCCESS(rc)) { if (hPipeStdOutR != NIL_RTPIPE && RT_SUCCESS(rc)) rc = RTPollSetAddPipe(hPollSet, hPipeStdOutR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 1); if (hPipeStdErrR != NIL_RTPIPE) rc = RTPollSetAddPipe(hPollSet, hPipeStdErrR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 2); } if (RT_SUCCESS(rc)) { /* * Create the process. */ RTPROCESS hProc; rc = RTProcCreateEx(g_szSvnPath, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL /*phStdIn*/, phChildStdOut, phChildStdErr, NULL /*pszAsUser*/, NULL /*pszPassword*/, &hProc); rc2 = RTHandleClose(&hChildStdErr); AssertRC(rc2); rc2 = RTHandleClose(&hChildStdOut); AssertRC(rc2); if (RT_SUCCESS(rc)) { /* * Process output and wait for the process to finish. */ size_t cbStdOut = 0; size_t offStdOut = 0; size_t cbStdErr = 0; size_t offStdErr = 0; for (;;) { if (hPipeStdOutR != NIL_RTPIPE) rc = rtProcProcessOutput(rc, &hPipeStdOutR, &cbStdOut, &offStdOut, ppszStdOut, hPollSet, 1); if (hPipeStdErrR != NIL_RTPIPE) rc = rtProcProcessOutput(rc, &hPipeStdErrR, &cbStdErr, &offStdErr, ppszStdErr, hPollSet, 2); if (hPipeStdOutR == NIL_RTPIPE && hPipeStdErrR == NIL_RTPIPE) break; if (hProc != NIL_RTPROCESS) { rc2 = RTProcWait(hProc, RTPROCWAIT_FLAGS_NOBLOCK, pStatus); if (rc2 != VERR_PROCESS_RUNNING) { if (RT_FAILURE(rc2)) rc = rc2; hProc = NIL_RTPROCESS; } } rc2 = RTPoll(hPollSet, 10000, NULL, NULL); Assert(RT_SUCCESS(rc2) || rc2 == VERR_TIMEOUT); } if (RT_SUCCESS(rc)) { if ( (ppszStdOut && *ppszStdOut && !RTStrIsValidEncoding(*ppszStdOut)) || (ppszStdErr && *ppszStdErr && !RTStrIsValidEncoding(*ppszStdErr)) ) rc = VERR_NO_TRANSLATION; } /* * No more output, just wait for it to finish. */ if (hProc != NIL_RTPROCESS) { rc2 = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, pStatus); if (RT_FAILURE(rc2)) rc = rc2; } } RTPollSetDestroy(hPollSet); } } rc2 = RTHandleClose(&hChildStdErr); AssertRC(rc2); rc2 = RTHandleClose(&hChildStdOut); AssertRC(rc2); rc2 = RTHandleClose(&hChildStdIn); AssertRC(rc2); rc2 = RTPipeClose(hPipeStdErrR); AssertRC(rc2); rc2 = RTPipeClose(hPipeStdOutR); AssertRC(rc2); return rc; }
/** * Construct a TCP socket stream driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvTCPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { RT_NOREF(fFlags); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP); /* * Init the static parts. */ pThis->pDrvIns = pDrvIns; pThis->pszLocation = NULL; pThis->fIsServer = false; pThis->hTcpServ = NULL; pThis->hTcpSock = NIL_RTSOCKET; pThis->hPollSet = NIL_RTPOLLSET; pThis->hPipeWakeR = NIL_RTPIPE; pThis->hPipeWakeW = NIL_RTPIPE; pThis->fTcpSockInPollSet = false; pThis->ListenThread = NIL_RTTHREAD; pThis->fShutdown = false; /* IBase */ pDrvIns->IBase.pfnQueryInterface = drvTCPQueryInterface; /* IStream */ pThis->IStream.pfnPoll = drvTcpPoll; pThis->IStream.pfnPollInterrupt = drvTcpPollInterrupt; pThis->IStream.pfnRead = drvTcpRead; pThis->IStream.pfnWrite = drvTcpWrite; /* * Validate and read the configuration. */ PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", ""); int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc); rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc); rc = RTPipeCreate(&pThis->hPipeWakeR, &pThis->hPipeWakeW, 0 /* fFlags */); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: Failed to create wake pipe"), pDrvIns->iInstance); rc = RTPollSetCreate(&pThis->hPollSet); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: Failed to create poll set"), pDrvIns->iInstance); rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeWakeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, DRVTCP_POLLSET_ID_WAKEUP); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to add wakeup pipe for %s to poll set"), pDrvIns->iInstance, pThis->pszLocation); /* * Create/Open the socket. */ if (pThis->fIsServer) { uint32_t uPort = 0; rc = RTStrToUInt32Ex(pThis->pszLocation, NULL, 10, &uPort); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: The port part of the location is not a numerical value"), pDrvIns->iInstance); /** @todo Allow binding to distinct interfaces. */ rc = RTTcpServerCreateEx(NULL, uPort, &pThis->hTcpServ); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to create server socket"), pDrvIns->iInstance); rc = RTThreadCreate(&pThis->ListenThread, drvTCPListenLoop, (void *)pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "DrvTCPStream"); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to create listening thread"), pDrvIns->iInstance); } else { char *pszPort = strchr(pThis->pszLocation, ':'); if (!pszPort) return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_FOUND, RT_SRC_POS, N_("DrvTCP#%d: The location misses the port to connect to"), pDrvIns->iInstance); *pszPort = '\0'; /* Overwrite temporarily to avoid copying the hostname into a temporary buffer. */ uint32_t uPort = 0; rc = RTStrToUInt32Ex(pszPort + 1, NULL, 10, &uPort); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: The port part of the location is not a numerical value"), pDrvIns->iInstance); rc = RTTcpClientConnect(pThis->pszLocation, uPort, &pThis->hTcpSock); *pszPort = ':'; /* Restore delimiter before checking the status. */ if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to connect to socket %s"), pDrvIns->iInstance, pThis->pszLocation); rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR, DRVTCP_POLLSET_ID_SOCKET); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to add socket for %s to poll set"), pDrvIns->iInstance, pThis->pszLocation); pThis->fTcpSockInPollSet = true; } LogRel(("DrvTCP: %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client")); return VINF_SUCCESS; }