chiark / gitweb /
Debianization.
[libspamc] / utils.c
1 /*
2  * This code is copyright 2001 by Craig Hughes
3  * Portions copyright 2002 by Brad Jorsch
4  * It is licensed under the same license as Perl itself.  The text of this
5  * license is included in the SpamAssassin distribution in the file named
6  * "License".
7  */
8
9 #include <unistd.h>
10 #include <errno.h>
11 #include <signal.h>
12 #include <sys/types.h>
13 #include <sys/uio.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include "utils.h"
17
18 /* Dec 13 2001 jm: added safe full-read and full-write functions.  These
19  * can cope with networks etc., where a write or read may not read all
20  * the data that's there, in one call.
21  */
22 /* Aug 14, 2002 bj: EINTR and EAGAIN aren't fatal, are they? */
23 /* Aug 14, 2002 bj: moved these to utils.c */
24 /* Jan 13, 2003 ym: added timeout functionality */
25
26 /* -------------------------------------------------------------------------- */
27
28 typedef void    sigfunc(int);   /* for signal handlers */
29
30 sigfunc* sig_catch(int sig, void (*f)(int))
31 {
32   struct sigaction act, oact;
33   act.sa_handler = f;
34   act.sa_flags = 0;
35   sigemptyset(&act.sa_mask);
36   sigaction(sig, &act, &oact);
37   return oact.sa_handler;
38 }
39
40 static void catch_alrm(int x) {
41   /* dummy */
42 }
43
44 ssize_t
45 fd_timeout_read (int fd, void *buf, size_t nbytes)
46 {
47   ssize_t nred;
48   sigfunc* sig;
49
50   sig = sig_catch(SIGALRM, catch_alrm);
51   if (libspamc_timeout > 0) {
52     alarm(libspamc_timeout);
53   }
54
55   do {
56     nred = read (fd, buf, nbytes);
57   } while(nred < 0 && errno == EAGAIN);
58
59   if(nred < 0 && errno == EINTR)
60     errno = ETIMEDOUT;
61
62   if (libspamc_timeout > 0) {
63     alarm(0);
64   }
65
66   /* restore old signal handler */
67   sig_catch(SIGALRM, sig);
68
69   return nred;
70 }
71
72 int
73 ssl_timeout_read (SSL *ssl, void *buf, int nbytes)
74 {
75   int nred;
76   sigfunc* sig;
77
78   sig = sig_catch(SIGALRM, catch_alrm);
79   if (libspamc_timeout > 0) {
80     alarm(libspamc_timeout);
81   }
82
83   do {
84 #ifdef SPAMC_SSL
85     nred = SSL_read (ssl, buf, nbytes);
86 #else
87     nred = 0;                   /* never used */
88 #endif
89   } while(nred < 0 && errno == EAGAIN);
90
91   if(nred < 0 && errno == EINTR)
92     errno = ETIMEDOUT;
93
94   if (libspamc_timeout > 0) {
95     alarm(0);
96   }
97
98   /* restore old signal handler */
99   sig_catch(SIGALRM, sig);
100
101   return nred;
102 }
103
104 /* -------------------------------------------------------------------------- */
105
106 int
107 full_read (int fd, unsigned char *buf, int min, int len)
108 {
109   int total;
110   int thistime;
111
112   for (total = 0; total < min; ) {
113     thistime = fd_timeout_read (fd, buf+total, len-total);
114
115     if (thistime < 0) {
116       return -1;
117     } else if (thistime == 0) {
118       /* EOF, but we didn't read the minimum.  return what we've read
119        * so far and next read (if there is one) will return 0. */
120       return total;
121     }
122
123     total += thistime;
124   }
125   return total;
126 }
127
128 int
129 full_write (int fd, const unsigned char *buf, int len)
130 {
131   int total;
132   int thistime;
133
134   for (total = 0; total < len; ) {
135     thistime = write (fd, buf+total, len-total);
136
137     if (thistime < 0) {
138       if(EINTR == errno || EAGAIN == errno) continue;
139       return thistime;        /* always an error for writes */
140     }
141     total += thistime;
142   }
143   return total;
144 }