Main Page | Class List | Directories | File List | Class Members | File Members

utils.c

Go to the documentation of this file.
00001 /* <@LICENSE>
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to you under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at:
00008  * 
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  * 
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  * </@LICENSE>
00017  */
00018 
00019 #ifndef _WIN32
00020 #include <unistd.h>
00021 #include <sys/uio.h>
00022 #include <sys/types.h>
00023 #include <sys/socket.h>
00024 #else
00025 
00026 #ifdef _MSC_VER
00027 /* ignore MSVC++ warnings that are annoying and hard to remove:
00028  4115 named type definition in parentheses
00029  4127 conditional expression is constant
00030  4514 unreferenced inline function removed
00031  */
00032 #pragma warning( disable : 4115 4127 4514 )
00033 #endif
00034 
00035 #include <io.h>
00036 #endif
00037 #include <errno.h>
00038 #include <signal.h>
00039 #include <stdio.h>
00040 #include "utils.h"
00041 
00042 /* Dec 13 2001 jm: added safe full-read and full-write functions.  These
00043  * can cope with networks etc., where a write or read may not read all
00044  * the data that's there, in one call.
00045  */
00046 /* Aug 14, 2002 bj: EINTR and EAGAIN aren't fatal, are they? */
00047 /* Aug 14, 2002 bj: moved these to utils.c */
00048 /* Jan 13, 2003 ym: added timeout functionality */
00049 /* Apr 24, 2003 sjf: made full_read and full_write void* params */
00050 
00051 /* -------------------------------------------------------------------------- */
00052 #ifndef _WIN32
00053 typedef void sigfunc(int);      /* for signal handlers */
00054 
00055 sigfunc *sig_catch(int sig, void (*f) (int))
00056 {
00057     struct sigaction act, oact;
00058     act.sa_handler = f;
00059     act.sa_flags = 0;
00060     sigemptyset(&act.sa_mask);
00061     sigaction(sig, &act, &oact);
00062     return oact.sa_handler;
00063 }
00064 
00065 static void catch_alrm(int x)
00066 {
00067     UNUSED_VARIABLE(x);
00068 }
00069 #endif
00070 
00071 int timeout_connect (int sockfd, const struct sockaddr *serv_addr, size_t addrlen)
00072 {
00073     int ret;
00074 
00075 #ifndef _WIN32
00076     sigfunc* sig;
00077 
00078     sig = sig_catch(SIGALRM, catch_alrm);
00079     if (libspamc_timeout > 0) {
00080       alarm(libspamc_timeout);
00081     }
00082 #endif
00083 
00084     ret = connect(sockfd, serv_addr, addrlen);
00085 
00086 #ifndef _WIN32
00087     if (libspamc_timeout > 0) {
00088       alarm(0);
00089     }
00090   
00091     /* restore old signal handler */
00092     sig_catch(SIGALRM, sig);
00093 #endif
00094   
00095     return ret;
00096 }
00097 
00098 int fd_timeout_read(int fd, char fdflag, void *buf, size_t nbytes)
00099 {
00100     int nred;
00101     int origerr;
00102 #ifndef _WIN32
00103     sigfunc *sig;
00104 
00105     sig = sig_catch(SIGALRM, catch_alrm);
00106     if (libspamc_timeout > 0) {
00107         alarm(libspamc_timeout);
00108     }
00109 #endif
00110 
00111     do {
00112         if (fdflag) {
00113             nred = (int)read(fd, buf, nbytes);
00114             origerr = errno;
00115         }
00116         else {
00117             nred = (int)recv(fd, buf, nbytes, 0);
00118 #ifndef _WIN32
00119             origerr = errno;
00120 #else
00121             origerr = WSAGetLastError();
00122 #endif
00123         }
00124     } while (nred < 0 && origerr == EWOULDBLOCK);
00125 
00126 #ifndef _WIN32
00127     if (nred < 0 && origerr == EINTR)
00128         errno = ETIMEDOUT;
00129 
00130     if (libspamc_timeout > 0) {
00131         alarm(0);
00132     }
00133 
00134     /* restore old signal handler */
00135     sig_catch(SIGALRM, sig);
00136 #endif
00137 
00138     return nred;
00139 }
00140 
00141 int ssl_timeout_read(SSL * ssl, void *buf, int nbytes)
00142 {
00143     int nred;
00144 
00145 #ifndef _WIN32
00146     sigfunc *sig;
00147 
00148     sig = sig_catch(SIGALRM, catch_alrm);
00149     if (libspamc_timeout > 0) {
00150         alarm(libspamc_timeout);
00151     }
00152 #endif
00153 
00154     do {
00155 
00156 #ifdef SPAMC_SSL
00157         nred = SSL_read(ssl, buf, nbytes);
00158 #else
00159         UNUSED_VARIABLE(ssl);
00160         UNUSED_VARIABLE(buf);
00161         UNUSED_VARIABLE(nbytes);
00162         nred = 0;               /* never used */
00163 #endif
00164 
00165     } while (nred < 0 && errno == EWOULDBLOCK);
00166 
00167 #ifndef _WIN32
00168     if (nred < 0 && errno == EINTR)
00169         errno = ETIMEDOUT;
00170 
00171     if (libspamc_timeout > 0) {
00172         alarm(0);
00173     }
00174 
00175     /* restore old signal handler */
00176     sig_catch(SIGALRM, sig);
00177 #endif
00178 
00179     return nred;
00180 }
00181 
00182 /* -------------------------------------------------------------------------- */
00183 
00184 int full_read(int fd, char fdflag, void *vbuf, int min, int len)
00185 {
00186     unsigned char *buf = (unsigned char *) vbuf;
00187     int total;
00188     int thistime;
00189 
00190     for (total = 0; total < min;) {
00191         thistime = fd_timeout_read(fd, fdflag, buf + total, len - total);
00192 
00193         if (thistime < 0) {
00194             if (total >= min) {
00195                 /* error, but we read *some*.  return what we've read
00196                  * so far and next read (if there is one) will return -1. */
00197                 return total;
00198             } else {
00199                 return -1;
00200             }
00201         }
00202         else if (thistime == 0) {
00203             /* EOF, but we didn't read the minimum.  return what we've read
00204              * so far and next read (if there is one) will return 0. */
00205             return total;
00206         }
00207 
00208         total += thistime;
00209     }
00210     return total;
00211 }
00212 
00213 int full_read_ssl(SSL * ssl, unsigned char *buf, int min, int len)
00214 {
00215     int total;
00216     int thistime;
00217 
00218     for (total = 0; total < min;) {
00219         thistime = ssl_timeout_read(ssl, buf + total, len - total);
00220 
00221         if (thistime < 0) {
00222             if (total >= min) {
00223                 /* error, but we read *some*.  return what we've read
00224                  * so far and next read (if there is one) will return -1. */
00225                 return total;
00226             } else {
00227                 return -1;
00228             }
00229         }
00230         else if (thistime == 0) {
00231             /* EOF, but we didn't read the minimum.  return what we've read
00232              * so far and next read (if there is one) will return 0. */
00233             return total;
00234         }
00235 
00236         total += thistime;
00237     }
00238     return total;
00239 }
00240 
00241 int full_write(int fd, char fdflag, const void *vbuf, int len)
00242 {
00243     const char *buf = (const char *) vbuf;
00244     int total;
00245     int thistime;
00246     int origerr;
00247 
00248     for (total = 0; total < len;) {
00249         if (fdflag) {
00250             thistime = write(fd, buf + total, len - total);
00251             origerr = errno;
00252         }
00253         else {
00254             thistime = send(fd, buf + total, len - total, 0);
00255 #ifndef _WIN32
00256             origerr = errno;
00257 #else
00258             origerr = WSAGetLastError();
00259 #endif
00260         }
00261         if (thistime < 0) {
00262             if (EINTR == origerr || EWOULDBLOCK == origerr)
00263                 continue;
00264             return thistime;    /* always an error for writes */
00265         }
00266         total += thistime;
00267     }
00268     return total;
00269 }

© sourcejam.com 2005-2008