"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-socket-fd.c" (15 Mar 2019, 8145 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-socket-fd.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.52_vs_0.09.54.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #if defined(__linux__) &&   \
   28     defined(HAVE_SYS_UN_H)
   29 
   30 #define MSG_ID          'M'
   31 
   32 #endif
   33 
   34 /*
   35  *  stress_set_socket_fd_port()
   36  *  set port to use
   37  */
   38 int stress_set_socket_fd_port(const char *opt)
   39 {
   40     int socket_fd_port;
   41 
   42     stress_set_net_port("sockfd-port", opt,
   43         MIN_SOCKET_FD_PORT, MAX_SOCKET_FD_PORT - STRESS_PROCS_MAX,
   44         &socket_fd_port);
   45     return set_setting("sockfd-port", TYPE_ID_INT, &socket_fd_port);
   46 }
   47 
   48 #if defined(__linux__)
   49 
   50 /*
   51  *  stress_socket_fd_send()
   52  *  send a fd (fd_send) over a socket fd
   53  */
   54 static inline int stress_socket_fd_sendmsg(const int fd, const int fd_send)
   55 {
   56     struct iovec iov;
   57     struct msghdr msg;
   58     struct cmsghdr *cmsg;
   59     int *ptr;
   60 
   61     char ctrl[CMSG_SPACE(sizeof(int))];
   62     static char msg_data[1] = { MSG_ID };
   63 
   64     iov.iov_base = msg_data;
   65     iov.iov_len = 1;
   66 
   67     (void)memset(&msg, 0, sizeof(struct msghdr));
   68     msg.msg_iov = &iov;
   69     msg.msg_iovlen = 1;
   70 
   71     (void)memset(ctrl, 0, sizeof(ctrl));
   72     msg.msg_control = ctrl;
   73     msg.msg_controllen = sizeof(ctrl);
   74 
   75     cmsg = CMSG_FIRSTHDR(&msg);
   76     cmsg->cmsg_level = SOL_SOCKET;
   77     cmsg->cmsg_type = SCM_RIGHTS;
   78     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
   79 
   80     ptr = (int *)CMSG_DATA(cmsg);
   81     *ptr = fd_send;
   82     return sendmsg(fd, &msg, 0);
   83 }
   84 
   85 /*
   86  *  stress_socket_fd_recv()
   87  *  recv an fd over a socket, return fd or -1 if fail
   88  */
   89 static inline int stress_socket_fd_recv(const int fd)
   90 {
   91     struct iovec iov;
   92     struct msghdr msg;
   93     struct cmsghdr *cmsg;
   94     char msg_data[1];
   95     char ctrl[CMSG_SPACE(sizeof(int))];
   96 
   97     iov.iov_base = msg_data;
   98     iov.iov_len = 1;
   99 
  100     (void)memset(&msg, 0, sizeof(struct msghdr));
  101     msg.msg_iov = &iov;
  102     msg.msg_iovlen = 1;
  103 
  104     (void)memset(ctrl, 0, sizeof(ctrl));
  105     msg.msg_control = ctrl;
  106     msg.msg_controllen = sizeof(ctrl);
  107 
  108     if (recvmsg(fd, &msg, 0) <= 0)
  109         return -errno;
  110     if (msg_data[0] != MSG_ID)
  111         return -1;
  112     if ((msg.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
  113         return -1;
  114 
  115     cmsg = CMSG_FIRSTHDR(&msg);
  116     if (cmsg &&
  117         (cmsg->cmsg_level == SOL_SOCKET) &&
  118         (cmsg->cmsg_type == SCM_RIGHTS) &&
  119         ((size_t)cmsg->cmsg_len >= (size_t)CMSG_LEN(sizeof(int)))) {
  120         int *const ptr = (int *)CMSG_DATA(cmsg);
  121         return *ptr;
  122     }
  123 
  124     return -1;
  125 }
  126 
  127 /*
  128  *  stress_socket_client()
  129  *  client reader
  130  */
  131 static void stress_socket_client(
  132     const args_t *args,
  133     const pid_t ppid,
  134     const ssize_t max_fd,
  135     const int socket_fd_port)
  136 {
  137     struct sockaddr *addr;
  138     int ret = EXIT_FAILURE;
  139 
  140     (void)setpgid(0, g_pgrp);
  141     stress_parent_died_alarm();
  142 
  143     do {
  144         int fd, retries = 0, fds[max_fd];
  145         ssize_t i, n;
  146         socklen_t addr_len = 0;
  147 
  148         (void)memset(fds, 0, sizeof(fds));
  149 retry:
  150         if (!g_keep_stressing_flag) {
  151             ret = EXIT_SUCCESS;
  152             goto finish;
  153         }
  154 
  155         if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  156             pr_fail_dbg("socket");
  157             goto finish;
  158         }
  159 
  160         stress_set_sockaddr(args->name, args->instance, ppid,
  161             AF_UNIX, socket_fd_port,
  162             &addr, &addr_len, NET_ADDR_ANY);
  163         if (connect(fd, addr, addr_len) < 0) {
  164             (void)close(fd);
  165             (void)shim_usleep(10000);
  166             retries++;
  167             if (retries > 100) {
  168                 /* Give up.. */
  169                 pr_fail_dbg("connect");
  170                 goto finish;
  171             }
  172             goto retry;
  173         }
  174 
  175         if (!g_keep_stressing_flag) {
  176             ret = EXIT_SUCCESS;
  177             goto finish;
  178         }
  179 
  180         for (n = 0; keep_stressing() && (n < max_fd); n++)
  181             fds[n] = stress_socket_fd_recv(fd);
  182 
  183         for (i = 0; i < n; i++) {
  184             if (fds[i] >= 0)
  185                 (void)close(fds[i]);
  186         }
  187 
  188         (void)shutdown(fd, SHUT_RDWR);
  189         (void)close(fd);
  190     } while (keep_stressing());
  191 
  192     struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  193     (void)unlink(addr_un->sun_path);
  194 
  195     ret = EXIT_SUCCESS;
  196 
  197 finish:
  198     /* Inform parent we're all done */
  199     (void)kill(getppid(), SIGALRM);
  200     _exit(ret);
  201 }
  202 
  203 /*
  204  *  stress_socket_server()
  205  *  server writer
  206  */
  207 static int stress_socket_server(
  208     const args_t *args,
  209     const pid_t pid,
  210     const pid_t ppid,
  211     const ssize_t max_fd,
  212     const int socket_fd_port)
  213 {
  214     int fd, status;
  215     int so_reuseaddr = 1;
  216     struct sockaddr_un *addr_un;
  217     socklen_t addr_len = 0;
  218     struct sockaddr *addr = NULL;
  219     uint64_t msgs = 0;
  220     int rc = EXIT_SUCCESS;
  221 
  222     (void)setpgid(pid, g_pgrp);
  223 
  224     if (stress_sig_stop_stressing(args->name, SIGALRM)) {
  225         rc = EXIT_FAILURE;
  226         goto die;
  227     }
  228     if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  229         rc = exit_status(errno);
  230         pr_fail_dbg("socket");
  231         goto die;
  232     }
  233     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  234         &so_reuseaddr, sizeof(so_reuseaddr)) < 0) {
  235         pr_fail_dbg("setsockopt");
  236         rc = EXIT_FAILURE;
  237         goto die_close;
  238     }
  239 
  240     stress_set_sockaddr(args->name, args->instance, ppid,
  241         AF_UNIX, socket_fd_port,
  242         &addr, &addr_len, NET_ADDR_ANY);
  243     if (bind(fd, addr, addr_len) < 0) {
  244         rc = exit_status(errno);
  245         pr_fail_dbg("bind");
  246         goto die_close;
  247     }
  248     if (listen(fd, 10) < 0) {
  249         pr_fail_dbg("listen");
  250         rc = EXIT_FAILURE;
  251         goto die_close;
  252     }
  253 
  254     do {
  255         int sfd;
  256 
  257         if (!keep_stressing())
  258             break;
  259 
  260         sfd = accept(fd, (struct sockaddr *)NULL, NULL);
  261         if (sfd >= 0) {
  262             ssize_t i;
  263 
  264             for (i = 0; keep_stressing() && (i < max_fd); i++) {
  265                 int newfd;
  266 
  267                 newfd = open("/dev/null", O_RDWR);
  268                 if (newfd >= 0) {
  269                     int ret;
  270 
  271                     ret = stress_socket_fd_sendmsg(sfd, newfd);
  272                     if ((ret < 0) &&
  273                          ((errno != EAGAIN) && (errno != EINTR) &&
  274                           (errno != EWOULDBLOCK) && (errno != ECONNRESET) &&
  275                           (errno != ENOMEM) && (errno != EPIPE))) {
  276                         pr_fail_dbg("sendmsg");
  277                         (void)close(newfd);
  278                         break;
  279                     }
  280                     (void)close(newfd);
  281                     msgs++;
  282                 }
  283             }
  284             (void)close(sfd);
  285         }
  286         inc_counter(args);
  287     } while (keep_stressing());
  288 
  289 die_close:
  290     (void)close(fd);
  291 die:
  292     if (addr) {
  293         addr_un = (struct sockaddr_un *)addr;
  294         (void)unlink(addr_un->sun_path);
  295     }
  296 
  297     if (pid) {
  298         (void)kill(pid, SIGALRM);
  299         (void)waitpid(pid, &status, 0);
  300     }
  301     pr_dbg("%s: %" PRIu64 " messages sent\n", args->name, msgs);
  302 
  303     return rc;
  304 }
  305 
  306 /*
  307  *  stress_sockfd
  308  *  stress socket fd passing
  309  */
  310 static int stress_sockfd(const args_t *args)
  311 {
  312     pid_t pid, ppid = getppid();
  313     ssize_t max_fd = stress_get_file_limit();
  314     int socket_fd_port = DEFAULT_SOCKET_FD_PORT;
  315     int ret = EXIT_SUCCESS;
  316 
  317     (void)get_setting("sockfd-port", &socket_fd_port);
  318 
  319     /*
  320      * When run as root, we really don't want to use up all
  321      * the file descriptors. Limit ourselves to a head room
  322      * so that we don't ever run out of memory
  323      */
  324     if (geteuid() == 0) {
  325         max_fd -= 64;
  326         max_fd /= args->num_instances ? args->num_instances : 1;
  327         if (max_fd < 0)
  328             max_fd = 1;
  329     }
  330 
  331     pr_dbg("%s: process [%d] using socket port %d and %zd file descriptors\n",
  332         args->name, args->pid, socket_fd_port + args->instance, max_fd);
  333 
  334 again:
  335     pid = fork();
  336     if (pid < 0) {
  337         if (errno == EAGAIN) {
  338             if (g_keep_stressing_flag)
  339                 goto again;
  340             return EXIT_NO_RESOURCE;
  341         }
  342         pr_fail_dbg("fork");
  343         return EXIT_FAILURE;
  344     } else if (pid == 0) {
  345         set_oom_adjustment(args->name, false);
  346         stress_socket_client(args, ppid, max_fd, socket_fd_port);
  347         _exit(EXIT_SUCCESS);
  348     } else {
  349         ret = stress_socket_server(args, pid, ppid, max_fd, socket_fd_port);
  350     }
  351     return ret;
  352 }
  353 
  354 stressor_info_t stress_sockfd_info = {
  355     .stressor = stress_sockfd,
  356     .class = CLASS_NETWORK | CLASS_OS
  357 };
  358 #else
  359 stressor_info_t stress_sockfd_info = {
  360     .stressor = stress_not_implemented,
  361     .class = CLASS_NETWORK | CLASS_OS
  362 };
  363 #endif