VirtualBox

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


Ignore:
Timestamp:
Oct 8, 2009 4:56:52 PM (15 years ago)
Author:
vboxsync
Message:

Main: Somre more live migration stuff.

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

Legend:

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

    r23606 r23626  
    2626#include "Logging.h"
    2727
     28#include <iprt/err.h>
     29#include <iprt/rand.h>
     30#include <iprt/tcp.h>
     31#include <iprt/timer.h>
     32
    2833#include <VBox/vmapi.h>
    2934#include <VBox/ssm.h>
     
    3338
    3439
     40
     41/*******************************************************************************
     42*   Structures and Typedefs                                                    *
     43*******************************************************************************/
     44/**
     45 * Argument package for Console::migrationServeConnection.
     46 */
     47typedef struct MIGRATIONSERVEARGS
     48{
     49    Console    *pConsole;
     50    IMachine   *pMachine;
     51    PVM         pVM;
     52    const char *pszPassword;
     53    RTTIMERLR   hTimer;
     54} MIGRATIONSERVEARGS;
     55typedef MIGRATIONSERVEARGS *PMIGRATIONSERVEARGS;
     56
     57
     58/*******************************************************************************
     59*   Global Variables                                                           *
     60*******************************************************************************/
     61static const char g_szWelcome[] = "VirtualBox-LiveMigration-1.0\n";
     62
     63
     64
     65/**
     66 * @copydoc FNRTTIMERLR
     67 */
     68static DECLCALLBACK(void) migrationTimeout(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)
     69{
     70    /* This is harmless for any open connections. */
     71    RTTcpServerShutdown((PRTTCPSERVER)pvUser);
     72}
     73
     74
    3575STDMETHODIMP
    3676Console::Migrate(IN_BSTR aHostname, ULONG aPort, IN_BSTR aPassword, IProgress **aProgress)
     
    3979}
    4080
     81
     82/**
     83 * Creates a TCP server that listens for the source machine and passes control
     84 * over to Console::migrationServeConnection().
     85 *
     86 * @returns VBox status code.
     87 * @param   pVM                 The VM handle
     88 * @param   pMachine            The IMachine for the virtual machine.
     89 */
    4190int
    4291Console::migrationLoadRemote(PVM pVM, IMachine *pMachine)
     
    55104        return VERR_GENERAL_FAILURE;
    56105    Utf8Str strPassword(bstrPassword);
     106    strPassword.append('\n');           /* always ends with a newline. */
     107
     108    Utf8Str strBind("");
     109    /** @todo Add a bind address property. */
     110    const char *pszBindAddress = strBind.isEmpty() ? NULL : strBind.c_str();
    57111
    58112    /*
    59113     * Create the TCP server.
    60114     */
    61     //RTTcpServerCreateEx(NULL,
    62 
    63 
    64     return VERR_NOT_IMPLEMENTED;
    65 }
    66 
     115    int rc;
     116    PRTTCPSERVER hServer;
     117    if (uPort)
     118        rc = RTTcpServerCreateEx(pszBindAddress, uPort, &hServer);
     119    else
     120    {
     121        for (int cTries = 10240; cTries > 0; cTries--)
     122        {
     123            uPort = RTRandU32Ex(cTries >= 8192 ? 49152 : 1024, 65534);
     124            rc = RTTcpServerCreateEx(pszBindAddress, uPort, &hServer);
     125            if (rc != VERR_NET_ADDRESS_IN_USE)
     126                break;
     127        }
     128        if (RT_SUCCESS(rc))
     129        {
     130            HRESULT hrc = pMachine->COMSETTER(LiveMigrationPort)(uPort);
     131            if (FAILED(hrc))
     132            {
     133                RTTcpServerDestroy(hServer);
     134                return VERR_GENERAL_FAILURE;
     135            }
     136        }
     137    }
     138    if (RT_FAILURE(rc))
     139        return rc;
     140
     141    /*
     142     * Create a timer for timing out after 5 mins.
     143     */
     144    RTTIMERLR hTimer;
     145    rc = RTTimerLRCreateEx(&hTimer, 0, 0, migrationTimeout, hServer);
     146    if (RT_SUCCESS(rc))
     147    {
     148        rc = RTTimerLRStart(hTimer, 5*60*UINT64_C(1000000000) /*ns*/);
     149        if (RT_SUCCESS(rc))
     150        {
     151            /*
     152             * Do the job, when it returns we're done.
     153             */
     154            MIGRATIONSERVEARGS Args;
     155            Args.pConsole    = this;
     156            Args.pMachine    = pMachine;
     157            Args.pVM         = pVM;
     158            Args.pszPassword = strPassword.c_str();
     159            Args.hTimer      = hTimer;
     160            rc = RTTcpServerListen(hServer, Console::migrationServeConnection, &Args);
     161        }
     162
     163        RTTimerLRDestroy(hTimer);
     164    }
     165    RTTcpServerDestroy(hServer);
     166
     167    return rc;
     168}
     169
     170/**
     171 * Reads a string from the socket.
     172 *
     173 * @returns VBox status code.
     174 *
     175 * @param   Sock        The socket.
     176 * @param   pszBuf      The output buffer.
     177 * @param   cchBuf      The size of the output buffer.
     178 *
     179 */
     180static int migrationReadLine(RTSOCKET Sock, char *pszBuf, size_t cchBuf)
     181{
     182    char *pszStart = pszBuf;
     183    AssertReturn(cchBuf > 1, VERR_INTERNAL_ERROR);
     184
     185    /* dead simple (stupid) approach. */
     186    for (;;)
     187    {
     188        char ch;
     189        int rc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
     190        if (RT_FAILURE(rc))
     191        {
     192            LogRel(("Migration: RTTcpRead -> %Rrc while reading string ('%s')\n", rc, pszStart));
     193            return rc;
     194        }
     195        if (    ch == '\n'
     196            ||  ch == '\0')
     197            return VINF_SUCCESS;
     198        if (cchBuf <= 1)
     199        {
     200            LogRel(("Migration: String buffer overflow: '%s'\n", pszStart));
     201            return VERR_BUFFER_OVERFLOW;
     202        }
     203        *pszBuf++ = ch;
     204        *pszBuf   = '\0';
     205        cchBuf--;
     206    }
     207}
     208
     209
     210/**
     211 * @copydoc FNRTTCPSERVE
     212 * VERR_TCP_SERVER_STOP
     213 */
     214/*static*/ DECLCALLBACK(int)
     215Console::migrationServeConnection(RTSOCKET Sock, void *pvUser)
     216{
     217    PMIGRATIONSERVEARGS pArgs       = (PMIGRATIONSERVEARGS)pvUser;
     218    Console            *pConsole    = pArgs->pConsole;
     219    IMachine           *pMachine    = pArgs->pMachine;
     220    PVM                 pVM         = pArgs->pVM;
     221    const char         *pszPassword = pArgs->pszPassword;
     222
     223    /*
     224     * Say hello.
     225     */
     226    int rc = RTTcpWrite(Sock, g_szWelcome, sizeof(g_szWelcome) - 1);
     227    if (RT_FAILURE(rc))
     228    {
     229        LogRel(("Migration: Failed to write welcome message: %Rrc\n", rc));
     230        return VINF_SUCCESS;
     231    }
     232
     233    /*
     234     * Password (includes '\n', see migrationLoadRemote).  If it's right, tell
     235     * the TCP server to stop listening (frees up host resources and makes sure
     236     * this is the last connection attempt).
     237     */
     238    unsigned off = 0;
     239    while (pszPassword[off])
     240    {
     241        char ch;
     242        rc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
     243        if (RT_FAILURE(rc))
     244            break;
     245        if (pszPassword[off] != ch)
     246        {
     247            LogRel(("Migration: Invalid password (off=%u)\n", off));
     248            return VINF_SUCCESS;
     249        }
     250        off++;
     251    }
     252
     253    RTTcpServerShutdown((PRTTCPSERVER)pvUser);
     254
     255    /*
     256     * Command processing loop.
     257     */
     258    for (;;)
     259    {
     260        char szCmd[128];
     261        rc = migrationReadLine(Sock, szCmd, sizeof(szCmd));
     262        if (RT_FAILURE(rc))
     263            break;
     264
     265        if (!strcmp(szCmd, "state"))
     266        {
     267            /* restore the state. */
     268        }
     269        else if (!strcmp(szCmd, "done"))
     270            break;
     271        else
     272        {
     273            LogRel(("Migration: Unknown command '%s'\n", szCmd));
     274            break;
     275        }
     276    }
     277
     278    return VERR_TCP_SERVER_STOP;
     279}
     280
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r23606 r23626  
    514514    /** @name Live migration support
    515515     * @{ */
    516     int migrationLoadRemote(PVM pVM, IMachine *pMachine);
     516    int                         migrationLoadRemote(PVM pVM, IMachine *pMachine);
     517    static DECLCALLBACK(int)    migrationServeConnection(RTSOCKET Sock, void *pvUser);
    517518    /** @} */
    518519
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