/*

 * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.

 

 * K-NET is licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

      http://license.coscl.org.cn/MulanPSL2

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.

 * See the Mulan PSL v2 for more details.

 */





#include "securec.h"



#include <unistd.h>

#include <fcntl.h>

#include <dirent.h>

#include <dlfcn.h>



#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/ioctl.h>

#include <linux/if_arp.h>

#include <linux/if_tun.h>

#include <linux/if.h>

#include <sys/uio.h>



#include "knet_config.h"

#include "knet_log.h"

#include "knet_socket_api.h"



#include "tcp_fd.h"

#include "dp_zcopy_api.h"

#include "dp_pbuf_api.h"

#include "common.h"

#include "mock.h"



extern bool g_tcpInited;



DTEST_CASE_F(ZCOPY, TEST_IOV_ALLOC_NORMAL, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);



    void *ebuf = knet_mp_alloc(0);

    DT_ASSERT_EQUAL(ebuf, NULL);



    Mock->Create(DP_ZcopyAlloc, TEST_GetFuncRetPositive(1));

    g_tcpInited = true;

    ebuf = knet_mp_alloc(1);

    DT_ASSERT_NOT_EQUAL(ebuf, NULL);

    

    g_tcpInited = false;

    Mock->Delete(DP_ZcopyAlloc);

    DeleteMock(Mock);

}



static void FakeFreeCb(void *addr)

{

    (void)addr;

    return;

}



DTEST_CASE_F(ZCOPY, TEST_IOV_FREE_NORMAL, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);



    knet_mp_free(NULL, NULL);



    Mock->Create(DP_ZcopyFree, TEST_GetFuncRetPositive(0));

    g_tcpInited = true;

    knet_mp_free(NULL, NULL);

    

    g_tcpInited = false;

    Mock->Delete(DP_ZcopyFree);

    DeleteMock(Mock);

}



static bool KNET_IsFdHijackMock(int osFd)

{

    return true;

}



DTEST_CASE_F(ZCOPY, TEST_ZWRITEV_NORMAL, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);



    uint32_t ret;

    struct knet_iovec iov = {0};

    ret = knet_zwritev(0, NULL, 0);

    DT_ASSERT_EQUAL(ret, KNET_ERROR);



    Mock->Create(KNET_IsFdHijack, KNET_IsFdHijackMock);

    Mock->Create(DP_ZWritev, TEST_GetFuncRetPositive(0));

    Mock->Create(KNET_OsFdToDpFd, TEST_GetFuncRetPositive(0));

    g_tcpInited = true;

    ret = knet_zwritev(1, &iov, 1);

    DT_ASSERT_EQUAL(ret, KNET_OK);

    

    g_tcpInited = false;

    Mock->Delete(KNET_OsFdToDpFd);

    Mock->Delete(DP_ZWritev);

    Mock->Delete(KNET_IsFdHijack);

    DeleteMock(Mock);

}



DTEST_CASE_F(ZCOPY, TEST_ZREADV_NORMAL, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);



    uint32_t ret;

    struct knet_iovec iov = {0};

    ret = knet_zreadv(0, NULL, 0);

    DT_ASSERT_EQUAL(ret, KNET_ERROR);



    Mock->Create(KNET_IsFdHijack, KNET_IsFdHijackMock);

    Mock->Create(DP_ZReadv, TEST_GetFuncRetPositive(0));

    Mock->Create(KNET_OsFdToDpFd, TEST_GetFuncRetPositive(0));

    g_tcpInited = true;

    ret = knet_zreadv(1, &iov, 1);

    DT_ASSERT_EQUAL(ret, KNET_OK);



    if (iov.free_cb != NULL) {

        iov.free_cb(iov.iov_base, iov.opaque);

    }

    

    g_tcpInited = false;

    Mock->Delete(KNET_OsFdToDpFd);

    Mock->Delete(DP_ZReadv);

    Mock->Delete(KNET_IsFdHijack);

    DeleteMock(Mock);

}



static bool KNET_IsFdHijackMockNegative(int osFd)

{

    return false;

}



DTEST_CASE_F(ZCOPY, TEST_ZWRITEV_NOT_HIJACK, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);



    uint32_t ret;

    struct knet_iovec iov = {0};

    ret = knet_zwritev(0, NULL, 0);

    DT_ASSERT_EQUAL(ret, KNET_ERROR);



    ssize_t (*osWritev)(int fd, const struct iovec *iov, int iovcnt) = dlsym(g_sysLibcHandle, "writev");



    Mock->Create(KNET_IsFdHijack, KNET_IsFdHijackMockNegative);

    Mock->Create(osWritev, TEST_GetFuncRetPositive(0));

    g_tcpInited = true;

    ret = knet_zwritev(1, &iov, 1);

    DT_ASSERT_EQUAL(ret, KNET_OK);

    

    g_tcpInited = false;

    Mock->Delete(osWritev);

    Mock->Delete(KNET_IsFdHijack);

    DeleteMock(Mock);

}



DTEST_CASE_F(ZCOPY, TEST_ZREADV_NOT_HIJACK, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);



    uint32_t ret;

    struct knet_iovec iov = {0};

    ret = knet_zreadv(0, NULL, 0);

    DT_ASSERT_EQUAL(ret, KNET_ERROR);



    void *g_sysLibcHandle = dlopen("/usr/lib64/libc.so.6", RTLD_NOW | RTLD_GLOBAL);

    ssize_t (*osReadv)(int fd, const struct iovec *iov, int iovcnt) = dlsym(g_sysLibcHandle, "readv");



    Mock->Create(KNET_IsFdHijack, KNET_IsFdHijackMockNegative);

    Mock->Create(osReadv, TEST_GetFuncRetPositive(0));

    g_tcpInited = true;

    ret = knet_zreadv(1, &iov, 1);

    DT_ASSERT_EQUAL(ret, KNET_OK);



    if (iov.free_cb != NULL) {

        iov.free_cb(iov.iov_base, iov.opaque);

    }

    

    g_tcpInited = false;

    Mock->Delete(osReadv);

    Mock->Delete(KNET_IsFdHijack);

    DeleteMock(Mock);

}