Mercurial > dovecot > core-2.2
changeset 20787:11ea2902f99d
lib-program-client: Expose asynchronous API
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Fri, 07 Oct 2016 19:48:59 +0300 |
parents | 10510f5116ff |
children | c6717848c98a |
files | src/lib-program-client/program-client-private.h src/lib-program-client/program-client-remote.c src/lib-program-client/program-client.c src/lib-program-client/program-client.h |
diffstat | 4 files changed, 98 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-program-client/program-client-private.h Thu Oct 06 11:57:27 2016 +0300 +++ b/src/lib-program-client/program-client-private.h Fri Oct 07 19:48:59 2016 +0300 @@ -35,7 +35,6 @@ int fd_in, fd_out; struct io *io; - struct ioloop *ioloop; struct timeout *to; time_t start_time; @@ -45,6 +44,9 @@ ARRAY(struct program_client_extra_fd) extra_fds; + program_client_callback_t *callback; + void *context; + enum program_client_error error; int exit_code;
--- a/src/lib-program-client/program-client-remote.c Thu Oct 06 11:57:27 2016 +0300 +++ b/src/lib-program-client/program-client-remote.c Fri Oct 07 19:48:59 2016 +0300 @@ -199,8 +199,10 @@ program_client_init_streams(pclient); if (!slclient->noreply) { + struct istream *is = pclient->program_input; pclient->program_input = program_client_istream_create(pclient, pclient->program_input); + i_stream_unref(&is); } str = t_str_new(1024);
--- a/src/lib-program-client/program-client.c Thu Oct 06 11:57:27 2016 +0300 +++ b/src/lib-program-client/program-client.c Fri Oct 07 19:48:59 2016 +0300 @@ -17,8 +17,17 @@ #define MAX_OUTPUT_BUFFER_SIZE 16384 #define MAX_OUTPUT_MEMORY_BUFFER (1024*128) -static int program_client_seekable_fd_callback -(const char **path_r, void *context) +static +void program_client_callback(struct program_client *pclient, int result, void *context) +{ + program_client_callback_t *callback = pclient->callback; + i_assert(pclient->callback != NULL); + pclient->callback = NULL; + callback(result, context); +} + +static +int program_client_seekable_fd_callback(const char **path_r, void *context) { struct program_client *pclient = (struct program_client *)context; string_t *path; @@ -115,9 +124,6 @@ { int ret, error = FALSE; - if (pclient->ioloop != NULL) - io_loop_stop(pclient->ioloop); - if (pclient->disconnected) return; @@ -153,6 +159,12 @@ if (error && pclient->error == PROGRAM_CLIENT_ERROR_NONE) { pclient->error = PROGRAM_CLIENT_ERROR_OTHER; } + + program_client_callback(pclient, + pclient->error != PROGRAM_CLIENT_ERROR_NONE ? + -1 : + pclient->exit_code, + pclient->context); } void program_client_fail(struct program_client *pclient, enum program_client_error error) @@ -317,7 +329,8 @@ program_client_disconnect(pclient, FALSE); } } - } + } else + program_client_disconnect(pclient, FALSE); } static @@ -499,31 +512,85 @@ if (pclient->input != NULL) i_stream_unref(&pclient->input); + if (pclient->program_input != NULL) + i_stream_unref(&pclient->program_input); + if (pclient->program_output != NULL) + o_stream_unref(&pclient->program_output); if (pclient->output != NULL) o_stream_unref(&pclient->output); if (pclient->seekable_output != NULL) i_stream_unref(&pclient->seekable_output); if (pclient->io != NULL) io_remove(&pclient->io); - if (pclient->ioloop != NULL) - io_loop_destroy(&pclient->ioloop); i_free(pclient->temp_prefix); pool_unref(&pclient->pool); *_pclient = NULL; } +void program_client_switch_ioloop(struct program_client *pclient) +{ + if (pclient->input != NULL) + i_stream_switch_ioloop(pclient->input); + if (pclient->program_input != NULL) + i_stream_switch_ioloop(pclient->program_input); + if (pclient->seekable_output != NULL) + i_stream_switch_ioloop(pclient->seekable_output); + if (pclient->output != NULL) + o_stream_switch_ioloop(pclient->output); + if (pclient->program_output != NULL) + o_stream_switch_ioloop(pclient->program_output); + if (pclient->to != NULL) + pclient->to = io_loop_move_timeout(&pclient->to); + if (pclient->io != NULL) + pclient->io = io_loop_move_io(&pclient->io); +} + +static +void program_client_run_callback(int result, int *context) +{ + *context = result; + io_loop_stop(current_ioloop); +} + int program_client_run(struct program_client *pclient) { + int ret = 0; + struct ioloop *prev_ioloop = current_ioloop; + struct ioloop *ioloop = io_loop_create(); + + program_client_switch_ioloop(pclient); + + program_client_run_async(pclient, program_client_run_callback, &ret); + + if (ret == 0) { + io_loop_run(ioloop); + } + + io_loop_set_current(prev_ioloop); + program_client_switch_ioloop(pclient); + io_loop_set_current(ioloop); + io_loop_destroy(&ioloop); + + if (pclient->error != PROGRAM_CLIENT_ERROR_NONE) + return -1; + + return pclient->exit_code; +} + +#undef program_client_run_async +void program_client_run_async(struct program_client *pclient, program_client_callback_t *callback, void *context) +{ int ret; - /* reset */ + i_assert(callback != NULL); + pclient->disconnected = FALSE; pclient->exit_code = 1; pclient->error = PROGRAM_CLIENT_ERROR_NONE; - pclient->ioloop = io_loop_create(); - - if ((ret=program_client_connect(pclient)) >= 0) { + pclient->callback = callback; + pclient->context = context; + if ((ret = program_client_connect(pclient)) >= 0) { /* run output */ if (ret > 0 && pclient->program_output != NULL && (ret = o_stream_flush(pclient->program_output)) == 0) { @@ -531,27 +598,15 @@ (pclient->program_output, program_client_program_output, pclient); } - - /* run i/o event loop */ if (ret < 0) { i_error("write(%s) failed: %s", o_stream_get_name(pclient->program_output), o_stream_get_error(pclient->program_output)); pclient->error = PROGRAM_CLIENT_ERROR_IO; - } else if (!pclient->disconnected && - (ret == 0 || program_client_input_pending(pclient))) { - io_loop_run(pclient->ioloop); + program_client_callback(pclient, ret, context); + return; } - - /* finished */ - program_client_disconnect(pclient, FALSE); + } else { + program_client_callback(pclient, ret, context); } - - io_loop_destroy(&pclient->ioloop); - - if (pclient->error != PROGRAM_CLIENT_ERROR_NONE) - return -1; - - return pclient->exit_code; } -
--- a/src/lib-program-client/program-client.h Thu Oct 06 11:57:27 2016 +0300 +++ b/src/lib-program-client/program-client.h Fri Oct 07 19:48:59 2016 +0300 @@ -18,6 +18,7 @@ }; typedef void program_client_fd_callback_t(void *context, struct istream *input); +typedef void program_client_callback_t(int, void *); struct program_client *program_client_local_create(const char *bin_path, const char *const *args, @@ -37,6 +38,8 @@ const char *temp_prefix); struct istream *program_client_get_output_seekable(struct program_client *pclient); +void program_client_switch_ioloop(struct program_client *pclient); + /* Program provides side-channel output through an extra fd */ void program_client_set_extra_fd(struct program_client *pclient, int fd, program_client_fd_callback_t * callback, void *context); @@ -49,6 +52,13 @@ void program_client_set_env(struct program_client *pclient, const char *name, const char *value); +/* Since script service cannot return system exit code, the exit value shall be + -1, 0, or 1. -1 is internal error, 0 is failure and 1 is success */ int program_client_run(struct program_client *pclient); +void program_client_run_async(struct program_client *pclient, program_client_callback_t *, void*); +#define program_client_run_async(pclient, callback, context) \ + program_client_run_async(pclient, (program_client_callback_t*)callback, (char*)context + \ + CALLBACK_TYPECHECK(callback, \ + void (*)(int, typeof(context)))) #endif