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