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