diff --git a/apps/app_ices.c b/apps/app_ices.c
index d0fdf5cf1631636136c1ed533e21395303532d05..a043d3de49a2420c9d3f4752fde52eef9d5a28cc 100644
--- a/apps/app_ices.c
+++ b/apps/app_ices.c
@@ -115,7 +115,6 @@ static int ices_exec(struct ast_channel *chan, const char *data)
 	int fds[2];
 	int ms = -1;
 	int pid = -1;
-	int flags;
 	struct ast_format *oreadformat;
 	struct ast_frame *f;
 	char filename[256]="";
@@ -130,8 +129,7 @@ static int ices_exec(struct ast_channel *chan, const char *data)
 		ast_log(LOG_WARNING, "Unable to create pipe\n");
 		return -1;
 	}
-	flags = fcntl(fds[1], F_GETFL);
-	fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
+	ast_fd_set_flags(fds[1], O_NONBLOCK);
 	
 	ast_stopstream(chan);
 
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index b418b282b556acc231d79816295bea22c217d979..67b1e12428177cc4e2821fd391a5ede333351e22 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -1193,7 +1193,6 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai
 {
 	/* Make a phone_pvt structure for this interface */
 	struct phone_pvt *tmp;
-	int flags;	
 	
 	tmp = ast_calloc(1, sizeof(*tmp));
 	if (tmp) {
@@ -1226,8 +1225,7 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai
 		ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
 #endif
 		tmp->mode = mode;
-		flags = fcntl(tmp->fd, F_GETFL);
-		fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
+		ast_fd_set_flags(tmp->fd, O_NONBLOCK);
 		tmp->owner = NULL;
 		ao2_cleanup(tmp->lastformat);
 		tmp->lastformat = NULL;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 559e5c05b488b5e6c8713bb74fc389f831d64081..b8cc7bf76518b6c77a657d28090c45ed8e55cdf2 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -2948,14 +2948,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
 			goto cleanup;
 		}
 
-		if ((flags = fcntl(tcptls_session->fd, F_GETFL)) == -1) {
-			ast_log(LOG_ERROR, "error setting socket to non blocking mode, fcntl() failed: %s\n", strerror(errno));
-			goto cleanup;
-		}
-
-		flags |= O_NONBLOCK;
-		if (fcntl(tcptls_session->fd, F_SETFL, flags) == -1) {
-			ast_log(LOG_ERROR, "error setting socket to non blocking mode, fcntl() failed: %s\n", strerror(errno));
+		if (ast_fd_set_flags(tcptls_session->fd, O_NONBLOCK)) {
 			goto cleanup;
 		}
 
diff --git a/channels/vgrabbers.c b/channels/vgrabbers.c
index 45dced4e1ffe63bce873f44334845b8e9b75f61f..3deb32fd15a580ef588ba41711f285a85fc57cb1 100644
--- a/channels/vgrabbers.c
+++ b/channels/vgrabbers.c
@@ -227,12 +227,8 @@ static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
 	v->b = *geom;
 	b = &v->b;	/* shorthand */
 
-	i = fcntl(fd, F_GETFL);
-	if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) {
-		/* non fatal, just emit a warning */
-		ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
-			dev, strerror(errno));
-	}
+	ast_fd_set_flags(fd, O_NONBLOCK);
+
 	/* set format for the camera.
 	 * In principle we could retry with a different format if the
 	 * one we are asking for is not supported.
diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c
index f207b64865e4606041b3111695f89d2ed48eaf25..edf5038cafad29e7d3cbae042813b7319e6929a5 100644
--- a/codecs/codec_dahdi.c
+++ b/codecs/codec_dahdi.c
@@ -615,7 +615,6 @@ static int dahdi_translate(struct ast_trans_pvt *pvt, uint32_t dst_dahdi_fmt, ui
 	/* Request translation through zap if possible */
 	int fd;
 	struct codec_dahdi_pvt *dahdip = pvt->pvt;
