Blame SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch

6e9fa2
diff -up rsyslog-8.2102.0/runtime/nsd_gtls.c.orig rsyslog-8.2102.0/runtime/nsd_gtls.c
6e9fa2
--- rsyslog-8.2102.0/runtime/nsd_gtls.c.orig	2022-04-11 09:26:17.826271989 +0200
6e9fa2
+++ rsyslog-8.2102.0/runtime/nsd_gtls.c	2022-04-11 09:33:28.702012052 +0200
6e9fa2
@@ -556,7 +556,9 @@ gtlsRecordRecv(nsd_gtls_t *pThis)
6e9fa2
 	DEFiRet;
6e9fa2
 
6e9fa2
 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
6e9fa2
-	DBGPRINTF("gtlsRecordRecv: start\n");
6e9fa2
+	DBGPRINTF("gtlsRecordRecv: start (Pending Data: %zd | Wanted Direction: %s)\n",
6e9fa2
+		gnutls_record_check_pending(pThis->sess),
6e9fa2
+		(gnutls_record_get_direction(pThis->sess) == gtlsDir_READ ? "READ" : "WRITE") );
6e9fa2
 
6e9fa2
 	lenRcvd = gnutls_record_recv(pThis->sess, pThis->pszRcvBuf, NSD_GTLS_MAX_RCVBUF);
6e9fa2
 	if(lenRcvd >= 0) {
6e9fa2
@@ -581,14 +583,30 @@ gtlsRecordRecv(nsd_gtls_t *pThis)
6e9fa2
 					(NSD_GTLS_MAX_RCVBUF+lenRcvd));
6e9fa2
 				pThis->lenRcvBuf = NSD_GTLS_MAX_RCVBUF+lenRcvd;
6e9fa2
 			} else {
6e9fa2
-				goto sslerr;
6e9fa2
+				if (lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) {
6e9fa2
+					goto sslerragain;	/* Go to ERR AGAIN handling */
6e9fa2
+				} else {
6e9fa2
+					/* Do all other error handling */
6e9fa2
+					int gnuRet = lenRcvd;
6e9fa2
+					ABORTgnutls;
6e9fa2
+				}
6e9fa2
 			}
6e9fa2
 		}
6e9fa2
 	} else if(lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) {
6e9fa2
-sslerr:
6e9fa2
-		pThis->rtryCall = gtlsRtry_recv;
6e9fa2
-		dbgprintf("GnuTLS receive requires a retry (this most probably is OK and no error condition)\n");
6e9fa2
-		ABORT_FINALIZE(RS_RET_RETRY);
6e9fa2
+sslerragain:
6e9fa2
+		/* Check if the underlaying file descriptor needs to read or write data!*/
6e9fa2
+		if (gnutls_record_get_direction(pThis->sess) == gtlsDir_READ) {
6e9fa2
+			pThis->rtryCall = gtlsRtry_recv;
6e9fa2
+			dbgprintf("GnuTLS receive requires a retry, this most probably is OK and no error condition\n");
6e9fa2
+			ABORT_FINALIZE(RS_RET_RETRY);
6e9fa2
+		} else {
6e9fa2
+			uchar *pErr = gtlsStrerror(lenRcvd);
6e9fa2
+			LogError(0, RS_RET_GNUTLS_ERR, "GnuTLS receive error %zd has wrong read direction(wants write) "
6e9fa2
+				"- this could be caused by a broken connection. GnuTLS reports: %s\n",
6e9fa2
+				lenRcvd, pErr);
6e9fa2
+			free(pErr);
6e9fa2
+			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
6e9fa2
+		}
6e9fa2
 	} else {
6e9fa2
 		int gnuRet = lenRcvd;
6e9fa2
 		ABORTgnutls;
6e9fa2
@@ -1978,6 +1996,7 @@ static rsRetVal
6e9fa2
 Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
6e9fa2
 {
6e9fa2
 	int iSent;
6e9fa2
+	int wantsWriteData = 0;
6e9fa2
 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
6e9fa2
 	DEFiRet;
6e9fa2
 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
6e9fa2
@@ -1998,10 +2017,12 @@ Send(nsd_t *pNsd, uchar *pBuf, ssize_t *
6e9fa2
 			break;
6e9fa2
 		}
6e9fa2
 		if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN) {
6e9fa2
+			/* Check if the underlaying file descriptor needs to read or write data!*/
6e9fa2
+			wantsWriteData = gnutls_record_get_direction(pThis->sess);
6e9fa2
 			uchar *pErr = gtlsStrerror(iSent);
6e9fa2
-			LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d - this "
6e9fa2
-				"could be caused by a broken connection. GnuTLS reports: %s \n",
6e9fa2
-				iSent, pErr);
6e9fa2
+			LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d, wantsWriteData=%d - this "
6e9fa2
+				"could be caused by a broken connection. GnuTLS reports: %s\n",
6e9fa2
+				iSent, wantsWriteData, pErr);
6e9fa2
 			free(pErr);
6e9fa2
 			gnutls_perror(iSent);
