Exemplo n.º 1
0
int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
{
    int rc = VINF_SUCCESS;
    size_t cbNeeded;
    char *pBuf, *pNext;
    int aiMib[6];
    unsigned short u16DefaultIface = 0; /* shut up gcc. */
    bool fDefaultIfaceExistent = true;

    /* Get the index of the interface associated with default route. */
    rc = getDefaultIfaceIndex(&u16DefaultIface, PF_INET);
    if (RT_FAILURE(rc))
    {
        fDefaultIfaceExistent = false;
        rc = VINF_SUCCESS;
    }

    aiMib[0] = CTL_NET;
    aiMib[1] = PF_ROUTE;
    aiMib[2] = 0;
    aiMib[3] = 0;    /* address family */
    aiMib[4] = NET_RT_IFLIST;
    aiMib[5] = 0;

    if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
    {
        Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
        return RTErrConvertFromErrno(errno);
    }
    if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
        return VERR_NO_MEMORY;
    if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
    {
        free(pBuf);
        Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
        return RTErrConvertFromErrno(errno);
    }

    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock < 0)
    {
        free(pBuf);
        Log(("NetIfList: socket() -> %d\n", errno));
        return RTErrConvertFromErrno(errno);
    }

    char *pEnd = pBuf + cbNeeded;
    for (pNext = pBuf; pNext < pEnd;)
    {
        struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;

        if (pIfMsg->ifm_type != RTM_IFINFO)
        {
            Log(("NetIfList: Got message %u while expecting %u.\n",
                 pIfMsg->ifm_type, RTM_IFINFO));
            rc = VERR_INTERNAL_ERROR;
            break;
        }
        struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);

        size_t cbNameLen = pSdl->sdl_nlen + 1;
        PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
        if (!pNew)
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8));
        pNew->enmMediumType = NETIF_T_ETHERNET;
        Assert(sizeof(pNew->szShortName) >= cbNameLen);
        strlcpy(pNew->szShortName, pSdl->sdl_data, cbNameLen);
        strlcpy(pNew->szName, pSdl->sdl_data, cbNameLen);
        /* Generate UUID from name and MAC address. */
        RTUUID uuid;
        RTUuidClear(&uuid);
        memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
        uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
        uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
        memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node));
        pNew->Uuid = uuid;

        pNext += pIfMsg->ifm_msglen;
        while (pNext < pEnd)
        {
            struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;

            if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
                break;
            extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
                                      (char *)(pIfAddrMsg + 1),
                                      pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
                                      pNew);
            pNext += pIfAddrMsg->ifam_msglen;
        }

        if (pSdl->sdl_type == IFT_ETHER || pSdl->sdl_type == IFT_L2VLAN)
        {
            struct ifreq IfReq;
            strcpy(IfReq.ifr_name, pNew->szShortName);
            if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
            {
                Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
                pNew->enmStatus = NETIF_S_UNKNOWN;
            }
            else
                pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;

            HostNetworkInterfaceType_T enmType;
            if (strncmp("vboxnet", pNew->szName, 7))
                enmType = HostNetworkInterfaceType_Bridged;
            else
                enmType = HostNetworkInterfaceType_HostOnly;

            ComObjPtr<HostNetworkInterface> IfObj;
            IfObj.createObject();
            if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew)))
                /* Make sure the default interface gets to the beginning. */
                if (   fDefaultIfaceExistent
                    && pIfMsg->ifm_index == u16DefaultIface)
                    list.push_front(IfObj);
                else
                    list.push_back(IfObj);
        }
        RTMemFree(pNew);
    }

    close(sock);
    free(pBuf);
    return rc;


}
Exemplo n.º 2
0
int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVirtualBox,
                                        IHostNetworkInterface **aHostNetworkInterface,
                                        IProgress **aProgress,
                                        const char *pcszName)
{
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    /* create a progress object */
    ComObjPtr<Progress> progress;
    progress.createObject();

    ComPtr<IHost> host;
    HRESULT hrc = pVirtualBox->COMGETTER(Host)(host.asOutParam());
    if (SUCCEEDED(hrc))
    {
        hrc = progress->init(pVirtualBox, host,
                             Bstr("Creating host only network interface").raw(),
                             FALSE /* aCancelable */);
        if (SUCCEEDED(hrc))
        {
            progress.queryInterfaceTo(aProgress);

            char szAdpCtl[RTPATH_MAX];
            int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " add"));
            if (RT_FAILURE(rc))
            {
                progress->i_notifyComplete(E_FAIL,
                                           COM_IIDOF(IHostNetworkInterface),
                                           HostNetworkInterface::getStaticComponentName(),
                                           "Failed to get program path, rc=%Rrc\n", rc);
                return rc;
            }
            strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME " ");
            if (pcszName && strlen(pcszName) <= RTPATH_MAX - strlen(szAdpCtl) - sizeof(" add"))
            {
                strcat(szAdpCtl, pcszName);
                strcat(szAdpCtl, " add");
            }
            else
                strcat(szAdpCtl, "add");
            if (strlen(szAdpCtl) < RTPATH_MAX - sizeof(" 2>&1"))
                strcat(szAdpCtl, " 2>&1");
            FILE *fp = popen(szAdpCtl, "r");

            if (fp)
            {
                char szBuf[128]; /* We are not interested in long error messages. */
                if (fgets(szBuf, sizeof(szBuf), fp))
                {
                    /* Remove trailing new line characters. */
                    char *pLast = szBuf + strlen(szBuf) - 1;
                    if (pLast >= szBuf && *pLast == '\n')
                        *pLast = 0;

                    if (!strncmp(VBOXNETADPCTL_NAME ":", szBuf, sizeof(VBOXNETADPCTL_NAME)))
                    {
                        progress->i_notifyComplete(E_FAIL,
                                                   COM_IIDOF(IHostNetworkInterface),
                                                   HostNetworkInterface::getStaticComponentName(),
                                                   "%s", szBuf);
                        pclose(fp);
                        return E_FAIL;
                    }

                    size_t cbNameLen = strlen(szBuf) + 1;
                    PNETIFINFO pInfo = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
                    if (!pInfo)
                        rc = VERR_NO_MEMORY;
                    else
                    {
                        strcpy(pInfo->szShortName, szBuf);
                        strcpy(pInfo->szName, szBuf);
                        rc = NetIfGetConfigByName(pInfo);
                        if (RT_FAILURE(rc))
                        {
                            progress->i_notifyComplete(E_FAIL,
                                                       COM_IIDOF(IHostNetworkInterface),
                                                       HostNetworkInterface::getStaticComponentName(),
                                                       "Failed to get config info for %s (as reported by '" VBOXNETADPCTL_NAME " add')\n", szBuf);
                        }
                        else
                        {
                            Bstr IfName(szBuf);
                            /* create a new uninitialized host interface object */
                            ComObjPtr<HostNetworkInterface> iface;
                            iface.createObject();
                            iface->init(IfName, HostNetworkInterfaceType_HostOnly, pInfo);
                            iface->i_setVirtualBox(pVirtualBox);
                            iface.queryInterfaceTo(aHostNetworkInterface);
                        }
                        RTMemFree(pInfo);
                    }
                    if ((rc = pclose(fp)) != 0)
                    {
                        progress->i_notifyComplete(E_FAIL,
                                                   COM_IIDOF(IHostNetworkInterface),
                                                   HostNetworkInterface::getStaticComponentName(),
                                                   "Failed to execute '" VBOXNETADPCTL_NAME " add' (exit status: %d)", rc);
                        rc = VERR_INTERNAL_ERROR;
                    }
                }
                else
                {
                    /* Failed to add an interface */
                    rc = VERR_PERMISSION_DENIED;
                    progress->i_notifyComplete(E_FAIL,
                                               COM_IIDOF(IHostNetworkInterface),
                                               HostNetworkInterface::getStaticComponentName(),
                                               "Failed to execute '" VBOXNETADPCTL_NAME " add' (exit status: %d). Check permissions!", rc);
                    pclose(fp);
                }
            }
            if (RT_SUCCESS(rc))
                progress->i_notifyComplete(rc);
            else
                hrc = E_FAIL;
        }
    }

    return hrc;

#else
    NOREF(pVirtualBox);
    NOREF(aHostNetworkInterface);
    NOREF(aProgress);
    NOREF(pcszName);
    return VERR_NOT_IMPLEMENTED;
#endif
}
Exemplo n.º 3
0
static RTEXITCODE watchdogMain(HandlerArg *a)
{
    HRESULT rc = S_OK;

    do
    {
        /* Initialize global weak references. */
        g_pEventQ = com::NativeEventQueue::getMainEventQueue();

        /*
         * Install signal handlers.
         */
        signal(SIGINT,   signalHandler);
    #ifdef SIGBREAK
        signal(SIGBREAK, signalHandler);
    #endif

        /*
         * Setup the global event listeners:
         * - g_pEventSource for machine events
         * - g_pEventSourceClient for VBoxClient events (like VBoxSVC handling)
         */
        CHECK_ERROR_BREAK(g_pVirtualBox, COMGETTER(EventSource)(g_pEventSource.asOutParam()));
        CHECK_ERROR_BREAK(g_pVirtualBoxClient, COMGETTER(EventSource)(g_pEventSourceClient.asOutParam()));

        ComObjPtr<VirtualBoxEventListenerImpl> vboxListenerImpl;
        vboxListenerImpl.createObject();
        vboxListenerImpl->init(new VirtualBoxEventListener());

        com::SafeArray<VBoxEventType_T> eventTypes;
        eventTypes.push_back(VBoxEventType_OnMachineRegistered);
        eventTypes.push_back(VBoxEventType_OnMachineStateChanged);
        eventTypes.push_back(VBoxEventType_OnVBoxSVCAvailabilityChanged); /* Processed by g_pEventSourceClient. */

        g_pVBoxEventListener = vboxListenerImpl;
        CHECK_ERROR_BREAK(g_pEventSource, RegisterListener(g_pVBoxEventListener, ComSafeArrayAsInParam(eventTypes), true /* Active listener */));
        CHECK_ERROR_BREAK(g_pEventSourceClient, RegisterListener(g_pVBoxEventListener, ComSafeArrayAsInParam(eventTypes), true /* Active listener */));

        /*
         * Set up modules.
         */
        int vrc = watchdogStartModules();
        if (RT_FAILURE(vrc))
            break;

        for (;;)
        {
            /*
             * Do the actual work.
             */

            vrc = RTCritSectEnter(&g_csMachines);
            if (RT_SUCCESS(vrc))
            {
                for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++)
                    if (g_aModules[j].fEnabled)
                    {
                        int rc2 = g_aModules[j].pDesc->pfnMain();
                        if (RT_FAILURE(rc2))
                            serviceLog("Module '%s' reported an error: %Rrc\n",
                                       g_aModules[j].pDesc->pszName, rc2);
                        /* Keep going. */
                    }

                int rc2 = RTCritSectLeave(&g_csMachines);
                if (RT_SUCCESS(vrc))
                    vrc = rc2;
                AssertRC(vrc);
            }

            /*
             * Process pending events, then wait for new ones. Note, this
             * processes NULL events signalling event loop termination.
             */
            g_pEventQ->processEventQueue(50);

            if (g_fCanceled)
            {
                serviceLog("Signal caught, exiting ...\n");
                break;
            }
        }

        signal(SIGINT,   SIG_DFL);
    #ifdef SIGBREAK
        signal(SIGBREAK, SIG_DFL);
    #endif

        /* VirtualBox callback unregistration. */
        if (g_pVBoxEventListener)
        {
            if (!g_pEventSource.isNull())
                CHECK_ERROR(g_pEventSource, UnregisterListener(g_pVBoxEventListener));
            g_pVBoxEventListener.setNull();
        }

        g_pEventSource.setNull();
        g_pEventSourceClient.setNull();

        vrc = watchdogShutdownModules();
        AssertRC(vrc);

        if (RT_FAILURE(vrc))
            rc = VBOX_E_IPRT_ERROR;

    } while (0);

    return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