-	int flags;
 	int tried_once = 0;
 	const char *dev_filename = "/dev/dahdi/transcode";
 
@@ -661,11 +660,7 @@ retry:
 		return -1;
 	}
 
-	flags = fcntl(fd, F_GETFL);
-	if (flags > - 1) {
-		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
-			ast_log(LOG_WARNING, "Could not set non-block mode!\n");
-	}
+	ast_fd_set_flags(fd, O_NONBLOCK);
 
 	dahdip->fd = fd;
 
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index 03705b321ac58bd523c1aa5dedcffa357e626fb2..876e53c293ae65aa0a4516974e4a53cde89187fd 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -1142,4 +1142,44 @@ int ast_compare_versions(const char *version1, const char *version2);
  */
 int ast_check_ipv6(void);
 
+enum ast_fd_flag_operation {
+	AST_FD_FLAG_SET,
+	AST_FD_FLAG_CLEAR,
+};
+
+/*
+ * \brief Set flags on the given file descriptor
+ * \since 13.19
+ *
+ * If getting or setting flags of the given file descriptor fails, logs an
+ * error message.
+ *
+ * \param fd File descriptor to set flags on
+ * \param flags The flag(s) to set
+ *
+ * \return -1 on error
+ * \return 0 if successful
+ */
+#define ast_fd_set_flags(fd, flags) \
+	__ast_fd_set_flags((fd), (flags), AST_FD_FLAG_SET, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+/*
+ * \brief Clear flags on the given file descriptor
+ * \since 13.19
+ *
+ * If getting or setting flags of the given file descriptor fails, logs an
+ * error message.
+ *
+ * \param fd File descriptor to clear flags on
+ * \param flags The flag(s) to clear
+ *
+ * \return -1 on error
+ * \return 0 if successful
+ */
+#define ast_fd_clear_flags(fd, flags) \
+	__ast_fd_set_flags((fd), (flags), AST_FD_FLAG_CLEAR, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op,
+	const char *file, int lineno, const char *function);
+
 #endif /* _ASTERISK_UTILS_H */
diff --git a/main/alertpipe.c b/main/alertpipe.c
index fa6ec7bcce362c0ef51cc57e753dc835ae1fb677..7932a7346846ced08e8c0616c78acaaecc842a03 100644
--- a/main/alertpipe.c
+++ b/main/alertpipe.c
@@ -55,17 +55,8 @@ int ast_alertpipe_init(int alert_pipe[2])
 		ast_log(LOG_WARNING, "Failed to create alert pipe: %s\n", strerror(errno));
 		return -1;
 	} else {
-		int flags = fcntl(alert_pipe[0], F_GETFL);
-		if (fcntl(alert_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
-			ast_log(LOG_WARNING, "Failed to set non-blocking mode on alert pipe: %s\n",
-				strerror(errno));
-			ast_alertpipe_close(alert_pipe);
-			return -1;
-		}
-		flags = fcntl(alert_pipe[1], F_GETFL);
-		if (fcntl(alert_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
-			ast_log(LOG_WARNING, "Failed to set non-blocking mode on alert pipe: %s\n",
-				strerror(errno));
+		if (ast_fd_set_flags(alert_pipe[0], O_NONBLOCK)
+		   || ast_fd_set_flags(alert_pipe[1], O_NONBLOCK)) {
 			ast_alertpipe_close(alert_pipe);
 			return -1;
 		}
diff --git a/main/asterisk.c b/main/asterisk.c
index 0026b36d73fd0016139e1fcc47c14ceaafceb7e6..7edf66f34db8d54c2a159a962a1ea315c941d9d2 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1691,7 +1691,6 @@ static void *listener(void *unused)
 	int s;
 	socklen_t len;
 	int x;
-	int flags;
 	struct pollfd fds[1];
 	for (;;) {
 		if (ast_socket < 0)
@@ -1729,8 +1728,7 @@ static void *listener(void *unused)
 						close(s);
 						break;
 					}
-					flags = fcntl(consoles[x].p[1], F_GETFL);
-					fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
+					ast_fd_set_flags(consoles[x].p[1], O_NONBLOCK);
 					consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
 					/* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
 					   to know if the user didn't send the credentials. */
diff --git a/main/http.c b/main/http.c
index d1a443a4f0d0b8565963b54b945180eddb2a843e..e8d395b1542ec11793ee5354480363df58d35312 100644
--- a/main/http.c
+++ b/main/http.c
@@ -1955,9 +1955,7 @@ static void *httpd_helper_thread(void *data)
 	}
 
 	/* make sure socket is non-blocking */
-	flags = fcntl(ser->fd, F_GETFL);
-	flags |= O_NONBLOCK;
-	fcntl(ser->fd, F_SETFL, flags);
+	ast_fd_set_flags(ser->fd, O_NONBLOCK);
 
 	/* Setup HTTP worker private data to keep track of request body reading. */
 	ao2_cleanup(ser->private_data);
diff --git a/main/manager.c b/main/manager.c
index 5bc87d5476771b2a4e95e5572ec8a20288783a43..81052651e84e967fb36b7688dc80c9bdc02a4f3e 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -6684,9 +6684,7 @@ static void *session_do(void *data)
 	}
 
 	/* make sure socket is non-blocking */
-	flags = fcntl(ser->fd, F_GETFL);
-	flags |= O_NONBLOCK;
-	fcntl(ser->fd, F_SETFL, flags);
+	ast_fd_set_flags(ser->fd, O_NONBLOCK);
 
 	ao2_lock(session);
 	/* Hook to the tail of the event queue */
diff --git a/main/tcptls.c b/main/tcptls.c
index ef22094bf6f78231e4c232fef6fb1872f7b34cd3..3c2d6788f95c45c2ba839c0f6f5b6a163a2ae315 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -805,7 +805,7 @@ void *ast_tcptls_server_root(void *data)
 	pthread_t launched;
 
 	for (;;) {
-		int i, flags;
+		int i;
 
 		if (desc->periodic_fn) {
 			desc->periodic_fn(desc);
@@ -843,8 +843,7 @@ void *ast_tcptls_server_root(void *data)
 			close(fd);
 			continue;
 		}
-		flags = fcntl(fd, F_GETFL);
-		fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+		ast_fd_clear_flags(fd, O_NONBLOCK);
 		tcptls_session->fd = fd;
 		tcptls_session->parent = desc;
 		ast_sockaddr_copy(&tcptls_session->remote_address, &addr);
@@ -1061,7 +1060,6 @@ void ast_ssl_teardown(struct ast_tls_config *cfg)
 struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_session_instance *tcptls_session)
 {
 	struct ast_tcptls_session_args *desc;
-	int flags;
 
 	if (!(desc = tcptls_session->parent)) {
 		goto client_start_error;
@@ -1075,8 +1073,7 @@ struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_se
 		goto client_start_error;
 	}
 
-	flags = fcntl(desc->accept_fd, F_GETFL);
-	fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);
+	ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK);
 
 	if (desc->tls_cfg) {
 		desc->tls_cfg->enabled = 1;
@@ -1164,7 +1161,6 @@ error:
 
 void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
 {
-	int flags;
 	int x = 1;
 	int tls_changed = 0;
 
@@ -1267,8 +1263,7 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
 		ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
 		goto error;
 	}
-	flags = fcntl(desc->accept_fd, F_GETFL);
-	fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
+	ast_fd_set_flags(desc->accept_fd, O_NONBLOCK);
 	if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
 		ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
 			desc->name,
diff --git a/main/udptl.c b/main/udptl.c
index a568cd1ec4de856d6d9634622626f570e4baa7e0..44e9eb9bb7e6d02e8a7f42a5c327cd9f263675e1 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -1014,7 +1014,6 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct ast_sched_context *sched, s
 	int x;
 	int startplace;
 	int i;
-	long int flags;
 	RAII_VAR(struct udptl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
 
 	if (!cfg || !cfg->general) {
@@ -1045,8 +1044,7 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct ast_sched_context *sched, s
 		ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
 		return NULL;
 	}
-	flags = fcntl(udptl->fd, F_GETFL);
-	fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK);
+	ast_fd_set_flags(udptl->fd, O_NONBLOCK);
 
 #ifdef SO_NO_CHECK
 	if (cfg->general->nochecksums)
diff --git a/main/utils.c b/main/utils.c
index 03420304600e9f77a2a9d3cb13cacc6869fad9b5..0b8dc7aeb02f8cd2261a728e66a8c66317516b79 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -2798,3 +2798,37 @@ int ast_compare_versions(const char *version1, const char *version2)
 	}
 	return extra[0] - extra[1];
 }
