mirror of
https://git.proxmox.com/git/proxmox-spamassassin
synced 2025-04-29 23:46:01 +00:00
271 lines
6.0 KiB
C
271 lines
6.0 KiB
C
/* <@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;
|
|
}
|