/**
 * Creates a new guest session.
 * This will invoke VBoxService running on the guest creating a new (dedicated) guest session
 * On older Guest Additions this call has no effect on the guest, and only the credentials will be
 * used for starting/impersonating guest processes.
 *
 * @returns VBox status code.
 * @param   ssInfo              Guest session startup information.
 * @param   guestCreds          Guest OS (user) credentials to use on the guest for creating the session.
 *                              The specified user must be able to logon to the guest and able to start new processes.
 * @param   pGuestSession       Where to store the created guest session on success.
 */
int Guest::i_sessionCreate(const GuestSessionStartupInfo &ssInfo,
                           const GuestCredentials &guestCreds, ComObjPtr<GuestSession> &pGuestSession)
{
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    int rc = VERR_MAX_PROCS_REACHED;
    if (mData.mGuestSessions.size() >= VBOX_GUESTCTRL_MAX_SESSIONS)
        return rc;

    try
    {
        /* Create a new session ID and assign it. */
        uint32_t uNewSessionID = VBOX_GUESTCTRL_SESSION_ID_BASE;
        uint32_t uTries = 0;

        for (;;)
        {
            /* Is the context ID already used? */
            if (!i_sessionExists(uNewSessionID))
            {
                rc = VINF_SUCCESS;
                break;
            }
            uNewSessionID++;
            if (uNewSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS)
                uNewSessionID = VBOX_GUESTCTRL_SESSION_ID_BASE;

            if (++uTries == VBOX_GUESTCTRL_MAX_SESSIONS)
                break; /* Don't try too hard. */
        }
        if (RT_FAILURE(rc)) throw rc;

        /* Create the session object. */
        HRESULT hr = pGuestSession.createObject();
        if (FAILED(hr)) throw VERR_COM_UNEXPECTED;

        /** @todo Use an overloaded copy operator. Later. */
        GuestSessionStartupInfo startupInfo;
        startupInfo.mID = uNewSessionID; /* Assign new session ID. */
        startupInfo.mName = ssInfo.mName;
        startupInfo.mOpenFlags = ssInfo.mOpenFlags;
        startupInfo.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;

        GuestCredentials guestCredentials;
        if (!guestCreds.mUser.isEmpty())
        {
            /** @todo Use an overloaded copy operator. Later. */
            guestCredentials.mUser = guestCreds.mUser;
            guestCredentials.mPassword = guestCreds.mPassword;
            guestCredentials.mDomain = guestCreds.mDomain;
        }
        else
        {
            /* Internal (annonymous) session. */
            startupInfo.mIsInternal = true;
        }

        rc = pGuestSession->init(this, startupInfo, guestCredentials);
        if (RT_FAILURE(rc)) throw rc;

        /*
         * Add session object to our session map. This is necessary
         * before calling openSession because the guest calls back
         * with the creation result of this session.
         */
        mData.mGuestSessions[uNewSessionID] = pGuestSession;

        alock.release(); /* Release lock before firing off event. */

        fireGuestSessionRegisteredEvent(mEventSource, pGuestSession,
                                        true /* Registered */);
    }
    catch (int rc2)
    {
        rc = rc2;
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Exemplo n.º 5
0
/**
 * Initializes the system information object.
 *
 * @returns COM result indicator
 */
HRESULT SystemProperties::init(VirtualBox *aParent)
{
    LogFlowThisFunc(("aParent=%p\n", aParent));

    ComAssertRet(aParent, E_FAIL);

    /* Enclose the state transition NotReady->InInit->Ready */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), E_FAIL);

    unconst(mParent) = aParent;

    i_setDefaultMachineFolder(Utf8Str::Empty);
    i_setLoggingLevel(Utf8Str::Empty);
    i_setDefaultHardDiskFormat(Utf8Str::Empty);

    i_setVRDEAuthLibrary(Utf8Str::Empty);
    i_setDefaultVRDEExtPack(Utf8Str::Empty);

    m->ulLogHistoryCount = 3;


    /* On Windows and OS X, HW virtualization use isn't exclusive by
     * default so that VT-x or AMD-V can be shared with other
     * hypervisors without requiring user intervention.
     * NB: See also SystemProperties constructor in settings.h
     */
#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
    m->fExclusiveHwVirt = false;
#else
    m->fExclusiveHwVirt = true;
#endif

    HRESULT rc = S_OK;

    /* Fetch info of all available hd backends. */

    /// @todo NEWMEDIA VDBackendInfo needs to be improved to let us enumerate
    /// any number of backends

    VDBACKENDINFO aVDInfo[100];
    unsigned cEntries;
    int vrc = VDBackendInfo(RT_ELEMENTS(aVDInfo), aVDInfo, &cEntries);
    AssertRC(vrc);
    if (RT_SUCCESS(vrc))
    {
        for (unsigned i = 0; i < cEntries; ++ i)
        {
            ComObjPtr<MediumFormat> hdf;
            rc = hdf.createObject();
            if (FAILED(rc)) break;

            rc = hdf->init(&aVDInfo[i]);
            if (FAILED(rc)) break;

            m_llMediumFormats.push_back(hdf);
        }
    }

    /* Confirm a successful initialization */
    if (SUCCEEDED(rc))
        autoInitSpan.setSucceeded();

    return rc;
}
Exemplo n.º 6
0
int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
{
    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock < 0)
    {
        Log(("NetIfList: socket() -> %d\n", errno));
        return NULL;
    }
    struct ifaddrs *IfAddrs, *pAddr;
    int rc = getifaddrs(&IfAddrs);
    if (rc)
    {
        close(sock);
        Log(("NetIfList: getifaddrs() -> %d\n", rc));
        return VERR_INTERNAL_ERROR;
    }

    PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
    while (pEtherNICs)
    {
        size_t cbNameLen = strlen(pEtherNICs->szName) + 1;
        PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
        pNew->MACAddress = pEtherNICs->Mac;
        pNew->enmMediumType = NETIF_T_ETHERNET;
        pNew->Uuid = pEtherNICs->Uuid;
        Assert(sizeof(pNew->szShortName) > sizeof(pEtherNICs->szBSDName));
        memcpy(pNew->szShortName, pEtherNICs->szBSDName, sizeof(pEtherNICs->szBSDName));
        pNew->szShortName[sizeof(pEtherNICs->szBSDName)] = '\0';
        memcpy(pNew->szName, pEtherNICs->szName, cbNameLen);

        struct ifreq IfReq;
        strcpy(IfReq.ifr_name, pNew->szShortName);
        if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
        {
            Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
            pNew->enmStatus = NETIF_S_UNKNOWN;
        }
        else
            pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;

        for (pAddr = IfAddrs; pAddr != NULL; pAddr = pAddr->ifa_next)
        {
            if (strcmp(pNew->szShortName, pAddr->ifa_name))
                continue;

            struct sockaddr_in *pIPAddr, *pIPNetMask;
            struct sockaddr_in6 *pIPv6Addr, *pIPv6NetMask;

            switch (pAddr->ifa_addr->sa_family)
            {
                case AF_INET:
                    if (pNew->IPAddress.u)
                        break;
                    pIPAddr = (struct sockaddr_in *)pAddr->ifa_addr;
                    Assert(sizeof(pNew->IPAddress) == sizeof(pIPAddr->sin_addr));
                    pNew->IPAddress.u = pIPAddr->sin_addr.s_addr;
                    pIPNetMask = (struct sockaddr_in *)pAddr->ifa_netmask;
                    Assert(pIPNetMask->sin_family == AF_INET);
                    Assert(sizeof(pNew->IPNetMask) == sizeof(pIPNetMask->sin_addr));
                    pNew->IPNetMask.u = pIPNetMask->sin_addr.s_addr;
                    break;
                case AF_INET6:
                    if (pNew->IPv6Address.s.Lo || pNew->IPv6Address.s.Hi)
                        break;
                    pIPv6Addr = (struct sockaddr_in6 *)pAddr->ifa_addr;
                    Assert(sizeof(pNew->IPv6Address) == sizeof(pIPv6Addr->sin6_addr));
                    memcpy(pNew->IPv6Address.au8,
                           pIPv6Addr->sin6_addr.__u6_addr.__u6_addr8,
                           sizeof(pNew->IPv6Address));
                    pIPv6NetMask = (struct sockaddr_in6 *)pAddr->ifa_netmask;
                    Assert(pIPv6NetMask->sin6_family == AF_INET6);
                    Assert(sizeof(pNew->IPv6NetMask) == sizeof(pIPv6NetMask->sin6_addr));
                    memcpy(pNew->IPv6NetMask.au8,
                           pIPv6NetMask->sin6_addr.__u6_addr.__u6_addr8,
                           sizeof(pNew->IPv6NetMask));
                    break;
            }
        }

        ComObjPtr<HostNetworkInterface> IfObj;
        IfObj.createObject();
        if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), HostNetworkInterfaceType_Bridged, pNew)))
            list.push_back(IfObj);
        RTMemFree(pNew);

        /* next, free current */
        void *pvFree = pEtherNICs;
        pEtherNICs = pEtherNICs->pNext;
        RTMemFree(pvFree);
    }

    freeifaddrs(IfAddrs);
    close(sock);
    return VINF_SUCCESS;
}
Exemplo n.º 7
0
/**
 *  @note Locks this object for writing, together with the peer object (also
 *  for writing) if there is one.
 */
void USBDeviceFilters::i_commit()
{
    /* sanity */
    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    /* sanity too */
    AutoCaller peerCaller(m->pPeer);
    AssertComRCReturnVoid(peerCaller.rc());

    /* lock both for writing since we modify both (mPeer is "master" so locked
     * first) */
    AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);

#ifdef VBOX_WITH_USB
    bool commitFilters = false;

    if (m->llDeviceFilters.isBackedUp())
    {
        m->llDeviceFilters.commit();

        /* apply changes to peer */
        if (m->pPeer)
        {
            AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);

            /* commit all changes to new filters (this will reshare data with
             * peers for those who have peers) */
            DeviceFilterList *newList = new DeviceFilterList();
            DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
            while (it != m->llDeviceFilters->end())
            {
                (*it)->i_commit();

                /* look if this filter has a peer filter */
                ComObjPtr<USBDeviceFilter> peer = (*it)->i_peer();
                if (!peer)
                {
                    /* no peer means the filter is a newly created one;
                     * create a peer owning data this filter share it with */
                    peer.createObject();
                    peer->init(m->pPeer, *it, true /* aReshare */);
                }
                else
                {
                    /* remove peer from the old list */
                    m->pPeer->m->llDeviceFilters->remove(peer);
                }
                /* and add it to the new list */
                newList->push_back(peer);

                ++it;
            }

            /* uninit old peer's filters that are left */
            it = m->pPeer->m->llDeviceFilters->begin();
            while (it != m->pPeer->m->llDeviceFilters->end())
            {
                (*it)->uninit();
                ++it;
            }

            /* attach new list of filters to our peer */
            m->pPeer->m->llDeviceFilters.attach(newList);
        }
        else
        {
            /* we have no peer (our parent is the newly created machine);
             * just commit changes to filters */
            commitFilters = true;
        }
    }
    else
    {
        /* the list of filters itself is not changed,
         * just commit changes to filters themselves */
        commitFilters = true;
    }

    if (commitFilters)
    {
        DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
        while (it != m->llDeviceFilters->end())
        {
            (*it)->i_commit();
            ++it;
        }
    }
#endif /* VBOX_WITH_USB */
}
/**
 * Process any relevant changes in the attached USB devices.
 *
 * Except for the first call, this is always running on the service thread.
 */
void USBProxyService::processChanges(void)
{
    LogFlowThisFunc(("\n"));

    /*
     * Get the sorted list of USB devices.
     */
    PUSBDEVICE pDevices = getDevices();
    pDevices = sortDevices(pDevices);

    // get a list of all running machines while we're outside the lock
    // (getOpenedMachines requests higher priority locks)
    SessionMachinesList llOpenedMachines;
    mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    /*
     * Compare previous list with the new list of devices
     * and merge in any changes while notifying Host.
     */
    HostUSBDeviceList::iterator it = this->mDevices.begin();
    while (    it != mDevices.end()
            || pDevices)
    {
        ComObjPtr<HostUSBDevice> pHostDevice;

        if (it != mDevices.end())
            pHostDevice = *it;

        /*
         * Assert that the object is still alive (we still reference it in
         * the collection and we're the only one who calls uninit() on it.
         */
        AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
        AssertComRC(devCaller.rc());

        /*
         * Lock the device object since we will read/write its
         * properties. All Host callbacks also imply the object is locked.
         */
        AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
                              COMMA_LOCKVAL_SRC_POS);

        /*
         * Compare.
         */
        int iDiff;
        if (pHostDevice.isNull())
            iDiff = 1;
        else
        {
            if (!pDevices)
                iDiff = -1;
            else
                iDiff = pHostDevice->i_compare(pDevices);
        }
        if (!iDiff)
        {
            /*
             * The device still there, update the state and move on. The PUSBDEVICE
             * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
             */
            PUSBDEVICE pCur = pDevices;
            pDevices = pDevices->pNext;
            pCur->pPrev = pCur->pNext = NULL;

            bool fRunFilters = false;
            SessionMachine *pIgnoreMachine = NULL;
            devLock.release();
            alock.release();
            if (updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
                deviceChanged(pHostDevice,
                              (fRunFilters ? &llOpenedMachines : NULL),
                              pIgnoreMachine);
            alock.acquire();
            ++it;
        }
        else
        {
            if (iDiff > 0)
            {
                /*
                 * Head of pDevices was attached.
                 */
                PUSBDEVICE pNew = pDevices;
                pDevices = pDevices->pNext;
                pNew->pPrev = pNew->pNext = NULL;

                ComObjPtr<HostUSBDevice> NewObj;
                NewObj.createObject();
                NewObj->init(pNew, this);
                Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
                     (HostUSBDevice *)NewObj,
                     NewObj->i_getName().c_str(),
                     NewObj->i_getStateName(),
                     pNew,
                     pNew->idVendor,
                     pNew->idProduct,
                     pNew->pszProduct,
                     pNew->pszManufacturer));

                mDevices.insert(it, NewObj);

                devLock.release();
                alock.release();
                deviceAdded(NewObj, llOpenedMachines, pNew);
                alock.acquire();
            }
            else
            {
                /*
                 * Check if the device was actually detached or logically detached
                 * as the result of a re-enumeration.
                 */
                if (!pHostDevice->i_wasActuallyDetached())
                    ++it;
                else
                {
                    it = mDevices.erase(it);
                    devLock.release();
                    alock.release();
                    deviceRemoved(pHostDevice);
                    Log(("USBProxyService::processChanges: detached %p {%s}\n",
                         (HostUSBDevice *)pHostDevice,
                         pHostDevice->i_getName().c_str()));

                    /* from now on, the object is no more valid,
                     * uninitialize to avoid abuse */
                    devCaller.release();
                    pHostDevice->uninit();
                    alock.acquire();
                }
            }
        }
    } /* while */

    LogFlowThisFunc(("returns void\n"));
}
Exemplo n.º 9
0
STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo)
{
#ifndef VBOX_WITH_GUEST_CONTROL
    ReturnComNotImplemented();
#else
    LogFlowThisFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    GuestProcessStreamBlock curBlock;
    int guestRc;

    int rc = mData.mProcessTool.WaitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK,
                                       &curBlock, &guestRc);

    /*
     * Note: The guest process can still be around to serve the next
     *       upcoming stream block next time.
     */
    if (   RT_SUCCESS(rc)
        && !mData.mProcessTool.IsRunning())
    {
        rc = mData.mProcessTool.TerminatedOk(NULL /* Exit code */);
        if (rc == VERR_NOT_EQUAL)
            rc = VERR_ACCESS_DENIED;
    }

    if (RT_SUCCESS(rc))
    {
        if (curBlock.GetCount()) /* Did we get content? */
        {
            GuestFsObjData objData;
            rc = objData.FromLs(curBlock);
            if (RT_FAILURE(rc))
                rc = VERR_PATH_NOT_FOUND;

            if (RT_SUCCESS(rc))
            {
                /* Create the object. */
                ComObjPtr<GuestFsObjInfo> pFsObjInfo;
                HRESULT hr2 = pFsObjInfo.createObject();
                if (FAILED(hr2))
                    rc = VERR_COM_UNEXPECTED;

                if (RT_SUCCESS(rc))
                    rc = pFsObjInfo->init(objData);

                if (RT_SUCCESS(rc))
                {
                    /* Return info object to the caller. */
                    hr2 = pFsObjInfo.queryInterfaceTo(aInfo);
                    if (FAILED(hr2))
                        rc = VERR_COM_UNEXPECTED;
                }
            }
        }
        else
        {
            /* Nothing to read anymore. Tell the caller. */
            rc = VERR_NO_MORE_FILES;
        }
    }

    HRESULT hr = S_OK;

    if (RT_FAILURE(rc)) /** @todo Add more errors here. */
    {
        switch (rc)
        {
            case VERR_GSTCTL_GUEST_ERROR:
                hr = GuestProcess::setErrorExternal(this, guestRc);
                break;

            case VERR_ACCESS_DENIED:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
                              mData.mName.c_str());
                break;

            case VERR_PATH_NOT_FOUND:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
                              mData.mName.c_str());
                break;

            case VERR_NO_MORE_FILES:
                /* See SDK reference. */
                hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
                              mData.mName.c_str());
                break;

            default:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
                              mData.mName.c_str(), rc);
                break;
        }
    }

    LogFlowFuncLeaveRC(rc);
    return hr;
#endif /* VBOX_WITH_GUEST_CONTROL */
}
/**
 * Start teleporter to the specified target.
 *
 * @returns COM status code.
 *
 * @param   aHostname       The name of the target host.
 * @param   aPort           The TCP port number.
 * @param   aPassword       The password.
 * @param   aMaxDowntime    Max allowed "downtime" in milliseconds.
 * @param   aProgress       Where to return the progress object.
 */
