"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-dccp.c" (15 Mar 2019, 9470 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-dccp.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) 2016-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 #define DCCP_OPT_SEND       0x01
   28 #define DCCP_OPT_SENDMSG    0x02
   29 #define DCCP_OPT_SENDMMSG   0x03
   30 
   31 #define MSGVEC_SIZE     (4)
   32 
   33 typedef struct {
   34     const char *optname;
   35     int    opt;
   36 } dccp_opts_t;
   37 
   38 static const dccp_opts_t dccp_options[] = {
   39     { "send",   DCCP_OPT_SEND },
   40     { "sendmsg",    DCCP_OPT_SENDMSG },
   41 #if defined(HAVE_SENDMMSG)
   42     { "sendmmsg",   DCCP_OPT_SENDMMSG },
   43 #endif
   44     { NULL,     0 }
   45 };
   46 
   47 /*
   48  *  stress_set_dccp_opts()
   49  *  parse --dccp-opts
   50  */
   51 int stress_set_dccp_opts(const char *opt)
   52 {
   53     size_t i;
   54 
   55     for (i = 0; dccp_options[i].optname; i++) {
   56         if (!strcmp(opt, dccp_options[i].optname)) {
   57             int dccp_opt = dccp_options[i].opt;
   58 
   59             set_setting("dccp-opts", TYPE_ID_INT, &dccp_opt);
   60             return 0;
   61         }
   62     }
   63     (void)fprintf(stderr, "dccp-opts option '%s' not known, options are:", opt);
   64     for (i = 0; dccp_options[i].optname; i++) {
   65         (void)fprintf(stderr, "%s %s",
   66             i == 0 ? "" : ",", dccp_options[i].optname);
   67     }
   68     (void)fprintf(stderr, "\n");
   69     return -1;
   70 }
   71 
   72 /*
   73  *  stress_set_dccp_port()
   74  *  set port to use
   75  */
   76 int stress_set_dccp_port(const char *opt)
   77 {
   78     int dccp_port;
   79 
   80     stress_set_net_port("dccp-port", opt,
   81         MIN_DCCP_PORT, MAX_DCCP_PORT - STRESS_PROCS_MAX,
   82         &dccp_port);
   83     return set_setting("dccp-port", TYPE_ID_INT, &dccp_port);
   84 }
   85 
   86 /*
   87  *  stress_set_dccp_domain()
   88  *  set the socket domain option
   89  */
   90 int stress_set_dccp_domain(const char *name)
   91 {
   92     int ret, dccp_domain;
   93 
   94     ret = stress_set_net_domain(DOMAIN_INET | DOMAIN_INET6,
   95                 "dccp-domain", name, &dccp_domain);
   96     set_setting("dccp-domain", TYPE_ID_INT, &dccp_domain);
   97     return ret;
   98 }
   99 
  100 #if defined(SOCK_DCCP) && defined(IPPROTO_DCCP)
  101 
  102 /*
  103  *  stress_dccp_client()
  104  *  client reader
  105  */
  106 static void stress_dccp_client(
  107     const args_t *args,
  108     const pid_t ppid,
  109     const int dccp_port,
  110     const int dccp_domain)
  111 {
  112     struct sockaddr *addr;
  113 
  114     (void)setpgid(0, g_pgrp);
  115     stress_parent_died_alarm();
  116 
  117     do {
  118         char buf[DCCP_BUF];
  119         int fd;
  120         int retries = 0;
  121         socklen_t addr_len = 0;
  122 retry:
  123         if (!g_keep_stressing_flag) {
  124             (void)kill(getppid(), SIGALRM);
  125             _exit(EXIT_FAILURE);
  126         }
  127         if ((fd = socket(dccp_domain, SOCK_DCCP, IPPROTO_DCCP)) < 0) {
  128             if (errno == ESOCKTNOSUPPORT) {
  129                 /*
  130                  *  Protocol not supported - then return
  131                  *  EXIT_NOT_IMPLEMENTED and skip the test
  132                  */
  133                 _exit(EXIT_NOT_IMPLEMENTED);
  134             }
  135             pr_fail_dbg("socket");
  136             /* failed, kick parent to finish */
  137             (void)kill(getppid(), SIGALRM);
  138             _exit(EXIT_FAILURE);
  139         }
  140 
  141         stress_set_sockaddr(args->name, args->instance, ppid,
  142             dccp_domain, dccp_port,
  143             &addr, &addr_len, NET_ADDR_ANY);
  144         if (connect(fd, addr, addr_len) < 0) {
  145             int err = errno;
  146 
  147             (void)close(fd);
  148             (void)shim_usleep(10000);
  149             retries++;
  150             if (retries > 100) {
  151                 /* Give up.. */
  152                 errno = err;
  153                 pr_fail_dbg("connect");
  154                 (void)kill(getppid(), SIGALRM);
  155                 _exit(EXIT_FAILURE);
  156             }
  157             goto retry;
  158         }
  159 
  160         do {
  161             ssize_t n = recv(fd, buf, sizeof(buf), 0);
  162             if (n == 0)
  163                 break;
  164             if (n < 0) {
  165                 if (errno != EINTR)
  166                     pr_fail_dbg("recv");
  167                 break;
  168             }
  169         } while (keep_stressing());
  170         (void)shutdown(fd, SHUT_RDWR);
  171         (void)close(fd);
  172     } while (keep_stressing());
  173 
  174 #if defined(AF_UNIX)
  175     if (dccp_domain == AF_UNIX) {
  176         struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  177         (void)unlink(addr_un->sun_path);
  178     }
  179 #endif
  180     /* Inform parent we're all done */
  181     (void)kill(getppid(), SIGALRM);
  182 }
  183 
  184 /*
  185  *  stress_dccp_server()
  186  *  server writer
  187  */
  188 static int stress_dccp_server(
  189     const args_t *args,
  190     const pid_t pid,
  191     const pid_t ppid,
  192     const int dccp_port,
  193     const int dccp_domain,
  194     const int dccp_opts)
  195 {
  196     char buf[DCCP_BUF];
  197     int fd, status;
  198     int so_reuseaddr = 1;
  199     socklen_t addr_len = 0;
  200     struct sockaddr *addr = NULL;
  201     uint64_t msgs = 0;
  202     int rc = EXIT_SUCCESS;
  203 
  204     (void)setpgid(pid, g_pgrp);
  205 
  206     if (stress_sig_stop_stressing(args->name, SIGALRM) < 0) {
  207         rc = EXIT_FAILURE;
  208         goto die;
  209     }
  210     if ((fd = socket(dccp_domain, SOCK_DCCP, IPPROTO_DCCP)) < 0) {
  211         if (errno == ESOCKTNOSUPPORT) {
  212             /*
  213              *  Protocol not supported - then return
  214              *  EXIT_NOT_IMPLEMENTED and skip the test
  215              */
  216             if (args->instance == 0)
  217                 pr_inf("%s: DCCP protocol not supported, "
  218                     "skipping stressor\n", args->name);
  219             return EXIT_NOT_IMPLEMENTED;
  220         }
  221         rc = exit_status(errno);
  222         pr_fail_dbg("socket");
  223         goto die;
  224     }
  225     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  226         &so_reuseaddr, sizeof(so_reuseaddr)) < 0) {
  227         pr_fail_dbg("setsockopt");
  228         rc = EXIT_FAILURE;
  229         goto die_close;
  230     }
  231 
  232     stress_set_sockaddr(args->name, args->instance, ppid,
  233         dccp_domain, dccp_port,
  234         &addr, &addr_len, NET_ADDR_ANY);
  235     if (bind(fd, addr, addr_len) < 0) {
  236         rc = exit_status(errno);
  237         pr_fail_dbg("bind");
  238         goto die_close;
  239     }
  240     if (listen(fd, 10) < 0) {
  241         pr_fail_dbg("listen");
  242         rc = EXIT_FAILURE;
  243         goto die_close;
  244     }
  245 
  246     do {
  247         int sfd;
  248 
  249         if (!keep_stressing())
  250             break;
  251 
  252         sfd = accept(fd, (struct sockaddr *)NULL, NULL);
  253         if (sfd >= 0) {
  254             size_t i, j;
  255             struct sockaddr saddr;
  256             socklen_t len;
  257             int sndbuf;
  258             struct msghdr msg;
  259             struct iovec vec[sizeof(buf)/16];
  260 #if defined(HAVE_SENDMMSG)
  261             struct mmsghdr msgvec[MSGVEC_SIZE];
  262             unsigned int msg_len = 0;
  263 #endif
  264             len = sizeof(saddr);
  265             if (getsockname(fd, &saddr, &len) < 0) {
  266                 pr_fail_dbg("getsockname");
  267                 (void)close(sfd);
  268                 break;
  269             }
  270             len = sizeof(sndbuf);
  271             if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len) < 0) {
  272                 pr_fail_dbg("getsockopt");
  273                 (void)close(sfd);
  274                 break;
  275             }
  276 
  277             (void)memset(buf, 'A' + (get_counter(args) % 26), sizeof(buf));
  278             switch (dccp_opts) {
  279             case DCCP_OPT_SEND:
  280                 for (i = 16; i < sizeof(buf); i += 16) {
  281                     ssize_t ret;
  282 again:
  283                     ret = send(sfd, buf, i, 0);
  284                     if (ret < 0) {
  285                         if (errno == EAGAIN)
  286                             goto again;
  287                         if (errno != EINTR)
  288                             pr_fail_dbg("send");
  289                         break;
  290                     } else
  291                         msgs++;
  292                 }
  293                 break;
  294             case DCCP_OPT_SENDMSG:
  295                 for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) {
  296                     vec[j].iov_base = buf;
  297                     vec[j].iov_len = i;
  298                 }
  299                 (void)memset(&msg, 0, sizeof(msg));
  300                 msg.msg_iov = vec;
  301                 msg.msg_iovlen = j;
  302                 if (sendmsg(sfd, &msg, 0) < 0) {
  303                     if (errno != EINTR)
  304                         pr_fail_dbg("sendmsg");
  305                 } else
  306                     msgs += j;
  307                 break;
  308 #if defined(HAVE_SENDMMSG)
  309             case DCCP_OPT_SENDMMSG:
  310                 (void)memset(msgvec, 0, sizeof(msgvec));
  311                 for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) {
  312                     vec[j].iov_base = buf;
  313                     vec[j].iov_len = i;
  314                     msg_len += i;
  315                 }
  316                 for (i = 0; i < MSGVEC_SIZE; i++) {
  317                     msgvec[i].msg_hdr.msg_iov = vec;
  318                     msgvec[i].msg_hdr.msg_iovlen = j;
  319                 }
  320                 if (sendmmsg(sfd, msgvec, MSGVEC_SIZE, 0) < 0) {
  321                     if (errno != EINTR)
  322                         pr_fail_dbg("sendmmsg");
  323                 } else
  324                     msgs += (MSGVEC_SIZE * j);
  325                 break;
  326 #endif
  327             default:
  328                 /* Should never happen */
  329                 pr_err("%s: bad option %d\n", args->name, dccp_opts);
  330                 (void)close(sfd);
  331                 goto die_close;
  332             }
  333             if (getpeername(sfd, &saddr, &len) < 0) {
  334                 pr_fail_dbg("getpeername");
  335             }
  336             (void)close(sfd);
  337         }
  338         inc_counter(args);
  339     } while (keep_stressing());
  340 
  341 die_close:
  342     (void)close(fd);
  343 die:
  344 #if defined(AF_UNIX)
  345     if (addr && (dccp_domain == AF_UNIX)) {
  346         struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  347         (void)unlink(addr_un->sun_path);
  348     }
  349 #endif
  350     if (pid) {
  351         (void)kill(pid, SIGKILL);
  352         (void)waitpid(pid, &status, 0);
  353     }
  354     pr_dbg("%s: %" PRIu64 " messages sent\n", args->name, msgs);
  355 
  356     return rc;
  357 }
  358 
  359 /*
  360  *  stress_dccp
  361  *  stress by heavy dccp  I/O
  362  */
  363 static int stress_dccp(const args_t *args)
  364 {
  365     pid_t pid, ppid = getppid();
  366     int dccp_port = DEFAULT_DCCP_PORT;
  367     int dccp_domain = AF_INET;
  368     int dccp_opts = DCCP_OPT_SEND;
  369 
  370     (void)get_setting("dccp-port", &dccp_port);
  371     (void)get_setting("dccp-domain", &dccp_domain);
  372     (void)get_setting("dccp-opts", &dccp_opts);
  373 
  374     pr_dbg("%s: process [%d] using socket port %d\n",
  375         args->name, (int)args->pid, dccp_port + args->instance);
  376 
  377 again:
  378     pid = fork();
  379     if (pid < 0) {
  380         if (g_keep_stressing_flag &&
  381             ((errno == EAGAIN) || (errno == ENOMEM)))
  382             goto again;
  383         pr_fail_dbg("fork");
  384         return EXIT_FAILURE;
  385     } else if (pid == 0) {
  386         stress_dccp_client(args, ppid, dccp_port, dccp_domain);
  387         _exit(EXIT_SUCCESS);
  388     } else {
  389         return stress_dccp_server(args, pid, ppid, dccp_port,
  390             dccp_domain, dccp_opts);
  391     }
  392 }
  393 
  394 stressor_info_t stress_dccp_info = {
  395     .stressor = stress_dccp,
  396     .class = CLASS_NETWORK | CLASS_OS
  397 };
  398 #else
  399 stressor_info_t stress_dccp_info = {
  400     .stressor = stress_not_implemented,
  401     .class = CLASS_NETWORK | CLASS_OS
  402 };
  403 #endif