Virtuozzo Virtualization SDK C API Reference
ContentsIndex
Example
PrlEvent_CreateAnswerEvent Function

The following is a complete example that demonstrates how to handle events and how to answer to Virtuozzo Service questions. In the example, we create a blank virtual machine and try to add a virtual hard drive to it with the size larger than the free disk space available on the physical drive. This will trigger an event on the Virtuozzo Service side and a question will be sent to the client asking if we really want to create a drive like that. The virtual machine creation operation will not continue unless we send an answer to the Virtuozzo Service.

#include "Parallels.h"
#include "Wrappers/SdkWrap/SdkWrap.h"
#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN_
#include <windows.h>
#else
#include <unistd.h>
#endif

#define MY_JOB_TIMEOUT 10000 // Default timeout to use in the PrlJob_Wait function.
#define MY_HDD_SIZE 70*1024 // The size of the new hard drive.
#define MY_STR_BUF_SIZE 1024 // The default buffer size to use for string output.

////////////////////////////////////////////////////////////////////////////////

// A helper function that will attempt to crate a hard drive larger
// than the free space available, thus triggering an event on the
// Virtuozzo Service, which will result in Service sending us a question.
static PRL_RESULT create_big_hdd(PRL_HANDLE hVm);

// The callback function (event handler).
static PRL_RESULT callback(PRL_HANDLE, PRL_VOID_PTR);

