bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "lib.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "str.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "llist.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "array.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "path-util.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "hostpid.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "ioloop.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "istream.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "ostream.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "istream-base64.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "istream-crlf.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "iostream-temp.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "connection.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "test-common.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "smtp-server.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "smtp-client.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "smtp-client-connection.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include "smtp-client-transaction.h"
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <sys/types.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <sys/stat.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <sys/wait.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <signal.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <fcntl.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <unistd.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#include <dirent.h>
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic bool debug = FALSE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic unsigned int test_max_pending = 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic bool test_unknown_size = FALSE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct ip_addr bind_ip;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic in_port_t bind_port = 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic int fd_listen = -1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic pid_t server_pid = (pid_t)-1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/*
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch * Test files
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic ARRAY_TYPE(const_string) files;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic pool_t files_pool;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_files_read_dir(const char *path)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch DIR *dirp;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* open the directory */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if ((dirp = opendir(path)) == NULL) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (errno == ENOENT || errno == EACCES)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test files: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "failed to open directory %s: %m", path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* read entries */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch for (;;) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *file;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct dirent *dp;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct stat st;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#if 0
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (array_count(&files) > 10)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch break;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch#endif
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch errno = 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if ((dp=readdir(dirp)) == NULL)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch break;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (*dp->d_name == '.')
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch continue;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch file = t_abspath_to(dp->d_name, path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (stat(file, &st) == 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (S_ISREG(st.st_mode)) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch file += 2; /* skip "./" */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch file = p_strdup(files_pool, file);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch array_append(&files, &file, 1);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch } else {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_read_dir(file);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (errno != 0)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test files: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "failed to read directory %s: %m", path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* Close the directory */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (closedir(dirp) < 0)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_error("test files: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "failed to close directory %s: %m", path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_files_init(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* initialize file array */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch files_pool = pool_alloconly_create
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (MEMPOOL_GROWING"smtp_server_request", 4096);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch p_array_init(&files, files_pool, 512);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* obtain all filenames */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_read_dir(".");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_files_deinit(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pool_unref(&files_pool);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct istream *
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_file_open(const char *path)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *file;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch int fd;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fd = open(path, O_RDONLY);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fd < 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (errno != ENOENT && errno != EACCES) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test files: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "open(%s) failed: %m", path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test files: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "open(%s) failed: %m", path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch file = i_stream_create_fd_autoclose(&fd, 40960);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_set_name(file, path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return file;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/*
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch * Test server
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstruct client {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pool_t pool;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client *prev, *next;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_connection *smtp_conn;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch};
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstruct client_transaction {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client *client;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_cmd_ctx *data_cmd;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_transaction *trans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *payload, *file;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch};
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct smtp_server *smtp_server;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct io *io_listen;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct client *clients;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic int
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschclient_transaction_read_more(struct client_transaction *ctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *payload = ctrans->payload;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const unsigned char *pdata, *fdata;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch size_t psize, fsize, pleft;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch off_t ret;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: read more payload for [%s]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* read payload */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch while ((ret=i_stream_read_more(payload, &pdata, &psize)) > 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "got data for [%s] (size=%d)",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->path, (int)psize);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* compare with file on disk */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pleft = psize;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch while ((ret=i_stream_read_more
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (ctrans->file, &fdata, &fsize)) > 0 && pleft > 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fsize = (fsize > pleft ? pleft : fsize);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (memcmp(pdata, fdata, fsize) != 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "received data does not match file [%s] "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "(%"PRIuUOFF_T":%"PRIuUOFF_T")",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->path, payload->v_offset,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->file->v_offset);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_skip(ctrans->file, fsize);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pleft -= fsize;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pdata += fsize;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (ret < 0 && ctrans->file->stream_errno != 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "failed to read file: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_get_error(ctrans->file));
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_skip(payload, psize);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (ret == 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "need more data for [%s]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* we will be called again for this request */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)i_stream_read(ctrans->file);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (payload->stream_errno != 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "failed to read transaction payload: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_get_error(payload));
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch } if (i_stream_have_bytes_left(ctrans->file)) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (i_stream_read_more(ctrans->file, &fdata, &fsize) <= 0)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fsize = 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "payload ended prematurely "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "(at least %"PRIuSIZE_T" bytes left)", fsize);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "finished transaction for [%s]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* dereference payload stream; finishes the request */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&payload);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->payload = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&ctrans->file);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* finished */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_reply_all(ctrans->data_cmd, 250, "2.0.0", "OK");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschclient_transaction_handle_payload(struct client_transaction *ctrans,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path, struct istream *data_input)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_transaction *trans = ctrans->trans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *fstream;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->path = p_strdup(trans->pool, path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: got transaction for: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fstream = test_file_open(path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fstream == NULL)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test server: failed to open: %s", path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_ref(data_input);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->payload = data_input;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(ctrans->payload != NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->file = i_stream_create_base64_encoder(fstream, 80, TRUE),
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&fstream);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)client_transaction_read_more(ctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/* transaction */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct client_transaction *
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschclient_transaction_init(struct client *client,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_cmd_ctx *data_cmd,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_transaction *trans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client_transaction *ctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pool_t pool = trans->pool;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans = p_new(pool, struct client_transaction, 1);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->client = client;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->trans = trans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->data_cmd = data_cmd;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return ctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschclient_transaction_deinit(struct client_transaction **_ctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client_transaction *ctrans = *_ctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch *_ctrans = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&ctrans->payload);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&ctrans->file);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_conn_trans_free(void *context ATTR_UNUSED,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_transaction *trans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client_transaction *ctrans =
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (struct client_transaction *)trans->context;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_transaction_deinit(&ctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic int
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_conn_cmd_rcpt(void *conn_ctx ATTR_UNUSED,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_cmd_rcpt *data)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: RCPT TO:%s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_address_encode(data->path));
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic int
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_conn_cmd_data_begin(void *conn_ctx,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_cmd_ctx *cmd,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_transaction *trans,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *data_input)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client *client = (struct client *)conn_ctx;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *fpath = trans->params.envid;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client_transaction *ctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(fpath != NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: DATA (file path = %s)", fpath);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans = client_transaction_init(client, cmd, trans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_transaction_handle_payload
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (ctrans, fpath, data_input);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch trans->context = ctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic int
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_conn_cmd_data_continue(void *conn_ctx ATTR_UNUSED,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_cmd_ctx *cmd,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_transaction *trans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client_transaction *ctrans =
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ( struct client_transaction *)trans->context;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test server: DATA continue");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ctrans->data_cmd = cmd;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return client_transaction_read_more(ctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/* client connection */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_connection_destroy(void *context);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic const struct smtp_server_callbacks server_callbacks =
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch .conn_cmd_rcpt = test_server_conn_cmd_rcpt,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch .conn_cmd_data_begin = test_server_conn_cmd_data_begin,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch .conn_cmd_data_continue = test_server_conn_cmd_data_continue,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch .conn_trans_free = test_server_conn_trans_free,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch .conn_destroy = test_server_connection_destroy
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch};
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void client_init(int fd)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client *client;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pool_t pool;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch net_set_nonblock(fd, TRUE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pool = pool_alloconly_create("client", 256);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client = p_new(pool, struct client, 1);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client->pool = pool;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client->smtp_conn = smtp_server_connection_create(smtp_server,
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch fd, fd, NULL, 0, FALSE, NULL, &server_callbacks, client);
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch smtp_server_connection_start(client->smtp_conn);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch DLLIST_PREPEND(&clients, client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void client_deinit(struct client **_client)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client *client = *_client;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch *_client = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch DLLIST_REMOVE(&clients, client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (client->smtp_conn != NULL)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_connection_terminate(&client->smtp_conn, NULL, "deinit");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch pool_unref(&client->pool);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_connection_destroy(void *context)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct client *client = context;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client->smtp_conn = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_deinit(&client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void client_accept(void *context ATTR_UNUSED)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch int fd;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* accept new client */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fd = net_accept(fd_listen, NULL, NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fd == -1)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fd == -2) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test server: accept() failed: %m");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_init(fd);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/* */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_server_init(const struct smtp_server_settings *server_set)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* open server socket */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_listen = io_add(fd_listen,
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek IO_READ, client_accept, NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server = smtp_server_init(server_set);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_server_deinit(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* close server socket */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_remove(&io_listen);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* deinitialize */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_deinit(&smtp_server);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/*
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch * Test client
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstruct test_client_transaction {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct test_client_transaction *prev, *next;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_client_connection *conn;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_client_transaction *trans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct io *io;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *file;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int files_idx;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch};
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct smtp_client *smtp_client;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic enum smtp_protocol client_protocol;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct test_client_transaction *client_requests;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic unsigned int client_files_first, client_files_last;
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct timeout *client_to = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic struct test_client_transaction *
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_transaction_new(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct test_client_transaction *tctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans = i_new(struct test_client_transaction, 1);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch DLLIST_PREPEND(&client_requests, tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return tctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_transaction_destroy(struct test_client_transaction *tctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (tctrans->trans != NULL)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_transaction_destroy(&tctrans->trans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_remove(&tctrans->io);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&tctrans->file);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch DLLIST_REMOVE(&client_requests, tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_free(tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_client_continue(void *dummy);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_finished(unsigned int files_idx)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char **paths;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int count;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "finished [%u]", files_idx);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths = array_get_modifiable(&files, &count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(files_idx < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_first < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(paths[files_idx] != NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths[files_idx] = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (client_to == NULL)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_to = timeout_add_short(0, test_client_continue, NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_transaction_finish(struct test_client_transaction *tctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans->trans = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_transaction_destroy(tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_transaction_rcpt(const struct smtp_reply *reply,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct test_client_transaction *tctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char **paths;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int count;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths = array_get_modifiable(&files, &count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(tctrans->files_idx < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_first < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path = paths[tctrans->files_idx];
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(path != NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (reply->status / 100 != 2) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "SMTP RCPT for %s failed: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path, smtp_reply_log(reply));
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_transaction_rcpt_data(const struct smtp_reply *reply ATTR_UNUSED,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct test_client_transaction *tctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char **paths;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int count;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths = array_get_modifiable(&files, &count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(tctrans->files_idx < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_first < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path = paths[tctrans->files_idx];
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(path != NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (reply->status / 100 != 2) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "SMTP DATA for %s failed: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path, smtp_reply_log(reply));
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client_transaction_data(const struct smtp_reply *reply,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct test_client_transaction *tctrans)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char **paths;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int count;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "got response for DATA [%u]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans->files_idx);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths = array_get_modifiable(&files, &count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(tctrans->files_idx < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_first < count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path = paths[tctrans->files_idx];
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(path != NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "path for [%u]: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans->files_idx, path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (reply->status / 100 != 2) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "SMTP transaction for %s failed: %s",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path, smtp_reply_log(reply));
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_finished(tctrans->files_idx);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_client_continue(void *dummy ATTR_UNUSED)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct test_client_transaction *tctrans;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_params_mail mail_params;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char **paths;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int count;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: continue");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch timeout_remove(&client_to);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths = array_get_modifiable(&files, &count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_first <= count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_last <= count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_assert(client_files_first <= client_files_last);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch for (; client_files_first < client_files_last &&
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths[client_files_first] == NULL; client_files_first++);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "received until [%u/%u]", client_files_first-1, count);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug && client_files_first < count) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path = paths[client_files_first];
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "next blocking: %s [%d]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (path == NULL ? "none" : path),
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_files_first);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (client_files_first >= count) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_loop_stop(current_ioloop);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch return;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch for (; client_files_last < count &&
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (client_files_last - client_files_first) < test_max_pending;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_files_last++) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *fstream, *payload;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const char *path = paths[client_files_last];
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch unsigned int r, rcpts;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fstream = test_file_open(path);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fstream == NULL) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch paths[client_files_last] = NULL;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "skipping %s [%u]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path, client_files_last);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (client_to == NULL)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_to = timeout_add_short(0, test_client_continue, NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch continue;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "retrieving %s [%u]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch path, client_files_last);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans = test_client_transaction_new();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans->files_idx = client_files_last;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans->conn = smtp_client_connection_create(smtp_client,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_protocol, net_ip2addr(&bind_ip), bind_port,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch SMTP_CLIENT_SSL_MODE_NONE, NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_zero(&mail_params);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch mail_params.envid = path;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch tctrans->trans = smtp_client_transaction_create(tctrans->conn,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch SMTP_ADDRESS_LITERAL("user", "example.com"),
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch &mail_params, test_client_transaction_finish, tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_connection_unref(&tctrans->conn);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch rcpts = tctrans->files_idx % 10 + 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch for (r = 1; r <= rcpts; r++) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_transaction_add_rcpt(tctrans->trans,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_address_create_temp(
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch t_strdup_printf("rcpt%u", r), "example.com"), NULL,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_transaction_rcpt,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_transaction_rcpt_data, tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (!test_unknown_size)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch payload = i_stream_create_base64_encoder(fstream, 80, TRUE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch else {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct istream *b64_stream =
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_create_base64_encoder(fstream, 80, FALSE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch payload = i_stream_create_crlf(b64_stream);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&b64_stream);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug) {
836ed7eb3d79eb41b28d80d4f59099e54b7cb20aJosef 'Jeff' Sipek uoff_t raw_size = (uoff_t)-1, b64_size = (uoff_t)-1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)i_stream_get_size(fstream, TRUE, &raw_size);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)i_stream_get_size(payload, TRUE, &b64_size);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("test client: "
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch "sending %"PRIuUOFF_T"/%"PRIuUOFF_T" bytes payload %s [%u]",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch raw_size, b64_size, path, client_files_last);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_transaction_send(tctrans->trans, payload,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_transaction_data, tctrans);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&payload);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_stream_unref(&fstream);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_client(enum smtp_protocol protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const struct smtp_client_settings *client_set)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_protocol = protocol;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* create client */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client = smtp_client_init(client_set);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* start querying server */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_files_first = client_files_last = 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_continue(NULL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/* cleanup */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_client_deinit(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch timeout_remove(&client_to);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_deinit(&smtp_client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/*
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch * Tests
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_open_server_fd(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fd_listen != -1)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_close_fd(&fd_listen);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch fd_listen = net_listen(&bind_ip, &bind_port, 128);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (fd_listen == -1) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("listen(%s:%u) failed: %m",
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch net_ip2addr(&bind_ip), bind_port);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_server_kill(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (server_pid != (pid_t)-1) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)kill(server_pid, SIGKILL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)waitpid(server_pid, NULL, 0);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch server_pid = (pid_t)-1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_run_client_server(
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch enum smtp_protocol protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const struct smtp_client_settings *client_set,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const struct smtp_server_settings *server_set,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch void (*client_init)(enum smtp_protocol protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const struct smtp_client_settings *client_set))
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct ioloop *ioloop;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_open_server_fd();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if ((server_pid = fork()) == (pid_t)-1)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("fork() failed: %m");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (server_pid == 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch server_pid = (pid_t)-1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch hostpid_init();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("server: PID=%s", my_pid);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_set_failure_prefix("SERVER: ");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* child: server */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ioloop = io_loop_create();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_server_init(server_set);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_loop_run(ioloop);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_server_deinit();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_loop_destroy(&ioloop);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_close_fd(&fd_listen);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch } else {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (debug)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_debug("client: PID=%s", my_pid);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_set_failure_prefix("CLIENT: ");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_close_fd(&fd_listen);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* parent: client */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch ioloop = io_loop_create();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_init(protocol, client_set);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_loop_run(ioloop);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client_deinit();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch io_loop_destroy(&ioloop);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch bind_port = 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_server_kill();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_run_scenarios(enum smtp_protocol protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch enum smtp_capability capabilities,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch void (*client_init)(enum smtp_protocol protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch const struct smtp_client_settings *client_set))
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_server_settings smtp_server_set;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch struct smtp_client_settings smtp_client_set;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* server settings */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_zero(&smtp_server_set);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.protocol = protocol;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.capabilities = capabilities;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.hostname = "localhost";
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.max_client_idle_time_msecs = 10*000;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.max_pipelined_commands = 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.auth_optional = TRUE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.debug = debug;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* client settings */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_zero(&smtp_client_set);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_set.my_hostname = "localhost";
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_set.temp_path_prefix = "/tmp";
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_client_set.debug = debug;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_max_pending = 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_unknown_size = FALSE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_init();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_client_server(protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch &smtp_client_set, &smtp_server_set,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_init);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_deinit();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_out("sequential", TRUE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_max_pending = 200;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_unknown_size = FALSE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_init();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_client_server(protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch &smtp_client_set, &smtp_server_set,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_init);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_deinit();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_out("parallel", TRUE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.max_pipelined_commands = 5;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.capabilities |= SMTP_CAPABILITY_PIPELINING;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_max_pending = 200;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_unknown_size = FALSE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_init();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_client_server(protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch &smtp_client_set, &smtp_server_set,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_init);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_deinit();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_out("parallel pipelining", TRUE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.max_pipelined_commands = 5;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch smtp_server_set.capabilities |= SMTP_CAPABILITY_PIPELINING;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_max_pending = 200;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_unknown_size = TRUE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_init();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_client_server(protocol,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch &smtp_client_set, &smtp_server_set,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch client_init);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_files_deinit();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_out("unknown payload size", TRUE);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_smtp_normal(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_begin("smtp payload - normal");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_scenarios(SMTP_PROTOCOL_SMTP,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch SMTP_CAPABILITY_DSN, test_client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_end();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_smtp_chunking(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_begin("smtp payload - chunking");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_scenarios(SMTP_PROTOCOL_SMTP,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch SMTP_CAPABILITY_DSN | SMTP_CAPABILITY_CHUNKING,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_end();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_lmtp_normal(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_begin("lmtp payload - normal");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_scenarios(SMTP_PROTOCOL_LMTP,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch SMTP_CAPABILITY_DSN, test_client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_end();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_lmtp_chunking(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_begin("lmtp payload - chunking");
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run_scenarios(SMTP_PROTOCOL_LMTP,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch SMTP_CAPABILITY_DSN | SMTP_CAPABILITY_CHUNKING,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_client);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_end();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void (*const test_functions[])(void) = {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_smtp_normal,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_smtp_chunking,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_lmtp_normal,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_lmtp_chunking,
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch NULL
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch};
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch/*
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch * Main
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschvolatile sig_atomic_t terminating = 0;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschtest_signal_handler(int signo)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch if (terminating != 0)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch raise(signo);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch terminating = 1;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* make sure we don't leave any pesky children alive */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_server_kill();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(signo, SIG_DFL);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch raise(signo);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschstatic void test_atexit(void)
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_server_kill();
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Boschint main(int argc, char *argv[])
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch{
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch int c;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch atexit(test_atexit);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(SIGCHLD, SIG_IGN);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(SIGTERM, test_signal_handler);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(SIGQUIT, test_signal_handler);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(SIGINT, test_signal_handler);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(SIGSEGV, test_signal_handler);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch (void)signal(SIGABRT, test_signal_handler);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch while ((c = getopt(argc, argv, "D")) > 0) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch switch (c) {
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch case 'D':
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch debug = TRUE;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch break;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch default:
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_fatal("Usage: %s [-D]", argv[0]);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch }
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch /* listen on localhost */
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch i_zero(&bind_ip);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch bind_ip.family = AF_INET;
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch bind_ip.u.ip4.s_addr = htonl(INADDR_LOOPBACK);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch test_run(test_functions);
8620dc793885749c37000f11dd83b902b6844e20Stephan Bosch}