<commit_before>/*
 * This file is part of the Soletta Project
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
#include <linux/if_addr.h>
#include <linux/if_link.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>

#define SOL_LOG_DOMAIN &_log_domain
#include "sol-log-internal.h"
#include "sol-macros.h"
#include "sol-mainloop.h"
#include "sol-network.h"
#include "sol-network-util.h"
#include "sol-util-internal.h"
#include "sol-util-file.h"

SOL_LOG_INTERNAL_DECLARE_STATIC(_log_domain, "network");

struct callback {
    void (*cb)(void *data, const struct sol_network_link *link,
        enum sol_network_event event);
    const void *data;
};

struct sol_network_hostname_handle {
    char *hostname;
    enum sol_network_family family;
    void (*cb)(void *data, const struct sol_str_slice hostname,
        const struct sol_vector *addrs_list);
    const void *data;
};

struct sol_network {
    unsigned int count;
    int nl_socket;
    struct sockaddr_nl nl_addr;
    struct sol_fd *fd;
    struct sol_timeout *hostname_worker;

    struct sol_vector links;
    struct sol_vector callbacks;
    struct sol_ptr_vector hostname_handles;

    int seq;
};

static struct sol_network *network = NULL;

SOL_API const char *
sol_network_link_addr_to_str(const struct sol_network_link_addr *addr,
    struct sol_buffer *buf)
{
    const char *r;

    SOL_NULL_CHECK(addr, NULL);
    SOL_NULL_CHECK(buf, NULL);

    while (1) {
        int err;

        r = inet_ntop(sol_network_sol_to_af(addr->family), &addr->addr,
            sol_buffer_at_end(buf), buf->capacity - buf->used);

        if (r || (!r && errno != ENOSPC))
            break;

        err = sol_buffer_expand(buf, SOL_INET_ADDR_STRLEN);
        SOL_INT_CHECK(err, < 0, NULL);
    }

    if (r)
        buf->used += strlen(r);
    return r;
}

SOL_API const struct sol_network_link_addr *
sol_network_link_addr_from_str(struct sol_network_link_addr *addr, const char *buf)
{
    SOL_NULL_CHECK(addr, NULL);
    SOL_NULL_CHECK(buf, NULL);

    if (inet_pton(sol_network_sol_to_af(addr->family), buf, &addr->addr) != 1)
        return NULL;
    return addr;
}

static struct sol_network_link *
_get_link(int index)
{
    struct sol_network_link *link = NULL;
    uint16_t idx;

    SOL_VECTOR_FOREACH_IDX (&network->links, link, idx)
        if (link->index == index)
            return link;

    link = sol_vector_append(&network->links);
    SOL_NULL_CHECK(link, NULL);

    SOL_SET_API_VERSION(link->api_version = SOL_NETWORK_LINK_API_VERSION; )<commit_msg>sol-network: Add Bluetooth address conversion<commit_after>/*
 * This file is part of the Soletta Project
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
#include <linux/if_addr.h>
#include <linux/if_link.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>

#define SOL_LOG_DOMAIN &_log_domain
#include "sol-log-internal.h"
#include "sol-macros.h"
#include "sol-mainloop.h"
#include "sol-network.h"
#include "sol-network-util.h"
#include "sol-util-internal.h"
#include "sol-util-file.h"

SOL_LOG_INTERNAL_DECLARE_STATIC(_log_domain, "network");

struct callback {
    void (*cb)(void *data, const struct sol_network_link *link,
        enum sol_network_event event);
    const void *data;
};

struct sol_network_hostname_handle {
    char *hostname;
    enum sol_network_family family;
    void (*cb)(void *data, const struct sol_str_slice hostname,
        const struct sol_vector *addrs_list);
    const void *data;
};

struct sol_network {
    unsigned int count;
    int nl_socket;
    struct sockaddr_nl nl_addr;
    struct sol_fd *fd;
    struct sol_timeout *hostname_worker;

    struct sol_vector links;
    struct sol_vector callbacks;
    struct sol_ptr_vector hostname_handles;

    int seq;
};

static struct sol_network *network = NULL;

static struct sol_network_link_addr *
bluetooth_addr_from_str(struct sol_network_link_addr *addr, const char *str)
{
    unsigned int i;
    uint8_t *ba = addr->addr.bt_addr;
    const char *ptr;
    char *endptr = NULL;

    /* FIXME */
    addr->family = SOL_NETWORK_FAMILY_BLUETOOTH;
    addr->addr.bt_type = SOL_NETWORK_BT_ADDR_BASIC_RATE;

    ptr = str;

    for (i = 0; i < sizeof(addr->addr.bt_addr); i++) {
        ba[i] = strtoul(ptr, &endptr, 16);
        ptr = endptr + 1;
        endptr = NULL;
    }

    return addr;
}

