summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-04-04 16:57:25 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2008-04-04 16:57:25 +0000
commit0d5d42c52228964d76996c0e58fdf69258436716 (patch)
tree0505b84f979f9e369eebce188046fd6c7ed5902c /plugins
parentee629c4f742ac904c4a5055e85ef86d6decfb344 (diff)
downloadrsyslog-0d5d42c52228964d76996c0e58fdf69258436716.tar.gz
rsyslog-0d5d42c52228964d76996c0e58fdf69258436716.tar.xz
rsyslog-0d5d42c52228964d76996c0e58fdf69258436716.zip
an initial, somewhat working, tester for the mail functionality
Diffstat (limited to 'plugins')
-rw-r--r--plugins/ommail/ommail.c215
1 files changed, 212 insertions, 3 deletions
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
index 57de7fc0..4da4f58c 100644
--- a/plugins/ommail/ommail.c
+++ b/plugins/ommail/ommail.c
@@ -33,9 +33,10 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#include <unistd.h>
#include <errno.h>
-#include <ctype.h>
-#include <librelp.h>
+#include <netdb.h>
+#include <sys/socket.h>
#include "syslogd.h"
#include "syslogd-types.h"
#include "srUtils.h"
@@ -63,6 +64,9 @@ typedef struct _instanceData {
uchar *pszFrom;
uchar *pszTo;
uchar *pszSubject;
+ char RcvBuf[1024]; /* buffer for receiving server responses */
+ size_t lenRcvBuf;
+ size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */
int sock; /* socket to this server (most important when we do multiple msgs per mail) */
} smtp;
} md; /* mode-specific data */
@@ -104,6 +108,197 @@ CODESTARTdbgPrintInstInfo
ENDdbgPrintInstInfo
+/* TCP support code, should probably be moved to net.c or some place else... -- rgerhards, 2008-04-04 */
+
+/* "receive" a character from the remote server. A single character
+ * is returned. Returns RS_RET_NO_MORE_DATA if the server has closed
+ * the connection and RS_RET_IO_ERROR if something goes wrong. This
+ * is a blocking read.
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+getRcvChar(instanceData *pData, char *pC)
+{
+ DEFiRet;
+ ssize_t lenBuf;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.iRcvBuf == pData->md.smtp.lenRcvBuf) { /* buffer empty? */
+ /* yes, we need to read the next server response */
+ do {
+ lenBuf = recv(pData->md.smtp.sock, pData->md.smtp.RcvBuf, sizeof(pData->md.smtp.RcvBuf), 0);
+ if(lenBuf == 0) {
+ ABORT_FINALIZE(RS_RET_NO_MORE_DATA);
+ } else if(lenBuf < 0) {
+ if(errno != EAGAIN) {
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+ } else {
+ /* good read */
+ pData->md.smtp.iRcvBuf = 0;
+ pData->md.smtp.lenRcvBuf = lenBuf;
+ }
+
+ } while(lenBuf < 1);
+ }
+
+ /* when we reach this point, we have a non-empty buffer */
+ *pC = pData->md.smtp.RcvBuf[pData->md.smtp.iRcvBuf++];
+
+finalize_it:
+ RETiRet;
+}
+
+
+#if 0
+/* Initialize TCP socket (for sender), new socket is returned in
+ * pSock if all goes well.
+ */
+static rsRetVal
+CreateSocket(struct addrinfo *addrDest, int *pSock)
+{
+ DEFiRet;
+ int fd;
+ struct addrinfo *r;
+ char errStr[1024];
+
+ r = addrDest;
+
+ while(r != NULL) {
+ fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if(fd != -1) {
+ if(connect(fd, r->ai_addr, r->ai_addrlen) != 0) {
+ dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ } else {
+ *pSock = fd;
+ FINALIZE;
+ }
+ close(fd);
+ } else {
+ dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ }
+ r = r->ai_next;
+ }
+
+ dbgprintf("no working socket could be obtained");
+ iRet = RS_RET_NO_SOCKET;
+
+finalize_it:
+ RETiRet;
+}
+#endif
+
+
+/* open a connection to the mail server
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+serverConnect(instanceData *pData)
+{
+ struct addrinfo *res = NULL;
+ struct addrinfo hints;
+ char errStr[1024];
+
+ DEFiRet;
+ assert(pData != NULL);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; /* TODO: make configurable! */
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo((char*)pData->md.smtp.pszSrv, (char*)pData->md.smtp.pszSrvPort, &hints, &res) != 0) {
+ dbgprintf("error %d in getaddrinfo\n", errno);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if((pData->md.smtp.sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
+ dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if(connect(pData->md.smtp.sock, res->ai_addr, res->ai_addrlen) != 0) {
+ dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+finalize_it:
+ if(res != NULL)
+ freeaddrinfo(res);
+
+ if(iRet != RS_RET_OK) {
+ if(pData->md.smtp.sock != -1) {
+ close(pData->md.smtp.sock);
+ pData->md.smtp.sock = -1;
+ }
+ }
+
+ RETiRet;
+}
+
+
+
+/* send text to the server, blocking send */
+static rsRetVal
+Send(int sock, char *msg, size_t len)
+{
+ DEFiRet;
+ size_t offsBuf = 0;
+ ssize_t lenSend;
+
+ assert(msg != NULL);
+
+ if(len == 0) /* it's valid, but does not make much sense ;) */
+ FINALIZE;
+
+ do {
+ lenSend = send(sock, msg + offsBuf, len - offsBuf, 0);
+ dbgprintf("TCP sent %ld bytes, requested %ld\n", (long) lenSend, (long) len);
+
+ if(lenSend == -1) {
+ if(errno != EAGAIN) {
+ dbgprintf("message not (tcp)send, errno %d", errno);
+ ABORT_FINALIZE(RS_RET_TCP_SEND_ERROR);
+ }
+ } else if(lenSend != (ssize_t) len) {
+ offsBuf += len; /* on to next round... */
+ } else {
+ FINALIZE;
+ }
+ } while(1);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* send a message via SMTP
+ * TODO: care about the result codes, we can't do it that blindly ;)
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+sendSMTP(instanceData *pData, uchar *body)
+{
+ DEFiRet;
+
+ assert(pData != NULL);
+
+ CHKiRet(serverConnect(pData));
+ CHKiRet(Send(pData->md.smtp.sock, "HELO\r\n", 6));
+ CHKiRet(Send(pData->md.smtp.sock, "MAIL FROM: <rgerhards@adiscon.com>\r\n", sizeof("MAIL FROM: <rgerhards@adiscon.com>\r\n") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, "RCPT TO: <rgerhards@adiscon.com>\r\n", sizeof("RCPT TO: <rgerhards@adiscon.com>\r\n") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, body, strlen((char*) body)));
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n.\r\n", sizeof("\r\n.\r\n") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, "QUIT\r\n", sizeof("QUIT\r\n") - 1));
+
+ close(pData->md.smtp.sock);
+ pData->md.smtp.sock = -1;
+
+finalize_it:
+ RETiRet;
+}
+
+
+
/* connect to server
* rgerhards, 2008-04-04
*/
@@ -111,6 +306,10 @@ static rsRetVal doConnect(instanceData *pData)
{
DEFiRet;
+ iRet = serverConnect(pData);
+ if(iRet == RS_RET_IO_ERROR)
+ iRet = RS_RET_SUSPENDED;
+
RETiRet;
}
@@ -131,7 +330,7 @@ CODESTARTdoAction
/* forward */
iRet = sendSMTP(pData, ppString[0]);
- if(iRet != RELP_RET_OK) {
+ if(iRet != RS_RET_OK) {
/* error! */
dbgprintf("error sending mail, suspending\n");
iRet = RS_RET_SUSPENDED;
@@ -154,6 +353,16 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
if((iRet = createInstance(&pData)) != RS_RET_OK)
FINALIZE;
+ //pData->md.smtp.pszSrv = "172.19.2.10";
+ pData->md.smtp.pszSrv = "172.19.0.6";
+ pData->md.smtp.pszSrvPort = "25";
+ pData->md.smtp.pszFrom = "rgerhards@adiscon.com";
+ pData->md.smtp.pszTo = "rgerhards@adiscon.com";
+ pData->md.smtp.pszSubject = "rsyslog test message";
+
+ /* process template */
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_TraditionalForwardFormat"));
+
/* TODO: do we need to call freeInstance if we failed - this is a general question for
* all output modules. I'll address it later as the interface evolves. rgerhards, 2007-07-25
*/