/** * Tries to reconnect to the USB/IP host. * * @returns VBox status code. */ int USBProxyBackendUsbIp::reconnect() { /* Make sure we are disconnected. */ disconnect(); /* Connect to the USB/IP host. */ int rc = RTTcpClientConnect(m->pszHost, m->uPort, &m->hSocket); if (RT_SUCCESS(rc)) { rc = RTTcpSetSendCoalescing(m->hSocket, false); if (RT_FAILURE(rc)) LogRel(("USB/IP: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect increased latency\n", rc)); rc = RTPollSetAddSocket(m->hPollSet, m->hSocket, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, USBIP_POLL_ID_SOCKET); if (RT_FAILURE(rc)) { RTTcpClientCloseEx(m->hSocket, false /*fGracefulShutdown*/); m->hSocket = NIL_RTSOCKET; } } return rc; }
/** * Connects to the peer. * * @returns VBox status code. Updates g_hTcpClient and g_fTcpClientFromServer on * success */ static int txsTcpConnect(void) { int rc; if (g_enmTcpMode == TXSTCPMODE_SERVER) { g_fTcpClientFromServer = true; rc = RTTcpServerListen2(g_pTcpServer, &g_hTcpClient); Log(("txsTcpRecvPkt: RTTcpServerListen2 -> %Rrc\n", rc)); } else if (g_enmTcpMode == TXSTCPMODE_CLIENT) { g_fTcpClientFromServer = false; for (;;) { Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort)); rc = RTTcpClientConnect(g_szTcpConnectAddr, g_uTcpConnectPort, &g_hTcpClient); Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc)); if (RT_SUCCESS(rc) || txsTcpIsFatalClientConnectStatus(rc)) break; /* Delay a wee bit before retrying. */ RTThreadSleep(1536); } } else { Assert(g_enmTcpMode == TXSTCPMODE_BOTH); RTTHREAD hSelf = RTThreadSelf(); /* * Create client threads. */ RTCritSectEnter(&g_TcpCritSect); RTThreadUserReset(hSelf); g_hThreadMain = hSelf; g_fTcpStopConnecting = false; RTCritSectLeave(&g_TcpCritSect); txsTcpConnectWaitOnThreads(32); rc = VINF_SUCCESS; if (g_hThreadTcpConnect == NIL_RTTHREAD) { g_pTcpConnectCancelCookie = NULL; rc = RTThreadCreate(&g_hThreadTcpConnect, txsTcpClientConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tcpconn"); } if (g_hThreadTcpServer == NIL_RTTHREAD && RT_SUCCESS(rc)) rc = RTThreadCreate(&g_hThreadTcpServer, txsTcpServerConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tcpserv"); RTCritSectEnter(&g_TcpCritSect); /* * Wait for connection to be established. */ while ( RT_SUCCESS(rc) && g_hTcpClient == NIL_RTSOCKET) { RTCritSectLeave(&g_TcpCritSect); RTThreadUserWait(hSelf, 1536); rc = txsTcpConnectWaitOnThreads(0); RTCritSectEnter(&g_TcpCritSect); } /* * Cancel the threads. */ g_hThreadMain = NIL_RTTHREAD; g_fTcpStopConnecting = true; RTCritSectLeave(&g_TcpCritSect); RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie); } AssertMsg(RT_SUCCESS(rc) ? g_hTcpClient != NIL_RTSOCKET : g_hTcpClient == NIL_RTSOCKET, ("%Rrc %p\n", rc, g_hTcpClient)); g_cbTcpStashed = 0; return rc; }
/** * Do the teleporter. * * @returns VBox status code. * @param pState The teleporter state. */ HRESULT Console::teleporterSrc(TeleporterStateSrc *pState) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* * Wait for Console::Teleport to change the state. */ { AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); } BOOL fCanceled = TRUE; HRESULT hrc = pState->mptrProgress->COMGETTER(Canceled)(&fCanceled); if (FAILED(hrc)) return hrc; if (fCanceled) return setError(E_FAIL, tr("canceled")); /* * Try connect to the destination machine, disable Nagle. * (Note. The caller cleans up mhSocket, so we can return without worries.) */ int vrc = RTTcpClientConnect(pState->mstrHostname.c_str(), pState->muPort, &pState->mhSocket); if (RT_FAILURE(vrc)) return setError(E_FAIL, tr("Failed to connect to port %u on '%s': %Rrc"), pState->muPort, pState->mstrHostname.c_str(), vrc); vrc = RTTcpSetSendCoalescing(pState->mhSocket, false /*fEnable*/); AssertRC(vrc); /* Read and check the welcome message. */ char szLine[RT_MAX(128, sizeof(g_szWelcome))]; RT_ZERO(szLine); vrc = RTTcpRead(pState->mhSocket, szLine, sizeof(g_szWelcome) - 1, NULL); if (RT_FAILURE(vrc)) return setError(E_FAIL, tr("Failed to read welcome message: %Rrc"), vrc); if (strcmp(szLine, g_szWelcome)) return setError(E_FAIL, tr("Unexpected welcome %.*Rhxs"), sizeof(g_szWelcome) - 1, szLine); /* password */ pState->mstrPassword.append('\n'); vrc = RTTcpWrite(pState->mhSocket, pState->mstrPassword.c_str(), pState->mstrPassword.length()); if (RT_FAILURE(vrc)) return setError(E_FAIL, tr("Failed to send password: %Rrc"), vrc); /* ACK */ hrc = teleporterSrcReadACK(pState, "password", tr("Invalid password")); if (FAILED(hrc)) return hrc; /* * Start loading the state. * * Note! The saved state includes vital configuration data which will be * verified against the VM config on the other end. This is all done * in the first pass, so we should fail pretty promptly on misconfig. */ hrc = teleporterSrcSubmitCommand(pState, "load"); if (FAILED(hrc)) return hrc; RTSocketRetain(pState->mhSocket); void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(pState)); vrc = VMR3Teleport(VMR3GetVM(pState->mpUVM), pState->mcMsMaxDowntime, &g_teleporterTcpOps, pvUser, teleporterProgressCallback, pvUser, &pState->mfSuspendedByUs); RTSocketRelease(pState->mhSocket); if (RT_FAILURE(vrc)) { if ( vrc == VERR_SSM_CANCELLED && RT_SUCCESS(RTTcpSelectOne(pState->mhSocket, 1))) { hrc = teleporterSrcReadACK(pState, "load-complete"); if (FAILED(hrc)) return hrc; } return setError(E_FAIL, tr("VMR3Teleport -> %Rrc"), vrc); } hrc = teleporterSrcReadACK(pState, "load-complete"); if (FAILED(hrc)) return hrc; /* * We're at the point of no return. */ if (!pState->mptrProgress->notifyPointOfNoReturn()) { teleporterSrcSubmitCommand(pState, "cancel", false /*fWaitForAck*/); return E_FAIL; } /* * Hand over any media which we might be sharing. * * Note! This is only important on localhost teleportations. */ /** @todo Maybe we should only do this if it's a local teleportation... */ hrc = mControl->UnlockMedia(); if (FAILED(hrc)) return hrc; pState->mfUnlockedMedia = true; hrc = teleporterSrcSubmitCommand(pState, "lock-media"); if (FAILED(hrc)) return hrc; /* * The FINAL step is giving the target instructions how to proceed with the VM. */ if ( vrc == VINF_SSM_LIVE_SUSPENDED || pState->menmOldMachineState == MachineState_Paused) hrc = teleporterSrcSubmitCommand(pState, "hand-over-paused"); else hrc = teleporterSrcSubmitCommand(pState, "hand-over-resume"); if (FAILED(hrc)) return hrc; /* * teleporterSrcThreadWrapper will do the automatic power off because it * has to release the AutoVMCaller. */ return S_OK; }
/** * 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; }