18dffb485Schristos /* Hook for making file descriptor functions close(), ioctl() extensible.
2*4b169a6bSchristos Copyright (C) 2009-2022 Free Software Foundation, Inc.
38dffb485Schristos Written by Bruno Haible <bruno@clisp.org>, 2009.
48dffb485Schristos
5*4b169a6bSchristos This file is free software: you can redistribute it and/or modify
6*4b169a6bSchristos it under the terms of the GNU Lesser General Public License as
7*4b169a6bSchristos published by the Free Software Foundation; either version 2.1 of the
8*4b169a6bSchristos License, or (at your option) any later version.
98dffb485Schristos
10*4b169a6bSchristos This file is distributed in the hope that it will be useful,
118dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4b169a6bSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4b169a6bSchristos GNU Lesser General Public License for more details.
148dffb485Schristos
15*4b169a6bSchristos You should have received a copy of the GNU Lesser General Public License
168dffb485Schristos along with this program. If not, see <https://www.gnu.org/licenses/>. */
178dffb485Schristos
188dffb485Schristos #include <config.h>
198dffb485Schristos
208dffb485Schristos /* Specification. */
218dffb485Schristos #include "fd-hook.h"
228dffb485Schristos
238dffb485Schristos #include <stdlib.h>
248dffb485Schristos
258dffb485Schristos /* Currently, this entire code is only needed for the handling of sockets
268dffb485Schristos on native Windows platforms. */
278dffb485Schristos #if WINDOWS_SOCKETS
288dffb485Schristos
298dffb485Schristos /* The first and last link in the doubly linked list.
308dffb485Schristos Initially the list is empty. */
318dffb485Schristos static struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };
328dffb485Schristos
338dffb485Schristos int
execute_close_hooks(const struct fd_hook * remaining_list,gl_close_fn primary,int fd)348dffb485Schristos execute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,
358dffb485Schristos int fd)
368dffb485Schristos {
378dffb485Schristos if (remaining_list == &anchor)
388dffb485Schristos /* End of list reached. */
398dffb485Schristos return primary (fd);
408dffb485Schristos else
418dffb485Schristos return remaining_list->private_close_fn (remaining_list->private_next,
428dffb485Schristos primary, fd);
438dffb485Schristos }
448dffb485Schristos
458dffb485Schristos int
execute_all_close_hooks(gl_close_fn primary,int fd)468dffb485Schristos execute_all_close_hooks (gl_close_fn primary, int fd)
478dffb485Schristos {
488dffb485Schristos return execute_close_hooks (anchor.private_next, primary, fd);
498dffb485Schristos }
508dffb485Schristos
518dffb485Schristos int
execute_ioctl_hooks(const struct fd_hook * remaining_list,gl_ioctl_fn primary,int fd,int request,void * arg)528dffb485Schristos execute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,
538dffb485Schristos int fd, int request, void *arg)
548dffb485Schristos {
558dffb485Schristos if (remaining_list == &anchor)
568dffb485Schristos /* End of list reached. */
578dffb485Schristos return primary (fd, request, arg);
588dffb485Schristos else
598dffb485Schristos return remaining_list->private_ioctl_fn (remaining_list->private_next,
608dffb485Schristos primary, fd, request, arg);
618dffb485Schristos }
628dffb485Schristos
638dffb485Schristos int
execute_all_ioctl_hooks(gl_ioctl_fn primary,int fd,int request,void * arg)648dffb485Schristos execute_all_ioctl_hooks (gl_ioctl_fn primary,
658dffb485Schristos int fd, int request, void *arg)
668dffb485Schristos {
678dffb485Schristos return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);
688dffb485Schristos }
698dffb485Schristos
708dffb485Schristos void
register_fd_hook(close_hook_fn close_hook,ioctl_hook_fn ioctl_hook,struct fd_hook * link)718dffb485Schristos register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)
728dffb485Schristos {
738dffb485Schristos if (close_hook == NULL)
748dffb485Schristos close_hook = execute_close_hooks;
758dffb485Schristos if (ioctl_hook == NULL)
768dffb485Schristos ioctl_hook = execute_ioctl_hooks;
778dffb485Schristos
788dffb485Schristos if (link->private_next == NULL && link->private_prev == NULL)
798dffb485Schristos {
808dffb485Schristos /* Add the link to the doubly linked list. */
818dffb485Schristos link->private_next = anchor.private_next;
828dffb485Schristos link->private_prev = &anchor;
838dffb485Schristos link->private_close_fn = close_hook;
848dffb485Schristos link->private_ioctl_fn = ioctl_hook;
858dffb485Schristos anchor.private_next->private_prev = link;
868dffb485Schristos anchor.private_next = link;
878dffb485Schristos }
888dffb485Schristos else
898dffb485Schristos {
908dffb485Schristos /* The link is already in use. */
918dffb485Schristos if (link->private_close_fn != close_hook
928dffb485Schristos || link->private_ioctl_fn != ioctl_hook)
938dffb485Schristos abort ();
948dffb485Schristos }
958dffb485Schristos }
968dffb485Schristos
978dffb485Schristos void
unregister_fd_hook(struct fd_hook * link)988dffb485Schristos unregister_fd_hook (struct fd_hook *link)
998dffb485Schristos {
1008dffb485Schristos struct fd_hook *next = link->private_next;
1018dffb485Schristos struct fd_hook *prev = link->private_prev;
1028dffb485Schristos
1038dffb485Schristos if (next != NULL && prev != NULL)
1048dffb485Schristos {
1058dffb485Schristos /* The link is in use. Remove it from the doubly linked list. */
1068dffb485Schristos prev->private_next = next;
1078dffb485Schristos next->private_prev = prev;
1088dffb485Schristos /* Clear the link, to mark it unused. */
1098dffb485Schristos link->private_next = NULL;
1108dffb485Schristos link->private_prev = NULL;
1118dffb485Schristos link->private_close_fn = NULL;
1128dffb485Schristos link->private_ioctl_fn = NULL;
1138dffb485Schristos }
1148dffb485Schristos }
1158dffb485Schristos
1168dffb485Schristos #endif
117