~ubuntu-branches/ubuntu/quantal/dovecot/quantal

« back to all changes in this revision

Viewing changes to src/lib-dict/dict-client.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short, Scott Kitterman
  • Date: 2010-06-22 10:33:51 UTC
  • mfrom: (1.13.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100622103351-ifbmnklp8kxrhb30
Tags: 1:1.2.12-0ubuntu1
* New upstream release:
  - deliver: Don't crash when a message with Auto-submitted: header gets
   rejected.
  - lib-storage: Fixed header searches to work correctly when there are
    multiple headers with same name.
  - dict client: Disconnect from dict server after 1 second of idling.
  - dict: If process crashed, it wasn't automatically restarted
  - dict file: If dict file's group permissions equal world permissions,
    don't try to change its gid.
  - maildir: Fixed a memory leak when copying with hardlinks.
  - maildir: Expunging last messages may have assert-crashed if their
    filenames had just changed.
 * Update sieve patch to 0.1.17
 * debian/dovecot-common.postinst: Add warning about expired certificate.
   (Debian Bug: #576455)
 * Silence lintian warnings.

 [Scott Kitterman]
 * Rename dovecot-postfix to mail-stack-delivery per server-maverick-mail-
   integration spec.
   - Update debian/rules
   - Convert existing package to a dummy package and add new binary in debian/control
   - Update maintainer scripts.
   - Move previously installed backups and config files to new package name
     space in preinst
   - Add new debian/mail-stack-delivery.prerm to handle downgrades
   - Rename debian/dovecot-postfix.* to debian/mail-stack-delivery.*

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#include <unistd.h>
14
14
#include <fcntl.h>
15
15
 
 
16
/* Disconnect from dict server after this many milliseconds of idling after
 
17
   sending a command. This timeout is short, because dict server does blocking
 
18
   dict accesses, so it can handle only one client at a time. increasing the
 
19
   timeout increases number of idling dict processes. */
 
20
#define DICT_CLIENT_TIMEOUT_MSECS 1000
 
21
 
 
22
/* Abort dict lookup after this many seconds. */
 
23
#define DICT_CLIENT_READ_TIMEOUT_SECS 30
 
24
/* Log a warning if dict lookup takes longer than this many seconds. */
 
25
#define DICT_CLIENT_READ_WARN_TIMEOUT_SECS 5
 
26
 
16
27
struct client_dict {
17
28
        struct dict dict;
18
29
 
27
38
        struct istream *input;
28
39
        struct ostream *output;
29
40
        struct io *io;
 
41
        struct timeout *to_idle;
30
42
 
31
43
        struct client_dict_transaction_context *transactions;
32
44
 
258
270
                io_remove(&dict->io);
259
271
}
260
272
 
 
273
static ssize_t client_dict_read_timeout(struct client_dict *dict)
 
274
{
 
275
        time_t now, timeout;
 
276
        unsigned int diff;
 
277
        ssize_t ret;
 
278
 
 
279
        now = time(NULL);
 
280
        timeout = now + DICT_CLIENT_READ_TIMEOUT_SECS;
 
281
 
 
282
        do {
 
283
                alarm(timeout - now);
 
284
                ret = i_stream_read(dict->input);
 
285
                alarm(0);
 
286
                if (ret != 0)
 
287
                        break;
 
288
 
 
289
                /* interrupted most likely because of timeout,
 
290
                   but check anyway. */
 
291
                now = time(NULL);
 
292
        } while (now < timeout);
 
293
 
 
294
        if (ret > 0) {
 
295
                diff = time(NULL) - now;
 
296
                if (diff >= DICT_CLIENT_READ_WARN_TIMEOUT_SECS) {
 
297
                        i_warning("read(%s): dict lookup took %u seconds",
 
298
                                  dict->path, diff);
 
299
                }
 
300
        }
 
301
        return ret;
 
302
}
 
303
 
261
304
static int client_dict_read_one_line(struct client_dict *dict, char **line_r)
262
305
{
263
306
        unsigned int id;
264
307
        char *line;
265
 
        int ret;
 
308
        ssize_t ret;
266
309
 
267
310
        *line_r = NULL;
268
311
        while ((line = i_stream_next_line(dict->input)) == NULL) {
269
 
                ret = i_stream_read(dict->input);
 
312
                ret = client_dict_read_timeout(dict);
270
313
                switch (ret) {
271
314
                case -1:
272
315
                        if (dict->input->stream_errno != 0)
279
322
                case -2:
280
323
                        i_error("read(%s) returned too much data", dict->path);
281
324
                        return -1;
 
325
                case 0:
 
326
                        i_error("read(%s) failed: Timeout after %u seconds",
 
327
                                dict->path, DICT_CLIENT_READ_TIMEOUT_SECS);
 
328
                        return -1;
282
329
                default:
283
330
                        i_assert(ret > 0);
284
331
                        break;
308
355
        return 1;
309
356
}
310
357
 
 
358
static bool client_dict_is_finished(struct client_dict *dict)
 
359
{
 
360
        return dict->transactions == NULL && !dict->in_iteration &&
 
361
                dict->async_commits == 0;
 
362
}
 
363
 
 
364
static void client_dict_timeout(struct client_dict *dict)
 
365
{
 
366
        if (client_dict_is_finished(dict))
 
367
                client_dict_disconnect(dict);
 
368
}
 
369
 
 
370
static void client_dict_add_timeout(struct client_dict *dict)
 
371
{
 
372
        if (dict->to_idle != NULL)
 
373
                timeout_reset(dict->to_idle);
 
374
        else if (client_dict_is_finished(dict)) {
 
375
                dict->to_idle = timeout_add(DICT_CLIENT_TIMEOUT_MSECS,
 
376
                                            client_dict_timeout, dict);
 
377
        }
 
378
}
 
379
 
311
380
static char *client_dict_read_line(struct client_dict *dict)
312
381
{
313
382
        char *line;
314
383
 
315
384
        while (client_dict_read_one_line(dict, &line) == 0)
316
385
                ;
 
386
 
 
387
        client_dict_add_timeout(dict);
317
388
        return line;
318
389
}
319
390
 
339
410
        net_set_nonblock(dict->fd, FALSE);
340
411
 
341
412
        dict->input = i_stream_create_fd(dict->fd, (size_t)-1, FALSE);
342
 
        dict->input->blocking = TRUE;
343
413
        dict->output = o_stream_create_fd(dict->fd, 4096, FALSE);
344
414
        dict->transaction_id_counter = 0;
345
415
        dict->async_commits = 0;
363
433
        dict->connect_counter++;
364
434
        dict->handshaked = FALSE;
365
435
 
 
436
        if (dict->to_idle != NULL)
 
437
                timeout_remove(&dict->to_idle);
366
438
        if (dict->io != NULL)
367
439
                io_remove(&dict->io);
368
440
        if (dict->input != NULL)
542
614
        pool_unref(&ctx->pool);
543
615
        i_free(ctx);
544
616
        dict->in_iteration = FALSE;
 
617
 
 
618
        client_dict_add_timeout(dict);
545
619
}
546
620
 
547
621
static struct dict_transaction_context *
619
693
        if (ret < 0 || !async) {
620
694
                DLLIST_REMOVE(&dict->transactions, ctx);
621
695
                i_free(ctx);
 
696
 
 
697
                client_dict_add_timeout(dict);
622
698
        }
623
699
        return ret;
624
700
}
640
716
 
641
717
        DLLIST_REMOVE(&dict->transactions, ctx);
642
718
        i_free(ctx);
 
719
 
 
720
        client_dict_add_timeout(dict);
643
721
}
644
722
 
645
723
static void client_dict_set(struct dict_transaction_context *_ctx,