"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-socket.c" (15 Mar 2019, 11258 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.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 #define SOCKET_OPT_SEND     0x01
   28 #define SOCKET_OPT_SENDMSG  0x02
   29 #define SOCKET_OPT_SENDMMSG 0x03
   30 
   31 #define MSGVEC_SIZE     (4)
   32 
   33 typedef struct {
   34     const char *optname;
   35     int    opt;
   36 } socket_opts_t;
   37 
   38 typedef struct {
   39     const char *typename;
   40     const int   type;
   41 } socket_type_t;
   42 
   43 /*
   44  *  stress_set_socket_opts()
   45  *  parse --sock-opts
   46  */
   47 int stress_set_socket_opts(const char *opt)
   48 {
   49     static const socket_opts_t socket_opts[] = {
   50         { "send",   SOCKET_OPT_SEND },
   51         { "sendmsg",    SOCKET_OPT_SENDMSG },
   52 #if defined(HAVE_SENDMMSG)
   53         { "sendmmsg",   SOCKET_OPT_SENDMMSG },
   54 #endif
   55         { NULL,     0 }
   56     };
   57 
   58     int i;
   59 
   60     for (i = 0; socket_opts[i].optname; i++) {
   61         if (!strcmp(opt, socket_opts[i].optname)) {
   62             int opts = socket_opts[i].opt;
   63 
   64             set_setting("sock-opts", TYPE_ID_INT, &opts);
   65             return 0;
   66         }
   67     }
   68     (void)fprintf(stderr, "sock-opts option '%s' not known, options are:", opt);
   69     for (i = 0; socket_opts[i].optname; i++) {
   70         (void)fprintf(stderr, "%s %s",
   71             i == 0 ? "" : ",", socket_opts[i].optname);
   72     }
   73     (void)fprintf(stderr, "\n");
   74     return -1;
   75 }
   76 
   77 /*
   78  *  stress_set_socket_type()
   79  *  parse --sock-type
   80  */
   81 int stress_set_socket_type(const char *opt)
   82 {
   83     static const socket_type_t socket_type[] = {
   84 #if defined(SOCK_STREAM)
   85         { "stream", SOCK_STREAM  },
   86 #endif
   87 #if defined(SOCK_SEQPACKET)
   88         { "seqpacket",  SOCK_SEQPACKET },
   89 #endif
   90         { NULL,     0 }
   91     };
   92 
   93     int i;
   94 
   95     for (i = 0; socket_type[i].typename; i++) {
   96         if (!strcmp(opt, socket_type[i].typename)) {
   97             int type = socket_type[i].type;
   98 
   99             set_setting("sock-type", TYPE_ID_INT, &type);
  100             return 0;
  101         }
  102     }
  103     (void)fprintf(stderr, "sock-type option '%s' not known, options are:", opt);
  104     for (i = 0; socket_type[i].typename; i++) {
  105         (void)fprintf(stderr, "%s %s",
  106             i == 0 ? "" : ",", socket_type[i].typename);
  107     }
  108     (void)fprintf(stderr, "\n");
  109     return -1;
  110 }
  111 
  112 /*
  113  *  stress_set_socket_port()
  114  *  set port to use
  115  */
  116 int  stress_set_socket_port(const char *opt)
  117 {
  118     int socket_port;
  119 
  120     stress_set_net_port("sock-port", opt,
  121         MIN_SOCKET_PORT, MAX_SOCKET_PORT - STRESS_PROCS_MAX,
  122         &socket_port);
  123     return set_setting("sock-port", TYPE_ID_INT, &socket_port);
  124 }
  125 
  126 /*
  127  *  stress_set_socket_domain()
  128  *  set the socket domain option
  129  */
  130 int stress_set_socket_domain(const char *name)
  131 {
  132     int ret, socket_domain;
  133 
  134     ret = stress_set_net_domain(DOMAIN_ALL, "sock-domain",
  135                      name, &socket_domain);
  136     set_setting("sock-domain", TYPE_ID_INT, &socket_domain);
  137 
  138     return ret;
  139 }
  140 
  141 /*
  142  *  stress_sctp_client()
  143  *  client reader
  144  */
  145 static void stress_sctp_client(
  146     const args_t *args,
  147     const pid_t ppid,
  148     const int socket_type,
  149     const int socket_port,
  150     const int socket_domain)
  151 {
  152     struct sockaddr *addr;
  153 
  154     (void)setpgid(0, g_pgrp);
  155     stress_parent_died_alarm();
  156 
  157     do {
  158         char buf[SOCKET_BUF];
  159         int fd;
  160         int retries = 0;
  161 #if defined(FIONREAD)
  162         int count = 0;
  163 #endif
  164         socklen_t addr_len = 0;
  165 retry:
  166         if (!g_keep_stressing_flag) {
  167             (void)kill(getppid(), SIGALRM);
  168             _exit(EXIT_FAILURE);
  169         }
  170         if ((fd = socket(socket_domain, socket_type, 0)) < 0) {
  171             pr_fail_dbg("socket");
  172             /* failed, kick parent to finish */
  173             (void)kill(getppid(), SIGALRM);
  174             _exit(EXIT_FAILURE);
  175         }
  176 
  177         stress_set_sockaddr(args->name, args->instance, ppid,
  178             socket_domain, socket_port,
  179             &addr, &addr_len, NET_ADDR_ANY);
  180         if (connect(fd, addr, addr_len) < 0) {
  181             (void)close(fd);
  182             (void)shim_usleep(10000);
  183             retries++;
  184             if (retries > 100) {
  185                 /* Give up.. */
  186                 pr_fail_dbg("connect");
  187                 (void)kill(getppid(), SIGALRM);
  188                 _exit(EXIT_FAILURE);
  189             }
  190             goto retry;
  191         }
  192 
  193         do {
  194             ssize_t n;
  195 #if defined(FIONREAD)
  196             size_t bytes = sizeof(buf);
  197             /*
  198              *  Exercise FIONREAD ioctl. Linux supports
  199              *  this also with SIOCINQ but lets try and
  200              *  do the more standard way of peeking the
  201              *  pending data size.  Do this infrequently
  202              *  to ensure we exercise it without impacting
  203              *  performance.
  204              */
  205             if (count++ > 1024) {
  206                 int ret;
  207 
  208                 ret = ioctl(fd, FIONREAD, &bytes);
  209                 (void)ret;
  210                 count = 0;
  211 
  212                 if (bytes > sizeof(buf))
  213                     bytes = sizeof(buf);
  214             }
  215 #endif
  216             n = recv(fd, buf, sizeof(buf), 0);
  217             if (n == 0)
  218                 break;
  219             if (n < 0) {
  220                 if ((errno != EINTR) && (errno != ECONNRESET))
  221                     pr_fail_dbg("recv");
  222                 break;
  223             }
  224         } while (keep_stressing());
  225         (void)shutdown(fd, SHUT_RDWR);
  226         (void)close(fd);
  227     } while (keep_stressing());
  228 
  229 #if defined(AF_UNIX)
  230     if (socket_domain == AF_UNIX) {
  231         struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  232         (void)unlink(addr_un->sun_path);
  233     }
  234 #endif
  235     /* Inform parent we're all done */
  236     (void)kill(getppid(), SIGALRM);
  237 }
  238 
  239 /*
  240  *  stress_sctp_server()
  241  *  server writer
  242  */
  243 static int stress_sctp_server(
  244     const args_t *args,
  245     const pid_t pid,
  246     const pid_t ppid,
  247     const int socket_opts,
  248     const int socket_type,
  249     const int socket_port,
  250     const int socket_domain)
  251 {
  252     char buf[SOCKET_BUF];
  253     int fd, status;
  254     int so_reuseaddr = 1;
  255     socklen_t addr_len = 0;
  256     struct sockaddr *addr = NULL;
  257     uint64_t msgs = 0;
  258     int rc = EXIT_SUCCESS;
  259 
  260     (void)setpgid(pid, g_pgrp);
  261 
  262     if (stress_sig_stop_stressing(args->name, SIGALRM) < 0) {
  263         rc = EXIT_FAILURE;
  264         goto die;
  265     }
  266     if ((fd = socket(socket_domain, socket_type, 0)) < 0) {
  267         rc = exit_status(errno);
  268         pr_fail_dbg("socket");
  269         goto die;
  270     }
  271     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  272         &so_reuseaddr, sizeof(so_reuseaddr)) < 0) {
  273         pr_fail_dbg("setsockopt");
  274         rc = EXIT_FAILURE;
  275         goto die_close;
  276     }
  277 
  278     stress_set_sockaddr(args->name, args->instance, ppid,
  279         socket_domain, socket_port,
  280         &addr, &addr_len, NET_ADDR_ANY);
  281     if (bind(fd, addr, addr_len) < 0) {
  282         rc = exit_status(errno);
  283         pr_fail_dbg("bind");
  284         goto die_close;
  285     }
  286     if (listen(fd, 10) < 0) {
  287         pr_fail_dbg("listen");
  288         rc = EXIT_FAILURE;
  289         goto die_close;
  290     }
  291 
  292     do {
  293         int sfd;
  294 
  295         if (!keep_stressing())
  296             break;
  297 
  298 #if defined(HAVE_ACCEPT4)
  299         /*  Randomly use accept or accept4 to exercise both */
  300         if (mwc1()) {
  301             sfd = accept4(fd, (struct sockaddr *)NULL, NULL, SOCK_CLOEXEC);
  302         } else {
  303             sfd = accept(fd, (struct sockaddr *)NULL, NULL);
  304         }
  305 #else
  306         sfd = accept(fd, (struct sockaddr *)NULL, NULL);
  307 #endif
  308         if (sfd >= 0) {
  309             size_t i, j;
  310             struct sockaddr saddr;
  311             socklen_t len;
  312             int sndbuf;
  313             struct msghdr msg;
  314             struct iovec vec[sizeof(buf)/16];
  315 #if defined(HAVE_SENDMMSG)
  316             struct mmsghdr msgvec[MSGVEC_SIZE];
  317             unsigned int msg_len = 0;
  318 #endif
  319             len = sizeof(saddr);
  320             if (getsockname(fd, &saddr, &len) < 0) {
  321                 pr_fail_dbg("getsockname");
  322                 (void)close(sfd);
  323                 break;
  324             }
  325             len = sizeof(sndbuf);
  326             if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len) < 0) {
  327                 pr_fail_dbg("getsockopt");
  328                 (void)close(sfd);
  329                 break;
  330             }
  331 #if defined(SOL_TCP) && defined(TCP_QUICKACK)
  332             {
  333                 int ret, one = 1;
  334                 /*
  335                  * We try do to a TCP_QUICKACK, failing is OK as
  336                  * it's just a faster optimization option
  337                  */
  338                 ret = setsockopt(fd, SOL_TCP, TCP_QUICKACK, &one, sizeof(one));
  339                 (void)ret;
  340             }
  341 #endif
  342 
  343 #if defined(SOL_TCP) && defined(HAVE_NETINET_TCP_H)
  344             if (g_opt_flags & OPT_FLAGS_SOCKET_NODELAY) {
  345                 int one = 1;
  346 
  347                 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) {
  348                     pr_inf("%s: setsockopt TCP_NODELAY "
  349                         "failed and disabled, errno=%d (%s)\n",
  350                         args->name, errno, strerror(errno));
  351                     g_opt_flags &= ~OPT_FLAGS_SOCKET_NODELAY;
  352                 }
  353             }
  354 #endif
  355             (void)memset(buf, 'A' + (get_counter(args) % 26), sizeof(buf));
  356             switch (socket_opts) {
  357             case SOCKET_OPT_SEND:
  358                 for (i = 16; i < sizeof(buf); i += 16) {
  359                     ssize_t ret = send(sfd, buf, i, 0);
  360                     if (ret < 0) {
  361                         if (errno != EINTR)
  362                             pr_fail_dbg("send");
  363                         break;
  364                     } else
  365                         msgs++;
  366                 }
  367                 break;
  368             case SOCKET_OPT_SENDMSG:
  369                 for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) {
  370                     vec[j].iov_base = buf;
  371                     vec[j].iov_len = i;
  372                 }
  373                 (void)memset(&msg, 0, sizeof(msg));
  374                 msg.msg_iov = vec;
  375                 msg.msg_iovlen = j;
  376                 if (sendmsg(sfd, &msg, 0) < 0) {
  377                     if (errno != EINTR)
  378                         pr_fail_dbg("sendmsg");
  379                 } else
  380                     msgs += j;
  381                 break;
  382 #if defined(HAVE_SENDMMSG)
  383             case SOCKET_OPT_SENDMMSG:
  384                 (void)memset(msgvec, 0, sizeof(msgvec));
  385                 for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) {
  386                     vec[j].iov_base = buf;
  387                     vec[j].iov_len = i;
  388                     msg_len += i;
  389                 }
  390                 for (i = 0; i < MSGVEC_SIZE; i++) {
  391                     msgvec[i].msg_hdr.msg_iov = vec;
  392                     msgvec[i].msg_hdr.msg_iovlen = j;
  393                 }
  394                 if (sendmmsg(sfd, msgvec, MSGVEC_SIZE, 0) < 0) {
  395                     if (errno != EINTR)
  396                         pr_fail_dbg("sendmmsg");
  397                 } else
  398                     msgs += (MSGVEC_SIZE * j);
  399                 break;
  400 #endif
  401             default:
  402                 /* Should never happen */
  403                 pr_err("%s: bad option %d\n", args->name, socket_opts);
  404                 (void)close(sfd);
  405                 goto die_close;
  406             }
  407             if (getpeername(sfd, &saddr, &len) < 0) {
  408                 pr_fail_dbg("getpeername");
  409             }
  410             (void)close(sfd);
  411         }
  412         inc_counter(args);
  413     } while (keep_stressing());
  414 
  415 die_close:
  416     (void)close(fd);
  417 die:
  418 #if defined(AF_UNIX)
  419     if (addr && (socket_domain == AF_UNIX)) {
  420         struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  421         (void)unlink(addr_un->sun_path);
  422     }
  423 #endif
  424     if (pid) {
  425         (void)kill(pid, SIGKILL);
  426         (void)waitpid(pid, &status, 0);
  427     }
  428     pr_dbg("%s: %" PRIu64 " messages sent\n", args->name, msgs);
  429 
  430     return rc;
  431 }
  432 
  433 /*
  434  *  stress_sock
  435  *  stress by heavy socket I/O
  436  */
  437 static int stress_sock(const args_t *args)
  438 {
  439     pid_t pid, ppid = getppid();
  440     int socket_opts = SOCKET_OPT_SEND;
  441     int socket_type = SOCK_STREAM;
  442     int socket_port = DEFAULT_SOCKET_PORT;
  443     int socket_domain = AF_INET;
  444 
  445     (void)get_setting("sock-opts", &socket_opts);
  446     (void)get_setting("sock-type", &socket_type);
  447     (void)get_setting("sock-port", &socket_port);
  448     (void)get_setting("sock-domain", &socket_domain);
  449 
  450     pr_dbg("%s: process [%d] using socket port %d\n",
  451         args->name, (int)args->pid, socket_port + args->instance);
  452 
  453 again:
  454     pid = fork();
  455     if (pid < 0) {
  456         if (g_keep_stressing_flag && (errno == EAGAIN))
  457             goto again;
  458         pr_fail_dbg("fork");
  459         return EXIT_FAILURE;
  460     } else if (pid == 0) {
  461         stress_sctp_client(args, ppid, socket_type,
  462             socket_port, socket_domain);
  463         _exit(EXIT_SUCCESS);
  464     } else {
  465         return stress_sctp_server(args, pid, ppid, socket_opts,
  466             socket_type, socket_port, socket_domain);
  467     }
  468 }
  469 
  470 stressor_info_t stress_sock_info = {
  471     .stressor = stress_sock,
  472     .class = CLASS_NETWORK | CLASS_OS
  473 };