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
11#include <sm/gen.h>
12
13#if _FFR_DMTRIGGER && _FFR_NOTIFY < 2
14#include <sm/conf.h>	/* FDSET_CAST */
15#include <sm/fdset.h>
16#include <sm/assert.h>
17#include <sm/notify.h>
18#include "notify.h"
19#include <sm/time.h>
20#include <sm/string.h>
21
22#include <sys/types.h>
23#include <signal.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <stdbool.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <string.h>	/* for memset() */
31
32static int	Notifypipe[2];
33#define NotifyRDpipe Notifypipe[0]
34#define NotifyWRpipe Notifypipe[1]
35
36#define CLOSEFD(fd) do { \
37		if ((fd) != -1) {	\
38			(void) close(fd);	\
39			fd = - 1;	\
40		}	\
41	} while (0)	\
42
43
44/*
45**  SM_NOTIFY_INIT -- initialize notify system
46**
47**	Parameters:
48**		flags -- ignored
49**
50**	Returns:
51**		0: success
52**		<0: -errno
53*/
54
55int
56sm_notify_init(flags)
57	int flags;
58{
59	if (pipe(Notifypipe) < 0)
60		return -errno;
61	return 0;
62}
63
64/*
65**  SM_NOTIFY_START -- start notify system
66**
67**	Parameters:
68**		owner -- owner.
69**		flags -- currently ignored.
70**
71**	Returns:
72**		0: success
73**		<0: -errno
74*/
75
76int
77sm_notify_start(owner, flags)
78	bool owner;
79	int flags;
80{
81	int r;
82
83	r = 0;
84	if (owner)
85		CLOSEFD(NotifyWRpipe);
86	else
87		CLOSEFD(NotifyRDpipe);
88	return r;
89}
90
91/*
92**  SM_NOTIFY_STOP -- stop notify system
93**
94**	Parameters:
95**		owner -- owner.
96**		flags -- currently ignored.
97**
98**	Returns:
99**		0: success
100**		<0: -errno
101*/
102
103int
104sm_notify_stop(owner, flags)
105	bool owner;
106	int flags;
107{
108	if (owner)
109		CLOSEFD(NotifyRDpipe);
110	else
111		CLOSEFD(NotifyWRpipe);
112	return 0;
113}
114
115/*
116**  SM_NOTIFY_SND -- send notification
117**
118**	Parameters:
119**		buf -- where to write data
120**		buflen -- len of buffer
121**
122**	Returns:
123**		0: success
124**		<0: -errno
125*/
126
127int
128sm_notify_snd(buf, buflen)
129	char *buf;
130	size_t buflen;
131{
132	int r;
133	int save_errno;
134	size_t len;
135	char netstr[MAX_NETSTR];
136
137	SM_REQUIRE(buf != NULL);
138	SM_REQUIRE(buflen > 0);
139	if (NotifyWRpipe < 0)
140		return -EINVAL;
141	if (buflen >= MAX_NETSTR - 7)
142		return -E2BIG;	/* XXX "TOO LARGE"? */
143
144	len = sm_snprintf(netstr, sizeof(netstr), "%04d:%s,", (int)buflen, buf);
145	r = write(NotifyWRpipe, netstr, len);
146	save_errno = errno;
147	SM_DBG((stderr, "pid=%ld, write=%d, fd=%d, e=%d\n", (long)getpid(), r, NotifyWRpipe, save_errno));
148	return r >= 0 ? 0 : -save_errno;
149}
150
151/*
152**  SM_NOTIFY_RCV -- receive notification
153**
154**	Parameters:
155**		buf -- where to write data
156**		buflen -- len of buffer
157**		tmo -- timeout (micro seconds)
158**
159**	Returns:
160**		0: EOF (XXX need to provide info about client)
161**		>0: length of received data
162**		<0: -errno
163*/
164
165int
166sm_notify_rcv(buf, buflen, tmo)
167	char *buf;
168	size_t buflen;
169	long tmo;
170{
171	int r, len;
172	int save_errno;
173	fd_set readfds;
174	struct timeval timeout, *tval;
175
176	SM_REQUIRE(buf != NULL);
177	SM_REQUIRE(buflen > NETSTRPRE + 2);
178	if (NotifyRDpipe < 0)
179		return -EINVAL;
180	FD_ZERO(&readfds);
181	SM_FD_SET(NotifyRDpipe, &readfds);
182	SM_MICROS2TVAL(tmo, tval, timeout);
183
184	do {
185		r = select(NotifyRDpipe + 1, FDSET_CAST &readfds, NULL, NULL, tval);
186		save_errno = errno;
187		SM_DBG((stderr, "pid=%ld, select=%d, fd=%d, e=%d\n", (long)getpid(), r, NotifyRDpipe, save_errno));
188	} while (r < 0 && save_errno == EINTR);
189
190	RDNETSTR(r, NotifyRDpipe, (void)0);
191}
192#endif /* _FFR_DMTRIGGER && _FFR_NOTIFY < 2 */
193