6e9fa2
 			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
6e9fa2
diff -up rsyslog-8.2102.0/runtime/nsd_gtls.h.orig rsyslog-8.2102.0/runtime/nsd_gtls.h
6e9fa2
--- rsyslog-8.2102.0/runtime/nsd_gtls.h.orig	2022-04-11 09:26:32.744262781 +0200
6e9fa2
+++ rsyslog-8.2102.0/runtime/nsd_gtls.h	2022-04-11 09:34:29.909982895 +0200
6e9fa2
@@ -33,6 +33,11 @@ typedef enum {
6e9fa2
 	gtlsRtry_recv = 2
6e9fa2
 } gtlsRtryCall_t;		/**< IDs of calls that needs to be retried */
6e9fa2
 
6e9fa2
+typedef enum {
6e9fa2
+	gtlsDir_READ = 0,	/**< GNUTLS wants READ */
6e9fa2
+	gtlsDir_WRITE = 1	/**< GNUTLS wants WRITE */
6e9fa2
+} gtlsDirection_t;
6e9fa2
+
6e9fa2
 typedef nsd_if_t nsd_gtls_if_t; /* we just *implement* this interface */
6e9fa2
 
6e9fa2
 /* the nsd_gtls object */
6e9fa2
diff -up rsyslog-8.2102.0/runtime/nsdsel_gtls.c.orig rsyslog-8.2102.0/runtime/nsdsel_gtls.c
6e9fa2
--- rsyslog-8.2102.0/runtime/nsdsel_gtls.c.orig	2022-04-11 09:26:42.529256742 +0200
6e9fa2
+++ rsyslog-8.2102.0/runtime/nsdsel_gtls.c	2022-04-11 09:38:27.425869737 +0200
6e9fa2
@@ -81,6 +81,7 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsds
6e9fa2
 
6e9fa2
 	ISOBJ_TYPE_assert(pThis, nsdsel_gtls);
6e9fa2
 	ISOBJ_TYPE_assert(pNsdGTLS, nsd_gtls);
6e9fa2
+	DBGPRINTF("Add on nsd %p:\n", pNsdGTLS);
6e9fa2
 	if(pNsdGTLS->iMode == 1) {
6e9fa2
 		if(waitOp == NSDSEL_RD && gtlsHasRcvInBuffer(pNsdGTLS)) {
6e9fa2
 			++pThis->iBufferRcvReady;
6e9fa2
@@ -99,6 +100,8 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsds
6e9fa2
 		}
6e9fa2
 	}
6e9fa2
 
6e9fa2
+	dbgprintf("nsdsel_gtls: reached end on nsd %p, calling nsdsel_ptcp.Add with waitOp %d... \n", pNsdGTLS, waitOp);
6e9fa2
+
6e9fa2
 	/* if we reach this point, we need no special handling */
6e9fa2
 	CHKiRet(nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, waitOp));
6e9fa2
 
