]>
Commit | Line | Data |
---|---|---|
db137867 AC |
1 | /* |
2 | * ircd-ratbox: A slightly useful ircd | |
3 | * helper.c: Starts and deals with ircd helpers | |
55abcbb2 | 4 | * |
db137867 AC |
5 | * Copyright (C) 2006 Aaron Sethman <androsyn@ratbox.org> |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |
20 | * USA | |
21 | * | |
db137867 | 22 | */ |
c056dba2 | 23 | |
fe037171 EM |
24 | #include <librb_config.h> |
25 | #include <rb_lib.h> | |
db137867 AC |
26 | #include <commio-int.h> |
27 | ||
28 | struct _rb_helper | |
29 | { | |
30 | char *path; | |
31 | buf_head_t sendq; | |
32 | buf_head_t recvq; | |
33 | rb_fde_t *ifd; | |
34 | rb_fde_t *ofd; | |
35 | pid_t pid; | |
36 | int fork_count; | |
37 | rb_helper_cb *read_cb; | |
38 | rb_helper_cb *error_cb; | |
39 | }; | |
40 | ||
41 | ||
42 | /* setup all the stuff a new child needs */ | |
43 | rb_helper * | |
3202e249 | 44 | rb_helper_child(rb_helper_cb * read_cb, rb_helper_cb * error_cb, log_cb * ilog, |
29c92cf9 | 45 | restart_cb * irestart, die_cb * idie, size_t lb_heap_size, |
3202e249 | 46 | size_t dh_size, size_t fd_heap_size) |
db137867 AC |
47 | { |
48 | rb_helper *helper; | |
49 | int maxfd, x = 0; | |
50 | int ifd, ofd; | |
51 | char *tifd, *tofd, *tmaxfd; | |
3202e249 | 52 | |
db137867 AC |
53 | tifd = getenv("IFD"); |
54 | tofd = getenv("OFD"); | |
55 | tmaxfd = getenv("MAXFD"); | |
3202e249 | 56 | |
db137867 AC |
57 | if(tifd == NULL || tofd == NULL || tmaxfd == NULL) |
58 | return NULL; | |
59 | ||
60 | helper = rb_malloc(sizeof(rb_helper)); | |
3202e249 | 61 | ifd = (int)strtol(tifd, NULL, 10); |
db137867 AC |
62 | ofd = (int)strtol(tofd, NULL, 10); |
63 | maxfd = (int)strtol(tmaxfd, NULL, 10); | |
64 | ||
3202e249 VY |
65 | #ifndef _WIN32 |
66 | for(x = 0; x < maxfd; x++) | |
67 | { | |
68 | if(x != ifd && x != ofd) | |
69 | close(x); | |
db137867 AC |
70 | } |
71 | x = open("/dev/null", O_RDWR); | |
72 | if(ifd != 0 && ofd != 0) | |
73 | dup2(x, 0); | |
74 | if(ifd != 1 && ofd != 1) | |
75 | dup2(x, 1); | |
76 | if(ifd != 2 && ofd != 2) | |
77 | dup2(x, 2); | |
3202e249 | 78 | if(x > 2) /* don't undo what we just did */ |
db137867 AC |
79 | close(x); |
80 | #else | |
b1f7e409 | 81 | (void) x; /* shut gcc up */ |
db137867 AC |
82 | #endif |
83 | ||
84 | rb_lib_init(ilog, irestart, idie, 0, maxfd, dh_size, fd_heap_size); | |
85 | rb_linebuf_init(lb_heap_size); | |
86 | rb_linebuf_newbuf(&helper->sendq); | |
87 | rb_linebuf_newbuf(&helper->recvq); | |
88 | ||
89 | helper->ifd = rb_open(ifd, RB_FD_PIPE, "incoming connection"); | |
90 | helper->ofd = rb_open(ofd, RB_FD_PIPE, "outgoing connection"); | |
91 | rb_set_nb(helper->ifd); | |
92 | rb_set_nb(helper->ofd); | |
3202e249 | 93 | |
db137867 AC |
94 | helper->read_cb = read_cb; |
95 | helper->error_cb = error_cb; | |
96 | return helper; | |
97 | } | |
98 | ||
99 | /* | |
100 | * start_fork_helper | |
101 | * starts a new ircd helper | |
102 | * note that this function doesn't start doing reading..thats the job of the caller | |
103 | */ | |
104 | ||
105 | rb_helper * | |
3202e249 VY |
106 | rb_helper_start(const char *name, const char *fullpath, rb_helper_cb * read_cb, |
107 | rb_helper_cb * error_cb) | |
db137867 AC |
108 | { |
109 | rb_helper *helper; | |
110 | const char *parv[2]; | |
111 | char buf[128]; | |
112 | char fx[16], fy[16]; | |
113 | rb_fde_t *in_f[2]; | |
114 | rb_fde_t *out_f[2]; | |
115 | pid_t pid; | |
3202e249 | 116 | |
db137867 AC |
117 | if(access(fullpath, X_OK) == -1) |
118 | return NULL; | |
3202e249 | 119 | |
db137867 AC |
120 | helper = rb_malloc(sizeof(rb_helper)); |
121 | ||
5203cba5 | 122 | snprintf(buf, sizeof(buf), "%s helper - read", name); |
3202e249 | 123 | if(rb_pipe(&in_f[0], &in_f[1], buf) < 0) |
db137867 AC |
124 | { |
125 | rb_free(helper); | |
126 | return NULL; | |
127 | } | |
5203cba5 | 128 | snprintf(buf, sizeof(buf), "%s helper - write", name); |
db137867 AC |
129 | if(rb_pipe(&out_f[0], &out_f[1], buf) < 0) |
130 | { | |
131 | rb_free(helper); | |
132 | return NULL; | |
133 | } | |
3202e249 | 134 | |
5203cba5 VI |
135 | snprintf(fx, sizeof(fx), "%d", rb_get_fd(in_f[1])); |
136 | snprintf(fy, sizeof(fy), "%d", rb_get_fd(out_f[0])); | |
3202e249 | 137 | |
db137867 AC |
138 | rb_set_nb(in_f[0]); |
139 | rb_set_nb(in_f[1]); | |
140 | rb_set_nb(out_f[0]); | |
141 | rb_set_nb(out_f[1]); | |
3202e249 VY |
142 | |
143 | rb_setenv("IFD", fy, 1); | |
144 | rb_setenv("OFD", fx, 1); | |
145 | rb_setenv("MAXFD", "256", 1); | |
146 | ||
5203cba5 | 147 | snprintf(buf, sizeof(buf), "-ircd %s daemon", name); |
db137867 AC |
148 | parv[0] = buf; |
149 | parv[1] = NULL; | |
150 | ||
3202e249 VY |
151 | #ifdef _WIN32 |
152 | SetHandleInformation((HANDLE) rb_get_fd(in_f[1]), HANDLE_FLAG_INHERIT, 1); | |
153 | SetHandleInformation((HANDLE) rb_get_fd(out_f[0]), HANDLE_FLAG_INHERIT, 1); | |
db137867 | 154 | #endif |
3202e249 | 155 | |
db137867 | 156 | pid = rb_spawn_process(fullpath, (const char **)parv); |
3202e249 | 157 | |
db137867 AC |
158 | if(pid == -1) |
159 | { | |
160 | rb_close(in_f[0]); | |
161 | rb_close(in_f[1]); | |
162 | rb_close(out_f[0]); | |
163 | rb_close(out_f[1]); | |
164 | rb_free(helper); | |
165 | return NULL; | |
166 | } | |
167 | ||
168 | rb_close(in_f[1]); | |
169 | rb_close(out_f[0]); | |
3202e249 | 170 | |
db137867 AC |
171 | rb_linebuf_newbuf(&helper->sendq); |
172 | rb_linebuf_newbuf(&helper->recvq); | |
3202e249 | 173 | |
db137867 AC |
174 | helper->ifd = in_f[0]; |
175 | helper->ofd = out_f[1]; | |
176 | helper->read_cb = read_cb; | |
3202e249 | 177 | helper->error_cb = error_cb; |
db137867 AC |
178 | helper->fork_count = 0; |
179 | helper->pid = pid; | |
180 | ||
181 | return helper; | |
182 | } | |
183 | ||
184 | ||
185 | void | |
186 | rb_helper_restart(rb_helper *helper) | |
187 | { | |
188 | helper->error_cb(helper); | |
189 | } | |
190 | ||
191 | ||
192 | static void | |
193 | rb_helper_write_sendq(rb_fde_t *F, void *helper_ptr) | |
194 | { | |
195 | rb_helper *helper = helper_ptr; | |
196 | int retlen; | |
3202e249 | 197 | |
db137867 AC |
198 | if(rb_linebuf_len(&helper->sendq) > 0) |
199 | { | |
200 | while((retlen = rb_linebuf_flush(F, &helper->sendq)) > 0) | |
5ef68b13 | 201 | ; |
3202e249 VY |
202 | if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) |
203 | { | |
db137867 AC |
204 | rb_helper_restart(helper); |
205 | return; | |
206 | } | |
207 | } | |
208 | ||
209 | if(rb_linebuf_len(&helper->sendq) > 0) | |
210 | rb_setselect(helper->ofd, RB_SELECT_WRITE, rb_helper_write_sendq, helper); | |
211 | } | |
212 | ||
3202e249 | 213 | void |
db137867 AC |
214 | rb_helper_write_queue(rb_helper *helper, const char *format, ...) |
215 | { | |
216 | va_list ap; | |
4b1cce65 SA |
217 | rb_strf_t strings = { .format = format, .format_args = &ap, .next = NULL }; |
218 | ||
db137867 | 219 | va_start(ap, format); |
4b1cce65 | 220 | rb_linebuf_put(&helper->sendq, &strings); |
db137867 AC |
221 | va_end(ap); |
222 | } | |
223 | ||
224 | void | |
225 | rb_helper_write_flush(rb_helper *helper) | |
226 | { | |
3202e249 | 227 | rb_helper_write_sendq(helper->ofd, helper); |
db137867 AC |
228 | } |
229 | ||
230 | ||
231 | void | |
232 | rb_helper_write(rb_helper *helper, const char *format, ...) | |
233 | { | |
234 | va_list ap; | |
4b1cce65 SA |
235 | rb_strf_t strings = { .format = format, .format_args = &ap, .next = NULL }; |
236 | ||
db137867 | 237 | va_start(ap, format); |
4b1cce65 | 238 | rb_linebuf_put(&helper->sendq, &strings); |
db137867 | 239 | va_end(ap); |
4b1cce65 | 240 | |
db137867 AC |
241 | rb_helper_write_flush(helper); |
242 | } | |
243 | ||
244 | static void | |
8679c0fe | 245 | rb_helper_read_cb(rb_fde_t *F __attribute__((unused)), void *data) |
db137867 AC |
246 | { |
247 | rb_helper *helper = (rb_helper *)data; | |
248 | static char buf[32768]; | |
249 | int length; | |
250 | if(helper == NULL) | |
251 | return; | |
3202e249 | 252 | |
db137867 AC |
253 | while((length = rb_read(helper->ifd, buf, sizeof(buf))) > 0) |
254 | { | |
255 | rb_linebuf_parse(&helper->recvq, buf, length, 0); | |
256 | helper->read_cb(helper); | |
257 | } | |
258 | ||
259 | if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) | |
260 | { | |
261 | rb_helper_restart(helper); | |
262 | return; | |
263 | } | |
3202e249 | 264 | |
db137867 AC |
265 | rb_setselect(helper->ifd, RB_SELECT_READ, rb_helper_read_cb, helper); |
266 | } | |
267 | ||
268 | void | |
269 | rb_helper_run(rb_helper *helper) | |
270 | { | |
271 | if(helper == NULL) | |
272 | return; | |
273 | rb_helper_read_cb(helper->ifd, helper); | |
274 | } | |
275 | ||
276 | ||
277 | void | |
278 | rb_helper_close(rb_helper *helper) | |
279 | { | |
280 | if(helper == NULL) | |
281 | return; | |
3202e249 | 282 | rb_kill(helper->pid, SIGKILL); |
db137867 AC |
283 | rb_close(helper->ifd); |
284 | rb_close(helper->ofd); | |
3202e249 | 285 | rb_free(helper); |
db137867 AC |
286 | } |
287 | ||
288 | int | |
289 | rb_helper_read(rb_helper *helper, void *buf, size_t bufsize) | |
290 | { | |
291 | return rb_linebuf_get(&helper->recvq, buf, bufsize, LINEBUF_COMPLETE, LINEBUF_PARSED); | |
292 | } | |
293 | ||
294 | void | |
295 | rb_helper_loop(rb_helper *helper, long delay) | |
296 | { | |
297 | rb_helper_run(helper); | |
298 | while(1) | |
299 | { | |
300 | rb_lib_loop(delay); | |
301 | } | |
302 | } |