STDMETHODIMP
Console::Teleport(IN_BSTR aHostname, ULONG aPort, IN_BSTR aPassword, ULONG aMaxDowntime, IProgress **aProgress)
{
    /*
     * Validate parameters, check+hold object status, write lock the object
     * and validate the state.
     */
    CheckComArgOutPointerValid(aProgress);
    CheckComArgStrNotEmptyOrNull(aHostname);
    CheckComArgStrNotEmptyOrNull(aPassword);
    CheckComArgExprMsg(aPort, aPort > 0 && aPort <= 65535, ("is %u", aPort));
    CheckComArgExprMsg(aMaxDowntime, aMaxDowntime > 0, ("is %u", aMaxDowntime));

    Utf8Str strPassword(aPassword);
    if (!strPassword.isEmpty())
    {
        if (VBoxIsPasswordHashed(&strPassword))
            return setError(E_INVALIDARG, tr("The specified password resembles a hashed password, expected plain text"));
        VBoxHashPassword(&strPassword);
    }

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
    LogFlowThisFunc(("mMachineState=%d\n", mMachineState));

    switch (mMachineState)
    {
    case MachineState_Running:
    case MachineState_Paused:
        break;

    default:
        return setError(VBOX_E_INVALID_VM_STATE,
                        tr("Invalid machine state: %s (must be Running or Paused)"),
                        Global::stringifyMachineState(mMachineState));
    }


    /*
     * Create a progress object, spawn a worker thread and change the state.
     * Note! The thread won't start working until we release the lock.
     */
    LogFlowThisFunc(("Initiating TELEPORT request...\n"));

    ComObjPtr<Progress> ptrProgress;
    HRESULT hrc = ptrProgress.createObject();
    if (SUCCEEDED(hrc))
        hrc = ptrProgress->init(static_cast<IConsole *>(this),
                                Bstr(tr("Teleporter")).raw(),
                                TRUE /*aCancelable*/);
    if (FAILED(hrc))
        return hrc;

    TeleporterStateSrc *pState = new TeleporterStateSrc(this, mpUVM, ptrProgress, mMachineState);
    pState->mstrPassword    = strPassword;
    pState->mstrHostname    = aHostname;
    pState->muPort          = aPort;
    pState->mcMsMaxDowntime = aMaxDowntime;

    void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(pState));
    ptrProgress->setCancelCallback(teleporterProgressCancelCallback, pvUser);

    int vrc = RTThreadCreate(NULL, Console::teleporterSrcThreadWrapper, (void *)pState, 0 /*cbStack*/,
                             RTTHREADTYPE_EMULATION, 0 /*fFlags*/, "Teleport");
    if (RT_SUCCESS(vrc))
    {
        if (mMachineState == MachineState_Running)
            hrc = setMachineState(MachineState_Teleporting);
        else
            hrc = setMachineState(MachineState_TeleportingPausedVM);
        if (SUCCEEDED(hrc))
        {
            ptrProgress.queryInterfaceTo(aProgress);
            mptrCancelableProgress = ptrProgress;
        }
        else
            ptrProgress->Cancel();
    }
    else
    {
        ptrProgress->setCancelCallback(NULL, NULL);
        delete pState;
        hrc = setError(E_FAIL, tr("RTThreadCreate -> %Rrc"), vrc);
    }

    return hrc;
}
Exemplo n.º 11
0
UIConsoleEventHandler::UIConsoleEventHandler(UISession *pSession)
  : m_pSession(pSession)
{
    Assert(pSession);

//    RTPrintf("Self add: %RTthrd\n", RTThreadSelf());
    ComObjPtr<UIMainEventListenerImpl> pListener;
    pListener.createObject();
    pListener->init(new UIMainEventListener(), this);
    m_mainEventListener = CEventListener(pListener);
    QVector<KVBoxEventType> events;
    events
        << KVBoxEventType_OnMousePointerShapeChanged
        << KVBoxEventType_OnMouseCapabilityChanged
        << KVBoxEventType_OnKeyboardLedsChanged
        << KVBoxEventType_OnStateChanged
        << KVBoxEventType_OnAdditionsStateChanged
        << KVBoxEventType_OnNetworkAdapterChanged
        << KVBoxEventType_OnMediumChanged
        << KVBoxEventType_OnVRDEServerChanged
        << KVBoxEventType_OnVRDEServerInfoChanged
        << KVBoxEventType_OnUSBControllerChanged
        << KVBoxEventType_OnUSBDeviceStateChanged
        << KVBoxEventType_OnSharedFolderChanged
        << KVBoxEventType_OnRuntimeError
        << KVBoxEventType_OnCanShowWindow
        << KVBoxEventType_OnShowWindow
        << KVBoxEventType_OnCPUExecutionCapChanged
        << KVBoxEventType_OnGuestMonitorChanged;

    const CConsole &console = m_pSession->session().GetConsole();
    console.GetEventSource().RegisterListener(m_mainEventListener, events, TRUE);
    AssertWrapperOk(console);

    connect(pListener->getWrapped(), SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
            this, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigMouseCapabilityChange(bool, bool, bool)),
            this, SIGNAL(sigMouseCapabilityChange(bool, bool, bool)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
            this, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigStateChange(KMachineState)),
            this, SIGNAL(sigStateChange(KMachineState)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigAdditionsChange()),
            this, SIGNAL(sigAdditionsChange()),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
            this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigMediumChange(CMediumAttachment)),
            this, SIGNAL(sigMediumChange(CMediumAttachment)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigVRDEChange()),
            this, SIGNAL(sigVRDEChange()),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigUSBControllerChange()),
            this, SIGNAL(sigUSBControllerChange()),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
            this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigSharedFolderChange()),
            this, SIGNAL(sigSharedFolderChange()),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigRuntimeError(bool, QString, QString)),
            this, SIGNAL(sigRuntimeError(bool, QString, QString)),
            Qt::QueuedConnection);

    /* This is a vetoable event, so we have to respond to the event and have to
     * use a direct connection therefor. */
    connect(pListener->getWrapped(), SIGNAL(sigCanShowWindow(bool&, QString&)),
            this, SLOT(sltCanShowWindow(bool&, QString&)),
            Qt::DirectConnection);

    /* This returns a winId, so we have to respond to the event and have to use
     * a direct connection therefor. */
    connect(pListener->getWrapped(), SIGNAL(sigShowWindow(LONG64&)),
            this, SLOT(sltShowWindow(LONG64&)),
            Qt::DirectConnection);

    connect(pListener->getWrapped(), SIGNAL(sigCPUExecutionCapChange()),
            this, SIGNAL(sigCPUExecutionCapChange()),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
            this, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
            Qt::QueuedConnection);
}
Exemplo n.º 12
0
/**
 * Initializes a file object but does *not* open the file on the guest
 * yet. This is done in the dedidcated openFile call.
 *
 * @return  IPRT status code.
 * @param   pConsole                Pointer to console object.
 * @param   pSession                Pointer to session object.
 * @param   uFileID                 Host-based file ID (part of the context ID).
 * @param   openInfo                File opening information.
 */
int GuestFile::init(Console *pConsole, GuestSession *pSession,
                    ULONG uFileID, const GuestFileOpenInfo &openInfo)
{
    LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
                     pConsole, pSession, uFileID, openInfo.mFileName.c_str()));

    AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
    AssertPtrReturn(pSession, VERR_INVALID_POINTER);

    /* Enclose the state transition NotReady->InInit->Ready. */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);

#ifndef VBOX_WITH_GUEST_CONTROL
    autoInitSpan.setSucceeded();
    return VINF_SUCCESS;
#else
    int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
    if (RT_SUCCESS(vrc))
    {
        mSession = pSession;

        mData.mID = uFileID;
        mData.mInitialSize = 0;
        mData.mStatus = FileStatus_Undefined;
        mData.mOpenInfo = openInfo;

        unconst(mEventSource).createObject();
        HRESULT hr = mEventSource->init();
        if (FAILED(hr))
            vrc = VERR_COM_UNEXPECTED;
    }

    if (RT_SUCCESS(vrc))
    {
        try
        {
            GuestFileListener *pListener = new GuestFileListener();
            ComObjPtr<GuestFileListenerImpl> thisListener;
            HRESULT hr = thisListener.createObject();
            if (SUCCEEDED(hr))
                hr = thisListener->init(pListener, this);

            if (SUCCEEDED(hr))
            {
                com::SafeArray <VBoxEventType_T> eventTypes;
                eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
                eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
                eventTypes.push_back(VBoxEventType_OnGuestFileRead);
                eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
                hr = mEventSource->RegisterListener(thisListener,
                                                    ComSafeArrayAsInParam(eventTypes),
                                                    TRUE /* Active listener */);
                if (SUCCEEDED(hr))
                {
                    vrc = baseInit();
                    if (RT_SUCCESS(vrc))
                    {
                        mLocalListener = thisListener;
                    }
                }
                else
                    vrc = VERR_COM_UNEXPECTED;
            }
            else
                vrc = VERR_COM_UNEXPECTED;
        }
        catch(std::bad_alloc &)
        {
            vrc = VERR_NO_MEMORY;
        }
    }

    if (RT_SUCCESS(vrc))
    {
        /* Confirm a successful initialization when it's the case. */
        autoInitSpan.setSucceeded();
    }
    else
        autoInitSpan.setFailed();

    LogFlowFuncLeaveRC(vrc);
    return vrc;
#endif /* VBOX_WITH_GUEST_CONTROL */
}
STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo)
{
#ifndef VBOX_WITH_GUEST_CONTROL
    ReturnComNotImplemented();
#else
    LogFlowThisFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    ComObjPtr<GuestProcess> pProcess = mData.mProcess;
    Assert(!pProcess.isNull());

    GuestProcessStreamBlock streamBlock;
    GuestFsObjData objData;

    int rc = parseData(streamBlock);
    if (   RT_FAILURE(rc)
        || streamBlock.IsEmpty()) /* More data needed. */
    {
        rc = pProcess->waitForStart(30 * 1000 /* 30s timeout */);
    }

    if (RT_SUCCESS(rc))
    {
        BYTE byBuf[_64K];
        size_t cbRead = 0;

        /** @todo Merge with GuestSession::queryFileInfoInternal. */
        for (;RT_SUCCESS(rc);)
        {
            GuestProcessWaitResult waitRes;
            rc = pProcess->waitFor(  ProcessWaitForFlag_Terminate
                                   | ProcessWaitForFlag_StdOut,
                                   30 * 1000 /* Timeout */, waitRes);
            if (   RT_FAILURE(rc)
                || waitRes.mResult == ProcessWaitResult_Terminate
                || waitRes.mResult == ProcessWaitResult_Error
                || waitRes.mResult == ProcessWaitResult_Timeout)
            {
                if (RT_FAILURE(waitRes.mRC))
                    rc = waitRes.mRC;
                break;
            }

            rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
                                    30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
                                    &cbRead);
            if (RT_FAILURE(rc))
                break;

            if (cbRead)
            {
                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                rc = mData.mStream.AddData(byBuf, cbRead);
                if (RT_FAILURE(rc))
                    break;

                LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
                                 rc, cbRead, mData.mStream.GetSize()));

                rc = parseData(streamBlock);
                if (RT_SUCCESS(rc))
                {
                    /* Parsing the current stream block succeeded so
                     * we don't need more at the moment. */
                    break;
                }
            }
        }

        LogFlowThisFunc(("Reading done with rc=%Rrc, cbRead=%RU64, cbStream=%RU32\n",
                         rc, cbRead, mData.mStream.GetSize()));

        if (RT_SUCCESS(rc))
        {
            rc = parseData(streamBlock);
            if (rc == VERR_NO_DATA) /* Since this is the last parsing call, this is ok. */
                rc = VINF_SUCCESS;
        }

        /*
         * Note: The guest process can still be around to serve the next
         *       upcoming stream block next time.
         */
        if (RT_SUCCESS(rc))
        {
            /** @todo Move into common function. */
            ProcessStatus_T procStatus = ProcessStatus_Undefined;
            LONG exitCode = 0;

            HRESULT hr2 = pProcess->COMGETTER(Status(&procStatus));
            ComAssertComRC(hr2);
            hr2 = pProcess->COMGETTER(ExitCode(&exitCode));
            ComAssertComRC(hr2);

            if (   (   procStatus != ProcessStatus_Started
                    && procStatus != ProcessStatus_Paused
                    && procStatus != ProcessStatus_Terminating
                   )
                && exitCode != 0)
            {
                rc = VERR_ACCESS_DENIED;
            }
        }
    }

    if (RT_SUCCESS(rc))
    {
        if (streamBlock.GetCount()) /* Did we get content? */
        {
            rc = objData.FromLs(streamBlock);
            if (RT_FAILURE(rc))
                rc = VERR_PATH_NOT_FOUND;

            if (RT_SUCCESS(rc))
            {
                /* Create the object. */
                ComObjPtr<GuestFsObjInfo> pFsObjInfo;
                HRESULT hr2 = pFsObjInfo.createObject();
                if (FAILED(hr2))
                    rc = VERR_COM_UNEXPECTED;

                if (RT_SUCCESS(rc))
                    rc = pFsObjInfo->init(objData);

                if (RT_SUCCESS(rc))
                {
                    /* Return info object to the caller. */
                    hr2 = pFsObjInfo.queryInterfaceTo(aInfo);
                    if (FAILED(hr2))
                        rc = VERR_COM_UNEXPECTED;
                }
            }
        }
        else
        {
            /* Nothing to read anymore. Tell the caller. */
            rc = VERR_NO_MORE_FILES;
        }
    }

    HRESULT hr = S_OK;

    if (RT_FAILURE(rc)) /** @todo Add more errors here. */
    {
        switch (rc)
        {
            case VERR_ACCESS_DENIED:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
                              mData.mName.c_str());
                break;

            case VERR_PATH_NOT_FOUND:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
                              mData.mName.c_str());
                break;

            case VERR_NO_MORE_FILES:
                hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
                              mData.mName.c_str());
                break;

            default:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
                              mData.mName.c_str(), rc);
                break;
        }
    }

    LogFlowFuncLeaveRC(rc);
    return hr;
