blob: 0e130fbc6a6203fcbb08f960fbb90b213156f5a8 [file] [log] [blame]
/* <@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.
* </@LICENSE>
*/
#ifndef _WIN32
#include <unistd.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#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 <io.h>
#endif
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#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;
}