summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-12-28 14:14:52 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-12-28 14:14:52 +0000
commit505706d958e17ef729e15c24d58305b8dff198a9 (patch)
treeeab80066125f8a5637389409d532f955b8f37f5b
parentbcdb6dcfd7b28e3dbf9fa0c4e9f718b6b91a7b3f (diff)
downloadrsyslog-505706d958e17ef729e15c24d58305b8dff198a9.tar.gz
rsyslog-505706d958e17ef729e15c24d58305b8dff198a9.tar.xz
rsyslog-505706d958e17ef729e15c24d58305b8dff198a9.zip
took TCPSend() apart and made it generic via function pointers
-rw-r--r--omfwd.c215
-rw-r--r--rsyslog.h4
2 files changed, 122 insertions, 97 deletions
diff --git a/omfwd.c b/omfwd.c
index db5750b4..7e17d9a7 100644
--- a/omfwd.c
+++ b/omfwd.c
@@ -144,27 +144,27 @@ static char *getFwdSyslogPt(instanceData *pData)
/* Build frame based on selected framing */
-static rsRetVal TCPSendBldFrame(instanceData *pData, char **pmsg, size_t *plen, int *pbMustBeFreed, int *pbIsCompressed)
+static rsRetVal TCPSendBldFrame(instanceData *pData, char **pmsg, size_t *plen, int *pbMustBeFreed)
{
DEFiRet;
TCPFRAMINGMODE framingToUse;
+ int bIsCompressed;
size_t len;
char *msg;
char *buf = NULL; /* if this is non-NULL, it MUST be freed before return! */
assert(plen != NULL);
- assert(pbIsCompressed != NULL);
assert(pbMustBeFreed != NULL);
assert(pmsg != NULL);
msg = *pmsg;
len = *plen;
- *pbIsCompressed = *msg == 'z'; /* cache this, so that we can modify the message buffer */
+ bIsCompressed = *msg == 'z'; /* cache this, so that we can modify the message buffer */
/* select framing for this record. If we have a compressed record, we always need to
* use octet counting because the data potentially contains all control characters
* including LF.
*/
- framingToUse = *pbIsCompressed ? TCP_FRAMING_OCTET_COUNTING : pData->tcp_framing;
+ framingToUse = bIsCompressed ? TCP_FRAMING_OCTET_COUNTING : pData->tcp_framing;
/* now check if we need to add a line terminator. We need to
* copy the string in memory in this case, this is probably
@@ -445,8 +445,20 @@ static int TCPSendCreateSocket(instanceData *pData, struct addrinfo *addrDest)
#ifdef USE_GSSAPI
-static int TCPSendGSSInit(instanceData *pData)
+/* This function is called immediately before a send retry is attempted.
+ * It shall clean up whatever makes sense.
+ * rgerhards, 2007-12-28
+ */
+static rsRetVal TCPSendGSSPrepRetry(instanceData __attribute__((unused)) *pData)
{
+ /* in case of TCP/GSS, there is nothing to do */
+ return RS_RET_OK;
+}
+
+
+static rsRetVal TCPSendGSSInit(instanceData *pData)
+{
+ DEFiRet;
int s = -1;
char *base;
OM_uint32 maj_stat, min_stat, init_sec_min_stat, *sess_flags, ret_flags;
@@ -459,8 +471,9 @@ static int TCPSendGSSInit(instanceData *pData)
base = (gss_base_service_name == NULL) ? "host" : gss_base_service_name;
out_tok.length = strlen(pData->f_hname) + strlen(base) + 2;
- if ((out_tok.value = malloc(out_tok.length)) == NULL)
- return -1;
+ if ((out_tok.value = malloc(out_tok.length)) == NULL) {
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
strcpy(out_tok.value, base);
strcat(out_tok.value, "@");
strcat(out_tok.value, pData->f_hname);
@@ -532,7 +545,8 @@ static int TCPSendGSSInit(instanceData *pData)
dbgprintf("GSS-API Context initialized\n");
gss_release_name(&min_stat, &target_name);
- return 0;
+finalize_it:
+ return iRet;
fail:
logerror("GSS-API Context initialization failed\n");
@@ -545,11 +559,11 @@ static int TCPSendGSSInit(instanceData *pData)
if (s != -1)
close(s);
pData->sock = -1;
- return -1;
+ return RS_RET_GSS_SENDINIT_ERROR;
}
-static int TCPSendGSSSend(instanceData *pData, char *msg, size_t len)
+static rsRetVal TCPSendGSSSend(instanceData *pData, char *msg, size_t len)
{
int s;
gss_ctx_id_t *context;
@@ -576,7 +590,7 @@ static int TCPSendGSSSend(instanceData *pData, char *msg, size_t len)
}
gss_release_buffer(&min_stat, &out_buf);
- return 0;
+ return RS_RET_OK;
fail:
close(s);
@@ -584,11 +598,77 @@ static int TCPSendGSSSend(instanceData *pData, char *msg, size_t len)
gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER);
*context = GSS_C_NO_CONTEXT;
gss_release_buffer(&min_stat, &out_buf);
- return -1;
+ dbgprintf("message not (GSS/tcp)send");
+ return RS_RET_GSS_SEND_ERROR;
}
#endif /* #ifdef USE_GSSAPI */
+/* Send a frame via plain TCP protocol
+ * rgerhards, 2007-12-28
+ */
+static rsRetVal TCPSendFrame(instanceData *pData, char *msg, size_t len)
+{
+ DEFiRet;
+ ssize_t lenSend;
+
+ lenSend = send(pData->sock, msg, len, 0);
+ dbgprintf("TCP sent %ld bytes, requested %ld\n", (long) lenSend, (long) len);
+
+ if(lenSend == -1) {
+ /* we have an error case - check what we can live with */
+ switch(errno) {
+ case EMSGSIZE:
+ dbgprintf("message not (tcp)send, too large\n");
+ /* This is not a real error, so it is not flagged as one */
+ break;
+ default:
+ dbgprintf("message not (tcp)send");
+ iRet = RS_RET_TCP_SEND_ERROR;
+ break;
+ }
+ } else if(lenSend != (ssize_t) len) {
+ /* no real error, could "just" not send everything...
+ * For the time being, we ignore this...
+ * rgerhards, 2005-10-25
+ */
+ dbgprintf("message not completely (tcp)send, ignoring %ld\n", lenSend);
+ usleep(1000); /* experimental - might be benefitial in this situation */
+ /* TODO: we need to revisit this code -- rgerhards, 2007-12-28 */
+ }
+
+ return iRet;
+}
+
+
+/* This function is called immediately before a send retry is attempted.
+ * It shall clean up whatever makes sense.
+ * rgerhards, 2007-12-28
+ */
+static rsRetVal TCPSendPrepRetry(instanceData *pData)
+{
+ assert(pData != NULL);
+ close(pData->sock);
+ pData->sock = -1;
+ return RS_RET_OK;
+}
+
+
+/* initialies everything so that TCPSend can work.
+ * rgerhards, 2007-12-28
+ */
+static rsRetVal TCPSendInit(instanceData *pData)
+{
+ DEFiRet;
+
+ assert(pData != NULL);
+ if((pData->sock = TCPSendCreateSocket(pData, pData->f_addr)) <= 0)
+ iRet = RS_RET_TCP_SOCKCREATE_ERR;
+
+ return iRet;
+}
+
+
/* Sends a TCP message. It is first checked if the
* session is open and, if not, it is opened. Then the send
* is tried. If it fails, one silent re-try is made. If the send
@@ -623,109 +703,43 @@ static int TCPSendGSSSend(instanceData *pData, char *msg, size_t len)
* octet-counting, only this framing mode is used within the session.
* rgerhards, 2006-12-07
*/
-static int TCPSend(instanceData *pData, char *msg, size_t len)
+static int TCPSend(instanceData *pData, char *msg, size_t len,
+ rsRetVal (*initFunc)(instanceData*),
+ rsRetVal (*sendFunc)(instanceData*, char*, size_t),
+ rsRetVal (*prepRetryFunc)(instanceData*))
{
DEFiRet;
+ int bDone = 0;
int retry = 0;
- int bIsCompressed;
- int lenSend;
int bMsgMustBeFreed = 0;/* must msg be freed at end of function? 0 - no, 1 - yes */
assert(pData != NULL);
assert(msg != NULL);
assert(len > 0);
- iRet = TCPSendBldFrame(pData, &msg, &len, &bMsgMustBeFreed, &bIsCompressed);
- if(iRet != RS_RET_OK)
- return -1; /* TODO: change this code */
+ CHKiRet(TCPSendBldFrame(pData, &msg, &len, &bMsgMustBeFreed));
- while(1) { /* loop is broken when send succeeds or error occurs */
+ while(!bDone) { /* loop is broken when send succeeds or error occurs */
if(pData->sock <= 0) {
/* we need to open the socket first */
-# ifdef USE_GSSAPI
- if(gss_mode != GSSMODE_NONE) {
- if(TCPSendGSSInit(pData) != 0)
- return -1;
- } else
-# endif
- if((pData->sock = TCPSendCreateSocket(pData, pData->f_addr)) <= 0)
- return -1;
+ CHKiRet(initFunc(pData));
}
-# ifdef USE_GSSAPI
- if(gss_mode != GSSMODE_NONE) {
- if(TCPSendGSSSend(pData, msg, len) == 0) {
- if(bMsgMustBeFreed) {
- free(msg);
- }
- return 0;
- } else {
- if(retry == 0) {
- ++retry;
- /* try to recover */
- continue;
- } else {
- if(bMsgMustBeFreed)
- free(msg);
- dbgprintf("message not (tcp)send");
- return -1;
- }
- }
- } else {
-# endif
- lenSend = send(pData->sock, msg, len, 0);
- dbgprintf("TCP sent %d bytes, requested %ld, msg: '%s'\n", lenSend, (long) len,
- bIsCompressed ? "***compressed***" : msg);
- if((unsigned)lenSend == len) {
- /* all well */
- if(bMsgMustBeFreed) {
- free(msg);
- }
- return 0;
- } else if(lenSend != -1) {
- /* no real error, could "just" not send everything...
- * For the time being, we ignore this...
- * rgerhards, 2005-10-25
- */
- dbgprintf("message not completely (tcp)send, ignoring %d\n", lenSend);
- usleep(1000); /* experimental - might be benefitial in this situation */
- if(bMsgMustBeFreed)
- free(msg);
- return 0;
- }
-
- switch(errno) {
- case EMSGSIZE:
- dbgprintf("message not (tcp)send, too large\n");
- /* This is not a real error, so it is not flagged as one */
- if(bMsgMustBeFreed)
- free(msg);
- return 0;
- break;
- default:
- dbgprintf("message not (tcp)send");
- break;
- }
-
- if(retry == 0) {
- ++retry;
- /* try to recover */
- close(pData->sock);
- pData->sock = -1;
- } else {
- if(bMsgMustBeFreed)
- free(msg);
- return -1;
- }
-# ifdef USE_GSSAPI
+ iRet = sendFunc(pData, msg, len);
+
+ if(iRet == RS_RET_OK || retry > 0) {
+ /* we are done - either we succeeded or the retry failed */
+ bDone = 1;
+ } else { /* OK, one retry */
+ ++retry;
+ CHKiRet(prepRetryFunc(pData)); /* try to recover */
}
-# endif
}
- /*NOT REACHED*/
+finalize_it:
if(bMsgMustBeFreed)
free(msg);
- return -1; /* only to avoid compiler warning! */
+ return iRet;
}
@@ -871,7 +885,14 @@ dbgprintf("UDP send socket not yet initialized, doing it now\n");
CHKiRet(UDPSend(pData, psz, l));
} else {
/* forward via TCP */
- if(TCPSend(pData, psz, l) != 0) {
+ int ret;
+# ifdef USE_GSSAPI
+ if(gss_mode != GSSMODE_NONE) {
+ ret = TCPSend(pData, psz, l, TCPSendGSSInit, TCPSendGSSSend, TCPSendGSSPrepRetry);
+ } else
+# endif
+ ret = TCPSend(pData, psz, l, TCPSendInit, TCPSendFrame, TCPSendPrepRetry);
+ if(ret != 0) {
/* error! */
dbgprintf("error forwarding via tcp, suspending\n");
pData->eDestState = eDestFORW_SUSP;
diff --git a/rsyslog.h b/rsyslog.h
index cf950d98..20bbf1ef 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -89,6 +89,10 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_ADDRESS_UNKNOWN = -2020, /**< an address is unknown - not necessarily an error */
RS_RET_MALICIOUS_ENTITY = -2021, /**< there is an malicious entity involved */
RS_RET_NO_KERNEL_LOGSRC = -2022, /**< no source for kernel logs can be obtained */
+ RS_RET_TCP_SEND_ERROR = -2023, /**< error during TCP send process */
+ RS_RET_GSS_SEND_ERROR = -2024, /**< error during GSS (via TCP) send process */
+ RS_RET_TCP_SOCKCREATE_ERR = -2025, /**< error during creation of TCP socket */
+ RS_RET_GSS_SENDINIT_ERROR = -2024, /**< error during GSS (via TCP) send initialization process */
RS_RET_OK_DELETE_LISTENTRY = 1, /**< operation successful, but callee requested the deletion of an entry (special state) */
RS_RET_TERMINATE_NOW = 2, /**< operation successful, function is requested to terminate (mostly used with threads) */
RS_RET_NO_RUN = 3, /**< operation successful, but function does not like to be executed */