"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.10.00/stress-socket.c" (8 Jul 2019, 12696 Bytes) of package /linux/privat/stress-ng-0.10.00.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 latest Fossies "Diffs" side-by-side code changes report: 0.09.60_vs_0.10.00.

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