/src/samba/lib/tevent/tevent_fd.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | common events code for fd events |
5 | | |
6 | | Copyright (C) Stefan Metzmacher 2009 |
7 | | |
8 | | ** NOTE! The following LGPL license applies to the tevent |
9 | | ** library. This does NOT imply that all of Samba is released |
10 | | ** under the LGPL |
11 | | |
12 | | This library is free software; you can redistribute it and/or |
13 | | modify it under the terms of the GNU Lesser General Public |
14 | | License as published by the Free Software Foundation; either |
15 | | version 3 of the License, or (at your option) any later version. |
16 | | |
17 | | This library is distributed in the hope that it will be useful, |
18 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 | | Lesser General Public License for more details. |
21 | | |
22 | | You should have received a copy of the GNU Lesser General Public |
23 | | License along with this library; if not, see <http://www.gnu.org/licenses/>. |
24 | | */ |
25 | | |
26 | | #include "replace.h" |
27 | | #define TEVENT_DEPRECATED 1 |
28 | | #include "tevent.h" |
29 | | #include "tevent_internal.h" |
30 | | #include "tevent_util.h" |
31 | | |
32 | | _PRIVATE_ |
33 | | const char *tevent_common_fd_str(struct tevent_common_fd_buf *buf, |
34 | | const char *description, |
35 | | const struct tevent_fd *fde) |
36 | 0 | { |
37 | 0 | snprintf(buf->buf, sizeof(buf->buf), |
38 | 0 | "%s[fde=%p," |
39 | 0 | "fd=%d,flags=0x%x(%s%s%s),%s]", |
40 | 0 | description, fde, fde->fd, |
41 | 0 | fde->flags, |
42 | 0 | (fde->flags & TEVENT_FD_ERROR) ? "E" : "", |
43 | 0 | (fde->flags & TEVENT_FD_READ) ? "R" : "", |
44 | 0 | (fde->flags & TEVENT_FD_WRITE) ? "W" : "", |
45 | 0 | fde->handler_name); |
46 | 0 | return buf->buf; |
47 | 0 | } |
48 | | |
49 | | int tevent_common_fd_destructor(struct tevent_fd *fde) |
50 | 0 | { |
51 | 0 | struct tevent_fd *primary = NULL; |
52 | |
|
53 | 0 | if (fde->destroyed) { |
54 | 0 | tevent_common_check_double_free(fde, "tevent_fd double free"); |
55 | 0 | goto done; |
56 | 0 | } |
57 | 0 | fde->destroyed = true; |
58 | | |
59 | | /* |
60 | | * The caller should have cleared it from any mpx relationship |
61 | | */ |
62 | 0 | primary = tevent_common_fd_mpx_primary(fde); |
63 | 0 | if (primary != fde) { |
64 | 0 | tevent_abort(fde->event_ctx, |
65 | 0 | "tevent_common_fd_destructor: fde not mpx primary"); |
66 | 0 | } else if (fde->mpx.list != NULL) { |
67 | 0 | tevent_abort(fde->event_ctx, |
68 | 0 | "tevent_common_fd_destructor: fde has mpx fdes"); |
69 | 0 | } |
70 | |
|
71 | 0 | if (fde->event_ctx) { |
72 | 0 | tevent_trace_fd_callback(fde->event_ctx, fde, TEVENT_EVENT_TRACE_DETACH); |
73 | 0 | DLIST_REMOVE(fde->event_ctx->fd_events, fde); |
74 | 0 | } |
75 | |
|
76 | 0 | if (fde->close_fn) { |
77 | 0 | fde->close_fn(fde->event_ctx, fde, fde->fd, fde->private_data); |
78 | 0 | fde->fd = -1; |
79 | 0 | fde->close_fn = NULL; |
80 | 0 | } |
81 | |
|
82 | 0 | fde->event_ctx = NULL; |
83 | 0 | done: |
84 | 0 | if (fde->busy) { |
85 | 0 | return -1; |
86 | 0 | } |
87 | 0 | fde->wrapper = NULL; |
88 | |
|
89 | 0 | return 0; |
90 | 0 | } |
91 | | |
92 | | struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx, |
93 | | int fd, uint16_t flags, |
94 | | tevent_fd_handler_t handler, |
95 | | void *private_data, |
96 | | const char *handler_name, |
97 | | const char *location) |
98 | 0 | { |
99 | 0 | struct tevent_fd *fde; |
100 | | |
101 | | /* tevent will crash later on select() if we save |
102 | | * a negative file descriptor. Better to fail here |
103 | | * so that consumers will be able to debug it |
104 | | */ |
105 | 0 | if (fd < 0) return NULL; |
106 | | |
107 | 0 | fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd); |
108 | 0 | if (!fde) return NULL; |
109 | | |
110 | 0 | *fde = (struct tevent_fd) { |
111 | 0 | .event_ctx = ev, |
112 | 0 | .fd = fd, |
113 | 0 | .flags = flags, |
114 | 0 | .handler = handler, |
115 | 0 | .private_data = private_data, |
116 | 0 | .handler_name = handler_name, |
117 | 0 | .location = location, |
118 | 0 | }; |
119 | |
|
120 | 0 | tevent_trace_fd_callback(fde->event_ctx, fde, TEVENT_EVENT_TRACE_ATTACH); |
121 | 0 | DLIST_ADD(ev->fd_events, fde); |
122 | 0 | tevent_common_fd_mpx_reinit(fde); |
123 | |
|
124 | 0 | talloc_set_destructor(fde, tevent_common_fd_destructor); |
125 | | |
126 | |
|
127 | 0 | return fde; |
128 | 0 | } |
129 | | uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde) |
130 | 0 | { |
131 | 0 | return fde->flags; |
132 | 0 | } |
133 | | |
134 | | void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags) |
135 | 0 | { |
136 | 0 | if (fde->flags == flags) return; |
137 | 0 | fde->flags = flags; |
138 | 0 | } |
139 | | |
140 | | void tevent_common_fd_set_close_fn(struct tevent_fd *fde, |
141 | | tevent_fd_close_fn_t close_fn) |
142 | 0 | { |
143 | 0 | fde->close_fn = close_fn; |
144 | 0 | } |
145 | | |
146 | | int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags, |
147 | | bool *removed) |
148 | 0 | { |
149 | 0 | struct tevent_context *handler_ev = fde->event_ctx; |
150 | |
|
151 | 0 | if (removed != NULL) { |
152 | 0 | *removed = false; |
153 | 0 | } |
154 | |
|
155 | 0 | if (fde->event_ctx == NULL) { |
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | 0 | fde->busy = true; |
160 | 0 | if (fde->wrapper != NULL) { |
161 | 0 | handler_ev = fde->wrapper->wrap_ev; |
162 | |
|
163 | 0 | tevent_wrapper_push_use_internal(handler_ev, fde->wrapper); |
164 | 0 | fde->wrapper->ops->before_fd_handler( |
165 | 0 | fde->wrapper->wrap_ev, |
166 | 0 | fde->wrapper->private_state, |
167 | 0 | fde->wrapper->main_ev, |
168 | 0 | fde, |
169 | 0 | flags, |
170 | 0 | fde->handler_name, |
171 | 0 | fde->location); |
172 | 0 | } |
173 | 0 | tevent_trace_fd_callback(fde->event_ctx, fde, TEVENT_EVENT_TRACE_BEFORE_HANDLER); |
174 | 0 | fde->handler(handler_ev, fde, flags, fde->private_data); |
175 | 0 | if (fde->wrapper != NULL) { |
176 | 0 | fde->wrapper->ops->after_fd_handler( |
177 | 0 | fde->wrapper->wrap_ev, |
178 | 0 | fde->wrapper->private_state, |
179 | 0 | fde->wrapper->main_ev, |
180 | 0 | fde, |
181 | 0 | flags, |
182 | 0 | fde->handler_name, |
183 | 0 | fde->location); |
184 | 0 | tevent_wrapper_pop_use_internal(handler_ev, fde->wrapper); |
185 | 0 | } |
186 | 0 | fde->busy = false; |
187 | |
|
188 | 0 | if (fde->destroyed) { |
189 | 0 | talloc_set_destructor(fde, NULL); |
190 | 0 | TALLOC_FREE(fde); |
191 | 0 | if (removed != NULL) { |
192 | 0 | *removed = true; |
193 | 0 | } |
194 | 0 | } |
195 | |
|
196 | 0 | return 0; |
197 | 0 | } |
198 | | |
199 | | void tevent_fd_set_tag(struct tevent_fd *fde, uint64_t tag) |
200 | 0 | { |
201 | 0 | if (fde == NULL) { |
202 | 0 | return; |
203 | 0 | } |
204 | | |
205 | 0 | fde->tag = tag; |
206 | 0 | } |
207 | | |
208 | | uint64_t tevent_fd_get_tag(const struct tevent_fd *fde) |
209 | 0 | { |
210 | 0 | if (fde == NULL) { |
211 | 0 | return 0; |
212 | 0 | } |
213 | | |
214 | 0 | return fde->tag; |
215 | 0 | } |