#endif /* VBOX_WITH_GUEST_CONTROL */
}
Exemplo n.º 14
0
/**
 *  Entry point.
 */
extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
{
    const char *vrdePort = NULL;
    const char *vrdeAddress = NULL;
    const char *vrdeEnabled = NULL;
    unsigned cVRDEProperties = 0;
    const char *aVRDEProperties[16];
#ifdef VBOX_WITH_VNC
    bool        fVNCEnable      = false;
    unsigned    uVNCPort        = 0;          /* default port */
    char const *pszVNCPassword  = NULL;       /* no password */
#endif
    unsigned fRawR0 = ~0U;
    unsigned fRawR3 = ~0U;
    unsigned fPATM  = ~0U;
    unsigned fCSAM  = ~0U;
#ifdef VBOX_FFMPEG
    unsigned fFFMPEG = 0;
    unsigned long ulFrameWidth = 800;
    unsigned long ulFrameHeight = 600;
    unsigned long ulBitRate = 300000;
    char pszMPEGFile[RTPATH_MAX];
    const char *pszFileNameParam = "VBox-%d.vob";
#endif /* VBOX_FFMPEG */

    LogFlow (("VBoxHeadless STARTED.\n"));
    RTPrintf (VBOX_PRODUCT " Headless Interface " VBOX_VERSION_STRING "\n"
              "(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
              "All rights reserved.\n\n");

#ifdef VBOX_FFMPEG
    /* Parse the environment */
    parse_environ(&ulFrameWidth, &ulFrameHeight, &ulBitRate, &pszFileNameParam);
#endif

    enum eHeadlessOptions
    {
        OPT_RAW_R0 = 0x100,
        OPT_NO_RAW_R0,
        OPT_RAW_R3,
        OPT_NO_RAW_R3,
        OPT_PATM,
        OPT_NO_PATM,
        OPT_CSAM,
        OPT_NO_CSAM,
        OPT_COMMENT
    };

    static const RTGETOPTDEF s_aOptions[] =
    {
        { "-startvm", 's', RTGETOPT_REQ_STRING },
        { "--startvm", 's', RTGETOPT_REQ_STRING },
        { "-vrdpport", 'p', RTGETOPT_REQ_STRING },     /* VRDE: deprecated. */
        { "--vrdpport", 'p', RTGETOPT_REQ_STRING },    /* VRDE: deprecated. */
        { "-vrdpaddress", 'a', RTGETOPT_REQ_STRING },  /* VRDE: deprecated. */
        { "--vrdpaddress", 'a', RTGETOPT_REQ_STRING }, /* VRDE: deprecated. */
        { "-vrdp", 'v', RTGETOPT_REQ_STRING },         /* VRDE: deprecated. */
        { "--vrdp", 'v', RTGETOPT_REQ_STRING },        /* VRDE: deprecated. */
        { "-vrde", 'v', RTGETOPT_REQ_STRING },
        { "--vrde", 'v', RTGETOPT_REQ_STRING },
        { "-vrdeproperty", 'e', RTGETOPT_REQ_STRING },
        { "--vrdeproperty", 'e', RTGETOPT_REQ_STRING },
#ifdef VBOX_WITH_VNC
        { "--vncport", 'm', RTGETOPT_REQ_INT32 },
        { "--vncpass", 'o', RTGETOPT_REQ_STRING },
        { "--vnc", 'n', 0 },
#endif /* VBOX_WITH_VNC */
        { "-rawr0", OPT_RAW_R0, 0 },
        { "--rawr0", OPT_RAW_R0, 0 },
        { "-norawr0", OPT_NO_RAW_R0, 0 },
        { "--norawr0", OPT_NO_RAW_R0, 0 },
        { "-rawr3", OPT_RAW_R3, 0 },
        { "--rawr3", OPT_RAW_R3, 0 },
        { "-norawr3", OPT_NO_RAW_R3, 0 },
        { "--norawr3", OPT_NO_RAW_R3, 0 },
        { "-patm", OPT_PATM, 0 },
        { "--patm", OPT_PATM, 0 },
        { "-nopatm", OPT_NO_PATM, 0 },
        { "--nopatm", OPT_NO_PATM, 0 },
        { "-csam", OPT_CSAM, 0 },
        { "--csam", OPT_CSAM, 0 },
        { "-nocsam", OPT_NO_CSAM, 0 },
        { "--nocsam", OPT_NO_CSAM, 0 },
#ifdef VBOX_FFMPEG
        { "-capture", 'c', 0 },
        { "--capture", 'c', 0 },
        { "--width", 'w', RTGETOPT_REQ_UINT32 },
        { "--height", 'h', RTGETOPT_REQ_UINT32 }, /* great choice of short option! */
        { "--bitrate", 'r', RTGETOPT_REQ_UINT32 },
        { "--filename", 'f', RTGETOPT_REQ_STRING },
#endif /* VBOX_FFMPEG defined */
        { "-comment", OPT_COMMENT, RTGETOPT_REQ_STRING },
        { "--comment", OPT_COMMENT, RTGETOPT_REQ_STRING }
    };

    const char *pcszNameOrUUID = NULL;

    // parse the command line
    int ch;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /* fFlags */);
    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch(ch)
        {
            case 's':
                pcszNameOrUUID = ValueUnion.psz;
                break;
            case 'p':
                RTPrintf("Warning: '-p' or '-vrdpport' are deprecated. Use '-e \"TCP/Ports=%s\"'\n", ValueUnion.psz);
                vrdePort = ValueUnion.psz;
                break;
            case 'a':
                RTPrintf("Warning: '-a' or '-vrdpaddress' are deprecated. Use '-e \"TCP/Address=%s\"'\n", ValueUnion.psz);
                vrdeAddress = ValueUnion.psz;
                break;
            case 'v':
                vrdeEnabled = ValueUnion.psz;
                break;
            case 'e':
                if (cVRDEProperties < RT_ELEMENTS(aVRDEProperties))
                    aVRDEProperties[cVRDEProperties++] = ValueUnion.psz;
                else
                     RTPrintf("Warning: too many VRDE properties. Ignored: '%s'\n", ValueUnion.psz);
                break;
#ifdef VBOX_WITH_VNC
            case 'n':
                fVNCEnable = true;
                break;
            case 'm':
                uVNCPort = ValueUnion.i32;
                break;
            case 'o':
                pszVNCPassword = ValueUnion.psz;
                break;
#endif /* VBOX_WITH_VNC */
            case OPT_RAW_R0:
                fRawR0 = true;
                break;
            case OPT_NO_RAW_R0:
                fRawR0 = false;
                break;
            case OPT_RAW_R3:
                fRawR3 = true;
                break;
            case OPT_NO_RAW_R3:
                fRawR3 = false;
                break;
            case OPT_PATM:
                fPATM = true;
                break;
            case OPT_NO_PATM:
                fPATM = false;
                break;
            case OPT_CSAM:
                fCSAM = true;
                break;
            case OPT_NO_CSAM:
                fCSAM = false;
                break;
#ifdef VBOX_FFMPEG
            case 'c':
                fFFMPEG = true;
                break;
            case 'w':
                ulFrameWidth = ValueUnion.u32;
                break;
            case 'r':
                ulBitRate = ValueUnion.u32;
                break;
            case 'f':
                pszFileNameParam = ValueUnion.psz;
                break;
#endif /* VBOX_FFMPEG defined */
            case 'h':
#ifdef VBOX_FFMPEG
                if ((GetState.pDef->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
                {
                    ulFrameHeight = ValueUnion.u32;
                    break;
                }
#endif
                show_usage();
                return 0;
            case OPT_COMMENT:
                /* nothing to do */
                break;
            case 'V':
                RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
                return 0;
            default:
                ch = RTGetOptPrintError(ch, &ValueUnion);
                show_usage();
                return ch;
        }
    }

#ifdef VBOX_FFMPEG
    if (ulFrameWidth < 512 || ulFrameWidth > 2048 || ulFrameWidth % 2)
    {
        LogError("VBoxHeadless: ERROR: please specify an even frame width between 512 and 2048", 0);
        return 1;
    }
    if (ulFrameHeight < 384 || ulFrameHeight > 1536 || ulFrameHeight % 2)
    {
        LogError("VBoxHeadless: ERROR: please specify an even frame height between 384 and 1536", 0);
        return 1;
    }
    if (ulBitRate < 300000 || ulBitRate > 1000000)
    {
        LogError("VBoxHeadless: ERROR: please specify an even bitrate between 300000 and 1000000", 0);
        return 1;
    }
    /* Make sure we only have %d or %u (or none) in the file name specified */
    char *pcPercent = (char*)strchr(pszFileNameParam, '%');
    if (pcPercent != 0 && *(pcPercent + 1) != 'd' && *(pcPercent + 1) != 'u')
    {
        LogError("VBoxHeadless: ERROR: Only %%d and %%u are allowed in the capture file name.", -1);
        return 1;
    }
    /* And no more than one % in the name */
    if (pcPercent != 0 && strchr(pcPercent + 1, '%') != 0)
    {
        LogError("VBoxHeadless: ERROR: Only one format modifier is allowed in the capture file name.", -1);
        return 1;
    }
    RTStrPrintf(&pszMPEGFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
#endif /* defined VBOX_FFMPEG */

    if (!pcszNameOrUUID)
    {
        show_usage();
        return 1;
    }

    HRESULT rc;

    rc = com::Initialize();
    if (FAILED(rc))
    {
        RTPrintf("VBoxHeadless: ERROR: failed to initialize COM!\n");
        return 1;
    }

    ComPtr<IVirtualBoxClient> pVirtualBoxClient;
    ComPtr<IVirtualBox> virtualBox;
    ComPtr<ISession> session;
    ComPtr<IMachine> machine;
    bool fSessionOpened = false;
    ComPtr<IEventListener> vboxClientListener;
    ComPtr<IEventListener> vboxListener;
    ComObjPtr<ConsoleEventListenerImpl> consoleListener;

    do
    {
        rc = pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
        if (FAILED(rc))
        {
            RTPrintf("VBoxHeadless: ERROR: failed to create the VirtualBoxClient object!\n");
            com::ErrorInfo info;
            if (!info.isFullAvailable() && !info.isBasicAvailable())
            {
                com::GluePrintRCMessage(rc);
                RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n");
            }
            else
                GluePrintErrorInfo(info);
            break;
        }

        rc = pVirtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
        if (FAILED(rc))
        {
            RTPrintf("Failed to get VirtualBox object (rc=%Rhrc)!\n", rc);
            break;
        }
        rc = pVirtualBoxClient->COMGETTER(Session)(session.asOutParam());
        if (FAILED(rc))
        {
            RTPrintf("Failed to get session object (rc=%Rhrc)!\n", rc);
            break;
        }

        ComPtr<IMachine> m;

        rc = virtualBox->FindMachine(Bstr(pcszNameOrUUID).raw(), m.asOutParam());
        if (FAILED(rc))
        {
            LogError("Invalid machine name or UUID!\n", rc);
            break;
        }
        Bstr id;
        m->COMGETTER(Id)(id.asOutParam());
        AssertComRC(rc);
        if (FAILED(rc))
            break;

        Log(("VBoxHeadless: Opening a session with machine (id={%s})...\n",
              Utf8Str(id).c_str()));

        // open a session
        CHECK_ERROR_BREAK(m, LockMachine(session, LockType_Write));
        fSessionOpened = true;

        /* get the console */
        ComPtr<IConsole> console;
        CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam()));

        /* get the mutable machine */
        CHECK_ERROR_BREAK(console, COMGETTER(Machine)(machine.asOutParam()));

        ComPtr<IDisplay> display;
        CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));

