/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
/*
 *  (C) 2003 by Argonne National Laboratory.
 *      See COPYRIGHT in top-level directory.
 */
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void check_error(int, const char *);
void check_error(int error, const char *fcname)
{
    char err_string[MPI_MAX_ERROR_STRING] = "";
    int length;
    if (error != MPI_SUCCESS) {
        MPI_Error_string(error, err_string, &length);
        printf("%s failed: %s\n", fcname, err_string);
        fflush(stdout);
        MPI_Abort(MPI_COMM_WORLD, error);
    }
}

int main(int argc, char *argv[])
{
    int error;
    int rank, size;
    char port[MPI_MAX_PORT_NAME];
    MPI_Status status;
    MPI_Comm comm;
    int verbose = 0;

    if (getenv("MPITEST_VERBOSE")) {
        verbose = 1;
    }

    if (verbose) {
        printf("init.\n");
        fflush(stdout);
    }
    error = MPI_Init(&argc, &argv);
    check_error(error, "MPI_Init");

    /* To improve reporting of problems about operations, we
     * change the error handler to errors return */
    MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
    MPI_Comm_set_errhandler(MPI_COMM_SELF, MPI_ERRORS_RETURN);

    if (verbose) {
        printf("size.\n");
        fflush(stdout);
    }
    error = MPI_Comm_size(MPI_COMM_WORLD, &size);
    check_error(error, "MPI_Comm_size");

    if (verbose) {
        printf("rank.\n");
        fflush(stdout);
    }
    error = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    check_error(error, "MPI_Comm_rank");

    if (size < 2) {
        printf("Two processes needed.\n");
        MPI_Finalize();
        return 0;
    }

    if (rank == 0) {
        if (verbose) {
            printf("open_port.\n");
            fflush(stdout);
        }
        error = MPI_Open_port(MPI_INFO_NULL, port);
        check_error(error, "MPI_Open_port");

        if (verbose) {
            printf("0: opened port: <%s>\n", port);
            fflush(stdout);
        }
        if (verbose) {
            printf("send.\n");
            fflush(stdout);
        }
        error = MPI_Send(port, MPI_MAX_PORT_NAME, MPI_CHAR, 1, 0, MPI_COMM_WORLD);
        check_error(error, "MPI_Send");

        if (verbose) {
            printf("accept.\n");
            fflush(stdout);
        }
        error = MPI_Comm_accept(port, MPI_INFO_NULL, 0, MPI_COMM_SELF, &comm);
        check_error(error, "MPI_Comm_accept");

        if (verbose) {
            printf("close_port.\n");
            fflush(stdout);
        }
        error = MPI_Close_port(port);
        check_error(error, "MPI_Close_port");

        if (verbose) {
            printf("disconnect.\n");
            fflush(stdout);
        }
        error = MPI_Comm_disconnect(&comm);
        check_error(error, "MPI_Comm_disconnect");
    }
    else if (rank == 1) {
        if (verbose) {
            printf("recv.\n");
            fflush(stdout);
        }
        error = MPI_Recv(port, MPI_MAX_PORT_NAME, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &status);
        check_error(error, "MPI_Recv");

        if (verbose) {
            printf("1: received port: <%s>\n", port);
            fflush(stdout);
        }
        if (verbose) {
            printf("connect.\n");
            fflush(stdout);
        }
        error = MPI_Comm_connect(port, MPI_INFO_NULL, 0, MPI_COMM_SELF, &comm);
        check_error(error, "MPI_Comm_connect");

        MPI_Comm_set_errhandler(comm, MPI_ERRORS_RETURN);

        if (verbose) {
            printf("disconnect.\n");
            fflush(stdout);
        }
        error = MPI_Comm_disconnect(&comm);
        check_error(error, "MPI_Comm_disconnect");
    }

    error = MPI_Barrier(MPI_COMM_WORLD);
    check_error(error, "MPI_Barrier");

    if (rank == 0) {
        printf(" No Errors\n");
    }
    MPI_Finalize();
    return 0;
}
