1/*
2 * Copyright (C) 2024 HiHope Open Source Organization.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <cerrno>
17#include <cstdio>
18#include <cstdlib>
19#include <string>
20#include <vector>
21#include <fcntl.h>
22#include <pthread.h>
23#include <unistd.h>
24#include <arpa/inet.h>
25#include <gtest/gtest.h>
26#include <netinet/in.h>
27#include <sys/stat.h>
28#include <sys/socket.h>
29#include <sys/types.h>
30#include "securec.h"
31
32using namespace testing::ext;
33
34static const int BAD_SOCKET_FD = -1;
35static const int TEST_PORT = 22357;
36static const char *TEST_LOCAL_IP = "127.0.0.1";
37static int g_serviceFd = -1;
38
39class HatsAcceptTest : public testing::Test {
40public:
41    static void SetUpTestCase();
42    static void TearDownTestCase();
43    void SetUp();
44    void TearDown();
45private:
46};
47void HatsAcceptTest::SetUp()
48{
49    int ret;
50    int socketFd = -1;
51    int32_t optVal = 1;
52    struct sockaddr_in serAddr = {
53        .sin_family = AF_INET,
54        .sin_port = htons(TEST_PORT),
55        .sin_addr = {
56            .s_addr = inet_addr(TEST_LOCAL_IP),
57        }
58    };
59
60    socketFd = socket(AF_INET, SOCK_STREAM, 0);
61    EXPECT_TRUE(socketFd > 0);
62
63    ret = setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal));
64    EXPECT_EQ(ret, 0);
65
66    ret = bind(socketFd, reinterpret_cast<struct sockaddr *>(&serAddr), sizeof(serAddr));
67    EXPECT_EQ(ret, 0);
68
69    g_serviceFd = socketFd;
70}
71void HatsAcceptTest::TearDown()
72{
73    close(g_serviceFd);
74    g_serviceFd = -1;
75}
76void HatsAcceptTest::SetUpTestCase()
77{
78}
79void HatsAcceptTest::TearDownTestCase()
80{
81}
82
83static void *ClientConnect(void *args)
84{
85    int ret;
86    int clientFd = -1;
87    struct sockaddr_in serAddr = {
88        .sin_family = AF_INET,
89        .sin_port = htons(TEST_PORT),
90        .sin_addr = {
91            .s_addr = inet_addr(TEST_LOCAL_IP),
92        }
93    };
94
95    clientFd = socket(AF_INET, SOCK_STREAM, 0);
96    EXPECT_TRUE(clientFd > 0);
97
98    ret = connect(clientFd, reinterpret_cast<struct sockaddr *>(&serAddr), sizeof(struct sockaddr_in));
99
100    close(clientFd);
101    return nullptr;
102}
103
104/*
105 * @tc.number : SUB_KERNEL_SYSCALL_ACCEPT_0100
106 * @tc.name   : AcceptClientSuccess_0001
107 * @tc.desc   : accept client success.
108 * @tc.size   : MediumTest
109 * @tc.type   : Function
110 * @tc.level  : Level 1
111 */
112HWTEST_F(HatsAcceptTest, AcceptClientSuccess_0001, Function | MediumTest | Level1)
113{
114    int ret;
115    pthread_t thread;
116    int acceptFd = -1;
117    int32_t backLog = 5;
118    struct sockaddr_in dstAddr = { 0 };
119    socklen_t addrLen = sizeof(struct sockaddr_in);
120
121    ret = listen(g_serviceFd, backLog);
122    EXPECT_EQ(ret, 0);
123
124    pthread_create(&thread, nullptr, ClientConnect, nullptr);
125
126    acceptFd = accept(g_serviceFd, reinterpret_cast<struct sockaddr *>(&dstAddr), &addrLen);
127    EXPECT_TRUE(acceptFd > 0);
128
129    close(acceptFd);
130    pthread_join(thread, nullptr);
131}
132
133/*
134 * @tc.number : SUB_KERNEL_SYSCALL_ACCEPT_0200
135 * @tc.name   : AcceptUseInvalidFdFailed_0002
136 * @tc.desc   : accept use invalid fd failed.
137 * @tc.size   : MediumTest
138 * @tc.type   : Function
139 * @tc.level  : Level 2
140 */
141HWTEST_F(HatsAcceptTest, AcceptUseInvalidFdFailed_0002, Function | MediumTest | Level2)
142{
143    int acceptFd = -1;
144    struct sockaddr_in dstAddr = { 0 };
145    socklen_t addrLen = sizeof(struct sockaddr_in);
146
147    errno = 0;
148    acceptFd = accept(BAD_SOCKET_FD, reinterpret_cast<struct sockaddr *>(&dstAddr), &addrLen);
149    EXPECT_EQ(acceptFd, -1);
150    EXPECT_EQ(errno, EBADF);
151
152    errno = 0;
153    acceptFd = accept4(STDIN_FILENO, nullptr, nullptr, 0);
154    EXPECT_EQ(acceptFd, -1);
155    EXPECT_EQ(errno, ENOTSOCK);
156}