program-client.c revision 0d1b8b6bec79746c5d89d57dd8c1688946bd9237
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_callback(struct program_client *pclient, int result, void
f207fb0f2fd3113aa9a9f7911fb12d94dce19dffAki Tuomi /* do not call callback when destroying */
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_callback_t *callback = pclient->callback;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_seekable_fd_callback(const char **path_r, void *context)
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi struct program_client *pclient = (struct program_client *)context;
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("safe_mkstemp(%s) failed: %m", str_c(path));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* we just want the fd, unlink it */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* shouldn't happen.. */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_timeout(struct program_client *pclient)
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_error("program `%s' execution timed out (> %u msecs)",
17541ea25593c656060199715051db2c1eef221dAki Tuomi pclient->path, pclient->set.input_idle_timeout_msecs);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_RUN_TIMEOUT);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_connect_timeout(struct program_client *pclient)
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_error("program `%s' socket connection timed out (> %u msecs)",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->path, pclient->set.client_connect_timeout_msecs);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_CONNECT_TIMEOUT);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_connect(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->set.client_connect_timeout_msecs != 0) {
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi pclient->to = timeout_add(pclient->set.client_connect_timeout_msecs,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_close_output(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_disconnect_extra_fds(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int i, count;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efds[i].parent_fd != -1 && close(efds[i].parent_fd) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(fd=%d) failed: %m", efds[i].parent_fd);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomivoid program_client_disconnected(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->fd_in != -1 && close(pclient->fd_in) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->fd_out != -1 && pclient->fd_out != pclient->fd_in
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(%s/out) failed: %m", pclient->path);
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if (pclient->other_error && pclient->error == PROGRAM_CLIENT_ERROR_NONE) {
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomivoid program_client_disconnect(struct program_client *pclient, bool force)
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi if ((ret = program_client_close_output(pclient)) < 0)
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_fail(struct program_client *pclient,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomibool program_client_input_pending(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int count, i;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_program_output(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->dot_output = o_stream_create_dot(output, FALSE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if ((ret = o_stream_flush(pclient->dot_output)) <= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } else if (program_client_close_output(pclient) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_program_input(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const unsigned char *data;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->output_seekable && pclient->seekable_output == NULL) {
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi input = i_stream_create_seekable(input_list, MAX_OUTPUT_MEMORY_BUFFER,
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->dot_input = i_stream_create_dot(input, FALSE);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi /* just read it empty */
9b7b07d70c25c51be54d3b070216872ddaab6e6eAki Tuomi if (pclient->program_input != NULL && !input->eof) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_extra_fd_input(struct program_client_extra_fd *efd)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efd->input->closed || i_stream_is_eof(efd->input)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_connected(struct program_client *pclient)
17541ea25593c656060199715051db2c1eef221dAki Tuomi timeout_add(pclient->set.input_idle_timeout_msecs,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* run output */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (ret = program_client_program_output(pclient)) == 0) {
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi o_stream_set_flush_callback(pclient->program_output,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_init(struct program_client *pclient, pool_t pool,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *path,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *const *args,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_input(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_output(struct program_client *pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_output_seekable(struct program_client *pclient,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct istream *program_client_get_output_seekable(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_set_extra_fd(struct program_client *pclient, int fd,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int i, count;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi p_array_init(&pclient->extra_fds, pclient->pool, 2);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_set_env(struct program_client *pclient, const char *name,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *value)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const char *env;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi env = p_strdup_printf(pclient->pool, "%s=%s", name, value);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_init_streams(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Create streams for normal program I/O */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_set_name(pclient->program_output, "program stdin");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_set_name(pclient->program_input, "program stdout");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Create streams for additional output through side-channel fds */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int count, i;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_destroy(struct program_client **_pclient)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomivoid program_client_switch_ioloop(struct program_client *pclient)
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainenint program_client_create(const char *uri, const char *const *args,
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen const char **error_r)
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi const char *host;
80521bcdd28b22818480a6e6e1ae84230e19c1baAki Tuomi if (net_str2hostport(uri+4, 0, &host, &port) < 0 || port == 0) {
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen "Invalid tcp syntax, must be host:port in '%s'", uri+4);
4a197212360f75bfc89254bfd5bc4a31151fe4b4Timo Sirainen "Unsupported program client scheme '%s'",
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomivoid program_client_run_callback(int result, int *context)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_run(struct program_client *pclient)
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi program_client_run_async(pclient, program_client_run_callback, &ret);
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_run_async(struct program_client *pclient,