f5352ff0 |
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 | } |