#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "mldapchecker.h"
#include "log.h"

static int connet_socket(int client_socket, struct sockaddr_un *server_addr) {
    int ret = MLDAP_SUCCESS;

    memset(server_addr, 0, sizeof(struct sockaddr_un));
    server_addr->sun_family = AF_UNIX;
    strncpy(server_addr->sun_path, "/dev/socket/bsd/bsd", 22);

    if ((ret = connect(client_socket, (struct sockaddr *)server_addr, sizeof(struct sockaddr_un))) == MLDAP_ERROR) {
        LOGD(
            "[client] client_socket: %d, server_addr.sun_name: %s, server_addr.sun_family: %d, "
            "errno: %d",
            client_socket, ((struct sockaddr_un *)server_addr)->sun_path,
            ((struct sockaddr_un *)server_addr)->sun_family, errno);
        LOGE("[client] Error: Failed in connect function. %s\n", strerror(errno));
        ret = MLDAP_ERROR;
    }

    return ret;
}

static int send_request(int client_socket, const char *req_buf) {
    int ret = MLDAP_SUCCESS;

    if (send(client_socket, req_buf, strlen(req_buf), MSG_EOR | MSG_NOSIGNAL) < 0) {
        LOGE("[client] Error: Failed to send data. %s\n", strerror(errno));
        ret = MLDAP_ERROR;
    }

    return ret;
}

int sendTobsd(const uint8_t *cmd) {
    int ret = MLDAP_SUCCESS;
    int ret_buf[MAX_BUFFER_SIZE] = {0};
    struct sockaddr_un server_addr;
    const int client_socket = socket(AF_UNIX, SOCK_STREAM, 0);

    if (client_socket == MLDAP_ERROR) {
        LOGE("[client] failed to create socket: %s\n", strerror(errno));
        ret = MLDAP_ERROR;
        goto exit;
    }

    do {
        ret = connet_socket(client_socket, &server_addr);
        if (ret != MLDAP_SUCCESS)
            break;
        while(1) {
            ret = send_request(client_socket, cmd);
            if (ret != MLDAP_SUCCESS) {
                close(client_socket);
                goto exit;
            }
            break;
        }
        while(1) {
            if(recv(client_socket, ret_buf, MAX_BUFFER_SIZE-1, 0) <= 0) {
                LOGE("[client] failed to receive return value");
                close(client_socket);
                goto exit;
            } else {
                if(ret_buf[0] != 0) {
                    ret = MLDAP_ERROR;
                    LOGE("[client] return value : %x", ret_buf[0]);
                }
                break;
            }
        }
    } while(0);

    close(client_socket);
exit:
    return ret;
}

JNIEXPORT jint JNICALL Java_com_sec_mldapchecker_MldapChecker_checkServiceKey(JNIEnv *a, jobject b)
{
    int ret = MLDAP_NO;

    LOGE("[client] mldapchecker servicekey check");
    if(!sendTobsd("mlcs"))
        ret = MLDAP_OK;
    else
        ret = MLDAP_NO;

    return ret;
}

JNIEXPORT jint JNICALL Java_com_sec_mldapchecker_MldapChecker_checkCertification(JNIEnv *a, jobject b)
{
    int ret = MLDAP_NO;

    LOGE("[client] mldapchecker certification check");
    if(!sendTobsd("mlcc"))
        ret = MLDAP_OK;
    else
        ret = MLDAP_NO;

    return ret;
}
