diff --git a/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch
new file mode 100644
index 0000000..b717972
--- /dev/null
+++ b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch
@@ -0,0 +1,47 @@
+diff -up rsyslog-8.2102.0/doc/configuration/modules/imfile.html.state-file-leaking-doc rsyslog-8.2102.0/doc/configuration/modules/imfile.html
+--- rsyslog-8.2102.0/doc/configuration/modules/imfile.html.state-file-leaking-doc	2021-02-15 12:53:31.000000000 +0100
++++ rsyslog-8.2102.0/doc/configuration/modules/imfile.html	2022-03-29 10:35:07.187827004 +0200
+@@ -294,6 +294,28 @@ rsyslog needs write permissions to work
+ also might require SELinux definitions (or similar for other enhanced security
+ systems).</p>
+ </div>
++<div class="section" id="deletestateonfilemove">
++<h4>deleteStateOnFileMove<a class="headerlink" href="#deletestateonfilemove" title="Permalink to this headline">¶</a></h4>
++<table border="1" class="colwidths-auto parameter-table docutils">
++<thead valign="bottom">
++<tr class="row-odd"><th class="head">type</th>
++<th class="head">default</th>
++<th class="head">mandatory</th>
++<th class="head"><code class="docutils literal notranslate"><span class="pre">obsolete</span> <span class="pre">legacy</span></code> directive</th>
++</tr>
++</thead>
++<tbody valign="top">
++<tr class="row-even"><td>binary</td>
++<td>off</td>
++<td>no</td>
++<td>none</td>
++</tr>
++</tbody>
++</table>
++<p>This parameter controls if state files are deleted if their associated main file is rotated via move. Usually, this is a good idea, because otherwise state files are not deleted when log rotation occurs.</p>
++
++<p>However, there is one situation where not deleting associated state file after log rotation makes sense: this is the case if a monitored file is later moved back to the same location as it was before.</p>
++</div>
+ </div>
+ <div class="section" id="input-parameters">
+ <h3>Input Parameters<a class="headerlink" href="#input-parameters" title="Permalink to this headline">¶</a></h3>
+@@ -1214,6 +1236,7 @@ and Others.</p>
+ <li><a class="reference internal" href="#sortfiles">sortFiles</a></li>
+ <li><a class="reference internal" href="#pollinginterval">PollingInterval</a></li>
+ <li><a class="reference internal" href="#statefile-directory">statefile.directory</a></li>
++<li><a class="reference internal" href="#deletestateonfilemove">deleteStateOnFileMove</a></li>
+ </ul>
+ </li>
+ <li><a class="reference internal" href="#input-parameters">Input Parameters</a><ul>
+@@ -1311,4 +1334,4 @@ and Others.</p>
+     <div class="footer" role="contentinfo">
+     </div>
+   </body>
+-</html>
+\ No newline at end of file
++</html>
diff --git a/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch
new file mode 100644
index 0000000..161f90c
--- /dev/null
+++ b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch
@@ -0,0 +1,162 @@
+diff -up rsyslog-8.2102.0/plugins/imfile/imfile.c.state-file-leaking rsyslog-8.2102.0/plugins/imfile/imfile.c
+--- rsyslog-8.2102.0/plugins/imfile/imfile.c.state-file-leaking	2021-01-18 11:21:14.000000000 +0100
++++ rsyslog-8.2102.0/plugins/imfile/imfile.c	2022-03-28 12:51:03.572554843 +0200
+@@ -259,6 +259,7 @@ struct modConfData_s {
+ 				   Must be manually reset to 0 if desired. Helper for
+ 				   polling mode.
+ 				 */
++	sbool deleteStateOnFileMove;
+ };
+ static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+ static modConfData_t *runModConf = NULL;/* modConf ptr to use for run process */
+@@ -305,7 +306,8 @@ static struct cnfparamdescr modpdescr[]
+ 	{ "sortfiles", eCmdHdlrBinary, 0 },
+ 	{ "statefile.directory", eCmdHdlrString, 0 },
+ 	{ "normalizepath", eCmdHdlrBinary, 0 },
+-	{ "mode", eCmdHdlrGetWord, 0 }
++	{ "mode", eCmdHdlrGetWord, 0 },
++	{ "deletestateonfilemove", eCmdHdlrBinary, 0 }
+ };
+ static struct cnfparamblk modpblk =
+ 	{ CNFPARAMBLK_VERSION,
+@@ -545,11 +547,20 @@ static int
+ in_setupWatch(act_obj_t *const act, const int is_file)
+ {
+ 	int wd = -1;
++	int flags;
+ 	if(runModConf->opMode != OPMODE_INOTIFY)
+ 		goto done;
+ 
+-	wd = inotify_add_watch(ino_fd, act->name,
+-		(is_file) ? IN_MODIFY|IN_DONT_FOLLOW : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
++	// wd = inotify_add_watch(ino_fd, act->name,
++	// 	(is_file) ? IN_MODIFY|IN_DONT_FOLLOW : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
++	if(is_file)
++		flags = IN_MODIFY|IN_DONT_FOLLOW;
++	else if(runModConf->deleteStateOnFileMove)
++		flags = IN_CREATE|IN_DELETE|IN_MOVED_TO;
++	else
++		flags = IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO;
++	wd = inotify_add_watch(ino_fd, act->name, flags);
++
+ 	if(wd < 0) {
+ 		if (errno == EACCES) { /* There is high probability of selinux denial on top-level paths */
+ 			DBGPRINTF("imfile: permission denied when adding watch for '%s'\n", act->name);
+@@ -713,7 +724,7 @@ act_obj_add(fs_edge_t *const edge, const
+ 	char basename[MAXFNAME];
+ 	DEFiRet;
+ 	int fd = -1;
+-	
++
+ 	DBGPRINTF("act_obj_add: edge %p, name '%s' (source '%s')\n", edge, name, source? source : "---");
+ 	for(act = edge->active ; act != NULL ; act = act->next) {
+ 		if(!strcmp(act->name, name)) {
+@@ -977,9 +988,18 @@ act_obj_destroy(act_obj_t *const act, co
+ 	if(act == NULL)
+ 		return;
+ 
+-	DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n",
+-		act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted,
+-		act->in_move);
++	// DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n",
++	// 	act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted,
++	// 	act->in_move);
++	if (runModConf->deleteStateOnFileMove) {
++		DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d\n",
++			act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted);
++	} else {
++		DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n",
++			act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm,
++			is_deleted, act->in_move);
++	}
++
+ 	if(act->is_symlink && is_deleted) {
+ 		act_obj_t *target_act;
+ 		for(target_act = act->edge->active ; target_act != NULL ; target_act = target_act->next) {
+@@ -996,13 +1016,15 @@ act_obj_destroy(act_obj_t *const act, co
+ 		pollFile(act); /* get any left-over data */
+ 		if(inst->bRMStateOnDel) {
+ 			statefn = getStateFileName(act, statefile, sizeof(statefile));
+-			getFullStateFileName(statefn, "", toDel, sizeof(toDel)); // TODO: check!
++			// getFullStateFileName(statefn, "", toDel, sizeof(toDel)); // TODO: check!
++			getFullStateFileName(statefn, act->file_id, toDel, sizeof(toDel)); // TODO: check!
+ 			statefn = toDel;
+ 		}
+ 		persistStrmState(act);
+ 		strm.Destruct(&act->pStrm);
+ 		/* we delete state file after destruct in case strm obj initiated a write */
+-		if(is_deleted && !act->in_move && inst->bRMStateOnDel) {
++		// if(is_deleted && !act->in_move && inst->bRMStateOnDel) {
++		if(is_deleted && inst->bRMStateOnDel && (runModConf->deleteStateOnFileMove || !act->in_move)) {
+ 			DBGPRINTF("act_obj_destroy: deleting state file %s\n", statefn);
+ 			unlink((char*)statefn);
+ 		}
+@@ -1012,6 +1034,7 @@ act_obj_destroy(act_obj_t *const act, co
+ 	}
+ 	#ifdef HAVE_INOTIFY_INIT
+ 	if(act->wd != -1) {
++		inotify_rm_watch(ino_fd, act->wd);
+ 		wdmapDel(act->wd);
+ 	}
+ 	#endif
+@@ -2026,6 +2049,7 @@ CODESTARTbeginCnfLoad
+ 	loadModConf->timeoutGranularity = 1000; /* default: 1 second */
+ 	loadModConf->haveReadTimeouts = 0; /* default: no timeout */
+ 	loadModConf->normalizePath = 1;
++	loadModConf->deleteStateOnFileMove = 0;
+ 	loadModConf->sortFiles = GLOB_NOSORT;
+ 	loadModConf->stateFileDirectory = NULL;
+ 	loadModConf->conf_tree = calloc(sizeof(fs_node_t), 1);
+@@ -2085,6 +2109,8 @@ CODESTARTsetModCnf
+ 			loadModConf->stateFileDirectory = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ 		} else if(!strcmp(modpblk.descr[i].name, "normalizepath")) {
+ 			loadModConf->normalizePath = (sbool) pvals[i].val.d.n;
++		} else if(!strcmp(modpblk.descr[i].name, "deletestateonfilemove")) {
++			loadModConf->deleteStateOnFileMove = (sbool) pvals[i].val.d.n;
+ 		} else if(!strcmp(modpblk.descr[i].name, "mode")) {
+ 			if(!es_strconstcmp(pvals[i].val.d.estr, "polling"))
+ 				loadModConf->opMode = OPMODE_POLLING;
+@@ -2388,16 +2414,35 @@ in_processEvent(struct inotify_event *ev
+ 	DBGPRINTF("in_processEvent process Event %x is_file %d, act->name '%s'\n",
+ 		ev->mask, etry->act->edge->is_file, etry->act->name);
+ 
+-	if((ev->mask & IN_MOVED_FROM)) {
+-		flag_in_move(etry->act->edge->node->edges, ev->name);
+-	}
+-	if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO))  {
+-		fs_node_walk(etry->act->edge->node, poll_tree);
+-	} else if(etry->act->edge->is_file && !(etry->act->is_symlink)) {
+-		in_handleFileEvent(ev, etry); // esentially poll_file()!
++	// if((ev->mask & IN_MOVED_FROM)) {
++	// 	flag_in_move(etry->act->edge->node->edges, ev->name);
++	// }
++	// if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO))  {
++	// 	fs_node_walk(etry->act->edge->node, poll_tree);
++	// } else if(etry->act->edge->is_file && !(etry->act->is_symlink)) {
++	// 	in_handleFileEvent(ev, etry); // esentially poll_file()!
++	// } else {
++	// 	fs_node_walk(etry->act->edge->node, poll_tree);
++	// }
++	if(!runModConf->deleteStateOnFileMove) {
++		if((ev->mask & IN_MOVED_FROM)) {
++			flag_in_move(etry->act->edge->node->edges, ev->name);
++		}
++		if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO))  {
++			fs_node_walk(etry->act->edge->node, poll_tree);
++		} else if(etry->act->edge->is_file && !(etry->act->is_symlink)) {
++			in_handleFileEvent(ev, etry); // esentially poll_file()!
++		} else {
++			fs_node_walk(etry->act->edge->node, poll_tree);
++		}
+ 	} else {
+-		fs_node_walk(etry->act->edge->node, poll_tree);
++		if((ev->mask & IN_MODIFY) && etry->act->edge->is_file && !(etry->act->is_symlink)) {
++			in_handleFileEvent(ev, etry); // esentially poll_file()!
++		} else {
++			fs_node_walk(etry->act->edge->node, poll_tree);
++		}
+ 	}
++
+ done:	return;
+ }
+ 
diff --git a/SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch b/SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch
new file mode 100644
index 0000000..0c3a3a7
--- /dev/null
+++ b/SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch
@@ -0,0 +1,215 @@
+diff -up rsyslog-8.2102.0/runtime/nsd_gtls.c.orig rsyslog-8.2102.0/runtime/nsd_gtls.c
+--- rsyslog-8.2102.0/runtime/nsd_gtls.c.orig	2022-04-11 09:26:17.826271989 +0200
++++ rsyslog-8.2102.0/runtime/nsd_gtls.c	2022-04-11 09:33:28.702012052 +0200
+@@ -556,7 +556,9 @@ gtlsRecordRecv(nsd_gtls_t *pThis)
+ 	DEFiRet;
+ 
+ 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
+-	DBGPRINTF("gtlsRecordRecv: start\n");
++	DBGPRINTF("gtlsRecordRecv: start (Pending Data: %zd | Wanted Direction: %s)\n",
++		gnutls_record_check_pending(pThis->sess),
++		(gnutls_record_get_direction(pThis->sess) == gtlsDir_READ ? "READ" : "WRITE") );
+ 
+ 	lenRcvd = gnutls_record_recv(pThis->sess, pThis->pszRcvBuf, NSD_GTLS_MAX_RCVBUF);
+ 	if(lenRcvd >= 0) {
+@@ -581,14 +583,30 @@ gtlsRecordRecv(nsd_gtls_t *pThis)
+ 					(NSD_GTLS_MAX_RCVBUF+lenRcvd));
+ 				pThis->lenRcvBuf = NSD_GTLS_MAX_RCVBUF+lenRcvd;
+ 			} else {
+-				goto sslerr;
++				if (lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) {
++					goto sslerragain;	/* Go to ERR AGAIN handling */
++				} else {
++					/* Do all other error handling */
++					int gnuRet = lenRcvd;
++					ABORTgnutls;
++				}
+ 			}
+ 		}
+ 	} else if(lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) {
+-sslerr:
+-		pThis->rtryCall = gtlsRtry_recv;
+-		dbgprintf("GnuTLS receive requires a retry (this most probably is OK and no error condition)\n");
+-		ABORT_FINALIZE(RS_RET_RETRY);
++sslerragain:
++		/* Check if the underlaying file descriptor needs to read or write data!*/
++		if (gnutls_record_get_direction(pThis->sess) == gtlsDir_READ) {
++			pThis->rtryCall = gtlsRtry_recv;
++			dbgprintf("GnuTLS receive requires a retry, this most probably is OK and no error condition\n");
++			ABORT_FINALIZE(RS_RET_RETRY);
++		} else {
++			uchar *pErr = gtlsStrerror(lenRcvd);
++			LogError(0, RS_RET_GNUTLS_ERR, "GnuTLS receive error %zd has wrong read direction(wants write) "
++				"- this could be caused by a broken connection. GnuTLS reports: %s\n",
++				lenRcvd, pErr);
++			free(pErr);
++			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
++		}
+ 	} else {
+ 		int gnuRet = lenRcvd;
+ 		ABORTgnutls;
+@@ -1978,6 +1996,7 @@ static rsRetVal
+ Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
+ {
+ 	int iSent;
++	int wantsWriteData = 0;
+ 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
+ 	DEFiRet;
+ 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
+@@ -1998,10 +2017,12 @@ Send(nsd_t *pNsd, uchar *pBuf, ssize_t *
+ 			break;
+ 		}
+ 		if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN) {
++			/* Check if the underlaying file descriptor needs to read or write data!*/
++			wantsWriteData = gnutls_record_get_direction(pThis->sess);
+ 			uchar *pErr = gtlsStrerror(iSent);
+-			LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d - this "
+-				"could be caused by a broken connection. GnuTLS reports: %s \n",
+-				iSent, pErr);
++			LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d, wantsWriteData=%d - this "
++				"could be caused by a broken connection. GnuTLS reports: %s\n",
++				iSent, wantsWriteData, pErr);
+ 			free(pErr);
+ 			gnutls_perror(iSent);
+ 			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
+diff -up rsyslog-8.2102.0/runtime/nsd_gtls.h.orig rsyslog-8.2102.0/runtime/nsd_gtls.h
+--- rsyslog-8.2102.0/runtime/nsd_gtls.h.orig	2022-04-11 09:26:32.744262781 +0200
++++ rsyslog-8.2102.0/runtime/nsd_gtls.h	2022-04-11 09:34:29.909982895 +0200
+@@ -33,6 +33,11 @@ typedef enum {
+ 	gtlsRtry_recv = 2
+ } gtlsRtryCall_t;		/**< IDs of calls that needs to be retried */
+ 
++typedef enum {
++	gtlsDir_READ = 0,	/**< GNUTLS wants READ */
++	gtlsDir_WRITE = 1	/**< GNUTLS wants WRITE */
++} gtlsDirection_t;
++
+ typedef nsd_if_t nsd_gtls_if_t; /* we just *implement* this interface */
+ 
+ /* the nsd_gtls object */
+diff -up rsyslog-8.2102.0/runtime/nsdsel_gtls.c.orig rsyslog-8.2102.0/runtime/nsdsel_gtls.c
+--- rsyslog-8.2102.0/runtime/nsdsel_gtls.c.orig	2022-04-11 09:26:42.529256742 +0200
++++ rsyslog-8.2102.0/runtime/nsdsel_gtls.c	2022-04-11 09:38:27.425869737 +0200
+@@ -81,6 +81,7 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsds
+ 
+ 	ISOBJ_TYPE_assert(pThis, nsdsel_gtls);
+ 	ISOBJ_TYPE_assert(pNsdGTLS, nsd_gtls);
++	DBGPRINTF("Add on nsd %p:\n", pNsdGTLS);
+ 	if(pNsdGTLS->iMode == 1) {
+ 		if(waitOp == NSDSEL_RD && gtlsHasRcvInBuffer(pNsdGTLS)) {
+ 			++pThis->iBufferRcvReady;
+@@ -99,6 +100,8 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsds
+ 		}
+ 	}
+ 
++	dbgprintf("nsdsel_gtls: reached end on nsd %p, calling nsdsel_ptcp.Add with waitOp %d... \n", pNsdGTLS, waitOp);
++
+ 	/* if we reach this point, we need no special handling */
+ 	CHKiRet(nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, waitOp));
+ 
+@@ -120,7 +123,8 @@ Select(nsdsel_t *pNsdsel, int *piNumRead
+ 	if(pThis->iBufferRcvReady > 0) {
+ 		/* we still have data ready! */
+ 		*piNumReady = pThis->iBufferRcvReady;
+-		dbgprintf("nsdsel_gtls: doing dummy select, data present\n");
++		dbgprintf("nsdsel_gtls: doing dummy select for %p->iBufferRcvReady=%d, data present\n",
++			pThis, pThis->iBufferRcvReady);
+ 	} else {
+ 		iRet = nsdsel_ptcp.Select(pThis->pTcp, piNumReady);
+ 	}
+@@ -138,7 +142,7 @@ doRetry(nsd_gtls_t *pNsd)
+ 	DEFiRet;
+ 	int gnuRet;
+ 
+-	dbgprintf("GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall);
++	dbgprintf("doRetry: GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall);
+ 
+ 	/* We follow a common scheme here: first, we do the systen call and
+ 	 * then we check the result. So far, the result is checked after the
+@@ -151,7 +155,7 @@ doRetry(nsd_gtls_t *pNsd)
+ 		case gtlsRtry_handshake:
+ 			gnuRet = gnutls_handshake(pNsd->sess);
+ 			if(gnuRet == GNUTLS_E_AGAIN || gnuRet == GNUTLS_E_INTERRUPTED) {
+-				dbgprintf("GnuTLS handshake retry did not finish - "
++				dbgprintf("doRetry: GnuTLS handshake retry did not finish - "
+ 					"setting to retry (this is OK and can happen)\n");
+ 				FINALIZE;
+ 			} else if(gnuRet == 0) {
+@@ -167,9 +171,20 @@ doRetry(nsd_gtls_t *pNsd)
+ 			}
+ 			break;
+ 		case gtlsRtry_recv:
+-			dbgprintf("retrying gtls recv, nsd: %p\n", pNsd);
+-			CHKiRet(gtlsRecordRecv(pNsd));
+-			pNsd->rtryCall = gtlsRtry_None; /* we are done */
++			dbgprintf("doRetry: retrying gtls recv, nsd: %p\n", pNsd);
++			iRet = gtlsRecordRecv(pNsd);
++			if (iRet == RS_RET_RETRY) {
++				// Check if there is pending data
++				size_t stBytesLeft = gnutls_record_check_pending(pNsd->sess);
++				if (stBytesLeft > 0) {
++					// We are in retry and more data waiting, finalize it
++					goto finalize_it;
++				} else {
++					dbgprintf("doRetry: gtlsRecordRecv returned RETRY, but there is no pending"
++						"data on nsd: %p\n", pNsd);
++				}
++			}
++			pNsd->rtryCall = gtlsRtry_None; /* no more data, we are done */
+ 			gnuRet = 0;
+ 			break;
+ 		case gtlsRtry_None:
+@@ -241,7 +256,7 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd,
+ 		 * socket. -- rgerhards, 2010-11-20
+ 		 */
+ 		if(pThis->iBufferRcvReady) {
+-			dbgprintf("nsd_gtls: dummy read, buffer not available for this FD\n");
++			dbgprintf("nsd_gtls: dummy read, %p->buffer not available for this FD\n", pThis);
+ 			*pbIsReady = 0;
+ 			FINALIZE;
+ 		}
+diff -up rsyslog-8.2102.0/runtime/tcpsrv.c.orig rsyslog-8.2102.0/runtime/tcpsrv.c
+--- rsyslog-8.2102.0/runtime/tcpsrv.c.orig	2022-04-11 09:27:00.376245726 +0200
++++ rsyslog-8.2102.0/runtime/tcpsrv.c	2022-04-11 09:41:57.885777708 +0200
+@@ -609,14 +609,15 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t *
+ 	int oserr = 0;
+ 
+ 	ISOBJ_TYPE_assert(pThis, tcpsrv);
+-	DBGPRINTF("netstream %p with new data\n", (*ppSess)->pStrm);
++	prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
++	DBGPRINTF("netstream %p with new data from remote peer %s\n", (*ppSess)->pStrm, pszPeer);
+ 	/* Receive message */
+ 	iRet = pThis->pRcvData(*ppSess, buf, sizeof(buf), &iRcvd, &oserr);
+ 	switch(iRet) {
+ 	case RS_RET_CLOSED:
+ 		if(pThis->bEmitMsgOnClose) {
+ 			errno = 0;
+-			prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
++			// prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
+ 			LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote "
+ 				"peer %s.\n", (*ppSess)->pStrm, pszPeer);
+ 		}
+@@ -632,13 +633,13 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t *
+ 			/* in this case, something went awfully wrong.
+ 			 * We are instructed to terminate the session.
+ 			 */
+-			prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
++			// prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
+ 			LogError(oserr, localRet, "Tearing down TCP Session from %s", pszPeer);
+ 			CHKiRet(closeSess(pThis, ppSess, pPoll));
+ 		}
+ 		break;
+ 	default:
+-		prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
++		// prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
+ 		LogError(oserr, iRet, "netstream session %p from %s will be closed due to error",
+ 				(*ppSess)->pStrm, pszPeer);
+ 		CHKiRet(closeSess(pThis, ppSess, pPoll));
+@@ -838,6 +839,7 @@ RunSelect(tcpsrv_t *pThis, nsd_epworkset
+ 		while(iTCPSess != -1) {
+ 			/* TODO: access to pNsd is NOT really CLEAN, use method... */
+ 			CHKiRet(nssel.Add(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD));
++			DBGPRINTF("tcpsrv process session %d:\n", iTCPSess);
+ 			/* now get next... */
+ 			iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess);
+ 		}
diff --git a/SOURCES/rsyslog-8.2102.0-rhbz2064318-errfile-maxsize-doc.patch b/SOURCES/rsyslog-8.2102.0-rhbz2064318-errfile-maxsize-doc.patch
new file mode 100644
index 0000000..01a6fc4
--- /dev/null
+++ b/SOURCES/rsyslog-8.2102.0-rhbz2064318-errfile-maxsize-doc.patch
@@ -0,0 +1,51 @@
+--- a/source/configuration/actions.rst	2020-01-13 09:35:54.000000000 +0100
++++ b/source/configuration/actions.rst	2022-03-09 10:46:23.945881936 +0100
+@@ -90,6 +90,12 @@
+    provided to the action in question, the action name as well as
+    the rsyslog status code roughly explaining why it failed.
+ 
++-  **action.errorfile.maxsize** integer
++
++   In some cases, error file needs to be limited in size.
++   This option allows specifying a maximum size, in bytes, for the error file.
++   When error file reaches that size, no more errors are written to it.
++
+ -  **action.execOnlyOnceEveryInterval** integer
+ 
+    Execute action only if the last execute is at last seconds in the
+--- a/build/_sources/configuration/actions.rst.txt	2020-01-13 09:35:54.000000000 +0100
++++ b/build/_sources/configuration/actions.rst.txt	2022-03-09 11:17:44.391213038 +0100
+@@ -90,6 +90,12 @@
+    provided to the action in question, the action name as well as
+    the rsyslog status code roughly explaining why it failed.
+ 
++-  **action.errorfile.maxsize** integer
++
++   In some cases, error file needs to be limited in size.
++   This option allows specifying a maximum size, in bytes, for the error file.
++   When error file reaches that size, no more errors are written to it.
++
+ -  **action.execOnlyOnceEveryInterval** integer
+ 
+    Execute action only if the last execute is at last seconds in the
+--- a/build/configuration/actions.html	2021-02-15 12:53:30.000000000 +0100
++++ b/build/configuration/actions.html	2022-03-09 11:27:04.035799702 +0100
+@@ -122,6 +122,11 @@
+ provided to the action in question, the action name as well as
+ the rsyslog status code roughly explaining why it failed.</p>
+ </li>
++<li><p class="first"><strong>action.errorfile.maxsize</strong> integer</p>
++<p>In some cases, error file needs to be limited in size.
++This option allows specifying a maximum size, in bytes, for the error file.
++When error file reaches that size, no more errors are written to it.</p>
++</li>
+ <li><p class="first"><strong>action.execOnlyOnceEveryInterval</strong> integer</p>
+ <p>Execute action only if the last execute is at last seconds in the
+ past (more info in ommail, but may be used with any action)</p>
+@@ -672,4 +677,4 @@
+     <div class="footer" role="contentinfo">
+     </div>
+   </body>
+-</html>
+\ No newline at end of file
++</html>
diff --git a/SOURCES/rsyslog-8.2102.0-rhbz2064318-errfile-maxsize.patch b/SOURCES/rsyslog-8.2102.0-rhbz2064318-errfile-maxsize.patch
new file mode 100644
index 0000000..ba5bec9
--- /dev/null
+++ b/SOURCES/rsyslog-8.2102.0-rhbz2064318-errfile-maxsize.patch
@@ -0,0 +1,192 @@
+--- rsyslog-8.2102.0-ori/action.c	2021-02-15 12:06:16.000000000 +0100
++++ rsyslog-8.2102.0-changes/action.c	2022-03-10 11:00:11.027242300 +0100
+@@ -198,6 +198,7 @@
+ 	{ "name", eCmdHdlrGetWord, 0 }, /* legacy: actionname */
+ 	{ "type", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: actionname */
+ 	{ "action.errorfile", eCmdHdlrString, 0 },
++	{ "action.errorfile.maxsize", eCmdHdlrInt, 0 },
+ 	{ "action.writeallmarkmessages", eCmdHdlrBinary, 0 }, /* legacy: actionwriteallmarkmessages */
+ 	{ "action.execonlyeverynthtime", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyeverynthtime */
+ 	{ "action.execonlyeverynthtimetimeout", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyeverynthtimetimeout */
+@@ -400,6 +401,8 @@
+ 	pThis->iResumeRetryCount = 0;
+ 	pThis->pszName = NULL;
+ 	pThis->pszErrFile = NULL;
++	pThis->maxErrFileSize = 0;
++	pThis->errFileWritten = 0;
+ 	pThis->pszExternalStateFile = NULL;
+ 	pThis->fdErrFile = -1;
+ 	pThis->bWriteAllMarkMsgs = 1;
+@@ -1436,6 +1439,14 @@
+ 				pThis->pszName, pThis->pszErrFile);
+ 			goto done;
+ 		}
++		if (pThis->maxErrFileSize > 0) {
++			struct stat statbuf;
++			if (fstat(pThis->fdErrFile, &statbuf) == -1) {
++				LogError(errno, RS_RET_ERR, "failed to fstat %s", pThis->pszErrFile);
++				goto done;
++			}
++			pThis->errFileWritten += statbuf.st_size;
++		}
+ 	}
+ 
+ 	for(int i = 0 ; i < nparams ; ++i) {
+@@ -1454,16 +1465,26 @@
+ 		char *const rendered = strdup((char*)fjson_object_to_json_string(etry));
+ 		if(rendered == NULL)
+ 			goto done;
+-		const size_t toWrite = strlen(rendered) + 1;
+-		/* note: we use the '\0' inside the string to store a LF - we do not
+-		 * otherwise need it and it safes us a copy/realloc.
+-		 */
+-		rendered[toWrite-1] = '\n'; /* NO LONGER A STRING! */
+-		const ssize_t wrRet = write(pThis->fdErrFile, rendered, toWrite);
+-		if(wrRet != (ssize_t) toWrite) {
+-			LogError(errno, RS_RET_IO_ERROR,
+-				"action %s: error writing errorFile %s, write returned %lld",
+-				pThis->pszName, pThis->pszErrFile, (long long) wrRet);
++		size_t toWrite = strlen(rendered) + 1;
++		// Check if need to truncate the amount of bytes to write
++		if (pThis->maxErrFileSize > 0) {
++			if (pThis->errFileWritten + toWrite > pThis->maxErrFileSize) {
++				// Truncate to the pending available
++				toWrite = pThis->maxErrFileSize - pThis->errFileWritten;
++			}
++			pThis->errFileWritten += toWrite;
++		}
++		if(toWrite > 0) {
++			/* note: we use the '\0' inside the string to store a LF - we do not
++			 * otherwise need it and it safes us a copy/realloc.
++			 */
++			rendered[toWrite-1] = '\n'; /* NO LONGER A STRING! */
++			const ssize_t wrRet = write(pThis->fdErrFile, rendered, toWrite);
++			if(wrRet != (ssize_t) toWrite) {
++				LogError(errno, RS_RET_IO_ERROR,
++					"action %s: error writing errorFile %s, write returned %lld",
++					pThis->pszName, pThis->pszErrFile, (long long) wrRet);
++			}
+ 		}
+ 		free(rendered);
+ 
+@@ -2048,6 +2069,8 @@
+ 			continue; /* this is handled seperately during module select! */
+ 		} else if(!strcmp(pblk.descr[i].name, "action.errorfile")) {
+ 			pAction->pszErrFile = es_str2cstr(pvals[i].val.d.estr, NULL);
++		} else if(!strcmp(pblk.descr[i].name, "action.errorfile.maxsize")) {
++			pAction->maxErrFileSize = pvals[i].val.d.n;
+ 		} else if(!strcmp(pblk.descr[i].name, "action.externalstate.file")) {
+ 			pAction->pszExternalStateFile = es_str2cstr(pvals[i].val.d.estr, NULL);
+ 		} else if(!strcmp(pblk.descr[i].name, "action.writeallmarkmessages")) {
+--- rsyslog-8.2102.0-ori/action.h	2020-10-03 19:06:47.000000000 +0200
++++ rsyslog-8.2102.0-changes/action.h	2022-03-04 11:36:47.024588972 +0100
+@@ -77,6 +77,8 @@
+ 	/* error file */
+ 	const char *pszErrFile;
+ 	int fdErrFile;
++	size_t maxErrFileSize;
++	size_t errFileWritten;
+ 	pthread_mutex_t mutErrFile;
+ 	/* external stat file system */
+ 	const char *pszExternalStateFile;
+--- rsyslog-8.2102.0-ori/tests/Makefile.am	2021-02-15 12:06:16.000000000 +0100
++++ rsyslog-8.2102.0-changes/tests/Makefile.am	2022-03-04 11:38:01.625095709 +0100
+@@ -695,7 +695,8 @@
+ 	mysql-actq-mt.sh \
+ 	mysql-actq-mt-withpause.sh \
+ 	action-tx-single-processing.sh \
+-	action-tx-errfile.sh
++	action-tx-errfile.sh \
++	action-tx-errfile-maxsize.sh
+ 
+ mysql-basic.log: mysqld-start.log
+ mysql-basic-cnf6.log: mysqld-start.log
+@@ -2156,6 +2157,8 @@
+ 	sndrcv_omudpspoof_nonstdpt.sh \
+ 	sndrcv_gzip.sh \
+ 	action-tx-single-processing.sh \
++	omfwd-errfile-maxsize.sh \
++	action-tx-errfile-maxsize.sh \
+ 	action-tx-errfile.sh \
+ 	testsuites/action-tx-errfile.result \
+ 	pipeaction.sh \
+--- rsyslog-8.2102.0-ori/tests/omfwd-errfile-maxsize.sh	1970-01-01 01:00:00.000000000 +0100
++++ rsyslog-8.2102.0-changes/tests/omfwd-errfile-maxsize.sh	2022-03-04 11:39:02.060506234 +0100
+@@ -0,0 +1,17 @@
++#!/bin/bash
++# part of the rsyslog project, released under ASL 2.0
++. ${srcdir:=.}/diag.sh init
++
++export MAX_ERROR_SIZE=1999
++
++generate_conf
++add_conf '
++action(type="omfwd" target="1.2.3.4" port="1234" Protocol="tcp" NetworkNamespace="doesNotExist"
++       action.errorfile="'$RSYSLOG2_OUT_LOG'" action.errorfile.maxsize="'$MAX_ERROR_SIZE'")
++'
++startup
++shutdown_when_empty
++wait_shutdown
++check_file_exists ${RSYSLOG2_OUT_LOG}
++file_size_check ${RSYSLOG2_OUT_LOG} ${MAX_ERROR_SIZE}
++exit_test
+--- rsyslog-8.2102.0-ori/tests/action-tx-errfile-maxsize.sh	1970-01-01 01:00:00.000000000 +0100
++++ rsyslog-8.2102.0-changes/tests/action-tx-errfile-maxsize.sh	2022-03-04 11:59:22.592796989 +0100
+@@ -0,0 +1,35 @@
++#!/bin/bash
++# part of the rsyslog project, released under ASL 2.0
++
++. ${srcdir:=.}/diag.sh init
++
++export NUMMESSAGES=50 # enough to generate big file
++export MAX_ERROR_SIZE=100
++
++generate_conf
++add_conf '
++$ModLoad ../plugins/ommysql/.libs/ommysql
++global(errormessagestostderr.maxnumber="5")
++
++template(type="string" name="tpl" string="insert into SystemEvents (Message, Facility) values (\"%msg%\", %$!facility%)" option.sql="on")
++
++if((not($msg contains "error")) and ($msg contains "msgnum:")) then {
++	set $.num = field($msg, 58, 2);
++	if $.num % 2 == 0 then {
++		set $!facility = $syslogfacility;
++	} else {
++		set $/cntr = 0;
++	}
++	action(type="ommysql" name="mysql_action_errfile_maxsize" server="127.0.0.1" template="tpl"
++	       db="'$RSYSLOG_DYNNAME'" uid="rsyslog" pwd="testbench" action.errorfile="'$RSYSLOG2_OUT_LOG'" action.errorfile.maxsize="'$MAX_ERROR_SIZE'")
++}
++'
++mysql_prep_for_test
++startup
++injectmsg
++shutdown_when_empty
++wait_shutdown
++mysql_get_data
++check_file_exists ${RSYSLOG2_OUT_LOG}
++file_size_check ${RSYSLOG2_OUT_LOG} ${MAX_ERROR_SIZE}
++exit_test
+--- rsyslog-8.2102.0/tests/omfwd-errfile-maxsize-filled.sh	1970-01-01 01:00:00.000000000 +0100
++++ rsyslog-8.2102.0-changes/tests/omfwd-errfile-maxsize-filled.sh	2022-03-08 16:24:01.174365289 +0100
+@@ -0,0 +1,19 @@
++#!/bin/bash
++# part of the rsyslog project, released under ASL 2.0
++. ${srcdir:=.}/diag.sh init
++ERRFILE=$(mktemp)
++export MAX_ERROR_SIZE=1999
++export INITIAL_FILE_SIZE=$((MAX_ERROR_SIZE - 100))
++dd if=/dev/urandom of=${ERRFILE}  bs=1 count=${INITIAL_FILE_SIZE}
++generate_conf
++add_conf '
++action(type="omfwd" target="1.2.3.4" port="1234" Protocol="tcp" NetworkNamespace="doesNotExist"
++       action.errorfile="'$ERRFILE'" action.errorfile.maxsize="'$MAX_ERROR_SIZE'")
++'
++startup
++shutdown_when_empty
++wait_shutdown
++check_file_exists ${ERRFILE}
++file_size_check ${ERRFILE} ${MAX_ERROR_SIZE}
++exit_test
++rm ${ERRFILE}
diff --git a/SPECS/rsyslog.spec b/SPECS/rsyslog.spec
index 46890de..d5988f2 100644
--- a/SPECS/rsyslog.spec
+++ b/SPECS/rsyslog.spec
@@ -5,7 +5,7 @@
 Summary: Enhanced system logging and kernel message trapping daemon
 Name: rsyslog
 Version: 8.2102.0
-Release: 101%{?dist}.1
+Release: 105%{?dist}
 License: (GPLv3+ and ASL 2.0)
 URL: http://www.rsyslog.com/
 Source0: http://www.rsyslog.com/files/download/rsyslog/%{name}-%{version}.tar.gz
@@ -18,15 +18,20 @@ Source5: rsyslog.service
 # separatae sub-package with it statically linked(see rhbz#1713427)
 Source6: qpid-proton-0.34.0.tar.gz
 
-Patch0: openssl3-compatibility.patch
-Patch1: rsyslog-8.1911.0-rhbz1659898-imjournal-default-tag.patch
-Patch2: rsyslog-8.2102.0-rhbz1960536-fdleak-on-fsync.patch
-Patch3: rsyslog-8.2102.0-rhbz1886400-reduce-default-timeout.patch
-Patch4: rsyslog-8.2102.0-rhbz1984616-imuxsock-ratelimit.patch
-Patch5: rsyslog-8.2102.0-rhbz1984489-remove-abort-on-id-resolution-fail.patch
-Patch6: rsyslog-8.2102.0-rhbz1938863-covscan.patch
-Patch7: rsyslog-8.2102.0-rhbz2021076-prioritize-SAN.patch
-Patch8: rsyslog-8.37.0-rhbz2081396-CVE-2022-24903.patch
+Patch0:  rsyslog-8.2102.0-rhbz2064318-errfile-maxsize-doc.patch
+Patch1:  rsyslog-8.1911.0-rhbz1659898-imjournal-default-tag.patch
+Patch2:  rsyslog-8.2102.0-rhbz1960536-fdleak-on-fsync.patch
+Patch3:  rsyslog-8.2102.0-rhbz1886400-reduce-default-timeout.patch
+Patch4:  rsyslog-8.2102.0-rhbz1984616-imuxsock-ratelimit.patch
+Patch5:  rsyslog-8.2102.0-rhbz1984489-remove-abort-on-id-resolution-fail.patch
+Patch6:  rsyslog-8.2102.0-rhbz1938863-covscan.patch
+Patch7:  rsyslog-8.2102.0-rhbz2021076-prioritize-SAN.patch
+Patch8:  rsyslog-8.2102.0-rhbz2064318-errfile-maxsize.patch
+Patch9:  openssl3-compatibility.patch
+Patch10: rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch
+Patch11: rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch
+Patch12: rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch
+Patch13: rsyslog-8.37.0-rhbz2081396-CVE-2022-24903.patch
 
 BuildRequires: make
 BuildRequires: gcc
@@ -251,6 +256,8 @@ container metadata.
 %prep
 # set up rsyslog-doc sources
 %setup -q -a 1 -T -c
+%patch0 -p1
+
 rm -r LICENSE README.md source build/objects.inv
 mv build doc
 # set up rsyslog sources
@@ -258,17 +265,21 @@ mv build doc
 # Unpack qpid-proton for rhel
 %setup -q -D -T -b 6
 
-%patch1 -p1 -b .default-tag
-%patch2 -p1 -b .fd-leak-on-fsync
-%patch3 -p1 -b .timeout
-%patch4 -p1 -b .imuxsock-rate-limit
-%patch5 -p1 -b .abort-on-id-resolution-fail
-%patch6 -p1 -b .covscan
-%patch7 -p1 -b .prioritize-SAN
-%patch8 -p1 -b .CVE-24903
+%patch1  -p1 -b .default-tag
+%patch2  -p1 -b .fd-leak-on-fsync
+%patch3  -p1 -b .timeout
+%patch4  -p1 -b .imuxsock-rate-limit
+%patch5  -p1 -b .abort-on-id-resolution-fail
+%patch6  -p1 -b .covscan
+%patch7  -p1 -b .prioritize-SAN
+%patch8  -p1 -b .errfile-maxsize
+%patch10 -p1 -b .statefile-fix
+%patch11 -p1
+%patch12 -p1 -b .gnutls-broken-connection
+%patch13 -p1 -b .CVE
 
 pushd ..
-%patch0 -p1 -b .openssl-compatibility
+%patch9 -p1 -b .openssl-compatibility
 popd
 
 %build
@@ -530,9 +541,24 @@ done
 
 
 %changelog
-* Tue May 10 2022 Attila Lakatos <alakatos@redhat.com> - 8.2102.0-101.1
+* Mon May 09 2022 Attila Lakatos <alakatos@redhat.com> - 8.2102.0-105
 - Address CVE-2022-24903, Heap-based overflow in TCP syslog server
-  resolves: rhbz#2081402
+  resolves: rhbz#2081403
+
+* Tue Apr 19 2022 Attila Lakatos <alakatos@redhat.com> - 8.2102.0-104
+- Do not save patched doc files
+  resolves: rhbz#2069664
+
+* Tue Apr 05 2022 Attila Lakatos <alakatos@redhat.com> - 8.2102.0-103
+- Add deleteStateOnFileMove imfile module option
+  resolves: rhbz#2069664
+- Add inotify_rm_watch() inotify API call when object needs to be destroyed
+  resolves: rhbz#2070528
+- Fix error handling in gtlsRecordRecv, which can cause full CPU usage
+
+* Fri Mar 11 2022 Sergio Arroutbi <sarroutb@redhat.com> - 8.2102.0-102
+- Add action.errorfile.maxsize parameter
+  resolves: rhbz#2064318
 
 * Wed Jan 19 2022 Sergio Arroutbi <sarroutb@redhat.com> - 8.2102.0-101
 - Prioritize SAN