/**************************************************************************** * apps/testing/testsuites/kernel/socket/cases/net_socket_test_011.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include "SocketTest.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define SERVER_PORT 7777 #define INVALID_SOCKET -1 /**************************************************************************** * Public Functions ****************************************************************************/ static int gfds[FD_SETSIZE]; static int gbye; static void initfds(void) { for (int i = 0; i < FD_SETSIZE; ++i) { gfds[i] = INVALID_SOCKET; } } static void getreadfds(fd_set *fds, int *nfd) { for (int i = 0; i < FD_SETSIZE; i++) { if (gfds[i] == INVALID_SOCKET) { continue; } FD_SET(gfds[i], fds); if (*nfd < gfds[i]) { *nfd = gfds[i]; } } } static int addfd(int fd) { for (int i = 0; i < FD_SETSIZE; ++i) { if (gfds[i] == INVALID_SOCKET) { gfds[i] = fd; return 0; } } return -1; } static void delfd(int fd) { for (int i = 0; i < FD_SETSIZE; ++i) { if (gfds[i] == fd) { gfds[i] = INVALID_SOCKET; } } (void)close(fd); } static int closeallfd(void) { for (int i = 0; i < FD_SETSIZE; ++i) { if (gfds[i] != INVALID_SOCKET) { (void)close(gfds[i]); gfds[i] = INVALID_SOCKET; } } return 0; } static int handlerecv(int fd) { char buf[128]; int ret = recv(fd, buf, sizeof(buf) - 1, 0); if (ret < 0) { syslog(LOG_INFO, "[%d]Error: %s", fd, strerror(errno)); delfd(fd); } else if (ret == 0) { syslog(LOG_INFO, "[%d]Closed", fd); delfd(fd); } else { buf[ret] = 0; syslog(LOG_INFO, "[%d]Received: %s", fd, buf); if (strstr(buf, "Bye") != NULL) { gbye++; } } return -(ret < 0); } static int handlereadfds(fd_set *fds, int lsfd) { int ret = 0; for (int i = 0; i < FD_SETSIZE; ++i) { if (gfds[i] == INVALID_SOCKET || !FD_ISSET(gfds[i], fds)) { continue; } ret += handlerecv(gfds[i]); } return ret; } static void *clientsthread(void *param) { int fd; int thrno = (int)(intptr_t)param; syslog(LOG_INFO, "<%d>socket client thread started", thrno); fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd == INVALID_SOCKET) { perror("socket"); return NULL; } struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sa.sin_port = htons(SERVER_PORT); if (connect(fd, (struct sockaddr *)(&sa), sizeof(sa)) == -1) { perror("connect"); return NULL; } syslog(LOG_INFO, "[%d]<%d>connected to udp://%s:%d successful", fd, thrno, inet_ntoa(sa.sin_addr), SERVER_PORT); const char *msg[] = { "ohos, ", "hello, ", "my name is net_socket_test_011, ", "see u next time, ", "Bye!", }; for (int i = 0; i < sizeof(msg) / sizeof(msg[0]); ++i) { if (send(fd, msg[i], strlen(msg[i]), 0) < 0) { syslog(LOG_INFO, "[%d]<%d>send msg [%s] fail", fd, thrno, msg[i]); } } (void)shutdown(fd, SHUT_RDWR); (void)close(fd); return param; } static int startclients(pthread_t *cli, int clinum) { int ret; pthread_attr_t attr = { 0 }; struct sched_param param = { 0 }; int policy; ret = pthread_getschedparam(pthread_self(), &policy, ¶m); assert_int_equal(ret, 0); for (int i = 0; i < clinum; ++i) { ret = pthread_attr_init(&attr); param.sched_priority = param.sched_priority + 1; pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedparam(&attr, ¶m); ret = pthread_create(&cli[i], &attr, clientsthread, (void *)(intptr_t)i); assert_int_equal(ret, 0); ret = pthread_attr_destroy(&attr); assert_int_equal(ret, 0); } return 0; } /**************************************************************************** * Name: test_nuttx_net_socket_test11 ****************************************************************************/ void test_nuttx_net_socket_test11(FAR void **state) { struct sockaddr_in sa = { 0 }; int lsfd; int ret; lsfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(lsfd, -1); sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_port = htons(SERVER_PORT); ret = bind(lsfd, (struct sockaddr *)(&sa), sizeof(sa)); assert_int_not_equal(ret, -1); initfds(); addfd(lsfd); syslog(LOG_INFO, "[%d]Waiting for client to connect on UDP port %d", lsfd, SERVER_PORT); pthread_t clients[CLIENT_NUM]; ret = startclients(clients, CLIENT_NUM); assert_int_equal(ret, 0); for (; ; ) { int nfd; fd_set readfds; struct timeval timeout; timeout.tv_sec = 3; timeout.tv_usec = 0; nfd = 0; FD_ZERO(&readfds); getreadfds(&readfds, &nfd); ret = select(nfd + 1, &readfds, NULL, NULL, &timeout); syslog(LOG_INFO, "select %d", ret); if (ret == -1) { perror("select"); break; /* error occurred */ } else if (ret == 0) { break; /* timed out */ } if (handlereadfds(&readfds, lsfd) < 0) { break; } } for (int i = 0; i < CLIENT_NUM; ++i) { ret = pthread_join(clients[i], NULL); assert_int_equal(ret, 0); } #ifdef CONFIG_NET_UDP_NOTIFIER assert_int_equal(gbye, CLIENT_NUM); #endif (void)closeallfd(); }