1 /* $OpenBSD: unconacc.c,v 1.1 2021/12/10 00:50:18 mvs Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Vitaliy Makkoveev <mvs@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Provide multithreaded connect(2) and accept(2) stress test on 21 * unix(4) socket. 22 */ 23 24 #include <sys/types.h> 25 #include <sys/select.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <sys/sysctl.h> 29 #include <sys/un.h> 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <pthread.h> 35 #include <string.h> 36 #include <time.h> 37 #include <unistd.h> 38 39 static pthread_mutex_t therr_mtx = PTHREAD_MUTEX_INITIALIZER; 40 41 static void 42 therr(int eval, const char *fmt, ...) 43 { 44 va_list ap; 45 46 pthread_mutex_lock(&therr_mtx); 47 48 va_start(ap, fmt); 49 verr(eval, fmt, ap); 50 va_end(ap); 51 } 52 53 static void 54 therrc(int eval, int code, const char *fmt, ...) 55 { 56 va_list ap; 57 58 pthread_mutex_lock(&therr_mtx); 59 60 va_start(ap, fmt); 61 verrc(eval, code, fmt, ap); 62 va_end(ap); 63 } 64 65 static void * 66 thr_acc(void *arg) 67 { 68 int s = *(int *)arg; 69 70 while (1) { 71 int n; 72 73 if ((n = accept(s, NULL, NULL)) < 0) { 74 switch (errno) { 75 case EMFILE: 76 case ENFILE: 77 continue; 78 default: 79 therr(1, "accept"); 80 } 81 } 82 83 close(n); 84 } 85 86 return NULL; 87 } 88 89 static void * 90 thr_conn(void *arg) 91 { 92 struct sockaddr_un *sun = arg; 93 int s; 94 95 while (1) { 96 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 97 switch (errno) { 98 case EMFILE: 99 case ENFILE: 100 case ENOBUFS: 101 continue; 102 default: 103 therr(1, "socket"); 104 } 105 } 106 107 if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) { 108 switch (errno) { 109 case ECONNREFUSED: 110 continue; 111 default: 112 therr(1, "connect"); 113 } 114 } 115 116 close(s); 117 } 118 119 return NULL; 120 } 121 122 static struct sockaddr_un sun; 123 124 int 125 main(int argc, char *argv[]) 126 { 127 struct timespec testtime = { 128 .tv_sec = 60, 129 .tv_nsec = 0, 130 }; 131 132 int s; 133 134 int mib[2], ncpu; 135 size_t len; 136 137 int i; 138 139 umask(0077); 140 141 if (argc == 2 && !strcmp(argv[1], "--infinite")) 142 testtime.tv_sec = (10 * 365 * 86400); 143 144 mib[0] = CTL_HW; 145 mib[1] = HW_NCPUONLINE; 146 len = sizeof(ncpu); 147 148 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) < 0) 149 err(1, "sysctl"); 150 if (ncpu <= 0) 151 errx(1, "Wrong number of CPUs online: %d", ncpu); 152 153 memset(&sun, 0, sizeof(sun)); 154 sun.sun_len = sizeof(sun); 155 sun.sun_family = AF_UNIX; 156 snprintf(sun.sun_path, sizeof(sun.sun_path) - 1, "unconacc.socket"); 157 158 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 159 err(1, "socket"); 160 161 unlink(sun.sun_path); 162 163 if (bind(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) 164 err(1, "bind"); 165 if (listen(s, 10) < 0) 166 err(1, "listen"); 167 168 for (i = 0; i < (ncpu * 2); ++i) { 169 pthread_t thr; 170 int error; 171 172 if ((error = pthread_create(&thr, NULL, thr_acc, &s))) 173 therrc(1, error, "pthread_create"); 174 } 175 176 for (i = 0; i < (ncpu * 2); ++i) { 177 pthread_t thr; 178 int error; 179 180 if ((error = pthread_create(&thr, NULL, thr_conn, &sun))) 181 therrc(1, error, "pthread_create"); 182 } 183 184 nanosleep(&testtime, NULL); 185 186 return 0; 187 } 188