<commit_before>/*
 * virnetsocket.c: generic network socket handling
 *
 * Copyright (C) 2006-2014 Red Hat, Inc.
 * Copyright (C) 2006 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif

#ifdef HAVE_SYS_UCRED_H
# include <sys/ucred.h>
#endif

#ifdef WITH_SELINUX
# include <selinux/selinux.h>
#endif

#include "virsocket.h"
#include "virnetsocket.h"
#include "virutil.h"
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
#include "virfile.h"
#include "virthread.h"
#include "virpidfile.h"
#include "virprobe.h"
#include "virprocess.h"
#include "virstring.h"

#if WITH_SSH2
# include "virnetsshsession.h"
#endif

#if WITH_LIBSSH
# include "virnetlibsshsession.h"
#endif

#define VIR_FROM_THIS VIR_FROM_RPC

VIR_LOG_INIT("rpc.netsocket");

struct _virNetSocket {
    virObjectLockable parent;

    int fd;
    int watch;
    pid_t pid;
    int errfd;
    bool isClient;
    bool ownsFd;
    bool quietEOF;
    bool unlinkUNIX;

    /* Event callback fields */
    virNetSocketIOFunc func;
    void *opaque;
    virFreeCallback ff;

    virSocketAddr localAddr;
    virSocketAddr remoteAddr;
    char *localAddrStrSASL;
    char *remoteAddrStrSASL;
    char *remoteAddrStrURI;

    virNetTLSSessionPtr tlsSession;
#if WITH_SASL
    virNetSASLSessionPtr saslSession;

    const char *saslDecoded;
    size_t saslDecodedLength;
    size_t saslDecodedOffset;

    const char *saslEncoded;
    size_t saslEncodedLength;
    size_t saslEncodedRawLength;
    size_t saslEncodedOffset;
#endif
#if WITH_SSH2
    virNetSSHSessionPtr sshSession;
#endif
#if WITH_LIBSSH
    virNetLibsshSessionPtr libsshSession;
#endif
};


static virClassPtr virNetSocketClass;
static void virNetSocketDispose(void *obj);

static int virNetSocketOnceInit(void)
{
    if (!VIR_CLASS_NEW(virNetSocket, virClassForObjectLockable()))
        return -1;

    return 0;
}

VIR_ONCE_GLOBAL_INIT(virNetSocket);


#ifndef WIN32
static int virNetSocketForkDaemon(const char *binary)
{
    int ret;
    virCommandPtr cmd = virCommandNewArgList(binary,
                                             "--timeout=120",
                                             NULL);

    virCommandAddEnvPassCommon(cmd);
    virCommandAddEnvPass(cmd, "XDG_CACHE_HOME");
    virCommandAddEnvPass(cmd, "XDG_CONFIG_HOME");
    virCommandAddEnvPass(cmd, "XDG_RUNTIME_DIR");
    virCommandClearCaps(cmd);
    virCommandDaemonize(cmd);
    ret = virCommandRun(cmd, NULL);
    virCommandFree(cmd);
    return ret;
}
#endif

int virNetSocketCheckProtocols(bool *hasIPv4,
                               bool *hasIPv6)
{
#ifdef HAVE_IFADDRS_H
    struct ifaddrs *ifaddr = NULL, *ifa;
    struct addrinfo hints;
    struct addrinfo *ai = NULL;
    int gaierr;

    memset(&hints, 0, sizeof(hints));

    *hasIPv4 = *hasIPv6 = false;

    if (getifaddrs(&ifaddr) < 0) {
        virReportSystemError(errno, "%s",
                             _("Cannot get host interface addresses"));
        return -1;
    }

    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr)
            continue;

        if (ifa->ifa_addr->sa_family == AF_INET)
            *hasIPv4 = true;
        if (ifa->ifa_addr->sa_family == AF_INET6)
            *hasIPv6 = true;
    }

    freeifaddrs(ifaddr);

    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;

    if ((gaierr = getaddrinfo("::1", NULL, &hints, &ai)) != 0) {
        if (gaierr == EAI_FAMILY ||
# ifdef EAI_ADDRFAMILY
            gaierr == EAI_ADDRFAMILY ||
# endif
            gaierr == EAI_NONAME) {
            *hasIPv6 = false;
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot resolve ::1 address: %s"),
                           gai_strerror(gaierr));
            return -1;
        }
    }

    freeaddrinfo(ai);

    VIR_DEBUG("Protocols: v4 %d v6 %d", *hasIPv4, *hasIPv6);

    return 0;
#else
    *hasIPv4 = *hasIPv6 = false;
    virReportError(VIR_ERR_NO_SUPPORT, "%s",
                   _("Cannot check address family on this platform"));
    return -1;
