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) {