<commit_before>/*
 * This file is part of the Soletta Project
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *   * Neither the name of Intel Corporation nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "sol-log.h"
#include "sol-mainloop.h"
#include "sol-network.h"
#include "sol-network-util.h"
#include "sol-util.h"

#include "sol-socket.h"
#include "sol-socket-impl.h"

struct sol_socket_linux {
    struct sol_socket base;

    int fd;
    struct {
        bool (*cb)(void *data, struct sol_socket *s);
        const void *data;
        struct sol_fd *watch;
    } read, write;
};

static bool
on_socket_read(void *data, int fd, unsigned int flags)
{
    struct sol_socket_linux *s = data;
    bool ret;

    ret = s->read.cb((void *)s->read.data, &s->base);
    if (!ret) {
        s->read.cb = NULL;
        s->read.data = NULL;
        s->read.watch = NULL;
    }
    return ret;
}

static bool
on_socket_write(void *data, int fd, unsigned int flags)
{
    struct sol_socket_linux *s = data;
    bool ret;

    ret = s->write.cb((void *)s->write.data, &s->base);
    if (!ret) {
        s->write.cb = NULL;
        s->write.data = NULL;
        s->write.watch = NULL;
    }
    return ret;
}

static int
from_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen,
    struct sol_network_link_addr *addr)
{
    SOL_NULL_CHECK(sockaddr, -EINVAL);
    SOL_NULL_CHECK(addr, -EINVAL);

    if (sockaddr->sa_family != AF_INET && sockaddr->sa_family != AF_INET6)
        return -EINVAL;

    addr->family = sol_network_af_to_sol(sockaddr->sa_family);

    if (sockaddr->sa_family == AF_INET) {
        struct sockaddr_in *sock4 = (struct sockaddr_in *)sockaddr;
        if (socklen < sizeof(struct sockaddr_in))
            return -EINVAL;

        addr->port = ntohs(sock4->sin_port);
        memcpy(&addr->addr.in, &sock4->sin_addr, sizeof(sock4->sin_addr));
    } else {
        struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sockaddr;
        if (socklen < sizeof(struct sockaddr_in6))
            return -EINVAL;

        addr->port = ntohs(sock6->sin6_port);
        memcpy(&addr->addr.in6, &sock6->sin6_addr, sizeof(sock6->sin6_addr));
    }

    return 0;
}

static int
to_sockaddr(const struct sol_network_link_addr *addr, struct sockaddr *sockaddr, socklen_t *socklen)
{
    SOL_NULL_CHECK(addr, -EINVAL);
    SOL_NULL_CHECK(sockaddr, -EINVAL);
    SOL_NULL_CHECK(socklen, -EINVAL);

    if (addr->family == SOL_NETWORK_FAMILY_INET) {
        struct sockaddr_in *sock4 = (struct sockaddr_in *)sockaddr;
        if (*socklen < sizeof(struct sockaddr_in))
            return -EINVAL;

        memcpy(&sock4->sin_addr, addr->addr.in, sizeof(addr->addr.in));
        sock4->sin_port = htons(addr->port);
        sock4->sin_family = AF_INET;
        *socklen = sizeof(*sock4);
    } else if (addr->family == SOL_NETWORK_FAMILY_INET6) {
        struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sockaddr;
        if (*socklen < sizeof(struct sockaddr_in6))
            return -EINVAL;

        memcpy(&sock6->sin6_addr, addr->addr.in6, sizeof(addr->addr.in6));
        sock6->sin6_port = htons(addr->port);
        sock6->sin6_family = AF_INET6;
        *socklen = sizeof(*sock6);
    } else {
        return -EINVAL;
    }

    return *socklen;
}

static struct sol_socket *
sol_socket_linux_new(int domain, enum sol_socket_type type, int protocol)
{
    struct sol_socket_linux *s;
    int fd, socktype = SOCK_CLOEXEC | SOCK_NONBLOCK;

    switch (type) {
    case SOL_SOCKET_UDP:
        socktype |= SOCK_DGRAM;
        break;
    default:
        SOL_WRN("Unsupported socket type: %d", type);
        errno = EPROTOTYPE;
        return NULL;
    }

    fd = socket(domain, socktype, protocol);
    SOL_INT_CHECK(fd, < 0, NULL);

    s = calloc(1, sizeof(*s));
    SOL_NULL_CHECK_GOTO(s, calloc_error);

    s->fd = fd;
<commit_msg>sol-socket: Convert from sol_to_af before using it.<commit_after>/*
 * This file is part of the Soletta Project
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *   * Neither the name of Intel Corporation nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "sol-log.h"
#include "sol-mainloop.h"
#include "sol-network.h"
#include "sol-network-util.h"
#include "sol-util.h"

#include "sol-socket.h"
#include "sol-socket-impl.h"

struct sol_socket_linux {
    struct sol_socket base;

    int fd;
    struct {
        bool (*cb)(void *data, struct sol_socket *s);
        const void *data;
        struct sol_fd *watch;
    } read, write;
};

static bool
on_socket_read(void *data, int fd, unsigned int flags)
{
    struct sol_socket_linux *s = data;
    bool ret;

    ret = s->read.cb((void *)s->read.data, &s->base);
    if (!ret) {
        s->read.cb = NULL;
        s->read.data = NULL;
        s->read.watch = NULL;
    }
    return ret;
}

static bool
on_socket_write(void *data, int fd, unsigned int flags)
{
    struct sol_socket_linux *s = data;
    bool ret;

    ret = s->write.cb((void *)s->write.data, &s->base);
    if (!ret) {
        s->write.cb = NULL;
        s->write.data = NULL;
        s->write.watch = NULL;
    }
    return ret;
}

static int
from_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen,
    struct sol_network_link_addr *addr)
{
    SOL_NULL_CHECK(sockaddr, -EINVAL);
    SOL_NULL_CHECK(addr, -EINVAL);

    if (sockaddr->sa_family != AF_INET && sockaddr->sa_family != AF_INET6)
        return -EINVAL;

    addr->family = sol_network_af_to_sol(sockaddr->sa_family);

    if (sockaddr->sa_family == AF_INET) {
        struct sockaddr_in *sock4 = (struct sockaddr_in *)sockaddr;
        if (socklen < sizeof(struct sockaddr_in))
            return -EINVAL;

        addr->port = ntohs(sock4->sin_port);
        memcpy(&addr->addr.in, &sock4->sin_addr, sizeof(sock4->sin_addr));
    } else {
        struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sockaddr;
        if (socklen < sizeof(struct sockaddr_in6))
            return -EINVAL;

        addr->port = ntohs(sock6->sin6_port);
        memcpy(&addr->addr.in6, &sock6->sin6_addr, sizeof(sock6->sin6_addr));
    }

    return 0;
}

static int
to_sockaddr(const struct sol_network_link_addr *addr, struct sockaddr *sockaddr, socklen_t *socklen)
{
    SOL_NULL_CHECK(addr, -EINVAL);
    SOL_NULL_CHECK(sockaddr, -EINVAL);
    SOL_NULL_CHECK(socklen, -EINVAL);

    if (addr->family == SOL_NETWORK_FAMILY_INET) {
        struct sockaddr_in *sock4 = (struct sockaddr_in *)sockaddr;
        if (*socklen < sizeof(struct sockaddr_in))
            return -EINVAL;

        memcpy(&sock4->sin_addr, addr->addr.in, sizeof(addr->addr.in));
        sock4->sin_port = htons(addr->port);
        sock4->sin_family = AF_INET;
        *socklen = sizeof(*sock4);
    } else if (addr->family == SOL_NETWORK_FAMILY_INET6) {
        struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sockaddr;
        if (*socklen < sizeof(struct sockaddr_in6))
            return -EINVAL;

        memcpy(&sock6->sin6_addr, addr->addr.in6, sizeof(addr->addr.in6));
        sock6->sin6_port = htons(addr->port);
        sock6->sin6_family = AF_INET6;
        *socklen = sizeof(*sock6);
    } else {
        return -EINVAL;
    }

    return *socklen;
}

static struct sol_socket *
sol_socket_linux_new(int domain, enum sol_socket_type type, int protocol)
{
    struct sol_socket_linux *s;
    int fd, socktype = SOCK_CLOEXEC | SOCK_NONBLOCK;

    switch (type) {
    case SOL_SOCKET_UDP:
        socktype |= SOCK_DGRAM;
        break;
    default:
        SOL_WRN("Unsupported socket type: %d", type);
        errno = EPROTOTYPE;
        return NULL;
    }

    fd = socket(sol_network_sol_to_af(domain), socktype, protocol);
    SOL_INT_CHECK(fd, < 0, NULL);

    s = calloc(1, sizeof(*s));
    SOL_NULL_CHECK_GOTO(s, calloc_error);

    s->fd = fd;

{'fraction_non_alphanumeric': 0.10728428032047149, 'fraction_numerical': 0.007919697946403905, 'mean_word_length': 3.108967082860386, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 95, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4772635', 'n_tokens_mistral': 3570, 'n_tokens_neox': 3397, 'n_words': 1036}