static bool
is_bluetooth_addr_str(const char *str)
{
    const char *p = str;

    while (*str) {
        if (!isxdigit(*str++))
            return false;

        if (!isxdigit(*str++))
            return false;

        if (*str == 0)
            break;

        if (*str++ != ':')
            return false;
    }

    return (str - p) == 17;
}

static const char *
bluetooth_addr_to_str(const struct sol_network_link_addr *addr,
    struct sol_buffer *buffer)
{
    const uint8_t *ba = addr->addr.bt_addr;
    int r;

    r = sol_buffer_append_printf(buffer, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
        ba[0], ba[1], ba[2], ba[3], ba[4], ba[5]);
    SOL_INT_CHECK(r, < 0, NULL);

    return buffer->data;
}

static inline bool
is_bluetooth_family(int family)
{
    switch (family) {
    case SOL_NETWORK_FAMILY_BLUETOOTH:
    case SOL_NETWORK_FAMILY_BLUETOOTH_RFCOMM:
    case SOL_NETWORK_FAMILY_BLUETOOTH_L2CAP:
        return true;
    }

    return false;
}

SOL_API const char *
sol_network_link_addr_to_str(const struct sol_network_link_addr *addr,
    struct sol_buffer *buf)
{
    const char *r;

    SOL_NULL_CHECK(addr, NULL);
    SOL_NULL_CHECK(buf, NULL);

    if (is_bluetooth_family(addr->family))
        return bluetooth_addr_to_str(addr, buf);

    while (1) {
        int err;

        r = inet_ntop(sol_network_sol_to_af(addr->family), &addr->addr,
            sol_buffer_at_end(buf), buf->capacity - buf->used);

        if (r || (!r && errno != ENOSPC))
            break;

        err = sol_buffer_expand(buf, SOL_INET_ADDR_STRLEN);
        SOL_INT_CHECK(err, < 0, NULL);
    }

    if (r)
        buf->used += strlen(r);
    return r;
}

SOL_API const struct sol_network_link_addr *
sol_network_link_addr_from_str(struct sol_network_link_addr *addr, const char *buf)
{
    SOL_NULL_CHECK(addr, NULL);
    SOL_NULL_CHECK(buf, NULL);

    if (is_bluetooth_addr_str(buf))
        return bluetooth_addr_from_str(addr, buf);

    if (inet_pton(sol_network_sol_to_af(addr->family), buf, &addr->addr) != 1)
        return NULL;
    return addr;
}

static struct sol_network_link *
_get_link(int index)
{
    struct sol_network_link *link = NULL;
    uint16_t idx;

    SOL_VECTOR_FOREACH_IDX (&network->links, link, idx)
        if (link->index == index)
            return link;

    link = sol_vector_append(&network->links);
    SOL_NULL_CHECK(link, NULL);

    SOL_SET_API_VERSION(link->api_version = SOL_NETWORK_LINK_API_VERSION; )
{'fraction_non_alphanumeric': 0.11359886872495875, 'fraction_numerical': 0.00648126325712939, 'mean_word_length': 3.459800315291645, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4027009', 'n_tokens_mistral': 3025, 'n_tokens_neox': 2920, 'n_words': 757}