#ifdef VBOX_FFMPEG
        IFramebuffer *pFramebuffer = 0;
        RTLDRMOD hLdrFFmpegFB;
        PFNREGISTERFFMPEGFB pfnRegisterFFmpegFB;

        if (fFFMPEG)
        {
            HRESULT         rcc = S_OK;
            int             rrc = VINF_SUCCESS;
            RTERRINFOSTATIC ErrInfo;

            Log2(("VBoxHeadless: loading VBoxFFmpegFB shared library\n"));
            RTErrInfoInitStatic(&ErrInfo);
            rrc = SUPR3HardenedLdrLoadAppPriv("VBoxFFmpegFB", &hLdrFFmpegFB, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);

            if (RT_SUCCESS(rrc))
            {
                Log2(("VBoxHeadless: looking up symbol VBoxRegisterFFmpegFB\n"));
                rrc = RTLdrGetSymbol(hLdrFFmpegFB, "VBoxRegisterFFmpegFB",
                                     reinterpret_cast<void **>(&pfnRegisterFFmpegFB));
                if (RT_FAILURE(rrc))
                    LogError("Failed to load the video capture extension, possibly due to a damaged file\n", rrc);
            }
            else
                LogError("Failed to load the video capture extension\n", rrc); /** @todo stupid function, no formatting options. */
            if (RT_SUCCESS(rrc))
            {
                Log2(("VBoxHeadless: calling pfnRegisterFFmpegFB\n"));
                rcc = pfnRegisterFFmpegFB(ulFrameWidth, ulFrameHeight, ulBitRate,
                                         pszMPEGFile, &pFramebuffer);
                if (rcc != S_OK)
                    LogError("Failed to initialise video capturing - make sure that the file format\n"
                             "you wish to use is supported on your system\n", rcc);
            }
            if (RT_SUCCESS(rrc) && rcc == S_OK)
            {
                Log2(("VBoxHeadless: Registering framebuffer\n"));
                pFramebuffer->AddRef();
                display->SetFramebuffer(VBOX_VIDEO_PRIMARY_SCREEN, pFramebuffer);
            }
            if (!RT_SUCCESS(rrc) || rcc != S_OK)
                rc = E_FAIL;
        }
        if (rc != S_OK)
        {
            break;
        }
#endif /* defined(VBOX_FFMPEG) */
#ifdef VBOX_WITH_VNC
        if (fVNCEnable)
        {
            Bstr machineName;
            machine->COMGETTER(Name)(machineName.asOutParam());
            g_pFramebufferVNC = new VNCFB(console, uVNCPort, pszVNCPassword);
            rc = g_pFramebufferVNC->init(machineName.raw() ? Utf8Str(machineName.raw()).c_str() : "");
            if (rc != S_OK)
            {
                LogError("Failed to load the vnc server extension, possibly due to a damaged file\n", rc);
                delete g_pFramebufferVNC;
                break;
            }

            Log2(("VBoxHeadless: Registering VNC framebuffer\n"));
            g_pFramebufferVNC->AddRef();
            display->SetFramebuffer(VBOX_VIDEO_PRIMARY_SCREEN, g_pFramebufferVNC);
        }
        if (rc != S_OK)
            break;
