• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /* Hook for making making file descriptor functions close(), ioctl() extensible.
2     Copyright (C) 2009-2012 Free Software Foundation, Inc.
3     Written by Bruno Haible <bruno@clisp.org>, 2009.
4  
5     This program is free software: you can redistribute it and/or modify it
6     under the terms of the GNU General Public License as published
7     by the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9  
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17  
18  #include <config.h>
19  
20  /* Specification.  */
21  #include "fd-hook.h"
22  
23  #include <stdlib.h>
24  
25  /* Currently, this entire code is only needed for the handling of sockets
26     on native Windows platforms.  */
27  #if WINDOWS_SOCKETS
28  
29  /* The first and last link in the doubly linked list.
30     Initially the list is empty.  */
31  static struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };
32  
33  int
execute_close_hooks(const struct fd_hook * remaining_list,gl_close_fn primary,int fd)34  execute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,
35                       int fd)
36  {
37    if (remaining_list == &anchor)
38      /* End of list reached.  */
39      return primary (fd);
40    else
41      return remaining_list->private_close_fn (remaining_list->private_next,
42                                               primary, fd);
43  }
44  
45  int
execute_all_close_hooks(gl_close_fn primary,int fd)46  execute_all_close_hooks (gl_close_fn primary, int fd)
47  {
48    return execute_close_hooks (anchor.private_next, primary, fd);
49  }
50  
51  int
execute_ioctl_hooks(const struct fd_hook * remaining_list,gl_ioctl_fn primary,int fd,int request,void * arg)52  execute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,
53                       int fd, int request, void *arg)
54  {
55    if (remaining_list == &anchor)
56      /* End of list reached.  */
57      return primary (fd, request, arg);
58    else
59      return remaining_list->private_ioctl_fn (remaining_list->private_next,
60                                               primary, fd, request, arg);
61  }
62  
63  int
execute_all_ioctl_hooks(gl_ioctl_fn primary,int fd,int request,void * arg)64  execute_all_ioctl_hooks (gl_ioctl_fn primary,
65                           int fd, int request, void *arg)
66  {
67    return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);
68  }
69  
70  void
register_fd_hook(close_hook_fn close_hook,ioctl_hook_fn ioctl_hook,struct fd_hook * link)71  register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)
72  {
73    if (close_hook == NULL)
74      close_hook = execute_close_hooks;
75    if (ioctl_hook == NULL)
76      ioctl_hook = execute_ioctl_hooks;
77  
78    if (link->private_next == NULL && link->private_prev == NULL)
79      {
80        /* Add the link to the doubly linked list.  */
81        link->private_next = anchor.private_next;
82        link->private_prev = &anchor;
83        link->private_close_fn = close_hook;
84        link->private_ioctl_fn = ioctl_hook;
85        anchor.private_next->private_prev = link;
86        anchor.private_next = link;
87      }
88    else
89      {
90        /* The link is already in use.  */
91        if (link->private_close_fn != close_hook
92            || link->private_ioctl_fn != ioctl_hook)
93          abort ();
94      }
95  }
96  
97  void
unregister_fd_hook(struct fd_hook * link)98  unregister_fd_hook (struct fd_hook *link)
99  {
100    struct fd_hook *next = link->private_next;
101    struct fd_hook *prev = link->private_prev;
102  
103    if (next != NULL && prev != NULL)
104      {
105        /* The link is in use.  Remove it from the doubly linked list.  */
106        prev->private_next = next;
107        next->private_prev = prev;
108        /* Clear the link, to mark it unused.  */
109        link->private_next = NULL;
110        link->private_prev = NULL;
111        link->private_close_fn = NULL;
112        link->private_ioctl_fn = NULL;
113      }
114  }
115  
116  #endif
117