xref: /freebsd/contrib/sendmail/libsm/t-notify.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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