/* <@LICENSE> * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to you under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifndef _WIN32 #include #include #include #include #else #ifdef _MSC_VER /* ignore MSVC++ warnings that are annoying and hard to remove: 4115 named type definition in parentheses 4127 conditional expression is constant 4514 unreferenced inline function removed 4996 deprecated "unsafe" functions */ #pragma warning( disable : 4115 4127 4514 4996 ) #endif #include #endif #include #include #include #include "utils.h" /* Dec 13 2001 jm: added safe full-read and full-write functions. These * can cope with networks etc., where a write or read may not read all * the data that's there, in one call. */ /* Aug 14, 2002 bj: EINTR and EAGAIN aren't fatal, are they? */ /* Aug 14, 2002 bj: moved these to utils.c */ /* Jan 13, 2003 ym: added timeout functionality */ /* Apr 24, 2003 sjf: made full_read and full_write void* params */ /* -------------------------------------------------------------------------- */ #ifndef _WIN32 typedef void sigfunc(int); /* for signal handlers */ sigfunc *sig_catch(int sig, void (*f) (int)) { struct sigaction act, oact; act.sa_handler = f; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(sig, &act, &oact); return oact.sa_handler; } static void catch_alrm(int x) { UNUSED_VARIABLE(x); } #endif int timeout_connect (int sockfd, const struct sockaddr *serv_addr, size_t addrlen) { int ret; #ifndef _WIN32 sigfunc* sig; sig = sig_catch(SIGALRM, catch_alrm); if (libspamc_connect_timeout > 0) { alarm(libspamc_connect_timeout); } #endif ret = connect(sockfd, serv_addr, addrlen); #ifndef _WIN32 if (libspamc_connect_timeout > 0) { alarm(0); } /* restore old signal handler */ sig_catch(SIGALRM, sig); #endif return ret; } int fd_timeout_read(int fd, char fdflag, void *buf, size_t nbytes) { int nred; int origerr; #ifndef _WIN32 sigfunc *sig; sig = sig_catch(SIGALRM, catch_alrm); if (libspamc_timeout > 0) { alarm(libspamc_timeout); } #endif do { if (fdflag) { nred = (int)read(fd, buf, nbytes); origerr = errno; } else { nred = (int)recv(fd, buf, nbytes, 0); #ifndef _WIN32 origerr = errno; #else origerr = WSAGetLastError(); #endif } } while (nred < 0 && origerr == EWOULDBLOCK); #ifndef _WIN32 if (nred < 0 && origerr == EINTR) errno = ETIMEDOUT; if (libspamc_timeout > 0) { alarm(0); } /* restore old signal handler */ sig_catch(SIGALRM, sig); #endif return nred; } int ssl_timeout_read(SSL * ssl, void *buf, int nbytes) { int nred; #ifndef _WIN32 sigfunc *sig; sig = sig_catch(SIGALRM, catch_alrm); if (libspamc_timeout > 0) { alarm(libspamc_timeout); } #endif do { #ifdef SPAMC_SSL nred = SSL_read(ssl, buf, nbytes); #else UNUSED_VARIABLE(ssl); UNUSED_VARIABLE(buf); UNUSED_VARIABLE(nbytes); nred = 0; /* never used */ #endif } while (nred < 0 && errno == EWOULDBLOCK); #ifndef _WIN32 if (nred < 0 && errno == EINTR) errno = ETIMEDOUT; if (libspamc_timeout > 0) { alarm(0); } /* restore old signal handler */ sig_catch(SIGALRM, sig); #endif return nred; } /* -------------------------------------------------------------------------- */ int full_read(int fd, char fdflag, void *vbuf, int min, int len) { unsigned char *buf = (unsigned char *) vbuf; int total; int thistime; for (total = 0; total < min;) { thistime = fd_timeout_read(fd, fdflag, buf + total, len - total); if (thistime < 0) { if (total >= min) { /* error, but we read *some*. return what we've read * so far and next read (if there is one) will return -1. */ return total; } else { return -1; } } else if (thistime == 0) { /* EOF, but we didn't read the minimum. return what we've read * so far and next read (if there is one) will return 0. */ return total; } total += thistime; } return total; } int full_read_ssl(SSL * ssl, unsigned char *buf, int min, int len) { int total; int thistime; for (total = 0; total < min;) { thistime = ssl_timeout_read(ssl, buf + total, len - total); if (thistime < 0) { if (total >= min) { /* error, but we read *some*. return what we've read * so far and next read (if there is one) will return -1. */ return total; } else { return -1; } } else if (thistime == 0) { /* EOF, but we didn't read the minimum. return what we've read * so far and next read (if there is one) will return 0. */ return total; } total += thistime; } return total; } int full_write(int fd, char fdflag, const void *vbuf, int len) { const char *buf = (const char *) vbuf; int total; int thistime; int origerr; for (total = 0; total < len;) { if (fdflag) { thistime = write(fd, buf + total, len - total); origerr = errno; } else { thistime = send(fd, buf + total, len - total, 0); #ifndef _WIN32 origerr = errno; #else origerr = WSAGetLastError(); #endif } if (thistime < 0) { if (EINTR == origerr || EWOULDBLOCK == origerr) continue; return thistime; /* always an error for writes */ } total += thistime; } return total; }