bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "lib.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "ioloop.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "str.h"
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch#include "strescape.h"
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch#include "array.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "net.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "write-full.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "eacces-error.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "istream-private.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "ostream.h"
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi#include "dns-lookup.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "program-client-private.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <unistd.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <sys/wait.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <sysexits.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
b383ed51d75bce0f69f126bc4ff7192985ca30f2Stephan Bosch#define PROGRAM_CLIENT_VERSION_MAJOR "4"
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi#define PROGRAM_CLIENT_VERSION_MINOR "0"
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi#define PROGRAM_CLIENT_VERSION_STRING "VERSION\tscript\t" \
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi PROGRAM_CLIENT_VERSION_MAJOR "\t" \
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi PROGRAM_CLIENT_VERSION_MINOR "\n"
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_net_connect_again(struct program_client *pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi/*
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi * Script client input stream
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct program_client_istream {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct istream_private istream;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct stat statbuf;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client *client;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi};
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_istream_destroy(struct iostream_private *stream)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_istream *scstream =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (struct program_client_istream *) stream;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_unref(&scstream->istream.parent);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
d9683a6493b2298ecd309522df315f8e7188e869Stephan Boschstatic void
d9683a6493b2298ecd309522df315f8e7188e869Stephan Boschprogram_client_istream_parse_result(struct program_client_istream *scstream,
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch size_t pos)
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch{
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch struct istream_private *stream = &scstream->istream;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch if (stream->buffer == NULL || pos < 2 ||
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch stream->buffer[pos - 1] != '\n') {
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch scstream->client->exit_code =
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch PROGRAM_CLIENT_EXIT_INTERNAL_FAILURE;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch return;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch }
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch switch (stream->buffer[pos - 2]) {
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch case '+':
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch scstream->client->exit_code = PROGRAM_CLIENT_EXIT_SUCCESS;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch break;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch case '-':
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch scstream->client->exit_code = PROGRAM_CLIENT_EXIT_FAILURE;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch break;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch default:
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch scstream->client->exit_code =
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch PROGRAM_CLIENT_EXIT_INTERNAL_FAILURE;
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch }
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch}
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic ssize_t
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiprogram_client_istream_read(struct istream_private *stream)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_istream *scstream =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (struct program_client_istream *) stream;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi size_t pos, reserved;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ssize_t ret = 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_skip(stream->parent, stream->skip);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->skip = 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->buffer = i_stream_get_data(stream->parent, &pos);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi reserved = 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (stream->buffer != NULL && pos >= 1) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* retain/hide potential return code at end of buffer */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi reserved = (stream->buffer[pos - 1] == '\n' && pos > 1 ? 2 : 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pos -= reserved;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (stream->parent->eof) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pos == 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_skip(stream->parent, reserved);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->istream.eof = TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ret = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } else
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi do {
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen if ((ret = i_stream_read_memarea(stream->parent)) == -2) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -2; /* input buffer full */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret == 0 || (ret < 0 && !stream->parent->eof))
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi break;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->istream.stream_errno =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->parent->stream_errno;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->buffer =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_get_data(stream->parent, &pos);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (stream->parent->eof) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Check return code at EOF */
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch program_client_istream_parse_result(scstream, pos);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (stream->buffer != NULL && pos >= 1) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* retain/hide potential return code at end of buffer */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi size_t old_reserved = reserved;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ssize_t reserve_mod;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi reserved = (stream->buffer[pos - 1] == '\n' &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pos > 1 ? 2 : 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi reserve_mod = reserved - old_reserved;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pos -= reserved;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret >= reserve_mod) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ret -= reserve_mod;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret <= 0 && stream->parent->eof) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Parent EOF and not more data to return; EOF here as well */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pos == 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_skip(stream->parent, reserved);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->istream.eof = TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ret = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } while (ret == 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->pos = pos;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(ret != -1 || stream->istream.eof ||
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi stream->istream.stream_errno != 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid ATTR_NORETURN program_client_istream_sync(struct istream_private *stream ATTR_UNUSED)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_panic("program_client_istream sync() not implemented");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_istream_stat(struct istream_private *stream, bool exact)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_istream *scstream =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (struct program_client_istream *) stream;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const struct stat *st;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Stat the original stream */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ret = i_stream_stat(stream->parent, exact, &st);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (ret < 0 || st->st_size == -1 || !exact)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->statbuf = *st;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->statbuf.st_size = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return ret;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct istream *program_client_istream_create(struct program_client *program_client,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct istream *input)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_istream *scstream;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream = i_new(struct program_client_istream, 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->client = program_client;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.iostream.destroy = program_client_istream_destroy;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.read = program_client_istream_read;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.sync = program_client_istream_sync;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.stat = program_client_istream_stat;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.istream.readable_fd = FALSE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.istream.blocking = input->blocking;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi scstream->istream.istream.seekable = FALSE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_seek(input, 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen return i_stream_create(&scstream->istream, input, -1, 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi/*
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi * Program client
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct program_client_remote {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client client;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi bool noreply:1;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi bool resolved:1;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi const char *hostname;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct dns_lookup_settings dns_set;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct dns_lookup *lookup;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi unsigned int ips_count;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi unsigned int ips_left;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct ip_addr *ips;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi in_port_t port;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct timeout *to_retry;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi};
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomivoid program_client_remote_connected(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (struct program_client_remote *) pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const char **args = pclient->args;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi string_t *str;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi timeout_remove(&pclient->to);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi io_remove(&pclient->io);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_init_streams(pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (!prclient->noreply) {
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi struct istream *is = pclient->program_input;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->program_input =
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi program_client_istream_create(pclient,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi pclient->program_input);
98bc2ecdbfd4f2f20c3a5e96ae445072fbe22223Aki Tuomi i_stream_unref(&is);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str = t_str_new(1024);
1c0dd964c40f9457af090128a4a5e96f23197020Aki Tuomi str_append(str, PROGRAM_CLIENT_VERSION_STRING);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch if (array_is_created(&pclient->envs)) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *const *env;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch array_foreach(&pclient->envs, env) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch str_append(str, "env_");
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch str_append_tabescaped(str, *env);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch str_append_c(str, '\n');
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (prclient->noreply)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str_append(str, "noreply\n");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi else
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str_append(str, "-\n");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (args != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(; *args != NULL; args++) {
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch str_append_tabescaped(str, *args);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str_append_c(str, '\n');
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str_append_c(str, '\n');
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (o_stream_send(pclient->program_output,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi str_data(str), str_len(str)) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("write(%s) failed: %s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_name(pclient->program_output),
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi o_stream_get_error(pclient->program_output));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (void)program_client_connected(pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomistatic
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomiint program_client_unix_connect(struct program_client *pclient);
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomistatic
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomivoid program_client_unix_reconnect(struct program_client *pclient)
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi{
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi (void)program_client_unix_connect(pclient);
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi}
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
9f29dfcbf3812c4f88ffb1c99b5a56b2e8091ea4Aki Tuomiint program_client_unix_connect(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (struct program_client_remote *) pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int fd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi if (pclient->set.debug)
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi i_debug("Trying to connect %s", pclient->path);
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&prclient->to_retry);
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi
92c8109f71ed1b801806fba307e3032306bbcbafTimo Sirainen if ((fd = net_connect_unix(pclient->path)) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi switch (errno) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi case EACCES:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("%s",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi eacces_error_get("net_connect_unix",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->path));
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi case EAGAIN:
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi prclient->to_retry =
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi timeout_add_short(100,
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi program_client_unix_reconnect,
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi pclient);
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi return 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi default:
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("net_connect_unix(%s) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient->fd_in = (prclient->noreply && pclient->output == NULL &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi !pclient->output_seekable ? -1 : fd);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_out = fd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->io =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi io_add(fd, IO_WRITE, program_client_remote_connected, pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return 0;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_net_connect_timeout(struct program_client *pclient)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi io_remove(&pclient->io);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi timeout_remove(&pclient->to);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_error("connect(%s) failed: timeout in %u milliseconds",
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->path,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->set.client_connect_timeout_msecs);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* set error to timeout here */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->error = PROGRAM_CLIENT_ERROR_CONNECT_TIMEOUT;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_close_fd(&pclient->fd_out);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->fd_in = pclient->fd_out = -1;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_again(pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
211c638d81d382517d196ad47565e0d85012c927klemens/* see if connect succeeded or not, if it did, then proceed
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi normally, otherwise try reconnect to next address */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_net_connected(struct program_client *pclient)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi io_remove(&pclient->io);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if ((errno = net_geterror(pclient->fd_out)) != 0) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_error("connect(%s) failed: %m",
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->path);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* disconnect and try again */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_close_fd(&pclient->fd_out);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->fd_in = pclient->fd_out = -1;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_again(pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi } else {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->io = io_add(pclient->fd_out, IO_WRITE,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_remote_connected, pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_net_connect_real(struct program_client *pclient)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
1b6f7fc2c404852c0f23ca4a0bf3a4f6186e7d5bAki Tuomi const char *str;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi (struct program_client_remote *) pclient;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&pclient->to);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&prclient->to_retry);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch i_assert(prclient->ips_count > 0);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
1b6f7fc2c404852c0f23ca4a0bf3a4f6186e7d5bAki Tuomi if (net_ipport2str(prclient->ips, prclient->port, &str) < 0)
1b6f7fc2c404852c0f23ca4a0bf3a4f6186e7d5bAki Tuomi i_unreached();
1b6f7fc2c404852c0f23ca4a0bf3a4f6186e7d5bAki Tuomi pclient->path = p_strdup(pclient->pool, str);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if (pclient->debug) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_debug("Trying to connect %s (timeout %u msecs)",
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->path,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->set.client_connect_timeout_msecs);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* try to connect */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi int fd;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if ((fd = net_connect_ip(prclient->ips, prclient->port,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch (prclient->ips->family == AF_INET ?
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi &net_ip4_any : &net_ip6_any))) < 0) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_error("connect(%s) failed: %m", pclient->path);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->to_retry = timeout_add_short(0,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_again,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient->fd_in = (prclient->noreply && pclient->output == NULL &&
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi !pclient->output_seekable ? -1 : fd);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->fd_out = fd;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->io = io_add(fd, IO_WRITE, program_client_net_connected, pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if (pclient->set.client_connect_timeout_msecs != 0) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->to = timeout_add(pclient->set.client_connect_timeout_msecs,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_timeout, pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_net_connect_again(struct program_client *pclient)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi (struct program_client_remote *) pclient;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi enum program_client_error error = pclient->error;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->error = PROGRAM_CLIENT_ERROR_NONE;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (--prclient->ips_left == 0) {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (prclient->ips_count > 1)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_error("program-client-net: %s: No addresses left to try",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->hostname);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_fail(pclient,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi error != PROGRAM_CLIENT_ERROR_NONE ?
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi error :
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi PROGRAM_CLIENT_ERROR_OTHER);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi };
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips++;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_real(pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_net_connect_resolved(const struct dns_lookup_result *result,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct program_client *pclient)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi (struct program_client_remote *) pclient;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if (result->ret != 0) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_error("program-client-net: Cannot resolve '%s': %s",
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->path,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi result->error);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_fail(pclient, PROGRAM_CLIENT_ERROR_OTHER);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* reduce timeout */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if (pclient->set.client_connect_timeout_msecs > 0) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if (pclient->set.client_connect_timeout_msecs <= result->msecs) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* we ran out of time */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_fail(pclient,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi PROGRAM_CLIENT_ERROR_CONNECT_TIMEOUT);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->set.client_connect_timeout_msecs -= result->msecs;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* then connect */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips_count = result->ips_count;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips_left = prclient->ips_count;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips = p_memdup(pclient->pool, result->ips,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi sizeof(struct ip_addr)*result->ips_count);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_real(pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomiint program_client_net_connect_init(struct program_client *pclient)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi (struct program_client_remote *) pclient;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct ip_addr ip;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (prclient->ips != NULL) {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->hostname = p_strdup(pclient->pool,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch net_ip2addr(prclient->ips));
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi } else if (net_addr2ip(pclient->path, &ip) == 0) {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->hostname = p_strdup(pclient->pool,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi net_ip2addr(&ip));
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->resolved = TRUE;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips = p_new(pclient->pool, struct ip_addr, 1);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch *prclient->ips = ip;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips_count = 1;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi } else {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->resolved = FALSE;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->hostname = p_strdup(pclient->pool, pclient->path);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if (pclient->set.dns_client_socket_path != NULL) {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->dns_set.dns_client_socket_path =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->set.dns_client_socket_path;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->dns_set.timeout_msecs =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->set.client_connect_timeout_msecs;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch dns_lookup(pclient->path, &prclient->dns_set,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_resolved,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient, &prclient->lookup);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return 0;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi } else {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct ip_addr *ips;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi unsigned int ips_count;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi int err;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi /* guess we do it here then.. */
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi if ((err = net_gethostbyname(pclient->path,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi &ips, &ips_count)) != 0) {
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_error("program-client-remote: "
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi "Cannot resolve '%s': %s",
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->path,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi net_gethosterror(err));
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return -1;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips_count = ips_count;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips = p_memdup(pclient->pool,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi ips,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi sizeof(*ips)*ips_count);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi }
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->ips_left = prclient->ips_count;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->to_retry = timeout_add_short(0,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_net_connect_real,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return 0;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_remote_close_output(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int fd_out = pclient->fd_out, fd_in = pclient->fd_in;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_out = -1;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (fd_out >= 0 && pclient->set.use_dotstream)
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi return 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Shutdown output; program stdin will get EOF */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out >= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_in >= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (shutdown(fd_out, SHUT_WR) < 0 && errno != ENOTCONN) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("shutdown(%s, SHUT_WR) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } else if (close(fd_out) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(%s) failed: %m", pclient->path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomivoid program_client_remote_disconnect(struct program_client *pclient, bool force)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (struct program_client_remote *)pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&prclient->to_retry);
a0c57666729eacf4fe1429ae6fa7e8af61f94eddAki Tuomi
3e1b133686cac6670f6f93479525200772c5e233Stephan Bosch if (pclient->program_input == NULL) {
3e1b133686cac6670f6f93479525200772c5e233Stephan Bosch /* nothing */
3e1b133686cac6670f6f93479525200772c5e233Stephan Bosch } else if (pclient->error == PROGRAM_CLIENT_ERROR_NONE &&
3e1b133686cac6670f6f93479525200772c5e233Stephan Bosch !prclient->noreply && !force) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const unsigned char *data;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi size_t size;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Skip any remaining program output and parse the exit code */
76516caaa8bdaed1f3c21cc02f2156915cb89d40Aki Tuomi while (i_stream_read_more
76516caaa8bdaed1f3c21cc02f2156915cb89d40Aki Tuomi (pclient->program_input, &data, &size) > 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_stream_skip(pclient->program_input, size);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
23a7a07d4d7cab538509ceef21a280dcc243362fStephan Bosch /* Check for error and EOF. Since we're disconnected, always
23a7a07d4d7cab538509ceef21a280dcc243362fStephan Bosch mark an internal error when not all input is read. This is
23a7a07d4d7cab538509ceef21a280dcc243362fStephan Bosch generally unlikely to occur. */
23a7a07d4d7cab538509ceef21a280dcc243362fStephan Bosch if (pclient->program_input->stream_errno != 0 ||
23a7a07d4d7cab538509ceef21a280dcc243362fStephan Bosch i_stream_have_bytes_left(pclient->program_input))
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch pclient->exit_code = PROGRAM_CLIENT_EXIT_INTERNAL_FAILURE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi } else {
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch pclient->exit_code = PROGRAM_CLIENT_EXIT_SUCCESS;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
097dbdf543bc5d1689c5570f5faaec1e864e3a87Aki Tuomi program_client_disconnected(pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomistatic
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomivoid program_client_remote_switch_ioloop(struct program_client *pclient)
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_remote *prclient =
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi (struct program_client_remote *)pclient;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (prclient->to_retry != NULL)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch prclient->to_retry = io_loop_move_timeout(&prclient->to_retry);
59cd0982252ea1a416f9ed04fd083697ba31fb3aStephan Bosch if (prclient->lookup != NULL)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch dns_lookup_switch_ioloop(prclient->lookup);
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi}
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct program_client *
9f29dfcbf3812c4f88ffb1c99b5a56b2e8091ea4Aki Tuomiprogram_client_unix_create(const char *socket_path, const char *const *args,
9f29dfcbf3812c4f88ffb1c99b5a56b2e8091ea4Aki Tuomi const struct program_client_settings *set,
9f29dfcbf3812c4f88ffb1c99b5a56b2e8091ea4Aki Tuomi bool noreply)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_remote *pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pool_t pool;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
9f29dfcbf3812c4f88ffb1c99b5a56b2e8091ea4Aki Tuomi pool = pool_alloconly_create("program client unix", 1024);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient = p_new(pool, struct program_client_remote, 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_init(&pclient->client, pool, socket_path, args, set);
9f29dfcbf3812c4f88ffb1c99b5a56b2e8091ea4Aki Tuomi pclient->client.connect = program_client_unix_connect;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->client.close_output = program_client_remote_close_output;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->client.disconnect = program_client_remote_disconnect;
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi pclient->client.switch_ioloop = program_client_remote_switch_ioloop;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->noreply = noreply;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return &pclient->client;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistruct program_client *
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomiprogram_client_net_create(const char *host, in_port_t port,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi const char *const *args,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi const struct program_client_settings *set,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi bool noreply)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct program_client_remote *pclient;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pool_t pool;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pool = pool_alloconly_create("program client net", 1024);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient = p_new(pool, struct program_client_remote, 1);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_init(&pclient->client, pool, host, args, set);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->port = port;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.connect = program_client_net_connect_init;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.close_output = program_client_remote_close_output;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.disconnect = program_client_remote_disconnect;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->noreply = noreply;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->client.set.use_dotstream = TRUE;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return &pclient->client;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomistruct program_client *
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomiprogram_client_net_create_ips(const struct ip_addr *ips, size_t ips_count,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi in_port_t port,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi const char *const *args,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi const struct program_client_settings *set,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi bool noreply)
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi{
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi struct program_client_remote *pclient;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pool_t pool;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi i_assert(ips != NULL && ips_count > 0);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pool = pool_alloconly_create("program client net", 1024);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient = p_new(pool, struct program_client_remote, 1);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi program_client_init(&pclient->client, pool, net_ip2addr(ips), args, set);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->port = port;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.connect = program_client_net_connect_init;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.close_output = program_client_remote_close_output;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.disconnect = program_client_remote_disconnect;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->client.switch_ioloop = program_client_remote_switch_ioloop;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->noreply = noreply;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi pclient->client.set.use_dotstream = TRUE;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->ips = p_memdup(pool, ips,
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi sizeof(struct ip_addr)*ips_count);
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi pclient->ips_count = ips_count;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi return &pclient->client;
366f669495b4b507084e43a56c0a9d201f120b7dAki Tuomi}
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi