• 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 <sys/select.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #define SERVER_PORT 7777
40 #define INVALID_SOCKET -1
41 #define CLIENT_NUM 25
42 
43 static int gFds[FD_SETSIZE];
44 static int gBye;
45 
InitFds()46 static void InitFds()
47 {
48     for (int i = 0; i < FD_SETSIZE; ++i) {
49         gFds[i] = INVALID_SOCKET;
50     }
51 }
52 
GetReadfds(fd_set * fds,int * nfd)53 static void GetReadfds(fd_set *fds, int *nfd)
54 {
55     for (int i = 0; i < FD_SETSIZE; i++) {
56         if (gFds[i] == INVALID_SOCKET) {
57             continue;
58         }
59         FD_SET(gFds[i], fds);
60         if (*nfd < gFds[i]) {
61             *nfd = gFds[i];
62         }
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[128];
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             gBye++;
113         }
114     }
115     return -(ret < 0);
116 }
117 
HandleReadfds(fd_set * fds,int lsfd)118 static int HandleReadfds(fd_set *fds, int lsfd)
119 {
120     int ret = 0;
121     for (int i = 0; i < FD_SETSIZE; ++i) {
122         if (gFds[i] == INVALID_SOCKET || !FD_ISSET(gFds[i], fds)) {
123             continue;
124         }
125         ret += HandleRecv(gFds[i]);
126     }
127     return ret;
128 }
129 
ClientsThread(void * param)130 static void *ClientsThread(void *param)
131 {
132     int fd;
133     int thrNo = (int)(intptr_t)param;
134 
135     LogPrintln("<%d>socket client thread started", thrNo);
136     fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
137     if (fd == INVALID_SOCKET) {
138         perror("socket");
139         return NULL;
140     }
141 
142     struct sockaddr_in sa;
143     sa.sin_family = AF_INET;
144     sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
145     sa.sin_port = htons(SERVER_PORT);
146     if (connect(fd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa)) == -1) {
147         perror("connect");
148         return NULL;
149     }
150 
151     LogPrintln("[%d]<%d>connected to udp://%s:%d successful", fd, thrNo, inet_ntoa(sa.sin_addr), SERVER_PORT);
152 
153     const char *msg[] = {
154             "ohos, ",
155             "hello, ",
156             "my name is net_socket_test_011, ",
157             "see u next time, ",
158             "Bye!",
159     };
160 
161     for (int i = 0; i < sizeof(msg) / sizeof(msg[0]); ++i) {
162         if (send(fd, msg[i], strlen(msg[i]), 0) < 0) {
163             LogPrintln("[%d]<%d>send msg [%s] fail", fd, thrNo, msg[i]);
164         }
165     }
166 
167     (void)shutdown(fd, SHUT_RDWR);
168     (void)close(fd);
169     return param;
170 }
171 
StartClients(pthread_t * cli,int cliNum)172 static int StartClients(pthread_t *cli, int cliNum)
173 {
174     int ret;
175     pthread_attr_t attr = {0};
176     struct sched_param param = { 0 };
177     int policy;
178     ret = pthread_getschedparam(pthread_self(), &policy, &param);
179     ICUNIT_ASSERT_EQUAL(ret, 0, -ret);
180 
181     for (int i = 0; i < cliNum; ++i) {
182         ret = pthread_attr_init(&attr);
183         param.sched_priority = param.sched_priority + 1;
184         if (param.sched_priority > 31) {    /* 31: prio */
185             param.sched_priority = 31;  /* 31: prio */
186         }
187         pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
188         pthread_attr_setschedparam(&attr, &param);
189 
190         ret = pthread_create(&cli[i], &attr, ClientsThread, (void *)(intptr_t)i);
191         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
192         ret = pthread_attr_destroy(&attr);
193         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
194     }
195     return 0;
196 }
197 
UdpSelectTest(void)198 static int UdpSelectTest(void)
199 {
200     struct sockaddr_in sa = {0};
201     int lsfd;
202     int ret;
203 
204     lsfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
205     ICUNIT_ASSERT_NOT_EQUAL(lsfd, -1, errno);
206 
207     sa.sin_family = AF_INET;
208     sa.sin_addr.s_addr = htonl(INADDR_ANY);
209     sa.sin_port = htons(SERVER_PORT);
210     ret = bind(lsfd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa));
211     ICUNIT_ASSERT_NOT_EQUAL(ret, -1, errno + CloseAllFd());
212 
213     InitFds();
214     AddFd(lsfd);
215     LogPrintln("[%d]Waiting for client to connect on UDP port %d", lsfd, SERVER_PORT);
216 
217     pthread_t clients[CLIENT_NUM];
218 
219     ret = StartClients(clients, CLIENT_NUM);
220     ICUNIT_ASSERT_EQUAL(ret, 0, ret + CloseAllFd());
221 
222     for ( ; ; ) {
223         int nfd;
224         fd_set readfds;
225         struct timeval timeout;
226 
227         timeout.tv_sec = 3;
228         timeout.tv_usec = 0;
229 
230         nfd = 0;
231         FD_ZERO(&readfds);
232 
233         GetReadfds(&readfds, &nfd);
234 
235         ret = select(nfd + 1, &readfds, NULL, NULL, &timeout);
236         LogPrintln("select %d", ret);
237         if (ret == -1) {
238             perror("select");
239             break; // error occurred
240         } else if (ret == 0) {
241             break; // timed out
242         }
243 
244         if (HandleReadfds(&readfds, lsfd) < 0) {
245             break;
246         }
247     }
248 
249     for (int i = 0; i < CLIENT_NUM; ++i) {
250         ret = pthread_join(clients[i], NULL);
251         ICUNIT_ASSERT_EQUAL(ret, 0, ret + CloseAllFd());
252     }
253 
254     ICUNIT_ASSERT_EQUAL(gBye, CLIENT_NUM, gBye + CloseAllFd());
255     (void)CloseAllFd();
256     return ICUNIT_SUCCESS;
257 }
258 
NetSocketTest011(void)259 void NetSocketTest011(void)
260 {
261     TEST_ADD_CASE(__FUNCTION__, UdpSelectTest, TEST_POSIX, TEST_TCP, TEST_LEVEL0, TEST_FUNCTION);
262 }
263