6e9fa2
@@ -120,7 +123,8 @@ Select(nsdsel_t *pNsdsel, int *piNumRead
6e9fa2
 	if(pThis->iBufferRcvReady > 0) {
6e9fa2
 		/* we still have data ready! */
6e9fa2
 		*piNumReady = pThis->iBufferRcvReady;
6e9fa2
-		dbgprintf("nsdsel_gtls: doing dummy select, data present\n");
6e9fa2
+		dbgprintf("nsdsel_gtls: doing dummy select for %p->iBufferRcvReady=%d, data present\n",
6e9fa2
+			pThis, pThis->iBufferRcvReady);
6e9fa2
 	} else {
6e9fa2
 		iRet = nsdsel_ptcp.Select(pThis->pTcp, piNumReady);
6e9fa2
 	}
6e9fa2
@@ -138,7 +142,7 @@ doRetry(nsd_gtls_t *pNsd)
6e9fa2
 	DEFiRet;
6e9fa2
 	int gnuRet;
6e9fa2
 
6e9fa2
-	dbgprintf("GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall);
6e9fa2
+	dbgprintf("doRetry: GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall);
6e9fa2
 
6e9fa2
 	/* We follow a common scheme here: first, we do the systen call and
6e9fa2
 	 * then we check the result. So far, the result is checked after the
6e9fa2
@@ -151,7 +155,7 @@ doRetry(nsd_gtls_t *pNsd)
6e9fa2
 		case gtlsRtry_handshake:
6e9fa2
 			gnuRet = gnutls_handshake(pNsd->sess);
6e9fa2
 			if(gnuRet == GNUTLS_E_AGAIN || gnuRet == GNUTLS_E_INTERRUPTED) {
6e9fa2
-				dbgprintf("GnuTLS handshake retry did not finish - "
6e9fa2
+				dbgprintf("doRetry: GnuTLS handshake retry did not finish - "
6e9fa2
 					"setting to retry (this is OK and can happen)\n");
6e9fa2
 				FINALIZE;
6e9fa2
 			} else if(gnuRet == 0) {
6e9fa2
@@ -167,9 +171,20 @@ doRetry(nsd_gtls_t *pNsd)
6e9fa2
 			}
6e9fa2
 			break;
6e9fa2
 		case gtlsRtry_recv:
6e9fa2
-			dbgprintf("retrying gtls recv, nsd: %p\n", pNsd);
6e9fa2
-			CHKiRet(gtlsRecordRecv(pNsd));
6e9fa2
-			pNsd->rtryCall = gtlsRtry_None; /* we are done */
6e9fa2
+			dbgprintf("doRetry: retrying gtls recv, nsd: %p\n", pNsd);
6e9fa2
+			iRet = gtlsRecordRecv(pNsd);
6e9fa2
+			if (iRet == RS_RET_RETRY) {
6e9fa2
+				// Check if there is pending data
6e9fa2
+				size_t stBytesLeft = gnutls_record_check_pending(pNsd->sess);
6e9fa2
+				if (stBytesLeft > 0) {
6e9fa2
+					// We are in retry and more data waiting, finalize it
6e9fa2
+					goto finalize_it;
6e9fa2
+				} else {
6e9fa2
+					dbgprintf("doRetry: gtlsRecordRecv returned RETRY, but there is no pending"
6e9fa2
+						"data on nsd: %p\n", pNsd);
6e9fa2
+				}
6e9fa2
+			}
6e9fa2
+			pNsd->rtryCall = gtlsRtry_None; /* no more data, we are done */
6e9fa2
 			gnuRet = 0;
6e9fa2
 			break;
6e9fa2
 		case gtlsRtry_None:
6e9fa2
@@ -241,7 +256,7 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd,
6e9fa2
 		 * socket. -- rgerhards, 2010-11-20
6e9fa2
 		 */
6e9fa2
 		if(pThis->iBufferRcvReady) {
6e9fa2
-			dbgprintf("nsd_gtls: dummy read, buffer not available for this FD\n");
6e9fa2
+			dbgprintf("nsd_gtls: dummy read, %p->buffer not available for this FD\n", pThis);
6e9fa2
 			*pbIsReady = 0;
6e9fa2
 			FINALIZE;
6e9fa2
 		}
6e9fa2
diff -up rsyslog-8.2102.0/runtime/tcpsrv.c.orig rsyslog-8.2102.0/runtime/tcpsrv.c
6e9fa2
--- rsyslog-8.2102.0/runtime/tcpsrv.c.orig	2022-04-11 09:27:00.376245726 +0200
6e9fa2
+++ rsyslog-8.2102.0/runtime/tcpsrv.c	2022-04-11 09:41:57.885777708 +0200
6e9fa2
@@ -609,14 +609,15 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t *
6e9fa2
 	int oserr = 0;
6e9fa2
 
6e9fa2
 	ISOBJ_TYPE_assert(pThis, tcpsrv);
6e9fa2
-	DBGPRINTF("netstream %p with new data\n", (*ppSess)->pStrm);
6e9fa2
+	prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
+	DBGPRINTF("netstream %p with new data from remote peer %s\n", (*ppSess)->pStrm, pszPeer);
6e9fa2
 	/* Receive message */
6e9fa2
 	iRet = pThis->pRcvData(*ppSess, buf, sizeof(buf), &iRcvd, &oserr);
6e9fa2
 	switch(iRet) {
6e9fa2
 	case RS_RET_CLOSED:
6e9fa2
 		if(pThis->bEmitMsgOnClose) {
6e9fa2
 			errno = 0;
6e9fa2
-			prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
+			// prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
 			LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote "
6e9fa2
 				"peer %s.\n", (*ppSess)->pStrm, pszPeer);
6e9fa2
 		}
6e9fa2
@@ -632,13 +633,13 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t *
6e9fa2
 			/* in this case, something went awfully wrong.
6e9fa2
 			 * We are instructed to terminate the session.
6e9fa2
 			 */
6e9fa2
-			prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
+			// prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
 			LogError(oserr, localRet, "Tearing down TCP Session from %s", pszPeer);
6e9fa2
 			CHKiRet(closeSess(pThis, ppSess, pPoll));
6e9fa2
 		}
6e9fa2
 		break;
6e9fa2
 	default:
6e9fa2
-		prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
+		// prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
6e9fa2
 		LogError(oserr, iRet, "netstream session %p from %s will be closed due to error",
6e9fa2
 				(*ppSess)->pStrm, pszPeer);
6e9fa2
 		CHKiRet(closeSess(pThis, ppSess, pPoll));
6e9fa2
@@ -838,6 +839,7 @@ RunSelect(tcpsrv_t *pThis, nsd_epworkset
6e9fa2
 		while(iTCPSess != -1) {
6e9fa2
 			/* TODO: access to pNsd is NOT really CLEAN, use method... */
6e9fa2
 			CHKiRet(nssel.Add(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD));
6e9fa2
+			DBGPRINTF("tcpsrv process session %d:\n", iTCPSess);
6e9fa2
 			/* now get next... */
6e9fa2
 			iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess);
6e9fa2
 		}