1 /*
2 ** Copyright 1998 - 2001 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #if	HAVE_CONFIG_H
7 #include	"config.h"
8 #endif
9 #include	<stdio.h>
10 #if	HAVE_UNISTD_H
11 #include	<unistd.h>
12 #endif
13 #if	HAVE_FCNTL_H
14 #include	<fcntl.h>
15 #endif
16 #include	<ctype.h>
17 #include	<string.h>
18 #include	<stdlib.h>
19 #include	<sys/types.h>
20 #include	<sys/uio.h>
21 #include	<sys/time.h>
22 #include	<signal.h>
23 #include	<errno.h>
24 
25 #include	"esmtpiov.h"
26 
27 time_t iovread_timeout=300;
28 time_t iovwrite_timeout=60;
29 static char inputbuf[5120];
30 static char *inputbufhead=inputbuf, *inputbuftail=inputbuf;
31 static int overflowed=0;
32 static struct iovec iov[10];
33 static int	niovec=0;
34 
iovreset()35 void iovreset()
36 {
37 	inputbufhead=inputbuftail=inputbuf;
38 }
39 
iovflush()40 void iovflush()
41 {
42 struct iovec *iovp=iov;
43 unsigned niovp=niovec;
44 int	n;
45 fd_set	fds;
46 struct	timeval	tv;
47 
48 	while (niovp && niovec)
49 	{
50 		FD_ZERO(&fds);
51 		FD_SET(1, &fds);
52 		tv.tv_sec=iovwrite_timeout;
53 		tv.tv_usec=0;
54 		if (select(2, 0, &fds, 0, &tv) <= 0 ||
55 			!FD_ISSET(1, &fds) ||
56 			(n=writev(1, iov, niovec)) <= 0)
57 		{
58 			iov_logerror("writev: ",
59 #if HAVE_STRERROR
60 				     strerror(errno)
61 
62 #else
63 				     "write error"
64 #endif
65 				     );
66 			exit(1);
67 		}
68 
69 		while (n && niovp)
70 		{
71 			if (n >= iovp->iov_len)
72 			{
73 				n -= iovp->iov_len;
74 				++iovp;
75 				--niovp;
76 				continue;
77 			}
78 			iovp->iov_base=(caddr_t)
79 				( (char *)iovp->iov_base + n);
80 			iovp->iov_len -= n;
81 			break;
82 		}
83 	}
84 	niovec=0;
85 }
86 
iovwaitfordata(time_t * t,int abort)87 int iovwaitfordata(time_t *t, int abort)
88 {
89 time_t	now;
90 
91 	time(&now);
92 	if (now < *t)
93 	{
94 	fd_set	fds;
95 	struct	timeval	tv;
96 
97 		FD_ZERO(&fds);
98 		FD_SET(0, &fds);
99 		tv.tv_sec=*t - now;
100 		tv.tv_usec=0;
101 		if (select(1, &fds, 0, 0, &tv) > 0 &&
102 			FD_ISSET(0, &fds))
103 			return (0);
104 	}
105 
106 	errno=ETIMEDOUT;
107 
108 	{
109 #if HAVE_STRERROR
110 		const char *ip=getenv("TCPREMOTEIP");
111 
112 		if (ip && *ip)
113 			fprintf(stderr, "[%s]: %s\n", ip,
114 				strerror(errno));
115 		else
116 #endif
117 			perror("read");
118 	}
119 	if (abort)
120 		exit(1);
121 	return (-1);
122 }
123 
iovreadline()124 char *iovreadline()
125 {
126 char *p=inputbufhead;
127 time_t	t;
128 
129 	time(&t);
130 	t += iovread_timeout;
131 	iovflush();
132 	for (;;)
133 	{
134 		if (p >= inputbuftail)
135 		{
136 		int	n;
137 
138 			if (inputbufhead == inputbuftail)
139 			{
140 				inputbufhead=inputbuftail=inputbuf;
141 				iovwaitfordata(&t, 1);
142 				n=read(0, inputbuf, sizeof(inputbuf));
143 				if (n <= 0)	_exit(0);
144 				inputbuftail=inputbuf+n;
145 				p=inputbuf;
146 				continue;
147 			}
148 			if (inputbufhead > inputbuf)
149 			{
150 				n=0;
151 				while (inputbufhead < inputbuftail)
152 					inputbuf[n++]= *inputbufhead++;
153 				inputbuftail=p=inputbuf+n;
154 				inputbufhead=inputbuf;
155 			}
156 			if (inputbuftail >= inputbuf+sizeof(inputbuf))
157 			{
158 				if (overflowed)	/* Already overflowed once */
159 				{
160 					inputbuf[0]=inputbuftail[-1];
161 					inputbufhead=inputbuf;
162 					inputbuftail=inputbufhead+1;
163 					p=inputbuftail;
164 					continue;
165 				}
166 				overflowed=1;
167 				inputbuftail[-2]=0;
168 				inputbufhead=inputbuftail-1;
169 				return (inputbuf);
170 			}
171 			iovwaitfordata(&t, 1);
172 			n=read(0, inputbuftail, inputbuf+sizeof(inputbuf)-
173 					inputbuftail);
174 			if (n <= 0)	_exit(0);
175 			inputbuftail += n;
176 		}
177 
178 		if (*p == '\n' && p > inputbufhead && p[-1] == '\r')
179 		{
180 		char *q=inputbufhead;
181 
182 			p[-1]=0;
183 			*p++=0;
184 			inputbufhead=p;
185 			if (overflowed)
186 			{
187 				overflowed=0;
188 				continue;
189 			}
190 			return (q);
191 		}
192 		++p;
193 	}
194 }
195 
addiovec(const char * p,size_t l)196 void addiovec(const char *p, size_t l)
197 {
198 	iov[niovec].iov_base=(caddr_t)p;
199 	iov[niovec].iov_len=l;
200 	if (++niovec >= sizeof(iov)/sizeof(iov[0]))
201 		iovflush();
202 }
203