"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-sctp.c" (15 Mar 2019, 7601 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-sctp.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(HAVE_LIB_SCTP) &&   \
   28     defined(HAVE_NETINET_SCTP_H)
   29 
   30 #if !defined(LOCALTIME_STREAM)
   31 #define LOCALTIME_STREAM        0
   32 #endif
   33 
   34 static uint64_t sigpipe_count;
   35 #endif
   36 
   37 /*
   38  *  stress_set_sctp_port()
   39  *  set port to use
   40  */
   41 int stress_set_sctp_port(const char *opt)
   42 {
   43     int sctp_port;
   44 
   45     stress_set_net_port("sctp-port", opt,
   46         MIN_SCTP_PORT, MAX_SCTP_PORT - STRESS_PROCS_MAX,
   47         &sctp_port);
   48     return set_setting("sctp-port", TYPE_ID_INT, &sctp_port);
   49 }
   50 
   51 /*
   52  *  stress_set_sctp_domain()
   53  *  set the socket domain option
   54  */
   55 int stress_set_sctp_domain(const char *name)
   56 {
   57     int ret, sctp_domain;
   58 
   59     ret = stress_set_net_domain(DOMAIN_ALL, "sctp-domain",
   60                      name, &sctp_domain);
   61     set_setting("sctp-domain", TYPE_ID_INT, &sctp_domain);
   62 
   63     return ret;
   64 }
   65 
   66 #if defined(HAVE_LIB_SCTP) &&   \
   67     defined(HAVE_NETINET_SCTP_H)
   68 
   69 /*
   70  *  stress_sctp_client()
   71  *  client reader
   72  */
   73 static void stress_sctp_client(
   74     const args_t *args,
   75     const pid_t ppid,
   76     const int sctp_port,
   77     const int sctp_domain)
   78 {
   79     struct sockaddr *addr;
   80 
   81     (void)setpgid(0, g_pgrp);
   82     stress_parent_died_alarm();
   83 
   84     do {
   85         char buf[SOCKET_BUF];
   86         int fd;
   87         int retries = 0;
   88         socklen_t addr_len = 0;
   89         struct sctp_event_subscribe events;
   90 retry:
   91         if (!g_keep_stressing_flag) {
   92             (void)kill(getppid(), SIGALRM);
   93             _exit(EXIT_FAILURE);
   94         }
   95         if ((fd = socket(sctp_domain, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
   96             if (errno == EPROTONOSUPPORT) {
   97                 pr_inf("%s: SCTP protocol not supported, skipping stressor\n",
   98                     args->name);
   99                 (void)kill(getppid(), SIGALRM);
  100                 _exit(EXIT_NOT_IMPLEMENTED);
  101             }
  102             pr_fail_dbg("socket");
  103             /* failed, kick parent to finish */
  104             (void)kill(getppid(), SIGALRM);
  105             _exit(EXIT_FAILURE);
  106         }
  107 
  108         stress_set_sockaddr(args->name, args->instance, ppid,
  109             sctp_domain, sctp_port,
  110             &addr, &addr_len, NET_ADDR_LOOPBACK);
  111         if (connect(fd, addr, addr_len) < 0) {
  112             (void)close(fd);
  113             (void)shim_usleep(10000);
  114             retries++;
  115             if (retries > 100) {
  116                 /* Give up.. */
  117                 pr_fail_dbg("connect");
  118                 (void)kill(getppid(), SIGALRM);
  119                 _exit(EXIT_FAILURE);
  120             }
  121             goto retry;
  122         }
  123         (void)memset(&events, 0, sizeof(events));
  124         events.sctp_data_io_event = 1;
  125         if (setsockopt(fd, SOL_SCTP, SCTP_EVENTS, &events,
  126             sizeof(events)) < 0) {
  127             (void)close(fd);
  128             pr_fail_dbg("setsockopt");
  129             (void)kill(getppid(), SIGALRM);
  130             _exit(EXIT_FAILURE);
  131         }
  132 
  133         do {
  134             int flags;
  135             struct sctp_sndrcvinfo sndrcvinfo;
  136             ssize_t n;
  137 
  138             n = sctp_recvmsg(fd, buf, sizeof(buf),
  139                 NULL, 0, &sndrcvinfo, &flags);
  140             if (n <= 0)
  141                 break;
  142         } while (keep_stressing());
  143         (void)shutdown(fd, SHUT_RDWR);
  144         (void)close(fd);
  145     } while (keep_stressing());
  146 
  147 #if defined(AF_UNIX)
  148     if (sctp_domain == AF_UNIX) {
  149         struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  150         (void)unlink(addr_un->sun_path);
  151     }
  152 #endif
  153     /* Inform parent we're all done */
  154     (void)kill(getppid(), SIGALRM);
  155 }
  156 
  157 /*
  158  *  stress_sctp_server()
  159  *  server writer
  160  */
  161 static int stress_sctp_server(
  162     const args_t *args,
  163     const pid_t pid,
  164     const pid_t ppid,
  165     const int sctp_port,
  166     const int sctp_domain)
  167 {
  168     char buf[SOCKET_BUF];
  169     int fd, status;
  170     int so_reuseaddr = 1;
  171     socklen_t addr_len = 0;
  172     struct sockaddr *addr = NULL;
  173     uint64_t msgs = 0;
  174     int rc = EXIT_SUCCESS;
  175 
  176     (void)setpgid(pid, g_pgrp);
  177 
  178     if (stress_sig_stop_stressing(args->name, SIGALRM)) {
  179         rc = EXIT_FAILURE;
  180         goto die;
  181     }
  182     if ((fd = socket(sctp_domain, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
  183         if (errno == EPROTONOSUPPORT) {
  184             pr_inf("%s: SCTP protocol not supported, skipping stressor\n",
  185                 args->name);
  186             rc = EXIT_NOT_IMPLEMENTED;
  187             goto die;
  188         }
  189         rc = exit_status(errno);
  190         pr_fail_dbg("socket");
  191         goto die;
  192     }
  193     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  194         &so_reuseaddr, sizeof(so_reuseaddr)) < 0) {
  195         pr_fail_dbg("setsockopt");
  196         rc = EXIT_FAILURE;
  197         goto die_close;
  198     }
  199 
  200     stress_set_sockaddr(args->name, args->instance, ppid,
  201         sctp_domain, sctp_port, &addr, &addr_len, NET_ADDR_ANY);
  202     if (bind(fd, addr, addr_len) < 0) {
  203         rc = exit_status(errno);
  204         pr_fail_dbg("bind");
  205         goto die_close;
  206     }
  207     if (listen(fd, 10) < 0) {
  208         pr_fail_dbg("listen");
  209         rc = EXIT_FAILURE;
  210         goto die_close;
  211     }
  212 
  213     do {
  214         int sfd;
  215 
  216         if (!keep_stressing())
  217             break;
  218 
  219         sfd = accept(fd, (struct sockaddr *)NULL, NULL);
  220         if (sfd >= 0) {
  221             size_t i;
  222 
  223 #if defined(SOCKET_NODELAY)
  224             int one = 1;
  225 
  226             if (opt_flags & OPT_FLAGS_SOCKET_NODELAY) {
  227                 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) {
  228                     pr_inf("%s: setsockopt TCP_NODELAY "
  229                         "failed and disabled, errno=%d (%s)\n",
  230                         args->name, errno, strerror(errno));
  231                     opt_flags &= ~OPT_FLAGS_SOCKET_NODELAY;
  232                 }
  233             }
  234 #endif
  235 
  236             (void)memset(buf, 'A' + (get_counter(args) % 26), sizeof(buf));
  237 
  238             for (i = 16; i < sizeof(buf); i += 16) {
  239                 ssize_t ret = sctp_sendmsg(sfd, buf, i,
  240                         NULL, 0, 0, 0,
  241                         LOCALTIME_STREAM, 0, 0);
  242                 if (ret < 0)
  243                     break;
  244                 else {
  245                     inc_counter(args);
  246                     msgs++;
  247                 }
  248             }
  249             (void)close(sfd);
  250         }
  251     } while (keep_stressing());
  252 
  253 die_close:
  254     (void)close(fd);
  255 die:
  256 #if defined(AF_UNIX)
  257     if (addr && sctp_domain == AF_UNIX) {
  258         struct sockaddr_un *addr_un = (struct sockaddr_un *)addr;
  259         (void)unlink(addr_un->sun_path);
  260     }
  261 #endif
  262     if (pid) {
  263         (void)kill(pid, SIGKILL);
  264         (void)waitpid(pid, &status, 0);
  265     }
  266 
  267     return rc;
  268 }
  269 
  270 static void stress_sctp_sigpipe(int signum)
  271 {
  272     (void)signum;
  273 
  274     sigpipe_count++;
  275 }
  276 
  277 /*
  278  *  stress_sctp
  279  *  stress SCTP by heavy SCTP network I/O
  280  */
  281 static int stress_sctp(const args_t *args)
  282 {
  283     pid_t pid, ppid = getppid();
  284     int sctp_port = DEFAULT_SCTP_PORT;
  285     int sctp_domain = AF_INET;
  286     int ret = EXIT_FAILURE;
  287 
  288     (void)get_setting("sctp-port", &sctp_port);
  289     (void)get_setting("sctp-domain", &sctp_domain);
  290 
  291     if (stress_sighandler(args->name, SIGPIPE, stress_sctp_sigpipe, NULL) < 0)
  292         return EXIT_FAILURE;
  293 
  294     pr_dbg("%s: process [%d] using socket port %d\n",
  295         args->name, args->pid, sctp_port + args->instance);
  296 
  297 again:
  298     pid = fork();
  299     if (pid < 0) {
  300         if (g_keep_stressing_flag && (errno == EAGAIN))
  301             goto again;
  302         pr_fail_dbg("fork");
  303         return EXIT_FAILURE;
  304     } else if (pid == 0) {
  305         stress_sctp_client(args, ppid,
  306             sctp_port, sctp_domain);
  307         _exit(EXIT_SUCCESS);
  308     } else {
  309         ret = stress_sctp_server(args, pid, ppid,
  310             sctp_port, sctp_domain);
  311     }
  312 
  313     if (sigpipe_count)
  314         pr_dbg("%s: caught %" PRIu64 " SIGPIPE signals\n", args->name, sigpipe_count);
  315 
  316     return ret;
  317 }
  318 
  319 stressor_info_t stress_sctp_info = {
  320     .stressor = stress_sctp,
  321     .class = CLASS_NETWORK
  322 };
  323 #else
  324 stressor_info_t stress_sctp_info = {
  325     .stressor = stress_not_implemented,
  326     .class = CLASS_NETWORK
  327 };
  328 #endif