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
notify_wr(pid,nmsgs)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
validpid(nproc,cpid)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
notify_rd(nproc,nmsgs)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
main(argc,argv)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
main(argc,argv)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