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