#endif
        ULONG cMonitors = 1;
        machine->COMGETTER(MonitorCount)(&cMonitors);

        unsigned uScreenId;
        for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
        {
# ifdef VBOX_FFMPEG
            if (fFFMPEG && uScreenId == 0)
            {
                /* Already registered. */
                continue;
            }
# endif
# ifdef VBOX_WITH_VNC
            if (fVNCEnable && uScreenId == 0)
            {
                /* Already registered. */
                continue;
            }
# endif
            VRDPFramebuffer *pVRDPFramebuffer = new VRDPFramebuffer();
            if (!pVRDPFramebuffer)
            {
                RTPrintf("Error: could not create framebuffer object %d\n", uScreenId);
                break;
            }
            pVRDPFramebuffer->AddRef();
            display->SetFramebuffer(uScreenId, pVRDPFramebuffer);
        }
        if (uScreenId < cMonitors)
        {
            break;
        }

        // fill in remaining slots with null framebuffers
        for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
        {
            ComPtr<IFramebuffer> fb;
            LONG xOrigin, yOrigin;
            HRESULT hrc2 = display->GetFramebuffer(uScreenId,
                                                   fb.asOutParam(),
                                                   &xOrigin, &yOrigin);
            if (hrc2 == S_OK && fb.isNull())
            {
                NullFB *pNullFB =  new NullFB();
                pNullFB->AddRef();
                pNullFB->init();
                display->SetFramebuffer(uScreenId, pNullFB);
            }
        }

        /* get the machine debugger (isn't necessarily available) */
        ComPtr <IMachineDebugger> machineDebugger;
        console->COMGETTER(Debugger)(machineDebugger.asOutParam());
        if (machineDebugger)
        {
            Log(("Machine debugger available!\n"));
        }

        if (fRawR0 != ~0U)
        {
            if (!machineDebugger)
            {
                RTPrintf("Error: No debugger object; -%srawr0 cannot be executed!\n", fRawR0 ? "" : "no");
                break;
            }
            machineDebugger->COMSETTER(RecompileSupervisor)(!fRawR0);
        }
        if (fRawR3 != ~0U)
        {
            if (!machineDebugger)
            {
                RTPrintf("Error: No debugger object; -%srawr3 cannot be executed!\n", fRawR3 ? "" : "no");
                break;
            }
            machineDebugger->COMSETTER(RecompileUser)(!fRawR3);
        }
        if (fPATM != ~0U)
        {
            if (!machineDebugger)
            {
                RTPrintf("Error: No debugger object; -%spatm cannot be executed!\n", fPATM ? "" : "no");
                break;
            }
            machineDebugger->COMSETTER(PATMEnabled)(fPATM);
        }
        if (fCSAM != ~0U)
        {
            if (!machineDebugger)
            {
                RTPrintf("Error: No debugger object; -%scsam cannot be executed!\n", fCSAM ? "" : "no");
                break;
            }
            machineDebugger->COMSETTER(CSAMEnabled)(fCSAM);
        }

        /* initialize global references */
        gConsole = console;
        gEventQ = com::EventQueue::getMainEventQueue();

        /* VirtualBoxClient events registration. */
        {
            ComPtr<IEventSource> pES;
            CHECK_ERROR(pVirtualBoxClient, COMGETTER(EventSource)(pES.asOutParam()));
            ComObjPtr<VirtualBoxClientEventListenerImpl> listener;
            listener.createObject();
            listener->init(new VirtualBoxClientEventListener());
            vboxClientListener = listener;
            com::SafeArray<VBoxEventType_T> eventTypes;
            eventTypes.push_back(VBoxEventType_OnVBoxSVCAvailabilityChanged);
            CHECK_ERROR(pES, RegisterListener(vboxClientListener, ComSafeArrayAsInParam(eventTypes), true));
        }

        /* Console events registration. */
        {
            ComPtr<IEventSource> es;
            CHECK_ERROR(console, COMGETTER(EventSource)(es.asOutParam()));
            consoleListener.createObject();
            consoleListener->init(new ConsoleEventListener());
            com::SafeArray<VBoxEventType_T> eventTypes;
            eventTypes.push_back(VBoxEventType_OnMouseCapabilityChanged);
            eventTypes.push_back(VBoxEventType_OnStateChanged);
            eventTypes.push_back(VBoxEventType_OnVRDEServerInfoChanged);
            eventTypes.push_back(VBoxEventType_OnCanShowWindow);
            eventTypes.push_back(VBoxEventType_OnShowWindow);
            CHECK_ERROR(es, RegisterListener(consoleListener, ComSafeArrayAsInParam(eventTypes), true));
        }

        /* default is to enable the remote desktop server (backward compatibility) */
        BOOL fVRDEEnable = true;
        BOOL fVRDEEnabled;
        ComPtr <IVRDEServer> vrdeServer;
        CHECK_ERROR_BREAK(machine, COMGETTER(VRDEServer)(vrdeServer.asOutParam()));
        CHECK_ERROR_BREAK(vrdeServer, COMGETTER(Enabled)(&fVRDEEnabled));

        if (vrdeEnabled != NULL)
        {
            /* -vrdeServer on|off|config */
            if (!strcmp(vrdeEnabled, "off") || !strcmp(vrdeEnabled, "disable"))
                fVRDEEnable = false;
            else if (!strcmp(vrdeEnabled, "config"))
            {
                if (!fVRDEEnabled)
                    fVRDEEnable = false;
            }
            else if (strcmp(vrdeEnabled, "on") && strcmp(vrdeEnabled, "enable"))
            {
                RTPrintf("-vrdeServer requires an argument (on|off|config)\n");
                break;
            }
        }

        if (fVRDEEnable)
        {
            Log(("VBoxHeadless: Enabling VRDE server...\n"));

            /* set VRDE port if requested by the user */
            if (vrdePort != NULL)
            {
                Bstr bstr = vrdePort;
                CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), bstr.raw()));
            }
            /* set VRDE address if requested by the user */
            if (vrdeAddress != NULL)
            {
                CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Address").raw(), Bstr(vrdeAddress).raw()));
            }

            /* Set VRDE properties. */
            if (cVRDEProperties > 0)
            {
                for (unsigned i = 0; i < cVRDEProperties; i++)
                {
                    /* Parse 'name=value' */
                    char *pszProperty = RTStrDup(aVRDEProperties[i]);
                    if (pszProperty)
                    {
                        char *pDelimiter = strchr(pszProperty, '=');
                        if (pDelimiter)
                        {
                            *pDelimiter = '\0';

                            Bstr bstrName = pszProperty;
                            Bstr bstrValue = &pDelimiter[1];
                            CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
                        }
                        else
                        {
                            RTPrintf("Error: Invalid VRDE property '%s'\n", aVRDEProperties[i]);
                            RTStrFree(pszProperty);
                            rc = E_INVALIDARG;
                            break;
                        }
                        RTStrFree(pszProperty);
                    }
                    else
                    {
                        RTPrintf("Error: Failed to allocate memory for VRDE property '%s'\n", aVRDEProperties[i]);
                        rc = E_OUTOFMEMORY;
                        break;
                    }
                }
                if (FAILED(rc))
                    break;
            }

            /* enable VRDE server (only if currently disabled) */
            if (!fVRDEEnabled)
            {
                CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
            }
        }
        else
        {
            /* disable VRDE server (only if currently enabled */
            if (fVRDEEnabled)
            {
                CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
            }
        }

        /* Disable the host clipboard before powering up */
        console->COMSETTER(UseHostClipboard)(false);

        Log(("VBoxHeadless: Powering up the machine...\n"));

        ComPtr <IProgress> progress;
        CHECK_ERROR_BREAK(console, PowerUp(progress.asOutParam()));

        /*
         * Wait for the result because there can be errors.
         *
         * It's vital to process events while waiting (teleportation deadlocks),
         * so we'll poll for the completion instead of waiting on it.
         */
        for (;;)
        {
            BOOL fCompleted;
            rc = progress->COMGETTER(Completed)(&fCompleted);
            if (FAILED(rc) || fCompleted)
                break;

            /* Process pending events, then wait for new ones. Note, this
             * processes NULL events signalling event loop termination. */
            gEventQ->processEventQueue(0);
            if (!g_fTerminateFE)
                gEventQ->processEventQueue(500);
        }

        if (SUCCEEDED(progress->WaitForCompletion(-1)))
        {
            /* Figure out if the operation completed with a failed status
             * and print the error message. Terminate immediately, and let
             * the cleanup code take care of potentially pending events. */
            LONG progressRc;
            progress->COMGETTER(ResultCode)(&progressRc);
            rc = progressRc;
            if (FAILED(rc))
            {
                com::ProgressErrorInfo info(progress);
                if (info.isBasicAvailable())
                {
                    RTPrintf("Error: failed to start machine. Error message: %lS\n", info.getText().raw());
                }
                else
                {
                    RTPrintf("Error: failed to start machine. No error message available!\n");
                }
                break;
            }
        }

        /* VirtualBox events registration. */
        {
            ComPtr<IEventSource> es;
            CHECK_ERROR(virtualBox, COMGETTER(EventSource)(es.asOutParam()));
            ComObjPtr<VirtualBoxEventListenerImpl> listener;
            listener.createObject();
            listener->init(new VirtualBoxEventListener());
            vboxListener = listener;
            com::SafeArray<VBoxEventType_T> eventTypes;
            eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
            CHECK_ERROR(es, RegisterListener(vboxListener, ComSafeArrayAsInParam(eventTypes), true));
        }

#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
        signal(SIGINT, SaveState);
        signal(SIGTERM, SaveState);
#endif

        Log(("VBoxHeadless: Waiting for PowerDown...\n"));

        while (   !g_fTerminateFE
               && RT_SUCCESS(gEventQ->processEventQueue(RT_INDEFINITE_WAIT)))
            /* nothing */ ;

        Log(("VBoxHeadless: event loop has terminated...\n"));

#ifdef VBOX_FFMPEG
        if (pFramebuffer)
        {
            pFramebuffer->Release();
            Log(("Released framebuffer\n"));
            pFramebuffer = NULL;
        }
