VirtualBox

Changeset 23663 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Oct 9, 2009 6:14:30 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
53376
Message:

Main: More live migration work.

Location:
trunk/src/VBox/Main
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/ConsoleImpl-LiveMigration.cpp

    r23633 r23663  
    2424*******************************************************************************/
    2525#include "ConsoleImpl.h"
     26#include "Global.h"
    2627#include "Logging.h"
     28#include "ProgressImpl.h"
    2729
    2830#include <iprt/err.h>
     
    4345*******************************************************************************/
    4446/**
    45  * Argument package for Console::migrationServeConnection.
    46  */
    47 typedef struct MIGRATIONSTATE
    48 {
    49     Console    *pConsole;
    50     IMachine   *pMachine;
    51     PVM         pVM;
    52     const char *pszPassword;
    53     void       *pvVMCallbackTask;
    54     RTSOCKET    hSocket;
    55     uint64_t    offStream;
    56     int         rc;
    57 } MIGRATIONSTATE;
    58 typedef MIGRATIONSTATE *PMIGRATIONSTATE;
     47 * Base class for the migration state.
     48 *
     49 * These classes are used as advanced structs, not as proper classes.
     50 */
     51class MigrationState
     52{
     53public:
     54    ComPtr<Console>     mptrConsole;
     55    PVM                 mpVM;
     56    Utf8Str             mstrPassword;
     57
     58    /** @name stream stuff
     59     * @{  */
     60    RTSOCKET            mhSocket;
     61    uint64_t            moffStream;
     62    /** @} */
     63
     64    MigrationState(Console *pConsole, PVM pVM)
     65        : mptrConsole(pConsole)
     66        , mpVM(pVM)
     67        , mhSocket(NIL_RTSOCKET)
     68        , moffStream(UINT64_MAX / 2)
     69    {
     70    }
     71};
     72
     73
     74/**
     75 * Migration state used by the source side.
     76 */
     77class MigrationStateSrc : public MigrationState
     78{
     79public:
     80    ComPtr<Progress>    mptrProgress;
     81    Utf8Str             mstrHostname;
     82    uint32_t            muPort;
     83
     84    MigrationStateSrc(Console *pConsole, PVM pVM)
     85        : MigrationState(pConsole, pVM)
     86        , muPort(UINT32_MAX)
     87    {
     88    }
     89};
     90
     91
     92/**
     93 * Migration state used by the destiation side.
     94 */
     95class MigrationStateDst : public MigrationState
     96{
     97public:
     98    IMachine           *mpMachine;
     99    void               *mpvVMCallbackTask;
     100    int                 mRc;
     101
     102    MigrationStateDst(Console *pConsole, PVM pVM, IMachine *pMachine)
     103        : MigrationState(pConsole, pVM)
     104        , mpMachine(pMachine)
     105        , mpvVMCallbackTask(NULL)
     106        , mRc(VINF_SUCCESS)
     107    {
     108    }
     109};
     110
    59111
    60112
     
    66118
    67119/**
     120 * Reads a string from the socket.
     121 *
     122 * @returns VBox status code.
     123 *
     124 * @param   pState      The live migration state structure.
     125 * @param   pszBuf      The output buffer.
     126 * @param   cchBuf      The size of the output buffer.
     127 *
     128 */
     129static int migrationTcpReadLine(MigrationState *pState, char *pszBuf, size_t cchBuf)
     130{
     131    char       *pszStart = pszBuf;
     132    RTSOCKET    Sock     = pState->mhSocket;
     133
     134    AssertReturn(cchBuf > 1, VERR_INTERNAL_ERROR);
     135
     136    /* dead simple (stupid) approach. */
     137    for (;;)
     138    {
     139        char ch;
     140        int rc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
     141        if (RT_FAILURE(rc))
     142        {
     143            LogRel(("Migration: RTTcpRead -> %Rrc while reading string ('%s')\n", rc, pszStart));
     144            return rc;
     145        }
     146        if (    ch == '\n'
     147            ||  ch == '\0')
     148            return VINF_SUCCESS;
     149        if (cchBuf <= 1)
     150        {
     151            LogRel(("Migration: String buffer overflow: '%s'\n", pszStart));
     152            return VERR_BUFFER_OVERFLOW;
     153        }
     154        *pszBuf++ = ch;
     155        *pszBuf   = '\0';
     156        cchBuf--;
     157    }
     158}
     159
     160
     161static int migrationTcpWriteACK(MigrationState *pState)
     162{
     163    int rc = RTTcpWrite(pState->mhSocket, "ACK\n", sizeof("ACK\n") - 1);
     164    if (RT_FAILURE(rc))
     165        LogRel(("Migration: RTTcpWrite(,ACK,) -> %Rrc\n", rc));
     166    return rc;
     167}
     168
     169
     170static int migrationTcpWriteNACK(MigrationState *pState)
     171{
     172    int rc = RTTcpWrite(pState->mhSocket, "NACK\n", sizeof("NACK\n") - 1);
     173    if (RT_FAILURE(rc))
     174        LogRel(("Migration: RTTcpWrite(,NACK,) -> %Rrc\n", rc));
     175    return rc;
     176}
     177
     178
     179/**
     180 * Reads an ACK or NACK.
     181 *
     182 * @returns S_OK on ACK, E_FAIL+setError() on failure or NACK.
     183 * @param   pState              The live migration source state.
     184 *
     185 * @remarks the setError laziness forces this to be a Console member.
     186 */
     187HRESULT
     188Console::migrationSrcReadACK(MigrationStateSrc *pState)
     189{
     190    char szMsg[128];
     191    int vrc = migrationTcpReadLine(pState, szMsg, sizeof(szMsg));
     192    if (RT_FAILURE(vrc))
     193        return setError(E_FAIL, tr("Failed reading ACK: %Rrc"), vrc);
     194    if (strcmp(szMsg, "ACK\n"))
     195    {
     196        if (strcmp(szMsg, "NACK\n"))
     197            return setError(E_FAIL, "NACK");
     198        return setError(E_FAIL, tr("Expected ACK or NACK, got '%s'"), szMsg);
     199    }
     200    return S_OK;
     201}
     202
     203/**
     204 * Submitts a command to the destination and waits for the ACK.
     205 *
     206 * @returns S_OK on ACKed command, E_FAIL+setError() on failure.
     207 *
     208 * @param   pState              The live migration source state.
     209 * @param   pszCommand          The command.
     210 *
     211 * @remarks the setError laziness forces this to be a Console member.
     212 */
     213HRESULT
     214Console::migrationSrcSubmitCommand(MigrationStateSrc *pState, const char *pszCommand)
     215{
     216    size_t cchCommand = strlen(pszCommand);
     217    int vrc = RTTcpWrite(pState->mhSocket, pszCommand, cchCommand);
     218    if (RT_SUCCESS(vrc))
     219        vrc = RTTcpWrite(pState->mhSocket, "\n", sizeof("\n") - 1);
     220    if (RT_FAILURE(vrc))
     221        return setError(E_FAIL, tr("Failed writing command '%s': %Rrc"), pszCommand, vrc);
     222    return migrationSrcReadACK(pState);
     223}
     224
     225
     226/**
    68227 * @copydoc SSMSTRMOPS::pfnWrite
    69228 */
    70229static DECLCALLBACK(int) migrationTcpOpWrite(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite)
    71230{
    72     PMIGRATIONSTATE pState = (PMIGRATIONSTATE)pvUser;
    73     int rc = RTTcpWrite(pState->hSocket, pvBuf, cbToWrite);
     231    MigrationState *pState = (MigrationState *)pvUser;
     232    int rc = RTTcpWrite(pState->mhSocket, pvBuf, cbToWrite);
    74233    if (RT_SUCCESS(rc))
    75234    {
    76         pState->offStream += cbToWrite;
     235        pState->moffStream += cbToWrite;
    77236        return VINF_SUCCESS;
    78237    }
     
    86245static DECLCALLBACK(int) migrationTcpOpRead(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    87246{
    88     PMIGRATIONSTATE pState = (PMIGRATIONSTATE)pvUser;
    89     int rc = RTTcpRead(pState->hSocket, pvBuf, cbToRead, pcbRead);
     247    MigrationState *pState = (MigrationState *)pvUser;
     248    int rc = RTTcpRead(pState->mhSocket, pvBuf, cbToRead, pcbRead);
    90249    if (RT_SUCCESS(rc))
    91250    {
    92         pState->offStream += pcbRead ? *pcbRead : cbToRead;
     251        pState->moffStream += pcbRead ? *pcbRead : cbToRead;
    93252        return VINF_SUCCESS;
    94253    }
     
    111270static DECLCALLBACK(uint64_t) migrationTcpOpTell(void *pvUser)
    112271{
    113     PMIGRATIONSTATE pState = (PMIGRATIONSTATE)pvUser;
    114     return pState->offStream;
     272    MigrationState *pState = (MigrationState *)pvUser;
     273    return pState->moffStream;
    115274}
    116275
     
    161320
    162321/**
     322 * Do the live migration.
     323 *
     324 * @returns VBox status code.
     325 * @param   pState              The migration state.
     326 */
     327HRESULT
     328Console::migrationSrc(MigrationStateSrc *pState)
     329{
     330    AutoCaller autoCaller(this);
     331    CheckComRCReturnRC(autoCaller.rc());
     332
     333    /*
     334     * Wait for Console::Migrate to change the state.
     335     */
     336    { AutoWriteLock autoLock(); }
     337
     338    /*
     339     * Try connect to the destination machine.
     340     * (Note. The caller cleans up mhSocket, so we can return without worries.)
     341     */
     342    int vrc = RTTcpClientConnect(pState->mstrHostname.c_str(), pState->muPort, &pState->mhSocket);
     343    if (RT_SUCCESS(vrc))
     344        return setError(E_FAIL, tr("Failed to connect to port %u on '%s': %Rrc"),
     345                        pState->muPort, pState->mstrHostname.c_str(), vrc);
     346
     347    /* Read and check the welcome message. */
     348    char szLine[RT_MAX(128, sizeof(g_szWelcome))];
     349    vrc = RTTcpRead(pState->mhSocket, szLine, sizeof(g_szWelcome) - 1, NULL);
     350    if (RT_FAILURE(vrc))
     351        return setError(E_FAIL, tr("Failed to read welcome message: %Rrc"), vrc);
     352    if (!strcmp(szLine, g_szWelcome))
     353        return setError(E_FAIL, tr("Unexpected welcome '%s'"), szLine);
     354
     355    /* password */
     356    pState->mstrPassword.append('\n');
     357    vrc = RTTcpWrite(pState->mhSocket, pState->mstrPassword.c_str(), pState->mstrPassword.length());
     358    if (RT_FAILURE(vrc))
     359        return setError(E_FAIL, tr("Failed to send password: %Rrc"), vrc);
     360
     361    /* ACK */
     362    HRESULT hrc = migrationSrcReadACK(pState);
     363    if (FAILED(hrc))
     364        return hrc;
     365
     366    /*
     367     * Do compatability checks of the VM config and the host hardware.
     368     */
     369    /** @todo later */
     370
     371    /*
     372     * Start loading the state.
     373     */
     374    hrc = migrationSrcSubmitCommand(pState, "load");
     375    if (FAILED(hrc))
     376        return hrc;
     377
     378    void *pvUser = static_cast<void *>(static_cast<MigrationState *>(pState));
     379    vrc = VMR3Migrate(pState->mpVM, &g_migrationTcpOps, pvUser, NULL/** @todo progress*/, pvUser);
     380    if (vrc)
     381        return setError(E_FAIL, tr("VMR3Migrate -> %Rrc"), vrc);
     382
     383    hrc = migrationSrcReadACK(pState);
     384    if (FAILED(hrc))
     385        return hrc;
     386
     387    /*
     388     * State fun? Automatic power off?
     389     */
     390
     391    return S_OK;
     392}
     393
     394
     395/**
     396 * Static thread method wrapper.
     397 *
     398 * @returns VINF_SUCCESS (ignored).
     399 * @param   hThread             The thread.
     400 * @param   pvUser              Pointer to a MigrationStateSrc instance.
     401 */
     402/*static*/ DECLCALLBACK(int)
     403Console::migrationSrcThreadWrapper(RTTHREAD hThread, void *pvUser)
     404{
     405    MigrationStateSrc *pState = (MigrationStateSrc *)pvUser;
     406
     407    HRESULT hrc = pState->mptrConsole->migrationSrc(pState);
     408    pState->mptrProgress->notifyComplete(hrc);
     409
     410    if (pState->mhSocket != NIL_RTSOCKET)
     411    {
     412        RTTcpClientClose(pState->mhSocket);
     413        pState->mhSocket = NIL_RTSOCKET;
     414    }
     415    delete pState;
     416
     417    return VINF_SUCCESS;
     418}
     419
     420
     421/**
    163422 * Start live migration to the specified target.
    164423 *
     
    174433{
    175434    /*
    176      * Validate parameters.
    177      */
    178 
    179     /*
    180      * Try change the state, create a progress object and spawn a worker thread.
    181      */
     435     * Validate parameters, check+hold object status, write lock the object
     436     * and validate the state.
     437     */
     438    CheckComArgOutPointerValid(aProgress);
     439    CheckComArgStrNotEmptyOrNull(aHostname);
     440    CheckComArgNotNull(aHostname);
     441    CheckComArgExprMsg(aPort, aPort > 0 && aPort <= 65535, ("is %u", aPort));
     442
     443    AutoCaller autoCaller(this);
     444    CheckComRCReturnRC(autoCaller.rc());
     445
     446    AutoWriteLock autoLock(this);
     447    LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
     448
     449    switch (mMachineState)
     450    {
     451        case MachineState_Running:
     452        case MachineState_Paused:
     453            break;
     454
     455        default:
     456            return setError(VBOX_E_INVALID_VM_STATE,
     457                tr("Invalid machine state: %s (must be Running, Paused or Stuck)"),
     458                Global::stringifyMachineState(mMachineState));
     459    }
     460
     461
     462    /*
     463     * Create a progress object, spawn a worker thread and change the state.
     464     * Note! The thread won't start working until we release the lock.
     465     */
     466    LogFlowThisFunc(("Initiating LIVE MIGRATION request...\n"));
     467
     468    ComObjPtr<Progress> ptrMigrateProgress;
     469    HRESULT hrc = ptrMigrateProgress.createObject();
     470    CheckComRCReturnRC(hrc);
     471    hrc = ptrMigrateProgress->init(static_cast<IConsole *>(this),
     472                                   Bstr(tr("Live Migration")),
     473                                   TRUE /*aCancelable*/);
     474    CheckComRCReturnRC(hrc);
     475
     476    MigrationStateSrc *pState = new MigrationStateSrc(this, mpVM);
     477    pState->mstrPassword = aPassword;
     478    pState->mstrHostname = aHostname;
     479    pState->muPort       = aPort;
     480    pState->mptrProgress = ptrMigrateProgress;
     481
     482    int vrc = RTThreadCreate(NULL, Console::migrationSrcThreadWrapper, pState, 0 /*cbStack*/,
     483                             RTTHREADTYPE_EMULATION, 0 /*fFlags*/, "Migrate");
     484    if (RT_SUCCESS(vrc))
     485        delete pState;
    182486
    183487    return E_FAIL;
     
    187491/**
    188492 * Creates a TCP server that listens for the source machine and passes control
    189  * over to Console::migrationServeConnection().
     493 * over to Console::migrationDstServeConnection().
    190494 *
    191495 * @returns VBox status code.
     
    196500 */
    197501int
    198 Console::migrationLoadRemote(PVM pVM, IMachine *pMachine, void *pvVMCallbackTask)
     502Console::migrationDst(PVM pVM, IMachine *pMachine, void *pvVMCallbackTask)
    199503{
    200504    /*
     
    211515        return VERR_GENERAL_FAILURE;
    212516    Utf8Str strPassword(bstrPassword);
    213     strPassword.append('\n');           /* always ends with a newline. */
    214517
    215518    Utf8Str strBind("");
     
    220523     * Create the TCP server.
    221524     */
    222     int rc;
     525    int vrc;
    223526    PRTTCPSERVER hServer;
    224527    if (uPort)
    225         rc = RTTcpServerCreateEx(pszBindAddress, uPort, &hServer);
     528        vrc = RTTcpServerCreateEx(pszBindAddress, uPort, &hServer);
    226529    else
    227530    {
     
    229532        {
    230533            uPort = RTRandU32Ex(cTries >= 8192 ? 49152 : 1024, 65534);
    231             rc = RTTcpServerCreateEx(pszBindAddress, uPort, &hServer);
    232             if (rc != VERR_NET_ADDRESS_IN_USE)
     534            vrc = RTTcpServerCreateEx(pszBindAddress, uPort, &hServer);
     535            if (vrc != VERR_NET_ADDRESS_IN_USE)
    233536                break;
    234537        }
    235         if (RT_SUCCESS(rc))
     538        if (RT_SUCCESS(vrc))
    236539        {
    237540            HRESULT hrc = pMachine->COMSETTER(LiveMigrationPort)(uPort);
     
    243546        }
    244547    }
    245     if (RT_FAILURE(rc))
    246         return rc;
     548    if (RT_FAILURE(vrc))
     549        return vrc;
    247550
    248551    /*
     
    250553     */
    251554    RTTIMERLR hTimerLR;
    252     rc = RTTimerLRCreateEx(&hTimerLR, 0 /*ns*/, RTTIMER_FLAGS_CPU_ANY, migrationTimeout, hServer);
    253     if (RT_SUCCESS(rc))
    254     {
    255         rc = RTTimerLRStart(hTimerLR, 5*60*UINT64_C(1000000000) /*ns*/);
    256         if (RT_SUCCESS(rc))
     555    vrc = RTTimerLRCreateEx(&hTimerLR, 0 /*ns*/, RTTIMER_FLAGS_CPU_ANY, migrationTimeout, hServer);
     556    if (RT_SUCCESS(vrc))
     557    {
     558        vrc = RTTimerLRStart(hTimerLR, 5*60*UINT64_C(1000000000) /*ns*/);
     559        if (RT_SUCCESS(vrc))
    257560        {
    258561            /*
    259562             * Do the job, when it returns we're done.
    260563             */
    261             MIGRATIONSTATE State;
    262             State.pConsole      = this;
    263             State.pMachine      = pMachine;
    264             State.pVM           = pVM;
    265             State.pszPassword   = strPassword.c_str();
    266             State.hSocket       = NIL_RTSOCKET;
    267             State.offStream     = UINT64_MAX / 2;
    268             State.rc            = VINF_SUCCESS;
    269 
    270             rc = RTTcpServerListen(hServer, Console::migrationServeConnection, &State);
    271             if (rc == VERR_TCP_SERVER_STOP)
    272                 rc = State.rc;
    273             if (RT_FAILURE(rc))
    274                 LogRel(("Migration: RTTcpServerListen -> %Rrc\n", rc));
     564            MigrationStateDst State(this, pVM, pMachine);
     565            State.mstrPassword = strPassword;
     566
     567            vrc = RTTcpServerListen(hServer, Console::migrationDstServeConnection, &State);
     568            if (vrc == VERR_TCP_SERVER_STOP)
     569                vrc = State.mRc;
     570            if (RT_FAILURE(vrc))
     571                LogRel(("Migration: RTTcpServerListen -> %Rrc\n", vrc));
    275572        }
    276573
     
    279576    RTTcpServerDestroy(hServer);
    280577
    281     return rc;
    282 }
    283 
    284 
    285 /**
    286  * Reads a string from the socket.
    287  *
    288  * @returns VBox status code.
    289  *
    290  * @param   Sock        The socket.
    291  * @param   pszBuf      The output buffer.
    292  * @param   cchBuf      The size of the output buffer.
    293  *
    294  */
    295 static int migrationReadLine(RTSOCKET Sock, char *pszBuf, size_t cchBuf)
    296 {
    297     char *pszStart = pszBuf;
    298     AssertReturn(cchBuf > 1, VERR_INTERNAL_ERROR);
    299 
    300     /* dead simple (stupid) approach. */
    301     for (;;)
    302     {
    303         char ch;
    304         int rc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
    305         if (RT_FAILURE(rc))
    306         {
    307             LogRel(("Migration: RTTcpRead -> %Rrc while reading string ('%s')\n", rc, pszStart));
    308             return rc;
    309         }
    310         if (    ch == '\n'
    311             ||  ch == '\0')
    312             return VINF_SUCCESS;
    313         if (cchBuf <= 1)
    314         {
    315             LogRel(("Migration: String buffer overflow: '%s'\n", pszStart));
    316             return VERR_BUFFER_OVERFLOW;
    317         }
    318         *pszBuf++ = ch;
    319         *pszBuf   = '\0';
    320         cchBuf--;
    321     }
     578    return vrc;
    322579}
    323580
     
    325582/**
    326583 * @copydoc FNRTTCPSERVE
    327  * VERR_TCP_SERVER_STOP
    328584 */
    329585/*static*/ DECLCALLBACK(int)
    330 Console::migrationServeConnection(RTSOCKET Sock, void *pvUser)
    331 {
    332     PMIGRATIONSTATE pState   = (PMIGRATIONSTATE)pvUser;
    333     Console        *pConsole = pState->pConsole;
    334     IMachine       *pMachine = pState->pMachine;
     586Console::migrationDstServeConnection(RTSOCKET Sock, void *pvUser)
     587{
     588    MigrationStateDst *pState   = (MigrationStateDst *)pvUser;
    335589
    336590    /*
    337591     * Say hello.
    338592     */
    339     int rc = RTTcpWrite(Sock, g_szWelcome, sizeof(g_szWelcome) - 1);
    340     if (RT_FAILURE(rc))
    341     {
    342         LogRel(("Migration: Failed to write welcome message: %Rrc\n", rc));
     593    int vrc = RTTcpWrite(Sock, g_szWelcome, sizeof(g_szWelcome) - 1);
     594    if (RT_FAILURE(vrc))
     595    {
     596        LogRel(("Migration: Failed to write welcome message: %Rrc\n", vrc));
    343597        return VINF_SUCCESS;
    344598    }
    345599
    346600    /*
    347      * Password (includes '\n', see migrationLoadRemote).  If it's right, tell
     601     * Password (includes '\n', see migrationDst).  If it's right, tell
    348602     * the TCP server to stop listening (frees up host resources and makes sure
    349603     * this is the last connection attempt).
    350604     */
    351     const char *pszPassword = pState->pszPassword;
     605    pState->mstrPassword.append('\n');
     606    const char *pszPassword = pState->mstrPassword.c_str();
    352607    unsigned    off = 0;
    353608    while (pszPassword[off])
    354609    {
    355610        char ch;
    356         rc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
    357         if (RT_FAILURE(rc))
     611        vrc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
     612        if (    RT_FAILURE(vrc)
     613            ||  pszPassword[off] != ch)
     614        {
     615            if (RT_FAILURE(vrc))
     616                LogRel(("Migration: Password read failure (off=%u): %Rrc\n", off, vrc));
     617            else
     618                LogRel(("Migration: Invalid password (off=%u)\n", off));
     619            migrationTcpWriteNACK(pState);
     620            return VINF_SUCCESS;
     621        }
     622        off++;
     623    }
     624    vrc = migrationTcpWriteACK(pState);
     625    if (RT_FAILURE(vrc))
     626        return vrc;
     627    RTTcpServerShutdown((PRTTCPSERVER)pvUser);
     628
     629    /*
     630     * Command processing loop.
     631     */
     632    pState->mhSocket = Sock;
     633    for (;;)
     634    {
     635        char szCmd[128];
     636        vrc = migrationTcpReadLine(pState, szCmd, sizeof(szCmd));
     637        if (RT_FAILURE(vrc))
    358638            break;
    359         if (pszPassword[off] != ch)
    360         {
    361             LogRel(("Migration: Invalid password (off=%u)\n", off));
    362             return VINF_SUCCESS;
    363         }
    364         off++;
    365     }
    366 
    367     RTTcpServerShutdown((PRTTCPSERVER)pvUser);
    368 
    369     /*
    370      * Command processing loop.
    371      */
    372     pState->hSocket = Sock;
    373     for (;;)
    374     {
    375         char szCmd[128];
    376         rc = migrationReadLine(Sock, szCmd, sizeof(szCmd));
    377         if (RT_FAILURE(rc))
    378             break;
    379639
    380640        if (!strcmp(szCmd, "load"))
    381641        {
    382             pState->offStream = 0;
    383             rc = VMR3LoadFromStream(pState->pVM, &g_migrationTcpOps, pState,
    384                                     Console::stateProgressCallback, pState->pvVMCallbackTask);
    385             if (RT_FAILURE(rc))
     642            vrc = migrationTcpWriteACK(pState);
     643            if (RT_FAILURE(vrc))
     644                break;
     645
     646            pState->moffStream = 0;
     647            void *pvUser = static_cast<void *>(static_cast<MigrationState *>(pState));
     648            vrc = VMR3LoadFromStream(pState->mpVM, &g_migrationTcpOps, pvUser,
     649                                     Console::stateProgressCallback, pState->mpvVMCallbackTask);
     650            if (RT_FAILURE(vrc))
    386651            {
    387                 LogRel(("Migration: VMR3LoadFromStream -> %Rrc\n", rc));
     652                LogRel(("Migration: VMR3LoadFromStream -> %Rrc\n", vrc));
    388653                break;
    389654            }
     655
     656            vrc = migrationTcpWriteACK(pState);
     657            if (RT_FAILURE(vrc))
     658                break;
    390659        }
    391660        /** @todo implement config verification and hardware compatability checks. Or
    392661         *        maybe leave part of these to the saved state machinery? */
    393662        else if (!strcmp(szCmd, "done"))
     663        {
     664            migrationTcpWriteACK(pState);
    394665            break;
     666        }
    395667        else
    396668        {
     
    399671        }
    400672    }
    401     pState->hSocket = NIL_RTSOCKET;
     673    pState->mhSocket = NIL_RTSOCKET;
    402674
    403675    return VERR_TCP_SERVER_STOP;
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r23643 r23663  
    67466746                else if (task->mLiveMigrationTarget)
    67476747                    /* -> ConsoleImpl-LiveMigration.cpp */
    6748                     vrc = console->migrationLoadRemote(pVM, pMachine, static_cast<VMProgressTask*>(task.get()));
     6748                    vrc = console->migrationDst(pVM, pMachine, static_cast<VMProgressTask*>(task.get()));
    67496749                else if (task->mStartPaused)
    67506750                    /* done */
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r23643 r23663  
    3434class Display;
    3535class MachineDebugger;
     36class MigrationStateSrc;
    3637class OUSBDevice;
    3738class RemoteUSBDevice;
     
    515516    /** @name Live migration support
    516517     * @{ */
    517     int                         migrationLoadRemote(PVM pVM, IMachine *pMachine, void *pvVMCallbackTask);
    518     static DECLCALLBACK(int)    migrationServeConnection(RTSOCKET Sock, void *pvUser);
     518    static DECLCALLBACK(int)    migrationSrcThreadWrapper(RTTHREAD hThread, void *pvUser);
     519    HRESULT                     migrationSrc(MigrationStateSrc *pState);
     520    HRESULT                     migrationSrcReadACK(MigrationStateSrc *pState);
     521    HRESULT                     migrationSrcSubmitCommand(MigrationStateSrc *pState, const char *pszCommand);
     522    int                         migrationDst(PVM pVM, IMachine *pMachine, void *pvVMCallbackTask);
     523    static DECLCALLBACK(int)    migrationDstServeConnection(RTSOCKET Sock, void *pvUser);
    519524    /** @} */
    520525
Note: See TracChangeset for help on using the changeset viewer.

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