// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <atomic>
#include <cstdlib>
#include <cstring>
#include <fbl/algorithm.h>
#include <lib/fdio/directory.h>
#include <lib/zx/channel.h>
#include <lib/zx/process.h>
#include <lib/zx/socket.h>
#include <utility>
#include <zircon/assert.h>

#include <fuchsia/logger/c/fidl.h>
#include <lib/log-writer-logger/wire_format.h>
#include <lib/log/log.h>
#include <lib/log/log_writer.h>

#include <lib/log-writer-logger/log-writer-logger.h>

namespace {

zx_koid_t get_koid(zx_handle_t handle) {
    zx_info_handle_basic_t info;
    zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
                                            sizeof(info), nullptr, nullptr);
    return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
}

zx_koid_t get_current_process_koid() {
    auto koid = get_koid(zx_process_self());
    ZX_DEBUG_ASSERT(koid != ZX_KOID_INVALID);
    return koid;
}

// This thread's koid.
// Initialized on first use.
thread_local zx_koid_t tls_thread_koid{ZX_KOID_INVALID};

zx_koid_t get_current_thread_koid() {
    if (unlikely(tls_thread_koid == ZX_KOID_INVALID)) {
        tls_thread_koid = get_koid(zx_thread_self());
    }
    ZX_DEBUG_ASSERT(tls_thread_koid != ZX_KOID_INVALID);
    return tls_thread_koid;
}

bool connect_to_logger(zx::socket* socket) {
    zx::channel logger, logger_request;
    if (zx::channel::create(0, &logger, &logger_request) != ZX_OK) {
        return false;
    }
    if (fdio_service_connect("/svc/fuchsia.logger.LogSink", logger_request.release()) != ZX_OK) {
        return false;
    }
    zx::socket local, remote;
    if (zx::socket::create(ZX_SOCKET_DATAGRAM, &local, &remote) != ZX_OK) {
        return false;
    }
    fuchsia_logger_LogSinkConnectRequest req;
    memset(&req, 0, sizeof(req));
    req.hdr.ordinal = fuchsia_logger_LogSinkConnectOrdinal;
    req.socket = FIDL_HANDLE_PRESENT;
    zx_handle_t handles[1] = {remote.release()};
    if (logger.write(0, &req, sizeof(req), handles, 1) != ZX_OK) {
        close(handles[0]);
        return false;
    }
    *socket = std::move(local);
    return true;
}

class LoggerWriter final : public log_writer {
public:
    LoggerWriter()
        : log_writer{&kOps}, pid_(get_current_process_koid()), dropped_logs_(0) {
        socket_error_encountered_ = !connect_to_logger(&socket_);
    }

    void Write(const log_message_t* msg);
    void SetSocket(zx_handle_t handle);

private:
    static const log_writer_ops_t kOps;

    zx_koid_t pid_;
    zx::socket socket_;
    std::atomic<uint32_t> dropped_logs_;
    bool socket_error_encountered_;
};

void logger_writer_write(log_writer_t* writer, const log_message_t* message) {
    auto self = static_cast<LoggerWriter*>(writer);
    self->Write(message);
}

const log_writer_ops_t LoggerWriter::kOps = {
    .version = LOG_WRITER_OPS_V1,
    .reserved = 0,
    .v1 = {
        .write = logger_writer_write,
    },
};

// Given a c string and a destination to write the string, copies in a uint8_t
// of the string length, the string contents, and returns the number of bytes
// copied in (i.e. string length + 1). If the string length is greater than
// max_allowed_write, the write is aborted and 0 bytes are written.
size_t write_tag(const char* tag, void* dest, size_t max_allowed_write) {
    size_t tag_len = strlen(tag);
    if (max_allowed_write < tag_len + 1) {
        // Writing this tag would exceed our allowance, so write nothing instead
        return 0;
    }
    *(char*)dest = static_cast<char>(tag_len);
    memcpy((char*)dest + 1, tag, tag_len);
    return tag_len + 1;
}

void LoggerWriter::Write(const log_message* message) {
    if (socket_error_encountered_) {
        return;
    }

    zx_time_t time = zx_clock_get_monotonic();
    log_packet_t packet;
    memset(&packet, 0, sizeof(packet));
    constexpr size_t kDataSize = sizeof(packet.data);
    packet.metadata.pid = pid_;
    packet.metadata.tid = get_current_thread_koid();
    packet.metadata.time = time;
    packet.metadata.level = message->level;
    packet.metadata.dropped_logs = dropped_logs_.load();

    size_t pos = 0;

    // Write tags
    int tag_counter = 0;
    for (size_t i = 0; i < message->num_static_tags; i++) {
        if (++tag_counter > LOG_MAX_TAGS) {
            break;
        }
        pos += write_tag(message->static_tags[i], packet.data + pos,
                         fbl::min(kDataSize - pos, (long unsigned int)LOG_MAX_TAG_LEN));
    }
    for (size_t i = 0; i < message->num_dynamic_tags; i++) {
        if (++tag_counter > LOG_MAX_TAGS) {
            break;
        }
        pos += write_tag(message->dynamic_tags[i], packet.data + pos,
                         fbl::min(kDataSize - pos, (long unsigned int)LOG_MAX_TAG_LEN));
    }

    packet.data[pos++] = 0;
    ZX_DEBUG_ASSERT(pos < kDataSize);

    // Write msg
    size_t msg_len = message->text_len + 1; // Include the null byte here
    bool cutoff = false;
    if (msg_len > kDataSize - pos) {
        msg_len = kDataSize - pos;
        cutoff = true;
    }
    memcpy(packet.data + pos, message->text, msg_len);
    pos += msg_len;
    if (cutoff) {
        memcpy(packet.data + kDataSize - 4, "...", 4);
    }

    // Send msg
    auto size = sizeof(packet.metadata) + pos;
    ZX_DEBUG_ASSERT(size <= sizeof(packet));
    auto status = socket_.write(0, &packet, size, nullptr);
    if (status == ZX_ERR_BAD_STATE || status == ZX_ERR_PEER_CLOSED) {
        // The socket is no longer usable, mark this as broken.
        socket_error_encountered_ = true;
        return;
    }
    if (status != ZX_OK) {
        dropped_logs_.fetch_add(1);
    }
}

void LoggerWriter::SetSocket(zx_handle_t handle) {
    socket_ = zx::socket(handle);
    socket_error_encountered_ = false;
}

} // namespace

log_writer_t* log_create_logger_writer(void) {
    return new LoggerWriter();
}

void log_destroy_logger_writer(log_writer_t* writer) {
    delete static_cast<LoggerWriter*>(writer);
}

void log_set_logger_writer_socket(log_writer_t* writer, zx_handle_t handle) {
    static_cast<LoggerWriter*>(writer)->SetSocket(handle);
}