#endif /* defined(VBOX_FFMPEG) */

        /* we don't have to disable VRDE here because we don't save the settings of the VM */
    }
    while (0);

    /*
     * Get the machine state.
     */
    MachineState_T machineState = MachineState_Aborted;
    if (!machine.isNull())
        machine->COMGETTER(State)(&machineState);

    /*
     * Turn off the VM if it's running
     */
    if (   gConsole
        && (   machineState == MachineState_Running
            || machineState == MachineState_Teleporting
            || machineState == MachineState_LiveSnapshotting
            /** @todo power off paused VMs too? */
           )
       )
    do
    {
        consoleListener->getWrapped()->ignorePowerOffEvents(true);
        ComPtr<IProgress> pProgress;
        CHECK_ERROR_BREAK(gConsole, PowerDown(pProgress.asOutParam()));
        CHECK_ERROR_BREAK(pProgress, WaitForCompletion(-1));
        BOOL completed;
        CHECK_ERROR_BREAK(pProgress, COMGETTER(Completed)(&completed));
        ASSERT(completed);
        LONG hrc;
        CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&hrc));
        if (FAILED(hrc))
        {
            RTPrintf("VBoxHeadless: ERROR: Failed to power down VM!");
            com::ErrorInfo info;
            if (!info.isFullAvailable() && !info.isBasicAvailable())
                com::GluePrintRCMessage(hrc);
            else
                GluePrintErrorInfo(info);
            break;
        }
    } while (0);

    /* VirtualBox callback unregistration. */
    if (vboxListener)
    {
        ComPtr<IEventSource> es;
        CHECK_ERROR(virtualBox, COMGETTER(EventSource)(es.asOutParam()));
        if (!es.isNull())
            CHECK_ERROR(es, UnregisterListener(vboxListener));
        vboxListener.setNull();
    }

    /* Console callback unregistration. */
    if (consoleListener)
    {
        ComPtr<IEventSource> es;
        CHECK_ERROR(gConsole, COMGETTER(EventSource)(es.asOutParam()));
        if (!es.isNull())
            CHECK_ERROR(es, UnregisterListener(consoleListener));
        consoleListener.setNull();
    }

    /* VirtualBoxClient callback unregistration. */
    if (vboxClientListener)
    {
        ComPtr<IEventSource> pES;
        CHECK_ERROR(pVirtualBoxClient, COMGETTER(EventSource)(pES.asOutParam()));
        if (!pES.isNull())
            CHECK_ERROR(pES, UnregisterListener(vboxClientListener));
        vboxClientListener.setNull();
    }

    /* No more access to the 'console' object, which will be uninitialized by the next session->Close call. */
    gConsole = NULL;

    if (fSessionOpened)
    {
        /*
         * Close the session. This will also uninitialize the console and
         * unregister the callback we've registered before.
         */
        Log(("VBoxHeadless: Closing the session...\n"));
        session->UnlockMachine();
    }

    /* Must be before com::Shutdown */
    session.setNull();
    virtualBox.setNull();
    pVirtualBoxClient.setNull();
    machine.setNull();

    com::Shutdown();

    LogFlow(("VBoxHeadless FINISHED.\n"));

    return FAILED(rc) ? 1 : 0;
}
Exemplo n.º 15
0
static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNetworkInterfaceList)
{
    std::list<ComObjPtr<HostNetworkInterface> > *pList = (std::list<ComObjPtr<HostNetworkInterface> > *)pvHostNetworkInterfaceList;
    Assert(pList);

    typedef std::map <std::string, std::string> NICMap;
    typedef std::pair <std::string, std::string> NICPair;
    static NICMap SolarisNICMap;
    if (SolarisNICMap.empty())
    {
        SolarisNICMap.insert(NICPair("afe", "ADMtek Centaur/Comet Fast Ethernet"));
        SolarisNICMap.insert(NICPair("atge", "Atheros/Attansic Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("aggr", "Link Aggregation Interface"));
        SolarisNICMap.insert(NICPair("bfe", "Broadcom BCM4401 Fast Ethernet"));
        SolarisNICMap.insert(NICPair("bge", "Broadcom BCM57xx Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("bnx", "Broadcom NetXtreme Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("bnxe", "Broadcom NetXtreme II 10 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("ce", "Cassini Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("chxge", "Chelsio Ethernet"));
        SolarisNICMap.insert(NICPair("dmfe", "Davicom 9102 Fast Ethernet"));
        SolarisNICMap.insert(NICPair("dnet", "DEC 21040/41 21140 Ethernet"));
        SolarisNICMap.insert(NICPair("e1000", "Intel PRO/1000 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("e1000g", "Intel PRO/1000 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("elx", "3COM Etherlink III Ethernet"));
        SolarisNICMap.insert(NICPair("elxl", "3COM Etherlink XL Ethernet"));
        SolarisNICMap.insert(NICPair("eri", "eri Fast Ethernet"));
        SolarisNICMap.insert(NICPair("ge", "GEM Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("hme", "SUNW,hme Fast-Ethernet"));
        SolarisNICMap.insert(NICPair("hxge", "Sun Blade 10 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("igb", "Intel 82575 PCI-E Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("ipge", "PCI-E Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("iprb", "Intel 82557/58/59 Ethernet"));
        SolarisNICMap.insert(NICPair("ixgb", "Intel 82597ex 10 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("ixgbe", "Intel 10 Gigabit PCI-E Ethernet"));
        SolarisNICMap.insert(NICPair("mcxe", "Mellanox ConnectX-2 10 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("mxfe", "Macronix 98715 Fast Ethernet"));
        SolarisNICMap.insert(NICPair("nfo", "Nvidia Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("nge", "Nvidia Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("ntxn", "NetXen 10/1 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("nxge", "Sun 10/1 Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("pcelx", "3COM EtherLink III PCMCIA Ethernet"));
        SolarisNICMap.insert(NICPair("pcn", "AMD PCnet Ethernet"));
        SolarisNICMap.insert(NICPair("qfe", "SUNW,qfe Quad Fast-Ethernet"));
        SolarisNICMap.insert(NICPair("rge", "Realtek Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("rtls", "Realtek 8139 Fast Ethernet"));
        SolarisNICMap.insert(NICPair("sfe", "SiS900 Fast Ethernet"));
        SolarisNICMap.insert(NICPair("skge", "SksKonnect Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("spwr", "SMC EtherPower II 10/100 (9432) Ethernet"));
        SolarisNICMap.insert(NICPair("vboxnet", "VirtualBox Host Ethernet"));
        SolarisNICMap.insert(NICPair("vboxvnic_template", "VirtualBox Virtual Network Interface Template"));
        SolarisNICMap.insert(NICPair("vlan", "Virtual LAN Ethernet"));
        SolarisNICMap.insert(NICPair("vr", "VIA Rhine Fast Ethernet"));
        SolarisNICMap.insert(NICPair("vnic", "Virtual Network Interface Ethernet"));
        SolarisNICMap.insert(NICPair("xge", "Neterior Xframe 10Gigabit Ethernet"));
        SolarisNICMap.insert(NICPair("yge", "Marvell Yukon 2 Fast Ethernet"));
    }

    /*
     * Try picking up description from our NIC map.
     */
    char szNICInstance[128];
    RTStrPrintf(szNICInstance, sizeof(szNICInstance), "%s%d", pszIface, Instance);
    char szNICDesc[256];
    std::string Description = SolarisNICMap[pszIface];
    if (Description != "VirtualBox Host Ethernet")
    {
        if (Description != "")
            RTStrPrintf(szNICDesc, sizeof(szNICDesc), "%s - %s", szNICInstance, Description.c_str());
        else
            RTStrPrintf(szNICDesc, sizeof(szNICDesc), "%s - Ethernet", szNICInstance);
    }
    else
        RTStrPrintf(szNICDesc, sizeof(szNICDesc), "%s", szNICInstance);

    /*
     * Try to get IP V4 address and netmask as well as Ethernet address.
     */
    NETIFINFO Info;
    memset(&Info, 0, sizeof(Info));
    int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (Sock > 0)
    {
        struct lifreq IfReq;
        strcpy(IfReq.lifr_name, szNICInstance);
        if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0)
        {
            memcpy(Info.IPAddress.au8, &((struct sockaddr_in *)&IfReq.lifr_addr)->sin_addr.s_addr,
                    sizeof(Info.IPAddress.au8));
            struct arpreq ArpReq;
            memcpy(&ArpReq.arp_pa, &IfReq.lifr_addr, sizeof(struct sockaddr_in));

            /*
             * We might fail if the interface has not been assigned an IP address.
             * That doesn't matter; as long as it's plumbed we can pick it up.
             * But, if it has not acquired an IP address we cannot obtain it's MAC
             * address this way, so we just use all zeros there.
             */
            if (ioctl(Sock, SIOCGARP, &ArpReq) >= 0)
            {
                memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress));
            }

        }

        if (ioctl(Sock, SIOCGLIFNETMASK, &IfReq) >= 0)
        {
            memcpy(Info.IPNetMask.au8, &((struct sockaddr_in *)&IfReq.lifr_addr)->sin_addr.s_addr,
                    sizeof(Info.IPNetMask.au8));
        }
        if (ioctl(Sock, SIOCGLIFFLAGS, &IfReq) >= 0)
        {
            Info.enmStatus = IfReq.lifr_flags & IFF_UP ? NETIF_S_UP : NETIF_S_DOWN;
        }
        close(Sock);
    }
    /*
     * Try to get IP V6 address and netmask.
     */
    Sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
    if (Sock > 0)
    {
        struct lifreq IfReq;
        strcpy(IfReq.lifr_name, szNICInstance);
        if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0)
        {
            memcpy(Info.IPv6Address.au8, ((struct sockaddr_in6 *)&IfReq.lifr_addr)->sin6_addr.s6_addr,
                    sizeof(Info.IPv6Address.au8));
        }
        if (ioctl(Sock, SIOCGLIFNETMASK, &IfReq) >= 0)
        {
            memcpy(Info.IPv6NetMask.au8, ((struct sockaddr_in6 *)&IfReq.lifr_addr)->sin6_addr.s6_addr,
                    sizeof(Info.IPv6NetMask.au8));
        }
        close(Sock);
    }

    /*
     * Construct UUID with interface name and the MAC address if available.
     */
    RTUUID Uuid;
    RTUuidClear(&Uuid);
    memcpy(&Uuid, szNICInstance, RT_MIN(strlen(szNICInstance), sizeof(Uuid)));
    Uuid.Gen.u8ClockSeqHiAndReserved = (Uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
    Uuid.Gen.u16TimeHiAndVersion = (Uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
    Uuid.Gen.au8Node[0] = Info.MACAddress.au8[0];
    Uuid.Gen.au8Node[1] = Info.MACAddress.au8[1];
    Uuid.Gen.au8Node[2] = Info.MACAddress.au8[2];
    Uuid.Gen.au8Node[3] = Info.MACAddress.au8[3];
    Uuid.Gen.au8Node[4] = Info.MACAddress.au8[4];
    Uuid.Gen.au8Node[5] = Info.MACAddress.au8[5];
    Info.Uuid = Uuid;
    Info.enmMediumType = NETIF_T_ETHERNET;
    strncpy(Info.szShortName, szNICInstance, sizeof(Info.szShortName) - 1);

    HostNetworkInterfaceType_T enmType;
    if (strncmp("vboxnet", szNICInstance, 7))
        enmType = HostNetworkInterfaceType_Bridged;
    else
        enmType = HostNetworkInterfaceType_HostOnly;
    queryIfaceSpeed(&Info);
    ComObjPtr<HostNetworkInterface> IfObj;
    IfObj.createObject();
    if (SUCCEEDED(IfObj->init(Bstr(szNICDesc), enmType, &Info)))
        pList->push_back(IfObj);
}
void UIConsoleEventHandler::prepare()
{
    /* Make sure session is passed: */
    AssertPtrReturnVoid(m_pSession);

    /* Create Main-event listener instance: */
    ComObjPtr<UIMainEventListenerImpl> pListener;
    pListener.createObject();
    pListener->init(new UIMainEventListener, this);
    m_mainEventListener = CEventListener(pListener);

    /* Get console: */
    const CConsole console = m_pSession->session().GetConsole();
    AssertReturnVoid(!console.isNull() && console.isOk());
    /* Get event-source: */
    CEventSource eventSource = console.GetEventSource();
    AssertReturnVoid(!eventSource.isNull() && eventSource.isOk());
    /* Register listener for expected event-types: */
    QVector<KVBoxEventType> events;
    events
        << KVBoxEventType_OnMousePointerShapeChanged
        << KVBoxEventType_OnMouseCapabilityChanged
        << KVBoxEventType_OnKeyboardLedsChanged
        << KVBoxEventType_OnStateChanged
        << KVBoxEventType_OnAdditionsStateChanged
        << KVBoxEventType_OnNetworkAdapterChanged
        << KVBoxEventType_OnMediumChanged
        << KVBoxEventType_OnVRDEServerChanged
        << KVBoxEventType_OnVRDEServerInfoChanged
        << KVBoxEventType_OnVideoCaptureChanged
        << KVBoxEventType_OnUSBControllerChanged
        << KVBoxEventType_OnUSBDeviceStateChanged
        << KVBoxEventType_OnSharedFolderChanged
        << KVBoxEventType_OnCPUExecutionCapChanged
        << KVBoxEventType_OnGuestMonitorChanged
        << KVBoxEventType_OnRuntimeError
        << KVBoxEventType_OnCanShowWindow
        << KVBoxEventType_OnShowWindow;
    eventSource.RegisterListener(m_mainEventListener, events, TRUE);


    /* Prepare connections: */
    connect(pListener->getWrapped(), SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
            this, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
            this, SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
            this, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigStateChange(KMachineState)),
            this, SIGNAL(sigStateChange(KMachineState)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigAdditionsChange()),
            this, SIGNAL(sigAdditionsChange()),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
            this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigMediumChange(CMediumAttachment)),
            this, SIGNAL(sigMediumChange(CMediumAttachment)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigVRDEChange()),
            this, SIGNAL(sigVRDEChange()),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigVideoCaptureChange()),
            this, SIGNAL(sigVideoCaptureChange()),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigUSBControllerChange()),
            this, SIGNAL(sigUSBControllerChange()),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
            this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigSharedFolderChange()),
            this, SIGNAL(sigSharedFolderChange()),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigCPUExecutionCapChange()),
            this, SIGNAL(sigCPUExecutionCapChange()),
            Qt::QueuedConnection);
    connect(pListener->getWrapped(), SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
            this, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
            Qt::QueuedConnection);

    connect(pListener->getWrapped(), SIGNAL(sigRuntimeError(bool, QString, QString)),
            this, SIGNAL(sigRuntimeError(bool, QString, QString)),
            Qt::QueuedConnection);

    /* This is a vetoable event, so we have to respond to the event and have to
     * use a direct connection therefor. */
    connect(pListener->getWrapped(), SIGNAL(sigCanShowWindow(bool&, QString&)),
            this, SLOT(sltCanShowWindow(bool&, QString&)),
            Qt::DirectConnection);
    /* This returns a winId, so we have to respond to the event and have to use
     * a direct connection therefor. */
    connect(pListener->getWrapped(), SIGNAL(sigShowWindow(LONG64&)),
            this, SLOT(sltShowWindow(LONG64&)),
            Qt::DirectConnection);
}