]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/helper.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / helper.c
1 /*
2 * ircd-ratbox: A slightly useful ircd
3 * helper.c: Starts and deals with ircd helpers
4 *
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 *
22 * $Id: helper.c 26092 2008-09-19 15:13:52Z androsyn $
23 */
24 #include <libratbox_config.h>
25 #include <ratbox_lib.h>
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 *
44 rb_helper_child(rb_helper_cb * read_cb, rb_helper_cb * error_cb, log_cb * ilog,
45 restart_cb * irestart, die_cb * idie, int maxcon, size_t lb_heap_size,
46 size_t dh_size, size_t fd_heap_size)
47 {
48 rb_helper *helper;
49 int maxfd, x = 0;
50 int ifd, ofd;
51 char *tifd, *tofd, *tmaxfd;
52
53 tifd = getenv("IFD");
54 tofd = getenv("OFD");
55 tmaxfd = getenv("MAXFD");
56
57 if(tifd == NULL || tofd == NULL || tmaxfd == NULL)
58 return NULL;
59
60 helper = rb_malloc(sizeof(rb_helper));
61 ifd = (int)strtol(tifd, NULL, 10);
62 ofd = (int)strtol(tofd, NULL, 10);
63 maxfd = (int)strtol(tmaxfd, NULL, 10);
64
65 #ifndef _WIN32
66 for(x = 0; x < maxfd; x++)
67 {
68 if(x != ifd && x != ofd)
69 close(x);
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);
78 if(x > 2) /* don't undo what we just did */
79 close(x);
80 #else
81 x = 0; /* shut gcc up */
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);
93
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 *
106 rb_helper_start(const char *name, const char *fullpath, rb_helper_cb * read_cb,
107 rb_helper_cb * error_cb)
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;
116
117 if(access(fullpath, X_OK) == -1)
118 return NULL;
119
120 helper = rb_malloc(sizeof(rb_helper));
121
122 rb_snprintf(buf, sizeof(buf), "%s helper - read", name);
123 if(rb_pipe(&in_f[0], &in_f[1], buf) < 0)
124 {
125 rb_free(helper);
126 return NULL;
127 }
128 rb_snprintf(buf, sizeof(buf), "%s helper - write", name);
129 if(rb_pipe(&out_f[0], &out_f[1], buf) < 0)
130 {
131 rb_free(helper);
132 return NULL;
133 }
134
135 rb_snprintf(fx, sizeof(fx), "%d", rb_get_fd(in_f[1]));
136 rb_snprintf(fy, sizeof(fy), "%d", rb_get_fd(out_f[0]));
137
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]);
142
143 rb_setenv("IFD", fy, 1);
144 rb_setenv("OFD", fx, 1);
145 rb_setenv("MAXFD", "256", 1);
146
147 rb_snprintf(buf, sizeof(buf), "-ircd %s daemon", name);
148 parv[0] = buf;
149 parv[1] = NULL;
150
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);
154 #endif
155
156 pid = rb_spawn_process(fullpath, (const char **)parv);
157
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]);
170
171 rb_linebuf_newbuf(&helper->sendq);
172 rb_linebuf_newbuf(&helper->recvq);
173
174 helper->ifd = in_f[0];
175 helper->ofd = out_f[1];
176 helper->read_cb = read_cb;
177 helper->error_cb = error_cb;
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;
197
198 if(rb_linebuf_len(&helper->sendq) > 0)
199 {
200 while((retlen = rb_linebuf_flush(F, &helper->sendq)) > 0)
201 ;;
202 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
203 {
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
213 void
214 rb_helper_write_queue(rb_helper *helper, const char *format, ...)
215 {
216 va_list ap;
217 va_start(ap, format);
218 rb_linebuf_putmsg(&helper->sendq, format, &ap, NULL);
219 va_end(ap);
220 }
221
222 void
223 rb_helper_write_flush(rb_helper *helper)
224 {
225 rb_helper_write_sendq(helper->ofd, helper);
226 }
227
228
229 void
230 rb_helper_write(rb_helper *helper, const char *format, ...)
231 {
232 va_list ap;
233 va_start(ap, format);
234 rb_linebuf_putmsg(&helper->sendq, format, &ap, NULL);
235 va_end(ap);
236 rb_helper_write_flush(helper);
237 }
238
239 static void
240 rb_helper_read_cb(rb_fde_t *F, void *data)
241 {
242 rb_helper *helper = (rb_helper *)data;
243 static char buf[32768];
244 int length;
245 if(helper == NULL)
246 return;
247
248 while((length = rb_read(helper->ifd, buf, sizeof(buf))) > 0)
249 {
250 rb_linebuf_parse(&helper->recvq, buf, length, 0);
251 helper->read_cb(helper);
252 }
253
254 if(length == 0 || (length < 0 && !rb_ignore_errno(errno)))
255 {
256 rb_helper_restart(helper);
257 return;
258 }
259
260 rb_setselect(helper->ifd, RB_SELECT_READ, rb_helper_read_cb, helper);
261 }
262
263 void
264 rb_helper_run(rb_helper *helper)
265 {
266 if(helper == NULL)
267 return;
268 rb_helper_read_cb(helper->ifd, helper);
269 }
270
271
272 void
273 rb_helper_close(rb_helper *helper)
274 {
275 if(helper == NULL)
276 return;
277 rb_kill(helper->pid, SIGKILL);
278 rb_close(helper->ifd);
279 rb_close(helper->ofd);
280 rb_free(helper);
281 }
282
283 int
284 rb_helper_read(rb_helper *helper, void *buf, size_t bufsize)
285 {
286 return rb_linebuf_get(&helper->recvq, buf, bufsize, LINEBUF_COMPLETE, LINEBUF_PARSED);
287 }
288
289 void
290 rb_helper_loop(rb_helper *helper, long delay)
291 {
292 rb_helper_run(helper);
293 while(1)
294 {
295 rb_lib_loop(delay);
296 }
297 }