• 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 #include <net/if.h>
39 #include <sys/ioctl.h>
40 
41 #define SERVER_PORT 9999
42 #define INVALID_SOCKET -1
43 #define CLIENT_NUM 1
44 
45 static int gFds[FD_SETSIZE];
46 static int gBye;
47 
InitFds()48 static void InitFds()
49 {
50     for (int i = 0; i < FD_SETSIZE; ++i) {
51         gFds[i] = INVALID_SOCKET;
52     }
53 }
54 
GetReadfds(fd_set * fds,int * nfd)55 static void GetReadfds(fd_set *fds, int *nfd)
56 {
57     for (int i = 0; i < FD_SETSIZE; i++) {
58         if (gFds[i] == INVALID_SOCKET) {
59             continue;
60         }
61         FD_SET(gFds[i], fds);
62         if (*nfd < gFds[i]) {
63             *nfd = gFds[i];
64         }
65     }
66 }
67 
AddFd(int fd)68 static int AddFd(int fd)
69 {
70     for (int i = 0; i < FD_SETSIZE; ++i) {
71         if (gFds[i] == INVALID_SOCKET) {
72             gFds[i] = fd;
73             return 0;
74         }
75     }
76     return -1;
77 }
78 
DelFd(int fd)79 static void DelFd(int fd)
80 {
81     for (int i = 0; i < FD_SETSIZE; ++i) {
82         if (gFds[i] == fd) {
83             gFds[i] = INVALID_SOCKET;
84         }
85     }
86     (void)close(fd);
87 }
88 
CloseAllFd(void)89 static int CloseAllFd(void)
90 {
91     for (int i = 0; i < FD_SETSIZE; ++i) {
92         if (gFds[i] != INVALID_SOCKET) {
93             (void)close(gFds[i]);
94             gFds[i] = INVALID_SOCKET;
95         }
96     }
97     return 0;
98 }
99 
HandleRecv(int fd)100 static int HandleRecv(int fd)
101 {
102     char buf[256];
103     int ret = recv(fd, buf, sizeof(buf)-1, 0);
104     if (ret < 0) {
105         LogPrintln("[%d]Error: %s", fd, strerror(errno));
106         DelFd(fd);
107     } else if (ret == 0) {
108         LogPrintln("[%d]Closed", fd);
109         DelFd(fd);
110     } else {
111         buf[ret] = 0;
112         LogPrintln("[%d]Received: %s", fd, buf);
113         if (strstr(buf, "Bye") != NULL) {
114             gBye++;
115         }
116     }
117     return -(ret < 0);
118 }
119 
HandleReadfds(fd_set * fds,int lsfd)120 static int HandleReadfds(fd_set *fds, int lsfd)
121 {
122     int ret = 0;
123     for (int i = 0; i < FD_SETSIZE; ++i) {
124         if (gFds[i] == INVALID_SOCKET || !FD_ISSET(gFds[i], fds)) {
125             continue;
126         }
127         ret += HandleRecv(gFds[i]);
128     }
129     return ret;
130 }
131 
GetIp(int sfd,const char * ifname)132 static unsigned int GetIp(int sfd, const char *ifname)
133 {
134     struct ifreq ifr;
135     unsigned int ip = 0;
136     int ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name) - 1, ifname, sizeof(ifr.ifr_name) - 1);
137     if (ret < 0) {
138         return 0;
139     }
140     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
141     ret = ioctl(sfd, SIOCGIFADDR, &ifr);
142     if (ret == 0) {
143         ip = (reinterpret_cast<struct sockaddr_in *>(&(ifr.ifr_addr)))->sin_addr.s_addr;
144     }
145     return ip;
146 }
147 
GetNetmask(int sfd,const char * ifname)148 static unsigned int GetNetmask(int sfd, const char *ifname)
149 {
150     struct ifreq ifr;
151     unsigned int msk = 0;
152     int ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name) - 1, ifname, sizeof(ifr.ifr_name) - 1);
153     if (ret < 0) {
154         return 0;
155     }
156     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
157     ret = ioctl(sfd, SIOCGIFNETMASK, &ifr);
158     if (ret == 0) {
159         msk = (reinterpret_cast<struct sockaddr_in *>(&(ifr.ifr_addr)))->sin_addr.s_addr;
160     }
161     return msk;
162 }
163 
MyInetNtoa(unsigned int ip)164 static char *MyInetNtoa(unsigned int ip)
165 {
166     struct in_addr in = {ip};
167     return inet_ntoa(in);
168 }
169 
ClientsThread(void * param)170 static void *ClientsThread(void *param)
171 {
172     int fd;
173     int thrNo = (int)(intptr_t)param;
174     int ret;
175     const char *ifname[] = {"eth0", "wlan0", "et1", "wl1", "enp4s0f0"};
176     unsigned int ip, msk, brdcast;
177 
178     LogPrintln("<%d>socket client thread started", thrNo);
179     fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
180     if (fd == INVALID_SOCKET) {
181         perror("socket");
182         return NULL;
183     }
184 
185     int broadcast = 1;
186     ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
187     if (ret != 0) {
188         LogPrintln("[%d]<%d> set broadcast option fail", fd, thrNo);
189         close(fd);
190         return NULL;
191     }
192 
193     for (int j = 0; j < sizeof(ifname) / sizeof(ifname[0]); ++j) {
194         ip = GetIp(fd, ifname[j]);
195         msk = GetNetmask(fd, ifname[j]);
196         if (ip != 0) {
197             LogPrintln("[%d]<%d>%s: ip %s", fd, thrNo, ifname[j], MyInetNtoa(ip));
198             LogPrintln("[%d]<%d>%s: netmask %s", fd, thrNo, ifname[j], MyInetNtoa(msk));
199             break;
200         }
201     }
202 
203     brdcast = ip | ~msk;
204     LogPrintln("[%d]<%d>broadcast address %s", fd, thrNo, MyInetNtoa(brdcast));
205 
206     struct sockaddr_in sa;
207     sa.sin_family = AF_INET;
208     sa.sin_addr.s_addr = brdcast;
209     sa.sin_port = htons(SERVER_PORT);
210     if (connect(fd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa)) == -1) {
211         perror("connect");
212         return NULL;
213     }
214 
215     LogPrintln("[%d]<%d>connected to udp://%s:%d successful", fd, thrNo, inet_ntoa(sa.sin_addr), SERVER_PORT);
216 
217     const char *msg[] = {
218             "hello, ",
219             "ohos, ",
220             "my name is net_socket_test_013, ",
221             "see u next time, ",
222             "Bye!"
223     };
224 
225     for (int i = 0; i < sizeof(msg) / sizeof(msg[0]); ++i) {
226         if (send(fd, msg[i], strlen(msg[i]), 0) < 0) {
227             LogPrintln("[%d]<%d>send msg [%s] fail: errno %d", fd, thrNo, msg[i], errno);
228         }
229     }
230 
231     (void)shutdown(fd, SHUT_RDWR);
232     (void)close(fd);
233     return param;
234 }
235 
StartClients(pthread_t * cli,int cliNum)236 static int StartClients(pthread_t *cli, int cliNum)
237 {
238     int ret;
239     pthread_attr_t attr;
240 
241     for (int i = 0; i < cliNum; ++i) {
242         ret = pthread_attr_init(&attr);
243         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
244 
245         ret = pthread_create(&cli[i], &attr, ClientsThread, (void *)(intptr_t)i);
246         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
247 
248         ret = pthread_attr_destroy(&attr);
249         ICUNIT_ASSERT_EQUAL(ret, 0, ret);
250     }
251     return 0;
252 }
253 
UdpBrdcastSelectTest(void)254 static int UdpBrdcastSelectTest(void)
255 {
256     struct sockaddr_in sa = {0};
257     int lsfd;
258     int ret;
259 
260     lsfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
261     ICUNIT_ASSERT_NOT_EQUAL(lsfd, -1, errno);
262 
263     sa.sin_family = AF_INET;
264     sa.sin_addr.s_addr = htonl(INADDR_ANY);
265     sa.sin_port = htons(SERVER_PORT);
266     ret = bind(lsfd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa));
267     ICUNIT_ASSERT_NOT_EQUAL(ret, -1, errno + CloseAllFd());
268 
269     int broadcast = 1;
270     ret = setsockopt(lsfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
271     ICUNIT_ASSERT_EQUAL(ret, 0, errno + CloseAllFd());
272 
273     int loop = 0;
274     socklen_t len = sizeof(loop);
275     ret = getsockopt(lsfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &len);
276     ICUNIT_ASSERT_EQUAL(ret, 0, errno + CloseAllFd());
277     LogPrintln("IP_MULTICAST_LOOP default: %d", loop);
278 
279     loop = 0;
280     ret = setsockopt(lsfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
281     ICUNIT_ASSERT_EQUAL(ret, 0, errno + CloseAllFd());
282 
283     ret = getsockopt(lsfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &len);
284     ICUNIT_ASSERT_EQUAL(ret, 0, errno + CloseAllFd());
285     LogPrintln("IP_MULTICAST_LOOP changed to: %d", loop);
286 
287     InitFds();
288     AddFd(lsfd);
289     LogPrintln("[%d]Waiting for client to connect on UDP port %d", lsfd, SERVER_PORT);
290 
291     pthread_t clients[CLIENT_NUM];
292 
293     ret = StartClients(clients, CLIENT_NUM);
294     ICUNIT_ASSERT_EQUAL(ret, 0, ret + CloseAllFd());
295 
296     for ( ; ; ) {
297         int nfd;
298         fd_set readfds;
299         struct timeval timeout;
300 
301         timeout.tv_sec = 3;
302         timeout.tv_usec = 0;
303 
304         nfd = 0;
305         FD_ZERO(&readfds);
306 
307         GetReadfds(&readfds, &nfd);
308 
309         ret = select(nfd + 1, &readfds, NULL, NULL, &timeout);
310         LogPrintln("select %d", ret);
311         if (ret == -1) {
312             perror("select");
313             break; // error occurred
314         } else if (ret == 0) {
315             break; // timed out
316         }
317 
318         if (HandleReadfds(&readfds, lsfd) < 0) {
319             break;
320         }
321     }
322 
323     for (int i = 0; i < CLIENT_NUM; ++i) {
324         ret = pthread_join(clients[i], NULL);
325         ICUNIT_ASSERT_EQUAL(ret, 0, ret + CloseAllFd());
326     }
327 
328     ICUNIT_ASSERT_EQUAL(gBye, CLIENT_NUM, gBye + CloseAllFd());
329     (void)CloseAllFd();
330     return ICUNIT_SUCCESS;
331 }
332 
NetSocketTest013(void)333 void NetSocketTest013(void)
334 {
335     TEST_ADD_CASE(__FUNCTION__, UdpBrdcastSelectTest, TEST_POSIX, TEST_TCP, TEST_LEVEL0, TEST_FUNCTION);
336 }
337