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