Mercurial > dnsbl
comparison src/context.cpp @ 92:505e77188317
optimize verification step, cleanup documentation
author | carl |
---|---|
date | Wed, 21 Sep 2005 08:00:08 -0700 |
parents | ca46fafc6621 |
children | e107ade3b1c0 |
comparison
equal
deleted
inserted
replaced
91:ca46fafc6621 | 92:505e77188317 |
---|---|
63 extern int NULL_SOCKET; | 63 extern int NULL_SOCKET; |
64 extern time_t ERROR_SOCKET_TIME; // number of seconds between attempts to open a socket an smtp host for address verification | 64 extern time_t ERROR_SOCKET_TIME; // number of seconds between attempts to open a socket an smtp host for address verification |
65 | 65 |
66 | 66 |
67 int SMTP::writer() { | 67 int SMTP::writer() { |
68 // log("writer() sees buffer with %s", buffer); | 68 #ifdef VERIFY_DEBUG |
69 // log("writer() sees error %d", (int)error); | 69 log("writer() sees buffer with %s", buffer); |
70 log("writer() sees error %d", (int)error); | |
71 #endif | |
70 int rs = 0; | 72 int rs = 0; |
71 if (!error) { | 73 if (!error) { |
72 int len = strlen(buffer); | 74 int len = strlen(buffer); |
73 while (rs < len) { | 75 while (rs < len) { |
74 int ws = write(fd, buffer+rs, len-rs); | 76 int ws = write(fd, buffer+rs, len-rs); |
88 | 90 |
89 | 91 |
90 int SMTP::reader() { | 92 int SMTP::reader() { |
91 // read some bytes terminated by lf or end of buffer. | 93 // read some bytes terminated by lf or end of buffer. |
92 // we may have a multi line response or part thereof in the buffer. | 94 // we may have a multi line response or part thereof in the buffer. |
93 // log("reader() sees error %d", (int)error); | 95 #ifdef VERIFY_DEBUG |
96 log("reader() sees error %d", (int)error); | |
97 #endif | |
94 if (error) return 0; | 98 if (error) return 0; |
95 int len = maxlen-1; // room for null terminator | 99 int len = maxlen-1; // room for null terminator |
96 while (pending < len) { | 100 while (pending < len) { |
97 int ws = read(fd, buffer+pending, len-pending); | 101 int ws = read(fd, buffer+pending, len-pending); |
98 if (ws > 0) { | 102 if (ws > 0) { |
105 error = true; | 109 error = true; |
106 break; | 110 break; |
107 } | 111 } |
108 } | 112 } |
109 buffer[pending] = '\0'; | 113 buffer[pending] = '\0'; |
110 // log("reader() sees buffer with %s", buffer); | 114 #ifdef VERIFY_DEBUG |
115 log("reader() sees buffer with %s", buffer); | |
116 #endif | |
111 return pending; | 117 return pending; |
112 } | 118 } |
113 | 119 |
114 | 120 |
115 int SMTP::read_line() { | 121 int SMTP::read_line() { |
132 int SMTP::read_response() { | 138 int SMTP::read_response() { |
133 pending = 0; | 139 pending = 0; |
134 buffer[pending] = '\0'; | 140 buffer[pending] = '\0'; |
135 while (true) { | 141 while (true) { |
136 int r = read_line(); | 142 int r = read_line(); |
137 // log("read_response() sees line with %s", buffer); | 143 #ifdef VERIFY_DEBUG |
138 // log("read_response() sees line length %d", r); | 144 log("read_response() sees line with %s", buffer); |
145 log("read_response() sees line length %d", r); | |
146 #endif | |
139 if (r == 0) return 0; // failed to read any bytes | 147 if (r == 0) return 0; // failed to read any bytes |
140 if ((r > 4) && (buffer[3] == '-')) { | 148 if ((r > 4) && (buffer[3] == '-')) { |
141 flush_line(r); | 149 flush_line(r); |
142 continue; | 150 continue; |
143 } | 151 } |
166 return cmd(NULL); | 174 return cmd(NULL); |
167 } | 175 } |
168 | 176 |
169 | 177 |
170 int SMTP::rset() { | 178 int SMTP::rset() { |
171 return cmd("RSET"); | 179 int rc = cmd("RSET"); |
180 efrom[0] = '\0'; | |
181 return rc; | |
172 } | 182 } |
173 | 183 |
174 | 184 |
175 int SMTP::from(char *f) { | 185 int SMTP::from(char *f) { |
176 init(); | 186 if (strncmp(efrom, f, maxlen)) { |
177 append("MAIL FROM:<"); | 187 rset(); |
178 append(f); | 188 strncpy(efrom, f, maxlen); |
179 append(">"); | 189 init(); |
180 return cmd(NULL); | 190 append("MAIL FROM:<"); |
191 append(f); | |
192 append(">"); | |
193 return cmd(NULL); | |
194 } | |
195 return 250; // pretend it worked | |
181 } | 196 } |
182 | 197 |
183 | 198 |
184 int SMTP::rcpt(char *t) { | 199 int SMTP::rcpt(char *t) { |
185 init(); | 200 init(); |
189 return cmd(NULL); | 204 return cmd(NULL); |
190 } | 205 } |
191 | 206 |
192 | 207 |
193 int SMTP::quit() { | 208 int SMTP::quit() { |
194 int rc = cmd("QUIT"); | 209 return cmd("QUIT"); |
210 } | |
211 | |
212 | |
213 void SMTP::closefd() { | |
195 shutdown(fd, SHUT_RDWR); | 214 shutdown(fd, SHUT_RDWR); |
196 close(fd); | 215 close(fd); |
197 return rc; | 216 } |
198 } | 217 |
199 | 218 |
200 | 219 #ifdef VERIFY_DEBUG |
201 // void SMTP::log(char *m, int v) { | 220 void SMTP::log(char *m, int v) { |
202 // char buf[maxlen]; | 221 char buf[maxlen]; |
203 // snprintf(buf, maxlen, m, v); | 222 snprintf(buf, maxlen, m, v); |
204 // my_syslog(buf); | 223 my_syslog(buf); |
205 // } | 224 } |
206 // | 225 |
207 // | 226 |
208 // void SMTP::log(char *m, char *v) { | 227 void SMTP::log(char *m, char *v) { |
209 // char buf[maxlen]; | 228 char buf[maxlen]; |
210 // snprintf(buf, maxlen, m, v); | 229 snprintf(buf, maxlen, m, v); |
211 // my_syslog(buf); | 230 my_syslog(buf); |
212 // } | 231 } |
213 // | 232 #endif |
214 // | 233 |
234 | |
215 VERIFY::VERIFY(char *h) { | 235 VERIFY::VERIFY(char *h) { |
216 host = h; | 236 host = h; |
217 last_err = 0; | 237 last_err = 0; |
218 pthread_mutex_init(&mutex, 0); | 238 pthread_mutex_init(&mutex, 0); |
219 } | 239 } |
220 | 240 |
221 | 241 |
222 void VERIFY::closer() { | 242 void VERIFY::closer() { |
223 bool ok = true; | 243 bool ok = true; |
224 while (ok) { | 244 while (ok) { |
225 int fd = 0; | 245 SMTP *conn = NULL; |
226 pthread_mutex_lock(&mutex); | 246 pthread_mutex_lock(&mutex); |
227 if (sockets.empty()) { | 247 if (connections.empty()) { |
228 ok = false; | 248 ok = false; |
229 } | 249 } |
230 else { | 250 else { |
231 time_t t = times.front(); | 251 conn = connections.front(); |
232 time_t now = time(NULL); | 252 time_t now = time(NULL); |
233 if ((now - t) > maxage) { | 253 if ((now - conn->get_stamp()) > maxage) { |
234 // this socket is ancient, remove it | 254 // this connection is ancient, remove it |
235 fd = sockets.front(); | 255 connections.pop_front(); |
236 times.pop_front(); | |
237 sockets.pop_front(); | |
238 } | 256 } |
239 else { | 257 else { |
240 ok = false; | 258 ok = false; |
259 conn = NULL; | |
241 } | 260 } |
242 } | 261 } |
243 pthread_mutex_unlock(&mutex); | 262 pthread_mutex_unlock(&mutex); |
244 if (fd) { | 263 // avoid doing this work inside the mutex lock |
245 SMTP s(fd); | 264 if (conn) { |
246 s.quit(); // closes the fd | 265 #ifdef VERIFY_DEBUG |
247 // s.log("closer() closes ancient %d", fd); | 266 conn->log("closer() closes ancient %d", conn->get_fd()); |
248 } | 267 #endif |
249 } | 268 delete conn; |
250 } | 269 } |
251 | 270 } |
252 | 271 } |
253 int VERIFY::get_socket() { | 272 |
273 | |
274 SMTP* VERIFY::get_connection() { | |
275 SMTP *conn = NULL; | |
276 pthread_mutex_lock(&mutex); | |
277 if (!connections.empty()) { | |
278 conn = connections.front(); | |
279 connections.pop_front(); | |
280 #ifdef VERIFY_DEBUG | |
281 conn->log("get_connection() %d from cache", conn->get_fd()); | |
282 #endif | |
283 } | |
284 pthread_mutex_unlock(&mutex); | |
285 if (conn) return conn; | |
286 time_t now = time(NULL); | |
254 int sock = NULL_SOCKET; | 287 int sock = NULL_SOCKET; |
255 pthread_mutex_lock(&mutex); | 288 if ((now - last_err) > ERROR_SOCKET_TIME) { |
256 if (!sockets.empty()) { | 289 // nothing recent, maybe this time it will work |
257 sock = sockets.front(); | 290 hostent *h = gethostbyname(host); |
258 times.pop_front(); | 291 if (h) { |
259 sockets.pop_front(); | 292 sockaddr_in server; |
260 // SMTP::log("get_socket() %d from cache", sock); | 293 server.sin_family = h->h_addrtype; |
261 } | 294 server.sin_port = htons(25); |
262 pthread_mutex_unlock(&mutex); | 295 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length); |
263 | 296 sock = socket(PF_INET, SOCK_STREAM, 0); |
264 if (sock == NULL_SOCKET) { | 297 if (sock != NULL_SOCKET) { |
265 time_t now = time(NULL); | 298 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); |
266 if ((now - last_err) > ERROR_SOCKET_TIME) { | 299 if (!rc) { |
267 // nothing recent, maybe this time it will work | 300 shutdown(sock, SHUT_RDWR); |
268 hostent *h = gethostbyname(host); | 301 close(sock); |
269 if (h) { | 302 sock = NULL_SOCKET; |
270 sockaddr_in server; | 303 last_err = now; |
271 server.sin_family = h->h_addrtype; | 304 } |
272 server.sin_port = htons(25); | |
273 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length); | |
274 sock = socket(PF_INET, SOCK_STREAM, 0); | |
275 if (sock != NULL_SOCKET) { | |
276 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); | |
277 if (!rc) { | |
278 shutdown(sock, SHUT_RDWR); | |
279 close(sock); | |
280 sock = NULL_SOCKET; | |
281 last_err = now; | |
282 } | |
283 } | |
284 else last_err = now; | |
285 } | 305 } |
286 else last_err = now; | 306 else last_err = now; |
287 } | 307 } |
288 if (sock != NULL_SOCKET) { | 308 else last_err = now; |
289 SMTP s(sock); | 309 } |
290 if (s.helo() != 250) { | 310 if (sock != NULL_SOCKET) { |
291 put_socket(sock, true); | 311 conn = new SMTP(sock); |
292 sock = NULL_SOCKET; | 312 #ifdef VERIFY_DEBUG |
293 } | 313 conn->log("get_connection() %d new socket", conn->get_fd()); |
294 } | 314 #endif |
295 } | 315 if (conn->helo() == 250) return conn; |
296 return sock; | 316 delete conn; |
297 } | 317 } |
298 | 318 return NULL; |
299 | 319 } |
300 void VERIFY::put_socket(int fd, bool err) { | 320 |
301 if (err) { | 321 |
302 // SMTP::log("put_socket() %d with error, close it", fd); | 322 void VERIFY::put_connection(SMTP *conn) { |
303 shutdown(fd, SHUT_RDWR); | 323 if (conn->err()) { |
304 close(fd); | 324 #ifdef VERIFY_DEBUG |
325 conn->log("put_socket() %d with error, close it", conn->get_fd()); | |
326 #endif | |
327 delete conn; | |
305 last_err = time(NULL); | 328 last_err = time(NULL); |
306 } | 329 } |
307 else { | 330 else { |
308 // SMTP::log("put_socket() %d", fd); | 331 #ifdef VERIFY_DEBUG |
332 conn->log("put_socket() %d", conn->get_fd()); | |
333 #endif | |
334 conn->now(); | |
309 pthread_mutex_lock(&mutex); | 335 pthread_mutex_lock(&mutex); |
310 time_t now = time(NULL); | 336 connections.push_back(conn); |
311 times.push_back(now); | |
312 sockets.push_back(fd); | |
313 pthread_mutex_unlock(&mutex); | 337 pthread_mutex_unlock(&mutex); |
314 } | 338 } |
315 } | 339 } |
316 | 340 |
317 | 341 |
318 bool VERIFY::ok(char *from, char *to) { | 342 bool VERIFY::ok(char *from, char *to) { |
319 if (host == token_myhostname) return true; | 343 if (host == token_myhostname) return true; |
320 int fd = get_socket(); | 344 SMTP *conn = get_connection(); |
321 if (fd == NULL_SOCKET) return true; // cannot verify right now, we have socket errors | 345 if (!conn) return true; // cannot verify right now, we have socket errors |
322 SMTP s(fd); | |
323 s.rset(); | |
324 int rc; | 346 int rc; |
325 rc = s.from(from); | 347 rc = conn->from(from); |
326 // s.log("verify::ok from sees %d", rc); | 348 #ifdef VERIFY_DEBUG |
349 conn->log("verify::ok() from sees %d", rc); | |
350 #endif | |
327 if (rc != 250) { | 351 if (rc != 250) { |
328 put_socket(fd, s.err()); | 352 conn->rset(); |
353 put_connection(conn); | |
329 return (rc >= 500) ? false : true; | 354 return (rc >= 500) ? false : true; |
330 } | 355 } |
331 rc = s.rcpt(to); | 356 rc = conn->rcpt(to); |
332 // s.log("verify::ok rcpt sees %d", rc); | 357 #ifdef VERIFY_DEBUG |
333 put_socket(fd, s.err()); | 358 conn->log("verify::ok() rcpt sees %d", rc); |
359 #endif | |
360 put_connection(conn); | |
334 return (rc >= 500) ? false : true; | 361 return (rc >= 500) ? false : true; |
335 } | 362 } |
336 | 363 |
337 | 364 |
338 DNSBL::DNSBL(char *n, char *s, char *m) { | 365 DNSBL::DNSBL(char *n, char *s, char *m) { |