virDomainGraphicsListensParseXML(virDomainGraphicsDefPtr def,
                                 xmlNodePtr node,
                                 xmlXPathContextPtr ctxt,
                                 unsigned int flags)
{
    VIR_XPATH_NODE_AUTORESTORE(ctxt);
    virDomainGraphicsListenDef newListen = {0};
    int nListens;
    int ret = -1;
    g_autofree xmlNodePtr *listenNodes = NULL;
    g_autofree char *socketPath = NULL;

    ctxt->node = node;

    /* parse the <listen> subelements for graphics types that support it */
    nListens = virXPathNodeSet("./listen", ctxt, &listenNodes);
    if (nListens < 0)
        goto cleanup;

    if (nListens > 0) {
        size_t i;

        if (VIR_ALLOC_N(def->listens, nListens) < 0)
            goto cleanup;

        for (i = 0; i < nListens; i++) {
            if (virDomainGraphicsListenDefParseXML(&def->listens[i], def,
                                                   listenNodes[i],
                                                   i == 0 ? node : NULL,
                                                   flags) < 0)
                goto cleanup;

            def->nListens++;
        }
    }

    /* If no <listen/> element was found in XML for backward compatibility
     * we should try to parse 'listen' or 'socket' attribute from <graphics/>
     * element. */
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC)
        socketPath = virXMLPropString(node, "socket");

    if (socketPath) {
        newListen.type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET;
        newListen.socket = g_steal_pointer(&socketPath);
    } else {
        newListen.type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;
        newListen.address = virXMLPropString(node, "listen");
        if (STREQ_NULLABLE(newListen.address, ""))
            VIR_FREE(newListen.address);
    }

    /* If no <listen/> element was found add a new one created by parsing
     * <graphics/> element. */
    if (def->nListens == 0) {
        if (VIR_APPEND_ELEMENT(def->listens, def->nListens, newListen) < 0)
            goto cleanup;
    } else {
        virDomainGraphicsListenDefPtr glisten = &def->listens[0];

        /* If the first <listen/> element is 'address' or 'network' and we found
         * 'socket' attribute inside <graphics/> element for backward
         * compatibility we need to replace the first listen by
         * <listen type='socket' .../> element based on the 'socket' attribute. */
        if ((glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
             glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK) &&
            newListen.type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET) {
            virDomainGraphicsListenDefClear(glisten);
            *glisten = newListen;
            memset(&newListen, 0, sizeof(newListen));
        }
    }

    ret = 0;
 cleanup:
    virDomainGraphicsListenDefClear(&newListen);
    return ret;
}
virDomainGraphicsListensParseXML(virDomainGraphicsDefPtr def,
                                 xmlNodePtr node,
                                 xmlXPathContextPtr ctxt,
                                 unsigned int flags)
{
    VIR_XPATH_NODE_AUTORESTORE(ctxt);
    virDomainGraphicsListenDef newListen = {0};
    int nListens;
    int ret = -1;
    g_autofree xmlNodePtr *listenNodes = NULL;
    g_autofree char *socketPath = NULL;

    ctxt->node = node;

     
    nListens = virXPathNodeSet("./listen", ctxt, &listenNodes);
    if (nListens < 0)
        goto cleanup;

    if (nListens > 0) {
        size_t i;

        if (VIR_ALLOC_N(def->listens, nListens) < 0)
            goto cleanup;

        for (i = 0; i < nListens; i++) {
            if (virDomainGraphicsListenDefParseXML(&def->listens[i], def,
                                                   listenNodes[i],
                                                   i == 0 ? node : NULL,
                                                   flags) < 0)
                goto cleanup;

            def->nListens++;
        }
    }

     
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC)
        socketPath = virXMLPropString(node, "socket");

    if (socketPath) {
        newListen.type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET;
        newListen.socket = g_steal_pointer(&socketPath);
    } else {
        newListen.type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;
        newListen.address = virXMLPropString(node, "listen");
        if (STREQ_NULLABLE(newListen.address, ""))
            VIR_FREE(newListen.address);
    }

     
    if (def->nListens == 0) {
        if (VIR_APPEND_ELEMENT(def->listens, def->nListens, newListen) < 0)
            goto cleanup;
    } else {
        virDomainGraphicsListenDefPtr glisten = &def->listens[0];

         
        if ((glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
             glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK) &&
            newListen.type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET) {
            virDomainGraphicsListenDefClear(glisten);
            *glisten = newListen;
            memset(&newListen, 0, sizeof(newListen));
        }
    }

    ret = 0;
 cleanup:
    virDomainGraphicsListenDefClear(&newListen);
    return ret;
}