////////////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
    // Pick the correct dynamic library file depending on the platform.
    #ifdef _WIN_
        #define SDK_LIB_NAME "prl_sdk.dll"
    #elif defined(_LIN_)
        #define SDK_LIB_NAME "libprl_sdk.so"
    #elif defined(_MAC_)
        #define SDK_LIB_NAME "libprl_sdk.dylib"
    #endif

    // Load the dynamic library.
    if (PRL_FAILED(SdkWrap_Load(SDK_LIB_NAME)) &&
        PRL_FAILED(SdkWrap_Load("./" SDK_LIB_NAME)))
    {
        // Error handling goes here...
        return -1;
    }

    PRL_RESULT ret = PRL_ERR_UNINITIALIZED;
    PRL_RESULT err = PRL_ERR_UNINITIALIZED;
    PRL_RESULT rc = PRL_ERR_UNINITIALIZED;
    PRL_HANDLE hJob = PRL_INVALID_HANDLE;
    PRL_HANDLE hJobResult = PRL_INVALID_HANDLE;
    PRL_HANDLE hServer = PRL_INVALID_HANDLE;

    // Initialize API library.
    err = PrlApi_Init(PARALLELS_API_VER);
    if (PRL_FAILED(err))
    {
        // Error handling goes here...
        return -1;
    }

    // Create server object.
    PrlSrv_Create(&hServer);

    // Log in.
    hJob = PrlSrv_Login(
        hServer, // Server handle
        "10.30.22.82", // Host IP address
        "jdoe", // User
        "secret", // Password
        0, // Previous session ID
        0, // Port number
        0, // Timeout
        PSL_NORMAL_SECURITY); // Security

    ret = PrlJob_Wait(hJob, MY_JOB_TIMEOUT);
    PrlHandle_Free(hJob);

    if (PRL_FAILED(ret))
    {
        fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n",
            PRL_RESULT_TO_STRING(ret));
        PrlHandle_Free(hJob);
        PrlHandle_Free(hServer);
        PrlApi_Deinit();
        SdkWrap_Unload();
        return -1;
    }

    // Analyze the result of PrlSrv_Login.
    PRL_RESULT nJobResult;
    ret = PrlJob_GetRetCode( hJob, &nJobResult );
    if (PRL_FAILED( nJobResult))
    {
        PrlHandle_Free(hJob);
        PrlHandle_Free(hServer);
        printf( "Login job returned with error: %s\n",
            PRL_RESULT_TO_STRING(nJobResult));
        PrlHandle_Free(hJob);
        PrlHandle_Free(hServer);
        PrlApi_Deinit();
        SdkWrap_Unload();
        return -1;
    }

    // Create a new virtual machine.
    PRL_HANDLE hVm;
    PrlSrv_CreateVm(hServer, &hVm);
    PrlVm_SetName(hVm, "My simple VM");

    // Register the virtual machine with the Virtuozzo Service.
    hJob = PrlVm_Reg(hVm, "", PRL_FALSE);
    PrlJob_Wait(hJob, MY_JOB_TIMEOUT);
    PrlHandle_Free(hJob);

    // Register the event handler with the Service.
    // The second parameter is a pointer to our callback function.
    PrlSrv_RegEventHandler(hServer, &callback, NULL);

    // Try creating a virtual hard drive larger than the
    // free space available (increase MY_HDD_SIZE value if needed).
    // This should produce an event that will
    // contain a question from the Virtuozzo Service.
    create_big_hdd(hVm);

    //
    // At this point, the background thread should call the
    // callback function.
    //

    // We can now clean up and exit the program.
    // Unregister the event handler and log off.
    PrlSrv_UnregEventHandler(hServer, &callback, NULL);
    hJob = PrlSrv_Logoff(hServer);
    PrlJob_Wait(hJob, MY_JOB_TIMEOUT);
    PrlHandle_Free( hJob );
    PrlHandle_Free( hServer );
    PrlApi_Deinit();
    SdkWrap_Unload();
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
// The callback function implementation.
// The event handling is demonstrated here.
//
static PRL_RESULT callback(PRL_HANDLE hEvent, PRL_VOID_PTR pUserData)
{
    PRL_HANDLE_TYPE nHandleType;
    PrlHandle_GetType(hEvent, &nHandleType);

    // A callback function will be called more than once.
    // It will be called for every job that we initiate and it
    // will be called for the event that we intentionally trigger.
    // In this example, we are interested in events only.
    if (nHandleType != PHT_EVENT)
    {
        return PrlHandle_Free(hEvent);
    }

    // Get the type of the event received.
    PRL_EVENT_TYPE type;
    PrlEvent_GetType(hEvent, &type);

    // See if the received event is a "question".
    if (type == PET_DSP_EVT_VM_QUESTION)
    {
        PRL_UINT32 nParamsCount = 0;
        PRL_RESULT err = PRL_ERR_UNINITIALIZED;

        // Extract the text of the question and display it on the screen.
        // The question is stored in the object in the "event message" property.
        PRL_BOOL bIsBriefMessage = true;
        char errMsg [MY_STR_BUF_SIZE];
        PRL_UINT32 nBufSize = MY_STR_BUF_SIZE;

        PrlEvent_GetErrString(hEvent, bIsBriefMessage, errMsg, &nBufSize);
        printf("Question: %s\n\n", errMsg);

        // Extract answer choices. They are stored in the
        // hEvent object as event parameters.
        // First, determine the number of parameters.
        err = PrlEvent_GetParamsCount(hEvent, &nParamsCount);
        if (PRL_FAILED(err))
        {
            fprintf(stderr, "[3]%.8X: %s\n", err,
                PRL_RESULT_TO_STRING(err));
            PrlHandle_Free(hEvent);
            return err;
        }

        // Declare an array to hold the choices information.
        PRL_UINT32_PTR choices =(PRL_UINT32_PTR)
            malloc(nParamsCount * sizeof(PRL_UINT32));

        // Now, itereate through the parameter list obtaining a
        // handle of type PHT_EVENT_PARAMETER that will contain
        // an individual parameter data.
        for(PRL_UINT32 nParamIndex = 0; nParamIndex < nParamsCount; ++nParamIndex)
        {
            PRL_HANDLE hParam; // this will receive the event parameter handle.
            PRL_RESULT err = PRL_ERR_UNINITIALIZED;

            // The PrlEvent_GetParam function obtains a handle of type
            // PHT_EVENT_PARAMETER containing (in this case) an answer choice.
            err = PrlEvent_GetParam(hEvent, nParamIndex, &hParam);
            if (PRL_FAILED(err))
            {
                fprintf(stderr, "[4]%.8X: %s\n", err,
                    PRL_RESULT_TO_STRING(err));
                PrlHandle_Free(hParam);
                PrlHandle_Free(hEvent);
                return err;
            }

            // Get the answer description that can be shown to the user.
            // First, obtain the event parameter value.
            err = PrlEvtPrm_ToUint32(hParam, &choices[nParamIndex]);
            if (PRL_FAILED(err))
            {
                fprintf(stderr, "[9]%.8X: %s\n", err,
                    PRL_RESULT_TO_STRING(err));
                PrlHandle_Free(hParam);
                PrlHandle_Free(hEvent);
                return err;
            }

            // Now, get the answer description using the
            // event parameter value as input in the following call.
            char sDesc [MY_STR_BUF_SIZE];
            err = PrlApi_GetResultDescription(choices[nParamIndex], true, sDesc, &nBufSize);
            if (PRL_FAILED(err))
            {
                fprintf(stderr, "[8]%.8X: %s\n", err,
                    PRL_RESULT_TO_STRING(err));
                PrlHandle_Free(hParam);
                PrlHandle_Free(hEvent);
                return err;
            }

            // Display the answer choice on the screen.
            printf("Answer choice: %s\n", sDesc);
            PrlHandle_Free(hParam);
        }

        // Select an answer choice (we are using the "No" answer here) and
        // create a valid answer object (hAnswer).
        PRL_HANDLE hAnswer;
        err = PrlEvent_CreateAnswerEvent(hEvent, &hAnswer, choices[1]);
        if (PRL_FAILED(err))
        {
            fprintf(stderr, "[A]%.8X: %s\n", err, PRL_RESULT_TO_STRING(err));
            PrlHandle_Free(hEvent);
            return err;
        }

        // Obtain a server handle.
        PRL_HANDLE hServer;
        PrlEvent_GetServer(hEvent, &hServer);

        // Send the answer handle to the Virtuozzo Service.
        PrlSrv_SendAnswer(hServer, hAnswer);

        free(choices);
        PrlHandle_Free(hServer);
        PrlHandle_Free(hAnswer);
    }
    else // other event type
    {
        PrlHandle_Free(hEvent);
    }

    return PRL_ERR_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////

// A helper function that will attempt to crate a hard drive larger
// than the free space available, thus triggering an event.
PRL_RESULT create_big_hdd(PRL_HANDLE hVm)
{
    PRL_HANDLE hJobBeginEdit = PRL_INVALID_HANDLE;
    PRL_HANDLE hJobCommit = PRL_INVALID_HANDLE;
    PRL_HANDLE hJob = PRL_INVALID_HANDLE;
    PRL_RESULT nJobRetCode = PRL_ERR_UNINITIALIZED;
    PRL_RESULT err = PRL_ERR_UNINITIALIZED;

    // Timestamp the beginning of the configuration changes operation.
    hJobBeginEdit = PrlVm_BeginEdit(hVm);
    err = PrlJob_Wait(hJobBeginEdit, MY_JOB_TIMEOUT);
    PrlJob_GetRetCode(hJobBeginEdit, &nJobRetCode);
    if (PRL_FAILED(nJobRetCode))
    {
        fprintf(stderr, "[B]%.8X: %s\n", nJobRetCode,
            PRL_RESULT_TO_STRING(nJobRetCode));
        PrlHandle_Free(hJobBeginEdit);
        return nJobRetCode;
    }

    // Create a new device handle.
    // This will be our new virtual hard disk.
    PRL_HANDLE hHDD;
    err = PrlVm_CreateVmDev(
            hVm, // Target virtual machine.
            PDE_HARD_DISK, // Device type.
            &hHDD ); // Device handle.

    // Set disk type to "expanding".
    err = PrlVmDevHd_SetDiskType(hHDD, PHD_EXPANDING_HARD_DISK);

    // Set max disk size, in megabytes.
    err = PrlVmDevHd_SetDiskSize(hHDD, MY_HDD_SIZE);

    // This option determines whether the image file will be split
    // into chunks or created as a single file.
    err = PrlVmDevHd_SetSplitted(hHDD, PRL_FALSE);

    // Choose and set the name for the new image file.
    err = PrlVmDev_SetFriendlyName(hHDD, "harddisk4.hdd");
    err = PrlVmDev_SetSysName(hHDD, "harddisk4.hdd");

    // Set the emulation type.
    err = PrlVmDev_SetEmulatedType(hHDD, PDT_USE_IMAGE_FILE);

    // Enable the new disk on successful creation.
    err = PrlVmDev_SetEnabled(hHDD, PRL_TRUE);

    // Create the new image file.
    hJob = PrlVmDev_CreateImage(hHDD,
            PRL_TRUE, // Do not overwrite if file exists.
            PRL_FALSE ); // Use non-interactive mode.

    err = PrlJob_Wait(hJob, MY_JOB_TIMEOUT);
    if (PRL_FAILED(err))
    {
        fprintf(stderr, "[C]%.8X: %s\n", err,
            PRL_RESULT_TO_STRING(err));
        PrlHandle_Free(hJob);
        return err;
    }

    // Commit the changes.
    hJobCommit = PrlVm_Commit(hVm);
    err = PrlJob_Wait(hJobCommit, MY_JOB_TIMEOUT);
    PrlJob_GetRetCode(hJobCommit, &nJobRetCode);
    if (PRL_FAILED(nJobRetCode))
    {
        fprintf(stderr, "[D]%.8X: %s\n", nJobRetCode,
            PRL_RESULT_TO_STRING( nJobRetCode));
        PrlHandle_Free(hJobCommit);
        return nJobRetCode;
    }
    return PRL_ERR_SUCCESS;
}
Copyright ©2016-2017 Parallels International GmbH. All rights reserved.