#endif
}
<commit_msg>virNetSocketCheckProtocols: Separate out checking family via getaddrinfo()<commit_after>/*
 * virnetsocket.c: generic network socket handling
 *
 * Copyright (C) 2006-2014 Red Hat, Inc.
 * Copyright (C) 2006 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif

#ifdef HAVE_SYS_UCRED_H
# include <sys/ucred.h>
#endif

#ifdef WITH_SELINUX
# include <selinux/selinux.h>
#endif

#include "virsocket.h"
#include "virnetsocket.h"
#include "virutil.h"
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
#include "virfile.h"
#include "virthread.h"
#include "virpidfile.h"
#include "virprobe.h"
#include "virprocess.h"
#include "virstring.h"

#if WITH_SSH2
# include "virnetsshsession.h"
#endif

#if WITH_LIBSSH
# include "virnetlibsshsession.h"
#endif

#define VIR_FROM_THIS VIR_FROM_RPC

VIR_LOG_INIT("rpc.netsocket");

struct _virNetSocket {
    virObjectLockable parent;

    int fd;
    int watch;
    pid_t pid;
    int errfd;
    bool isClient;
    bool ownsFd;
    bool quietEOF;
    bool unlinkUNIX;

    /* Event callback fields */
    virNetSocketIOFunc func;
    void *opaque;
    virFreeCallback ff;

    virSocketAddr localAddr;
    virSocketAddr remoteAddr;
    char *localAddrStrSASL;
    char *remoteAddrStrSASL;
    char *remoteAddrStrURI;

    virNetTLSSessionPtr tlsSession;
#if WITH_SASL
    virNetSASLSessionPtr saslSession;

    const char *saslDecoded;
    size_t saslDecodedLength;
    size_t saslDecodedOffset;

    const char *saslEncoded;
    size_t saslEncodedLength;
    size_t saslEncodedRawLength;
    size_t saslEncodedOffset;
#endif
#if WITH_SSH2
    virNetSSHSessionPtr sshSession;
#endif
#if WITH_LIBSSH
    virNetLibsshSessionPtr libsshSession;
#endif
};


static virClassPtr virNetSocketClass;
static void virNetSocketDispose(void *obj);

static int virNetSocketOnceInit(void)
{
    if (!VIR_CLASS_NEW(virNetSocket, virClassForObjectLockable()))
        return -1;

    return 0;
}

VIR_ONCE_GLOBAL_INIT(virNetSocket);


#ifndef WIN32
static int virNetSocketForkDaemon(const char *binary)
{
    int ret;
    virCommandPtr cmd = virCommandNewArgList(binary,
                                             "--timeout=120",
                                             NULL);

    virCommandAddEnvPassCommon(cmd);
    virCommandAddEnvPass(cmd, "XDG_CACHE_HOME");
    virCommandAddEnvPass(cmd, "XDG_CONFIG_HOME");
    virCommandAddEnvPass(cmd, "XDG_RUNTIME_DIR");
    virCommandClearCaps(cmd);
    virCommandDaemonize(cmd);
    ret = virCommandRun(cmd, NULL);
    virCommandFree(cmd);
    return ret;
}
#endif


static int G_GNUC_UNUSED
virNetSocketCheckProtocolByLookup(const char *address,
                                  int family,
                                  bool *hasFamily)
{
    struct addrinfo hints;
    struct addrinfo *ai = NULL;
    int gaierr;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = family;
    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
    hints.ai_socktype = SOCK_STREAM;

    if ((gaierr = getaddrinfo(address, NULL, &hints, &ai)) != 0) {
        *hasFamily = false;

        if (gaierr == EAI_FAMILY ||
#ifdef EAI_ADDRFAMILY
            gaierr == EAI_ADDRFAMILY ||
#endif
            gaierr == EAI_NONAME) {
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot resolve %s address: %s"),
                           address,
                           gai_strerror(gaierr));
            return -1;
        }
    } else {
        *hasFamily = true;
    }

    freeaddrinfo(ai);
    return 0;
}

int virNetSocketCheckProtocols(bool *hasIPv4,
                               bool *hasIPv6)
{
#ifdef HAVE_IFADDRS_H
    struct ifaddrs *ifaddr = NULL, *ifa;

    *hasIPv4 = *hasIPv6 = false;

    if (getifaddrs(&ifaddr) < 0) {
        virReportSystemError(errno, "%s",
                             _("Cannot get host interface addresses"));
        return -1;
    }

    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr)
            continue;

        if (ifa->ifa_addr->sa_family == AF_INET)
            *hasIPv4 = true;
        if (ifa->ifa_addr->sa_family == AF_INET6)
            *hasIPv6 = true;
    }

    freeifaddrs(ifaddr);


    if (virNetSocketCheckProtocolByLookup("::1", AF_INET6, hasIPv6) < 0)
        return -1;

    VIR_DEBUG("Protocols: v4 %d v6 %d", *hasIPv4, *hasIPv6);

    return 0;
#else
    *hasIPv4 = *hasIPv6 = false;
    virReportError(VIR_ERR_NO_SUPPORT, "%s",
                   _("Cannot check address family on this platform"));
    return -1;
#endif
}

{'fraction_non_alphanumeric': 0.09895579193910413, 'fraction_numerical': 0.009368595686542403, 'mean_word_length': 2.821029082774049, 'pattern_counts': {'":': 2, '<': 26, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5864022', 'n_tokens_mistral': 3569, 'n_tokens_neox': 3445, 'n_words': 881}