• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  * conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  * of conditions and the following disclaimer in the documentation and/or other materials
13  * provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  * to endorse or promote products derived from this software without specific prior written
17  * permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 
33 #include <osTest.h>
34 #include <sys/socket.h>
35 #include <poll.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #define SERVER_PORT 8888
40 #define INVALID_SOCKET -1
41 #define CLIENT_NUM 25
42 #define BACKLOG CLIENT_NUM
43 
44 static int gFds[FD_SETSIZE];
45 static int gBye;
46 
InitFds()47 static void InitFds()
48 {
49     for (int i = 0; i < FD_SETSIZE; ++i) {
50         gFds[i] = INVALID_SOCKET;
51     }
52 }
53 
GetReadfds(struct pollfd * fds,int * nfd)54 static void GetReadfds(struct pollfd *fds, int *nfd)
55 {
56     for (int i = 0; i < FD_SETSIZE; i++) {
57         if (gFds[i] == INVALID_SOCKET) {
58             continue;
59         }
60         fds[*nfd].fd = gFds[i];
61         fds[*nfd].events = POLLIN;
62         (*nfd)++;
63     }
64 }
65 
AddFd(int fd)66 static int AddFd(int fd)
67 {
68     for (int i = 0; i < FD_SETSIZE; ++i) {
69         if (gFds[i] == INVALID_SOCKET) {
70             gFds[i] = fd;
71             return 0;
72         }
73     }
74     return -1;
75 }
76 
DelFd(int fd)77 static void DelFd(int fd)
78 {
79     for (int i = 0; i < FD_SETSIZE; ++i) {
80         if (gFds[i] == fd) {
81             gFds[i] = INVALID_SOCKET;
82         }
83     }
84     (void)close(fd);
85 }
86 
CloseAllFd(void)87 static int CloseAllFd(void)
88 {
89     for (int i = 0; i < FD_SETSIZE; ++i) {
90         if (gFds[i] != INVALID_SOCKET) {
91             (void)close(gFds[i]);
92             gFds[i] = INVALID_SOCKET;
93         }
94     }
95     return 0;
96 }
97 
HandleRecv(int fd)98 static int HandleRecv(int fd)
99 {
100     char buf[256];
101     int ret = recv(fd, buf, sizeof(buf)-1, 0);
102     if (ret < 0) {
103         LogPrintln("[%d]Error: %s", fd, strerror(errno));
104         DelFd(fd);
105     } else if (ret == 0) {
106         LogPrintln("[%d]Closed", fd);
107         DelFd(fd);
108     } else {
109         buf[ret] = 0;
110         LogPrintln("[%d]Received: %s", fd, buf);
111         if (strstr(buf, "Bye") != NULL) {
112             DelFd(fd);
113             gBye++;
114         }
115     }
116     return -(ret < 0);
117 }
118 
HandleAccept(int lsfd)119 static int HandleAccept(int lsfd)
120 {
121     struct sockaddr_in sa;
122     int saLen = sizeof(sa);
123     int fd = accept(lsfd, reinterpret_cast<struct sockaddr *>(&sa), reinterpret_cast<socklen_t *>(&saLen));
124     if (fd == INVALID_SOCKET) {
125         perror("accept");
126         return -1;
127     }
128 
129     if (AddFd(fd) == -1) {
130         LogPrintln("Too many clients, refuse %s:%d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
131         close(fd);
132         return -1;
133     }
134     LogPrintln("New client %d: %s:%d", fd, inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
135     return 0;
136 }
137 
HandleReadfds(struct pollfd * fds,int nfds,int lsfd)138 static int HandleReadfds(struct pollfd *fds, int nfds, int lsfd)
139 {
140     int ret = 0;
141     for (int i = 0; i < nfds; ++i) {
142         if (fds[i].revents == 0) {
143             continue;
144         }
145         LogPrintln("[%d]revents: %04hx", fds[i].fd, fds[i].revents);
146         if (fds[i].fd == lsfd) {
147             ret += HandleAccept(lsfd);
148         } else {
149             ret += HandleRecv(fds[i].fd);
150         }
151     }
152     return ret;
153 }
154 
ClientsThread(void * param)155 static void *ClientsThread(void *param)
156 {
157     int fd;
158     int thrNo = (int)(intptr_t)param;
159 
160     LogPrintln("<%d>socket client thread started", thrNo);
161     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
162     if (fd == INVALID_SOCKET) {
163         perror("socket");
164         return NULL;
165     }
166 
167     struct sockaddr_in sa;
168     sa.sin_family = AF_INET;
169     sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
170     sa.sin_port = htons(SERVER_PORT);
171     if (connect(fd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa)) == -1) {
172         perror("connect");
173         return NULL;
174     }
175 
176     LogPrintln("[%d]<%d>connected to %s:%d successful", fd, thrNo, inet_ntoa(sa.sin_addr), SERVER_PORT);
177 
178     const char *msg[] = {
179         "hello, ",
180         "ohos, ",
181         "my name is net_socket_test_009, ",
182         "see u next time, ",
183         "Bye!"
184     };
185 
186     for (int i = 0; i < sizeof(msg) / sizeof(msg[0]); ++i) {
187         if (send(fd, msg[i], strlen(msg[i]), 0) < 0) {
188             LogPrintln("[%d]<%d>send msg [%s] fail", fd, thrNo, msg[i]);
189         }
190     }
191 
192     (void)shutdown(fd, SHUT_RDWR);
193     (void)close(fd);
194     return param;
195 }
196 
StartClients(pthread_t * cli,int cliNum)197 static int StartClients(pthread_t *cli, int cliNum)
198 {
199     int ret;
200     pthread_attr_t attr;
201 
202     for (int i = 0; i < cliNum; ++i) {
203         ret = pthread_attr_init(&attr);
204         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
205 
206         ret = pthread_create(&cli[i], &attr, ClientsThread, (void *)(intptr_t)i);
207         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
208 
209         ret = pthread_attr_destroy(&attr);
210         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
211     }
212     return 0;
213 }
214 
PollTest(void)215 static int PollTest(void)
216 {
217     struct sockaddr_in sa = {0};
218     int lsfd;
219     int ret;
220 
221     lsfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
222     ICUNIT_ASSERT_NOT_EQUAL(lsfd, -1, errno);
223 
224     sa.sin_family = AF_INET;
225     sa.sin_addr.s_addr = htonl(INADDR_ANY);
226     sa.sin_port = htons(SERVER_PORT);
227     ret = bind(lsfd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa));
228     ICUNIT_ASSERT_NOT_EQUAL(ret, -1, errno + CloseAllFd());
229 
230     ret = listen(lsfd, BACKLOG);
231     ICUNIT_ASSERT_NOT_EQUAL(ret, -1, errno + CloseAllFd());
232 
233     InitFds();
234     AddFd(lsfd);
235     LogPrintln("[%d]Waiting for client to connect on port %d", lsfd, SERVER_PORT);
236 
237     pthread_t clients[CLIENT_NUM];
238 
239     ret = StartClients(clients, CLIENT_NUM);
240     ICUNIT_ASSERT_EQUAL(ret, 0, ret + CloseAllFd());
241 
242     for ( ; ; ) {
243         int nfd;
244         struct pollfd readfds[FD_SETSIZE];
245         int timeoutMs;
246 
247         timeoutMs = 3000;
248         nfd = 0;
249         GetReadfds(readfds, &nfd);
250 
251         ret = poll(readfds, nfd, timeoutMs);
252         LogPrintln("poll %d", ret);
253         if (ret == -1) {
254             perror("poll");
255             break; // error occurred
256         } else if (ret == 0) {
257             break; // timed out
258         }
259 
260         if (HandleReadfds(readfds, nfd, lsfd) < 0) {
261             break;
262         }
263     }
264 
265     for (int i = 0; i < CLIENT_NUM; ++i) {
266         ret = pthread_join(clients[i], NULL);
267         ICUNIT_ASSERT_EQUAL(ret, 0, ret + CloseAllFd());
268     }
269 
270     ICUNIT_ASSERT_EQUAL(gBye, CLIENT_NUM, gBye + CloseAllFd());
271     (void)CloseAllFd();
272     return ICUNIT_SUCCESS;
273 }
274 
NetSocketTest009(void)275 void NetSocketTest009(void)
276 {
277     TEST_ADD_CASE(__FUNCTION__, PollTest, TEST_POSIX, TEST_TCP, TEST_LEVEL0, TEST_FUNCTION);
278 }
279