+
+int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op,
+	const char *file, int lineno, const char *function)
+{
+	int f;
+
+	f = fcntl(fd, F_GETFL);
+	if (f == -1) {
+		ast_log(__LOG_ERROR, file, lineno, function,
+			"Failed to get fcntl() flags for file descriptor: %s\n", strerror(errno));
+		return -1;
+	}
+
+	switch (op) {
+	case AST_FD_FLAG_SET:
+		f |= flags;
+		break;
+	case AST_FD_FLAG_CLEAR:
+		f &= ~flags;
+		break;
+	default:
+		ast_assert(0);
+		break;
+	}
+
+	f = fcntl(fd, F_SETFL, f);
+	if (f == -1) {
+		ast_log(__LOG_ERROR, file, lineno, function,
+			"Failed to set fcntl() flags for file descriptor: %s\n", strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/res/res_agi.c b/res/res_agi.c
index 4caa13bb1ba03a94dc6e18cb3169666fef0aeb27..f19303f4dca90acbe6aeb9c7c6fed1c2740b3df0 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -2048,7 +2048,7 @@ static int handle_connection(const char *agiurl, const struct ast_sockaddr addr,
 	FastAGI defaults to port 4573 */
 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
 {
-	int s = 0, flags;
+	int s = 0;
 	char *host, *script;
 	int num_addrs = 0, i = 0;
 	struct ast_sockaddr *addrs;
@@ -2078,14 +2078,7 @@ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
 			continue;
 		}
 
-		if ((flags = fcntl(s, F_GETFL)) < 0) {
-			ast_log(LOG_WARNING, "fcntl(F_GETFL) failed: %s\n", strerror(errno));
-			close(s);
-			continue;
-		}
-
-		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
-			ast_log(LOG_WARNING, "fnctl(F_SETFL) failed: %s\n", strerror(errno));
+		if (ast_fd_set_flags(s, O_NONBLOCK)) {
 			close(s);
 			continue;
 		}
@@ -2251,9 +2244,8 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, int
 			close(toast[1]);
 			return AGI_RESULT_FAILURE;
 		}
-		res = fcntl(audio[1], F_GETFL);
-		if (res > -1)
-			res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
+
+		res = ast_fd_set_flags(audio[1], O_NONBLOCK);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
 			close(fromast[0]);
diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c
index 75a6eba64c94fb65a185c23cd1ae02b455842da9..a65fc8ae28507f5f131f59ab94f2bcf250bbc421 100644
--- a/res/res_http_websocket.c
+++ b/res/res_http_websocket.c
@@ -445,19 +445,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_is_secure)(struct ast_websocket *session
 
 int AST_OPTIONAL_API_NAME(ast_websocket_set_nonblock)(struct ast_websocket *session)
 {
-	int flags;
-
-	if ((flags = fcntl(session->fd, F_GETFL)) == -1) {
-		return -1;
-	}
-
-	flags |= O_NONBLOCK;
-
-	if ((flags = fcntl(session->fd, F_SETFL, flags)) == -1) {
-		return -1;
-	}
-
-	return 0;
+	return ast_fd_set_flags(session->fd, O_NONBLOCK);
 }
 
 int AST_OPTIONAL_API_NAME(ast_websocket_set_timeout)(struct ast_websocket *session, int timeout)
@@ -944,17 +932,11 @@ static struct ast_http_uri websocketuri = {
 /*! \brief Simple echo implementation which echoes received text and binary frames */
 static void websocket_echo_callback(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
 {
-	int flags, res;
+	int res;
 
 	ast_debug(1, "Entering WebSocket echo loop\n");
 
-	if ((flags = fcntl(ast_websocket_fd(session), F_GETFL)) == -1) {
-		goto end;
-	}
-
-	flags |= O_NONBLOCK;
-
-	if (fcntl(ast_websocket_fd(session), F_SETFL, flags) == -1) {
+	if (ast_fd_set_flags(ast_websocket_fd(session), O_NONBLOCK)) {
 		goto end;
 	}
 
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index d791516761629d66de4c5ec43712292b62260159..dee9c2da8edcd6b35ada5a06a29d9dab556270b9 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -924,7 +924,6 @@ static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, co
 static struct mohdata *mohalloc(struct mohclass *cl)
 {
 	struct mohdata *moh;
-	long flags;
 
 	if (!(moh = ast_calloc(1, sizeof(*moh))))
 		return NULL;
@@ -936,10 +935,8 @@ static struct mohdata *mohalloc(struct mohclass *cl)
 	}
 
 	/* Make entirely non-blocking */
-	flags = fcntl(moh->pipe[0], F_GETFL);
-	fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
-	flags = fcntl(moh->pipe[1], F_GETFL);
-	fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
+	ast_fd_set_flags(moh->pipe[0], O_NONBLOCK);
+	ast_fd_set_flags(moh->pipe[1], O_NONBLOCK);
 
 	moh->f.frametype = AST_FRAME_VOICE;
 	moh->f.subclass.format = cl->format;
diff --git a/res/res_pktccops.c b/res/res_pktccops.c
index 037e533d3caa5742a663a5aa16aac9de684daf3b..8a4c3a5c011b00732ee188de2598c29c55af4ca0 100644
--- a/res/res_pktccops.c
+++ b/res/res_pktccops.c
@@ -650,7 +650,7 @@ static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts,
 
 static int cops_connect(char *host, char *port)
 {
-	int s, sfd = -1, flags;
+	int s, sfd = -1;
 	struct addrinfo hints;
 	struct addrinfo *rp;
 	struct addrinfo *result;
@@ -676,8 +676,7 @@ static int cops_connect(char *host, char *port)
 		if (sfd == -1) {
 			ast_log(LOG_WARNING, "Failed socket\n");
 		}
-		flags = fcntl(sfd, F_GETFL);
-		fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
+		ast_fd_set_flags(sfd, O_NONBLOCK);
 #ifdef HAVE_SO_NOSIGPIPE
 		setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &trueval, sizeof(trueval));
 #endif
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 5271d1bf4725e3989409532f433da1933c9c1784..c921f36b315ed2312b58302a2bada1f7dca01299 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -2765,8 +2765,7 @@ static int create_new_socket(const char *type, int af)
 		}
 		ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno));
 	} else {
-		long flags = fcntl(sock, F_GETFL);
-		fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+		ast_fd_set_flags(sock, O_NONBLOCK);
 #ifdef SO_NO_CHECK
 		if (nochecksums) {
 			setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c
index 1e76720ecdfffef2d0dd92a25e850402774cf198..0654059f98260e743b0312626a643c6938037b72 100644
--- a/res/res_timing_pthread.c
+++ b/res/res_timing_pthread.c
@@ -132,9 +132,7 @@ static void *pthread_timer_open(void)
 	}
 
 	for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) {
-		int flags = fcntl(timer->pipe[i], F_GETFL);
-		flags |= O_NONBLOCK;
-		fcntl(timer->pipe[i], F_SETFL, flags);
+		ast_fd_set_flags(timer->pipe[i], O_NONBLOCK);
 	}
 	
 	ao2_lock(pthread_timers);