9c5860706f
A brief description of the improvements can be found at https://svn.open-mpi.org/trac/ompi/wiki/ORTEWDC#ChangesdonetotheORTEnotifier This commit was SVN r23157.
355 строки
9.4 KiB
C
355 строки
9.4 KiB
C
/*
|
|
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
|
* University Research and Technology
|
|
* Corporation. All rights reserved.
|
|
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
|
* of Tennessee Research Foundation. All rights
|
|
* reserved.
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
* University of Stuttgart. All rights reserved.
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
* All rights reserved.
|
|
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
|
|
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
|
|
* $COPYRIGHT$
|
|
*
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*/
|
|
|
|
/*
|
|
* Send an email upon notifier events.
|
|
*/
|
|
|
|
#include "orte_config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_STDARG_H
|
|
#include <stdarg.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_SIGNAL_H
|
|
#include <signal.h>
|
|
#endif
|
|
|
|
#include "opal/util/show_help.h"
|
|
#include "opal/util/argv.h"
|
|
|
|
#include "orte/constants.h"
|
|
#include "orte/mca/ess/ess.h"
|
|
#include "orte/util/error_strings.h"
|
|
#include "orte/util/name_fns.h"
|
|
#include "orte/util/show_help.h"
|
|
#include "orte/runtime/orte_globals.h"
|
|
#include "orte/mca/notifier/base/base.h"
|
|
|
|
#include "notifier_smtp.h"
|
|
|
|
|
|
/* Static API's */
|
|
static void mylog(orte_notifier_base_severity_t severity, int errcode,
|
|
const char *msg, va_list ap);
|
|
static void myhelplog(orte_notifier_base_severity_t severity, int errcode,
|
|
const char *filename,
|
|
const char *topic, va_list ap);
|
|
static void mypeerlog(orte_notifier_base_severity_t severity, int errcode,
|
|
orte_process_name_t *peer_proc,
|
|
const char *msg, va_list ap);
|
|
|
|
/* Module */
|
|
orte_notifier_base_module_t orte_notifier_smtp_module = {
|
|
NULL,
|
|
NULL,
|
|
mylog,
|
|
myhelplog,
|
|
mypeerlog,
|
|
NULL
|
|
};
|
|
|
|
typedef enum {
|
|
SENT_NONE,
|
|
SENT_HEADER,
|
|
SENT_BODY_PREFIX,
|
|
SENT_BODY,
|
|
SENT_BODY_SUFFIX,
|
|
SENT_ALL
|
|
} sent_flag_t;
|
|
|
|
typedef struct {
|
|
sent_flag_t sent_flag;
|
|
char *msg;
|
|
char *prev_string;
|
|
} message_status_t;
|
|
|
|
/*
|
|
* Convert lone \n's to \r\n
|
|
*/
|
|
static char *crnl(char *orig)
|
|
{
|
|
int i, j, max, count;
|
|
char *str;
|
|
return strdup(orig);
|
|
|
|
/* Count how much space we need */
|
|
count = max = strlen(orig);
|
|
for (i = 0; i < max; ++i) {
|
|
if (orig[i] == '\n' && i > 0 && orig[i - 1] != '\r') {
|
|
++count;
|
|
}
|
|
}
|
|
|
|
/* Copy, changing \n to \r\n */
|
|
str = malloc(count + 1);
|
|
for (j = i = 0; i < max; ++i) {
|
|
if (orig[i] == '\n' && i > 0 && orig[i - 1] != '\r') {
|
|
str[j++] = '\n';
|
|
}
|
|
str[j++] = orig[i];
|
|
}
|
|
str[j] = '\0';
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
* Callback function invoked via smtp_start_session()
|
|
*/
|
|
static const char *message_cb(void **buf, int *len, void *arg)
|
|
{
|
|
message_status_t *ms = (message_status_t*) arg;
|
|
|
|
if (NULL == *buf) {
|
|
*buf = malloc(8192);
|
|
}
|
|
if (NULL == len) {
|
|
ms->sent_flag = SENT_NONE;
|
|
return NULL;
|
|
}
|
|
|
|
/* Free the previous string */
|
|
if (NULL != ms->prev_string) {
|
|
free(ms->prev_string);
|
|
ms->prev_string = NULL;
|
|
}
|
|
|
|
switch (ms->sent_flag) {
|
|
case SENT_NONE:
|
|
/* Send a blank line to signify the end of the header */
|
|
ms->sent_flag = SENT_HEADER;
|
|
ms->prev_string = NULL;
|
|
*len = 2;
|
|
return "\r\n";
|
|
|
|
case SENT_HEADER:
|
|
if (NULL != mca_notifier_smtp_component.body_prefix) {
|
|
ms->sent_flag = SENT_BODY_PREFIX;
|
|
ms->prev_string = crnl(mca_notifier_smtp_component.body_prefix);
|
|
*len = strlen(ms->prev_string);
|
|
return ms->prev_string;
|
|
}
|
|
|
|
case SENT_BODY_PREFIX:
|
|
ms->sent_flag = SENT_BODY;
|
|
ms->prev_string = crnl(ms->msg);
|
|
*len = strlen(ms->prev_string);
|
|
return ms->prev_string;
|
|
|
|
case SENT_BODY:
|
|
if (NULL != mca_notifier_smtp_component.body_suffix) {
|
|
ms->sent_flag = SENT_BODY_SUFFIX;
|
|
ms->prev_string = crnl(mca_notifier_smtp_component.body_suffix);
|
|
*len = strlen(ms->prev_string);
|
|
return ms->prev_string;
|
|
}
|
|
|
|
case SENT_BODY_SUFFIX:
|
|
case SENT_ALL:
|
|
default:
|
|
ms->sent_flag = SENT_ALL;
|
|
*len = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Back-end function to actually send the email
|
|
*/
|
|
static int send_email(char *msg)
|
|
{
|
|
int i, err = ORTE_SUCCESS;
|
|
char *str = NULL;
|
|
char *errmsg = NULL;
|
|
struct sigaction sig, oldsig;
|
|
bool set_oldsig = false;
|
|
smtp_session_t session = NULL;
|
|
smtp_message_t message = NULL;
|
|
message_status_t ms;
|
|
orte_notifier_smtp_component_t *c = &mca_notifier_smtp_component;
|
|
|
|
if (NULL == c->to_argv) {
|
|
c->to_argv = opal_argv_split(c->to, ',');
|
|
if (NULL == c->to_argv ||
|
|
NULL == c->to_argv[0]) {
|
|
return ORTE_ERR_OUT_OF_RESOURCE;
|
|
}
|
|
}
|
|
|
|
ms.sent_flag = SENT_NONE;
|
|
ms.prev_string = NULL;
|
|
ms.msg = msg;
|
|
|
|
/* Temporarily disable SIGPIPE so that if remote servers timeout
|
|
or hang up on us, it doesn't kill this application. We'll
|
|
restore the original SIGPIPE handler when we're done. */
|
|
sig.sa_handler = SIG_IGN;
|
|
sigemptyset(&sig.sa_mask);
|
|
sig.sa_flags = 0;
|
|
sigaction(SIGPIPE, &sig, &oldsig);
|
|
set_oldsig = true;
|
|
|
|
/* Try to get a libesmtp session. If so, assume that libesmtp is
|
|
happy and proceeed */
|
|
session = smtp_create_session();
|
|
if (NULL == session) {
|
|
err = ORTE_ERR_NOT_SUPPORTED;
|
|
errmsg = "stmp_create_session";
|
|
goto error;
|
|
}
|
|
|
|
/* Create the message */
|
|
message = smtp_add_message(session);
|
|
if (NULL == message) {
|
|
err = ORTE_ERROR;
|
|
errmsg = "stmp_add_message";
|
|
goto error;
|
|
}
|
|
|
|
/* Set the SMTP server (yes, it's a weird return status!) */
|
|
asprintf(&str, "%s:%d", c->server, c->port);
|
|
if (0 == smtp_set_server(session, str)) {
|
|
err = ORTE_ERROR;
|
|
errmsg = "stmp_set_server";
|
|
goto error;
|
|
}
|
|
free(str);
|
|
str = NULL;
|
|
|
|
/* Add the sender */
|
|
if (0 == smtp_set_reverse_path(message, c->from_addr)) {
|
|
err = ORTE_ERROR;
|
|
errmsg = "stmp_set_reverse_path";
|
|
goto error;
|
|
}
|
|
|
|
/* Set the subject and some headers */
|
|
asprintf(&str, "Open MPI SMTP Notifier v%d.%d.%d",
|
|
c->super.base_version.mca_component_major_version,
|
|
c->super.base_version.mca_component_minor_version,
|
|
c->super.base_version.mca_component_release_version);
|
|
if (0 == smtp_set_header(message, "Subject", c->subject) ||
|
|
0 == smtp_set_header_option(message, "Subject", Hdr_OVERRIDE, 1) ||
|
|
0 == smtp_set_header(message, "To", NULL, NULL) ||
|
|
0 == smtp_set_header(message, "From",
|
|
(NULL != c->from_name ?
|
|
c->from_name : c->from_addr),
|
|
c->from_addr) ||
|
|
0 == smtp_set_header(message, "X-Mailer", str) ||
|
|
0 == smtp_set_header_option(message, "Subject", Hdr_OVERRIDE, 1)) {
|
|
err = ORTE_ERROR;
|
|
errmsg = "smtp_set_header";
|
|
goto error;
|
|
}
|
|
free(str);
|
|
str = NULL;
|
|
|
|
/* Add the recipients */
|
|
for (i = 0; NULL != c->to_argv[i]; ++i) {
|
|
if (NULL == smtp_add_recipient(message, c->to_argv[i])) {
|
|
err = ORTE_ERR_OUT_OF_RESOURCE;
|
|
errmsg = "stmp_add_recipient";
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* Set the callback to get the message */
|
|
if (0 == smtp_set_messagecb(message, message_cb, &ms)) {
|
|
err = ORTE_ERROR;
|
|
errmsg = "smtp_set_messagecb";
|
|
goto error;
|
|
}
|
|
|
|
/* Send it! */
|
|
if (0 == smtp_start_session(session)) {
|
|
err = ORTE_ERROR;
|
|
errmsg = "smtp_start_session";
|
|
goto error;
|
|
}
|
|
|
|
/* Fall through */
|
|
|
|
error:
|
|
if (NULL != str) {
|
|
free(str);
|
|
}
|
|
if (NULL != session) {
|
|
smtp_destroy_session(session);
|
|
}
|
|
/* Restore the SIGPIPE handler */
|
|
if (set_oldsig) {
|
|
sigaction(SIGPIPE, &oldsig, NULL);
|
|
}
|
|
if (ORTE_SUCCESS != err) {
|
|
int e;
|
|
char em[256];
|
|
|
|
e = smtp_errno();
|
|
smtp_strerror(e, em, sizeof(em));
|
|
orte_show_help("help-orte-notifier-smtp.txt",
|
|
"send_email failed",
|
|
true, "libesmtp library call failed",
|
|
errmsg, em, e, msg);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static void mylog(orte_notifier_base_severity_t severity, int errcode,
|
|
const char *msg, va_list ap)
|
|
{
|
|
char *output;
|
|
|
|
/* If there was a message, output it */
|
|
vasprintf(&output, msg, ap);
|
|
|
|
if (NULL != output) {
|
|
send_email(output);
|
|
free(output);
|
|
}
|
|
}
|
|
|
|
static void myhelplog(orte_notifier_base_severity_t severity, int errcode,
|
|
const char *filename,
|
|
const char *topic, va_list ap)
|
|
{
|
|
char *output = opal_show_help_vstring(filename, topic, false, ap);
|
|
|
|
if (NULL != output) {
|
|
send_email(output);
|
|
free(output);
|
|
}
|
|
}
|
|
|
|
static void mypeerlog(orte_notifier_base_severity_t severity, int errcode,
|
|
orte_process_name_t *peer_proc, const char *msg,
|
|
va_list ap)
|
|
{
|
|
char *buf = orte_notifier_base_peer_log(errcode, peer_proc, msg, ap);
|
|
|
|
if (NULL != buf) {
|
|
send_email(buf);
|
|
free(buf);
|
|
}
|
|
}
|