1 /* <@LICENSE>
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to you under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * </@LICENSE>
17 */
18
19 #ifndef _WIN32
20 #include <unistd.h>
21 #include <sys/uio.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #else
25
26 #ifdef _MSC_VER
27 /* ignore MSVC++ warnings that are annoying and hard to remove:
28 4115 named type definition in parentheses
29 4127 conditional expression is constant
30 4514 unreferenced inline function removed
31 4996 deprecated "unsafe" functions
32 */
33 #pragma warning( disable : 4115 4127 4514 4996 )
34 #endif
35
36 #include <io.h>
37 #endif
38 #include <errno.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include "utils.h"
42
43 /* Dec 13 2001 jm: added safe full-read and full-write functions. These
44 * can cope with networks etc., where a write or read may not read all
45 * the data that's there, in one call.
46 */
47 /* Aug 14, 2002 bj: EINTR and EAGAIN aren't fatal, are they? */
48 /* Aug 14, 2002 bj: moved these to utils.c */
49 /* Jan 13, 2003 ym: added timeout functionality */
50 /* Apr 24, 2003 sjf: made full_read and full_write void* params */
51
52 /* -------------------------------------------------------------------------- */
53 #ifndef _WIN32
54 typedef void sigfunc(int); /* for signal handlers */
55
sig_catch(int sig,void (* f)(int))56 sigfunc *sig_catch(int sig, void (*f) (int))
57 {
58 struct sigaction act, oact;
59 act.sa_handler = f;
60 act.sa_flags = 0;
61 sigemptyset(&act.sa_mask);
62 sigaction(sig, &act, &oact);
63 return oact.sa_handler;
64 }
65
catch_alrm(int x)66 static void catch_alrm(int x)
67 {
68 UNUSED_VARIABLE(x);
69 }
70 #endif
71
timeout_connect(int sockfd,const struct sockaddr * serv_addr,size_t addrlen)72 int timeout_connect (int sockfd, const struct sockaddr *serv_addr, size_t addrlen)
73 {
74 int ret;
75
76 #ifndef _WIN32
77 sigfunc* sig;
78
79 sig = sig_catch(SIGALRM, catch_alrm);
80 if (libspamc_connect_timeout > 0) {
81 alarm(libspamc_connect_timeout);
82 }
83 #endif
84
85 ret = connect(sockfd, serv_addr, addrlen);
86
87 #ifndef _WIN32
88 if (libspamc_connect_timeout > 0) {
89 alarm(0);
90 }
91
92 /* restore old signal handler */
93 sig_catch(SIGALRM, sig);
94 #endif
95
96 return ret;
97 }
98
fd_timeout_read(int fd,char fdflag,void * buf,size_t nbytes)99 int fd_timeout_read(int fd, char fdflag, void *buf, size_t nbytes)
100 {
101 int nred;
102 int origerr;
103 #ifndef _WIN32
104 sigfunc *sig;
105
106 sig = sig_catch(SIGALRM, catch_alrm);
107 if (libspamc_timeout > 0) {
108 alarm(libspamc_timeout);
109 }
110 #endif
111
112 do {
113 if (fdflag) {
114 nred = (int)read(fd, buf, nbytes);
115 origerr = errno;
116 }
117 else {
118 nred = (int)recv(fd, buf, nbytes, 0);
119 #ifndef _WIN32
120 origerr = errno;
121 #else
122 origerr = WSAGetLastError();
123 #endif
124 }
125 } while (nred < 0 && origerr == EWOULDBLOCK);
126
127 #ifndef _WIN32
128 if (nred < 0 && origerr == EINTR)
129 errno = ETIMEDOUT;
130
131 if (libspamc_timeout > 0) {
132 alarm(0);
133 }
134
135 /* restore old signal handler */
136 sig_catch(SIGALRM, sig);
137 #endif
138
139 return nred;
140 }
141
ssl_timeout_read(SSL * ssl,void * buf,int nbytes)142 int ssl_timeout_read(SSL * ssl, void *buf, int nbytes)
143 {
144 int nred;
145
146 #ifndef _WIN32
147 sigfunc *sig;
148
149 sig = sig_catch(SIGALRM, catch_alrm);
150 if (libspamc_timeout > 0) {
151 alarm(libspamc_timeout);
152 }
153 #endif
154
155 do {
156
157 #ifdef SPAMC_SSL
158 nred = SSL_read(ssl, buf, nbytes);
159 #else
160 UNUSED_VARIABLE(ssl);
161 UNUSED_VARIABLE(buf);
162 UNUSED_VARIABLE(nbytes);
163 nred = 0; /* never used */
164 #endif
165
166 } while (nred < 0 && errno == EWOULDBLOCK);
167
168 #ifndef _WIN32
169 if (nred < 0 && errno == EINTR)
170 errno = ETIMEDOUT;
171
172 if (libspamc_timeout > 0) {
173 alarm(0);
174 }
175
176 /* restore old signal handler */
177 sig_catch(SIGALRM, sig);
178 #endif
179
180 return nred;
181 }
182
183 /* -------------------------------------------------------------------------- */
184
full_read(int fd,char fdflag,void * vbuf,int min,int len)185 int full_read(int fd, char fdflag, void *vbuf, int min, int len)
186 {
187 unsigned char *buf = (unsigned char *) vbuf;
188 int total;
189 int thistime;
190
191 for (total = 0; total < min;) {
192 thistime = fd_timeout_read(fd, fdflag, buf + total, len - total);
193
194 if (thistime < 0) {
195 if (total >= min) {
196 /* error, but we read *some*. return what we've read
197 * so far and next read (if there is one) will return -1. */
198 return total;
199 } else {
200 return -1;
201 }
202 }
203 else if (thistime == 0) {
204 /* EOF, but we didn't read the minimum. return what we've read
205 * so far and next read (if there is one) will return 0. */
206 return total;
207 }
208
209 total += thistime;
210 }
211 return total;
212 }
213
full_read_ssl(SSL * ssl,unsigned char * buf,int min,int len)214 int full_read_ssl(SSL * ssl, unsigned char *buf, int min, int len)
215 {
216 int total;
217 int thistime;
218
219 for (total = 0; total < min;) {
220 thistime = ssl_timeout_read(ssl, buf + total, len - total);
221
222 if (thistime < 0) {
223 if (total >= min) {
224 /* error, but we read *some*. return what we've read
225 * so far and next read (if there is one) will return -1. */
226 return total;
227 } else {
228 return -1;
229 }
230 }
231 else if (thistime == 0) {
232 /* EOF, but we didn't read the minimum. return what we've read
233 * so far and next read (if there is one) will return 0. */
234 return total;
235 }
236
237 total += thistime;
238 }
239 return total;
240 }
241
full_write(int fd,char fdflag,const void * vbuf,int len)242 int full_write(int fd, char fdflag, const void *vbuf, int len)
243 {
244 const char *buf = (const char *) vbuf;
245 int total;
246 int thistime;
247 int origerr;
248
249 for (total = 0; total < len;) {
250 if (fdflag) {
251 thistime = write(fd, buf + total, len - total);
252 origerr = errno;
253 }
254 else {
255 thistime = send(fd, buf + total, len - total, 0);
256 #ifndef _WIN32
257 origerr = errno;
258 #else
259 origerr = WSAGetLastError();
260 #endif
261 }
262 if (thistime < 0) {
263 if (EINTR == origerr || EWOULDBLOCK == origerr)
264 continue;
265 return thistime; /* always an error for writes */
266 }
267 total += thistime;
268 }
269 return total;
270 }
271