1 /* 2 * Copyright (c) 2020 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10 #include <sm/gen.h> 11 #include <stdio.h> 12 13 #if _FFR_DMTRIGGER || _FFR_NOTIFY 14 # include <stdlib.h> 15 # include <unistd.h> 16 # include <errno.h> 17 # include <sm/heap.h> 18 # include <sm/string.h> 19 # include <sm/test.h> 20 # include <sm/notify.h> 21 # include <sm/conf.h> 22 # include "notify.h" 23 24 static int Verbose = 0; 25 #define MAX_CHILDREN 256 26 #define MAX_MSGS 1024 27 static pid_t pids[MAX_CHILDREN]; 28 static char msgs[MAX_CHILDREN][MAX_MSGS]; 29 30 /* 31 ** NOTIFY_WR -- test of notify write feature 32 ** 33 ** Parameters: 34 ** pid -- pid of process 35 ** nmsgs -- number of messages to write 36 ** 37 ** Returns: 38 ** >=0 on success 39 ** < 0 on failure 40 */ 41 42 static int 43 notify_wr(pid, nmsgs) 44 pid_t pid; 45 int nmsgs; 46 { 47 int r, i; 48 size_t len; 49 char buf[64]; 50 #define TSTSTR "qf0001" 51 52 r = sm_notify_start(false, 0); 53 if (r < 0) 54 { 55 perror("sm_notify_start failed"); 56 return -1; 57 } 58 59 for (i = 0; i < nmsgs; i++) 60 { 61 len = sm_snprintf(buf, sizeof(buf), "%s-%ld_%d", TSTSTR, 62 (long) pid, i); 63 r = sm_notify_snd(buf, len); 64 SM_TEST(r >= 0); 65 } 66 return r; 67 } 68 69 static int 70 validpid(nproc, cpid) 71 int nproc; 72 pid_t cpid; 73 { 74 int i; 75 76 for (i = 0; i < nproc; i++) 77 if (cpid == pids[i]) 78 return i; 79 if (Verbose > 0) 80 fprintf(stderr, "pid=%ld not found, nproc=%d\n", 81 (long) cpid, nproc); 82 return -1; 83 } 84 85 /* 86 ** NOTIFY_RD -- test of notify read feature 87 ** 88 ** Parameters: 89 ** nproc -- number of processes started 90 ** nmsgs -- number of messages to read for each process 91 ** 92 ** Returns: 93 ** 0 on success 94 ** < 0 on failure 95 */ 96 97 static int 98 notify_rd(nproc, nmsgs) 99 int nproc; 100 int nmsgs; 101 { 102 int r, i, pidx; 103 long cpid; 104 char buf[64], *p; 105 #define TSTSTR "qf0001" 106 107 r = sm_notify_start(true, 0); 108 if (r < 0) 109 { 110 perror("sm_notify_start failed"); 111 return -1; 112 } 113 114 for (i = 0; i < nmsgs * nproc; i++) 115 { 116 do 117 { 118 r = sm_notify_rcv(buf, sizeof(buf), 5 * SM_MICROS); 119 SM_TEST(r >= 0); 120 } while (0 == r); 121 if (r < 0) 122 { 123 fprintf(stderr, "pid=%ld, rcv=%d, i=%d\n", 124 (long)getpid(), r, i); 125 return r; 126 } 127 if (r > 0 && r < sizeof(buf)) 128 buf[r] = '\0'; 129 buf[sizeof(buf) - 1] = '\0'; 130 131 if (Verbose > 0) 132 fprintf(stderr, "pid=%ld, buf=\"%s\", i=%d\n", 133 (long)getpid(), buf, i); 134 135 SM_TEST(strncmp(buf, TSTSTR, sizeof(TSTSTR) - 1) == 0); 136 SM_TEST(r > sizeof(TSTSTR)); 137 138 r = sscanf(buf + sizeof(TSTSTR), "%ld", &cpid); 139 SM_TEST(1 == r); 140 pidx = validpid(nproc, (pid_t)cpid); 141 SM_TEST(pidx >= 0); 142 SM_TEST(pidx < nproc); 143 144 p = strchr(buf, '_'); 145 SM_TEST(NULL != p); 146 if (NULL != p && pidx < nproc && pidx >= 0) 147 { 148 int n; 149 150 r = sscanf(p + 1, "%d", &n); 151 SM_TEST(1 == r); 152 SM_TEST(n >= 0); 153 SM_TEST(n < nmsgs); 154 if (1 == r && n < nmsgs && n >= 0) 155 { 156 SM_TEST('\0' == msgs[pidx][n]); 157 msgs[pidx][n] = 'f'; 158 } 159 } 160 } 161 return 0; 162 } 163 164 int 165 main(argc, argv) 166 int argc; 167 char *argv[]; 168 { 169 int i; 170 int r = 0; 171 int nproc = 1; 172 int nmsgs = 1; 173 pid_t pid; 174 175 # define OPTIONS "n:p:V" 176 while ((i = getopt(argc, argv, OPTIONS)) != -1) 177 { 178 switch ((char) i) 179 { 180 case 'n': 181 nmsgs = atoi(optarg); 182 if (nmsgs < 1) 183 { 184 errno = EINVAL; 185 fprintf(stderr, "-%c: must be >0\n", (char) i); 186 return 1; 187 } 188 if (nmsgs >= MAX_MSGS) 189 { 190 errno = EINVAL; 191 fprintf(stderr, "-%c: must be <%d\n", (char) i, MAX_MSGS); 192 return 1; 193 } 194 break; 195 case 'p': 196 nproc = atoi(optarg); 197 if (nproc < 1) 198 { 199 errno = EINVAL; 200 fprintf(stderr, "-%c: must be >0\n", (char) i); 201 return 1; 202 } 203 if (nproc >= MAX_CHILDREN) 204 { 205 errno = EINVAL; 206 fprintf(stderr, "-%c: must be <%d\n", (char) i, MAX_CHILDREN); 207 return 1; 208 } 209 break; 210 case 'V': 211 ++Verbose; 212 break; 213 default: 214 break; 215 } 216 } 217 218 memset(msgs, '\0', sizeof(msgs)); 219 sm_test_begin(argc, argv, "test notify"); 220 r = sm_notify_init(0); 221 SM_TEST(r >= 0); 222 if (r < 0) 223 { 224 perror("sm_notify_init failed\n"); 225 return r; 226 } 227 228 pid = 0; 229 for (i = 0; i < nproc; i++) 230 { 231 if ((pid = fork()) < 0) 232 { 233 perror("fork failed\n"); 234 return -1; 235 } 236 237 if (pid == 0) 238 { 239 /* give the parent the chance to set up data */ 240 sleep(1); 241 r = notify_wr(getpid(), nmsgs); 242 break; 243 } 244 if (pid > 0) 245 pids[i] = pid; 246 } 247 if (pid > 0) 248 r = notify_rd(nproc, nmsgs); 249 SM_TEST(r >= 0); 250 return sm_test_end(); 251 } 252 #else /* _FFR_DMTRIGGER */ 253 int 254 main(argc, argv) 255 int argc; 256 char *argv[]; 257 { 258 printf("SKIPPED: no _FFR_DMTRIGGER || _FFR_NOTIFY\n"); 259 return 0; 260 } 261 #endif /* _FFR_DMTRIGGER || _FFR_NOTIFY */ 262