Beispiel #1
0
static void trigger_server_wakeup(int fd)
{
    char    buf[TRIGGER_BUF_SIZE];
    int     len;

    /*
     * Commit suicide when the master process disconnected from us. Don't
     * drop the already accepted client request after "postfix reload"; that
     * would be rude.
     */
    if (master_notify(var_pid, trigger_server_generation, MASTER_STAT_TAKEN) < 0)
	 /* void */ ;
    if (trigger_server_in_flow_delay && mail_flow_get(1) < 0)
	doze(var_in_flow_delay * 1000000);
    if ((len = read(fd, buf, sizeof(buf))) >= 0)
	trigger_server_service(buf, len, trigger_server_name,
			       trigger_server_argv);
    if (master_notify(var_pid, trigger_server_generation, MASTER_STAT_AVAIL) < 0)
	trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    if (var_idle_limit > 0)
	event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
    /* Avoid integer wrap-around in a persistent process.  */
    if (use_count < INT_MAX)
	use_count++;
}
Beispiel #2
0
static void multi_server_wakeup(int fd, HTABLE *attr)
{
    VSTREAM *stream;
    char   *tmp;

#if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
#ifndef THRESHOLD_FD_WORKAROUND
#define THRESHOLD_FD_WORKAROUND 128
#endif
    int     new_fd;

    /*
     * Leave some handles < FD_SETSIZE for DBMS libraries, in the unlikely
     * case of a multi-server with a thousand clients.
     */
    if (fd < THRESHOLD_FD_WORKAROUND) {
	if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
	    msg_fatal("fcntl F_DUPFD: %m");
	(void) close(fd);
	fd = new_fd;
    }
#endif
    if (msg_verbose)
	msg_info("connection established fd %d", fd);
    non_blocking(fd, BLOCKING);
    close_on_exec(fd, CLOSE_ON_EXEC);
    client_count++;
    stream = vstream_fdopen(fd, O_RDWR);
    tmp = concatenate(multi_server_name, " socket", (char *) 0);
    vstream_control(stream,
                    VSTREAM_CTL_PATH, tmp,
                    VSTREAM_CTL_CONTEXT, (char *) attr,
                    VSTREAM_CTL_END);
    myfree(tmp);
    timed_ipc_setup(stream);
    multi_server_saved_flags = vstream_flags(stream);
    if (multi_server_in_flow_delay && mail_flow_get(1) < 0)
	event_request_timer(multi_server_enable_read, (char *) stream,
			    var_in_flow_delay);
    else
	multi_server_enable_read(0, (char *) stream);
}
Beispiel #3
0
static void single_server_wakeup(int fd, HTABLE *attr)
{
    VSTREAM *stream;
    char   *tmp;

    /*
     * If the accept() succeeds, be sure to disable non-blocking I/O, because
     * the application is supposed to be single-threaded. Notice the master
     * of our (un)availability to service connection requests. Commit suicide
     * when the master process disconnected from us. Don't drop the already
     * accepted client request after "postfix reload"; that would be rude.
     */
    if (msg_verbose)
	msg_info("connection established");
    non_blocking(fd, BLOCKING);
    close_on_exec(fd, CLOSE_ON_EXEC);
    stream = vstream_fdopen(fd, O_RDWR);
    tmp = concatenate(single_server_name, " socket", (char *) 0);
    vstream_control(stream,
		    CA_VSTREAM_CTL_PATH(tmp),
		    CA_VSTREAM_CTL_CONTEXT((void *) attr),
		    CA_VSTREAM_CTL_END);
    myfree(tmp);
    timed_ipc_setup(stream);
    if (master_notify(var_pid, single_server_generation, MASTER_STAT_TAKEN) < 0)
	 /* void */ ;
    if (single_server_in_flow_delay && mail_flow_get(1) < 0)
	doze(var_in_flow_delay * 1000000);
    single_server_service(stream, single_server_name, single_server_argv);
    (void) vstream_fclose(stream);
    if (master_notify(var_pid, single_server_generation, MASTER_STAT_AVAIL) < 0)
	single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    if (msg_verbose)
	msg_info("connection closed");
    /* Avoid integer wrap-around in a persistent process.  */
    if (use_count < INT_MAX)
	use_count++;
    if (var_idle_limit > 0)
	event_request_timer(single_server_timeout, (void *) 0, var_idle_limit);
    if (attr)
	htable_free(attr, myfree);
}
Beispiel #4
0
static void trigger_server_wakeup(int fd)
{
    char    buf[TRIGGER_BUF_SIZE];
    int     len;

    /*
     * Commit suicide when the master process disconnected from us.
     */
    if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
	trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    if (trigger_server_in_flow_delay && mail_flow_get(1) < 0)
	doze(var_in_flow_delay * 1000000);
    if ((len = read(fd, buf, sizeof(buf))) >= 0)
	trigger_server_service(buf, len, trigger_server_name,
			       trigger_server_argv);
    if (master_notify(var_pid, MASTER_STAT_AVAIL) < 0)
	trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    if (var_idle_limit > 0)
	event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
    use_count++;
}
Beispiel #5
0
static int qmgr_loop(char *unused_name, char **unused_argv)
{
    char   *path;
    int     token_count;
    int     feed = 0;
    int     scan_idx;			/* Priority order scan index */
    static int first_scan_idx = QMGR_SCAN_IDX_INCOMING;
    int     last_scan_idx = QMGR_SCAN_IDX_COUNT - 1;
    int     delay;

    /*
     * This routine runs as part of the event handling loop, after the event
     * manager has delivered a timer or I/O event (including the completion
     * of a connection to a delivery process), or after it has waited for a
     * specified amount of time. The result value of qmgr_loop() specifies
     * how long the event manager should wait for the next event.
     */
#define DONT_WAIT	0
#define WAIT_FOR_EVENT	(-1)

    /*
     * Attempt to drain the active queue by allocating a suitable delivery
     * process and by delivering mail via it. Delivery process allocation and
     * mail delivery are asynchronous.
     */
    qmgr_active_drain();

    /*
     * Let some new blood into the active queue when the queue size is
     * smaller than some configurable limit, and when the number of in-core
     * recipients does not exceed some configurable limit.
     * 
     * We import one message per interrupt, to optimally tune the input count
     * for the number of delivery agent protocol wait states, as explained in
     * qmgr_transport.c.
     */
    delay = WAIT_FOR_EVENT;
    for (scan_idx = 0; qmgr_message_count < var_qmgr_active_limit
	 && qmgr_recipient_count < var_qmgr_rcpt_limit
	 && scan_idx < QMGR_SCAN_IDX_COUNT; ++scan_idx) {
	last_scan_idx = (scan_idx + first_scan_idx) % QMGR_SCAN_IDX_COUNT;
	if ((path = qmgr_scan_next(qmgr_scans[last_scan_idx])) != 0) {
	    delay = DONT_WAIT;
	    if ((feed = qmgr_active_feed(qmgr_scans[last_scan_idx], path)) != 0)
		break;
	}
    }

    /*
     * Round-robin the queue scans. When the active queue becomes full,
     * prefer new mail over deferred mail.
     */
    if (qmgr_message_count < var_qmgr_active_limit
	&& qmgr_recipient_count < var_qmgr_rcpt_limit) {
	first_scan_idx = (last_scan_idx + 1) % QMGR_SCAN_IDX_COUNT;
    } else if (first_scan_idx != QMGR_SCAN_IDX_INCOMING) {
	first_scan_idx = QMGR_SCAN_IDX_INCOMING;
    }

    /*
     * Global flow control. If enabled, slow down receiving processes that
     * get ahead of the queue manager, but don't block them completely.
     */
    if (var_in_flow_delay > 0) {
	token_count = mail_flow_count();
	if (token_count < var_proc_limit) {
	    if (feed != 0 && last_scan_idx == QMGR_SCAN_IDX_INCOMING)
		mail_flow_put(1);
	    else if (qmgr_scans[QMGR_SCAN_IDX_INCOMING]->handle == 0)
		mail_flow_put(var_proc_limit - token_count);
	} else if (token_count > var_proc_limit) {
	    mail_flow_get(token_count - var_proc_limit);
	}
    }
    return (delay);
}