1/*++
2/* NAME
3/*	mail_flow 3
4/* SUMMARY
5/*	global mail flow control
6/* SYNOPSIS
7/*	#include <mail_flow.h>
8/*
9/*	ssize_t	mail_flow_get(count)
10/*	ssize_t	count;
11/*
12/*	ssize_t	mail_flow_put(count)
13/*	ssize_t	count;
14/*
15/*	ssize_t	mail_flow_count()
16/* DESCRIPTION
17/*	This module implements a simple flow control mechanism that
18/*	is based on tokens that are consumed by mail receiving processes
19/*	and that are produced by mail sending processes.
20/*
21/*	mail_flow_get() attempts to read specified number of tokens. The
22/*	result is > 0 for success, < 0 for failure. In the latter case,
23/*	the process is expected to slow down a little.
24/*
25/*	mail_flow_put() produces the specified number of tokens. The
26/*	token producing process is expected to produce new tokens
27/*	whenever it falls idle and no more tokens are available.
28/*
29/*	mail_flow_count() returns the number of available tokens.
30/* BUGS
31/*	The producer needs to wake up periodically to ensure that
32/*	tokens are not lost due to leakage.
33/* LICENSE
34/* .ad
35/* .fi
36/*	The Secure Mailer license must be distributed with this software.
37/* AUTHOR(S)
38/*	Wietse Venema
39/*	IBM T.J. Watson Research
40/*	P.O. Box 704
41/*	Yorktown Heights, NY 10598, USA
42/*--*/
43
44/* System library. */
45
46#include <sys_defs.h>
47#include <sys/stat.h>
48#include <unistd.h>
49#include <stdlib.h>
50#include <string.h>
51
52/* Utility library. */
53
54#include <msg.h>
55#include <iostuff.h>
56#include <warn_stat.h>
57
58/* Global library. */
59
60#include <mail_flow.h>
61
62/* Master library. */
63
64#include <master_proto.h>
65
66#define BUFFER_SIZE	1024
67
68/* mail_flow_get - read N tokens */
69
70ssize_t mail_flow_get(ssize_t len)
71{
72    const char *myname = "mail_flow_get";
73    char    buf[BUFFER_SIZE];
74    struct stat st;
75    ssize_t count;
76    ssize_t n = 0;
77
78    /*
79     * Sanity check.
80     */
81    if (len <= 0)
82	msg_panic("%s: bad length %ld", myname, (long) len);
83
84    /*
85     * Silence some wild claims.
86     */
87    if (fstat(MASTER_FLOW_WRITE, &st) < 0)
88	msg_fatal("fstat flow pipe write descriptor: %m");
89
90    /*
91     * Read and discard N bytes. XXX AIX read() can return 0 when an open
92     * pipe is empty.
93     */
94    for (count = len; count > 0; count -= n)
95	if ((n = read(MASTER_FLOW_READ, buf, count > BUFFER_SIZE ?
96		      BUFFER_SIZE : count)) <= 0)
97	    return (-1);
98    if (msg_verbose)
99	msg_info("%s: %ld %ld", myname, (long) len, (long) (len - count));
100    return (len - count);
101}
102
103/* mail_flow_put - put N tokens */
104
105ssize_t mail_flow_put(ssize_t len)
106{
107    const char *myname = "mail_flow_put";
108    char    buf[BUFFER_SIZE];
109    ssize_t count;
110    ssize_t n = 0;
111
112    /*
113     * Sanity check.
114     */
115    if (len <= 0)
116	msg_panic("%s: bad length %ld", myname, (long) len);
117
118    /*
119     * Write or discard N bytes.
120     */
121    memset(buf, 0, len > BUFFER_SIZE ? BUFFER_SIZE : len);
122
123    for (count = len; count > 0; count -= n)
124	if ((n = write(MASTER_FLOW_WRITE, buf, count > BUFFER_SIZE ?
125		       BUFFER_SIZE : count)) < 0)
126	    return (-1);
127    if (msg_verbose)
128	msg_info("%s: %ld %ld", myname, (long) len, (long) (len - count));
129    return (len - count);
130}
131
132/* mail_flow_count - return number of available tokens */
133
134ssize_t mail_flow_count(void)
135{
136    const char *myname = "mail_flow_count";
137    ssize_t count;
138
139    if ((count = peekfd(MASTER_FLOW_READ)) < 0)
140	msg_warn("%s: %m", myname);
141    return (count);
142}
143