ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/contrib/soft_reboot.c
Revision: 777
Committed: Wed Aug 23 14:55:16 2006 UTC (20 years, 1 month ago) by adx
Content type: text/x-csrc
File size: 13060 byte(s)
Error occurred while calculating annotation data.
Log Message:
+ misc corrections

File Contents

# Content
1 /************************************************************************
2 * IRC - Internet Relay Chat, contrib/soft_reboot.c
3 * Copyright (C) 2006 Hybrid Development Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 1, or (at your option)
8 * 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
13 * GNU 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, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * $Id$
20 */
21
22 #include "stdinc.h"
23 #include "conf/conf.h"
24 #include "channel.h"
25 #include "channel_mode.h"
26 #include "client.h"
27 #include "hash.h"
28 #include "ircd.h"
29 #include "ircd_defs.h"
30 #include "listener.h"
31 #include "numeric.h"
32 #include "packet.h"
33 #include "parse.h"
34 #include "restart.h"
35 #include "s_serv.h"
36 #include "s_user.h"
37 #include "send.h"
38
39 #ifdef HAVE_LIBCRYPTO
40 #define CanForward(x) (!IsDefunct(x) && !(x)->localClient->fd.ssl && \
41 !(x)->localClient->ctrlfd.flags.open)
42 #else
43 #define CanForward(x) (!IsDefunct(x) && !(x)->localClient->ctrlfd.flags.open)
44 #endif
45
46 static dlink_node *h_shutdown, *h_verify;
47
48 struct SocketInfo
49 {
50 int fd;
51 int namelen;
52 int pwdlen;
53 int caplen;
54 int recvqlen;
55 int sendqlen;
56 };
57
58 /*
59 * serverize()
60 *
61 * Turns a dummy client into a server.
62 *
63 * inputs: client pointer
64 * output: none
65 */
66 static void
67 serverize(struct Client *client_p)
68 {
69 struct ConnectConf *sconf = ref_link_by_ptr(MyMalloc(sizeof(*sconf)));
70 char *hub_mask;
71
72 DupString(sconf->name, client_p->name);
73 sconf->flags = LINK_BURSTAWAY | LINK_TOPICBURST;
74
75 DupString(hub_mask, "*");
76 dlinkAdd(hub_mask, make_dlink_node(), &sconf->hub_list);
77
78 client_p->serv->sconf = ref_link_by_ptr(sconf);
79
80 SetServer(client_p);
81 }
82
83 /*
84 * make_dummy()
85 *
86 * Prepares a dummy server-alike local client.
87 *
88 * inputs: file descriptor to use
89 * output: client pointer
90 */
91 static struct Client *
92 make_dummy(int transfd)
93 {
94 dlink_node *m;
95 struct Client *client_p = make_client(NULL);
96
97 fd_open(&client_p->localClient->fd, transfd, 1, "Softboot");
98 client_p->localClient->caps = -1;
99
100 strcpy(client_p->name, ".");
101 strcpy(client_p->id, "...");
102 hash_add_client(client_p);
103 hash_add_id(client_p);
104 dlinkAdd(client_p, &client_p->node, &global_client_list);
105
106 m = dlinkFind(&unknown_list, client_p);
107 dlinkDelete(m, &unknown_list);
108 dlinkAdd(client_p, m, &serv_list);
109 dlinkAdd(client_p, make_dlink_node(), &global_serv_list);
110
111 make_server(client_p);
112 serverize(client_p);
113
114 return client_p;
115 }
116
117 /*
118 * write_dbuf()
119 *
120 * Writes the contents of a dbuf to the given socket.
121 *
122 * inputs:
123 * transfd - where to write to
124 * dbuf - dbuf pointer
125 * output: none
126 */
127 static void
128 write_dbuf(int transfd, struct dbuf_queue *dbuf)
129 {
130 while (dbuf_length(dbuf) > 0)
131 {
132 struct dbuf_block *first = dbuf->blocks.head->data;
133
134 write(transfd, first->data, first->size);
135 dbuf_delete(dbuf, first->size);
136 }
137 }
138
139 /*
140 * introduce_socket()
141 *
142 * Encodes and writes socket information about the given client.
143 *
144 * inputs:
145 * transfd - where to write to
146 * client_p - local client to inform about
147 * output: none
148 */
149 static void
150 introduce_socket(int transfd, struct Client *client_p)
151 {
152 struct SocketInfo si;
153 const char *capabs = "";
154
155 if (!CanForward(client_p))
156 return;
157
158 if (IsServer(client_p))
159 capabs = show_capabilities(client_p);
160
161 si.fd = client_p->localClient->fd.fd;
162 si.namelen = strlen(client_p->name);
163 si.pwdlen = EmptyString(client_p->localClient->passwd) ? 0 :
164 strlen(client_p->localClient->passwd);
165 si.caplen = strlen(capabs);
166 si.recvqlen = dbuf_length(&client_p->localClient->buf_recvq);
167 si.sendqlen = dbuf_length(&client_p->localClient->buf_sendq);
168
169 write(transfd, &si, sizeof(si));
170 write(transfd, client_p->name, si.namelen);
171 if (si.pwdlen > 0)
172 write(transfd, client_p->localClient->passwd, si.pwdlen);
173 if (si.caplen > 0)
174 write(transfd, capabs, si.caplen);
175
176 write_dbuf(transfd, &client_p->localClient->buf_recvq);
177 write_dbuf(transfd, &client_p->localClient->buf_sendq);
178 }
179
180 /*
181 * do_shutdown()
182 *
183 * Implements the /RESTART part of the soft reboot code.
184 *
185 * inputs:
186 * msg - shutdown message
187 * rboot - 1 if it's a restart, 0 if plain exit
188 * output: none
189 */
190 static void *
191 do_shutdown(va_list args)
192 {
193 const char *msg = va_arg(args, const char *);
194 int rboot = va_arg(args, int);
195 struct Client *client_p;
196 dlink_node *ptr;
197 int transfd[2];
198
199 if (!rboot || socketpair(AF_UNIX, SOCK_STREAM, 0, transfd) < 0)
200 return pass_callback(h_shutdown, msg, rboot);
201
202 if (EmptyString(msg))
203 {
204 ilog(L_CRIT, "Server Soft-Rebooting");
205 sendto_realops_flags(UMODE_ALL, L_ALL, "Server Soft-Rebooting");
206 }
207 else
208 {
209 ilog(L_CRIT, "Server Soft-Rebooting: %s", msg);
210 sendto_realops_flags(UMODE_ALL, L_ALL, "Server Soft-Rebooting: %s", msg);
211 }
212
213 //
214 // Prevent all sockets which belong to registered users/servers from
215 // being closed on exec().
216 //
217 fcntl(transfd[0], F_SETFD, 0);
218
219 DLINK_FOREACH(ptr, local_client_list.head)
220 {
221 client_p = ptr->data;
222 if (CanForward(client_p))
223 {
224 fcntl(client_p->localClient->fd.fd, F_SETFD, 0);
225 if (client_p->localClient->list_task != NULL)
226 sendto_one(client_p, form_str(RPL_LISTEND), me.name, client_p->name);
227 }
228 }
229
230 DLINK_FOREACH(ptr, serv_list.head)
231 {
232 client_p = ptr->data;
233 if (CanForward(client_p))
234 fcntl(client_p->localClient->fd.fd, F_SETFD, 0);
235 }
236
237 close_listeners();
238 unlink(ServerState.pidfile);
239
240 //
241 // Start the new ircd.
242 //
243 switch (fork())
244 {
245 case -1:
246 ilog(L_CRIT, "Unable to fork(): %s", strerror(errno));
247 exit(1);
248
249 case 0:
250 {
251 int i;
252 char **argv, buf[24];
253
254 close(transfd[1]);
255 snprintf(buf, sizeof(buf), "softboot_%d", transfd[0]);
256
257 for (i = 0; myargv[i] != NULL; i++);
258 argv = MyMalloc((i + 2) * sizeof(char *));
259
260 for (i = 0; myargv[i] != NULL; i++)
261 argv[i] = myargv[i];
262 argv[i++] = buf;
263 argv[i] = NULL;
264
265 execv(SPATH, argv);
266 ilog(L_CRIT, "Unable to exec(): %s", strerror(errno));
267 exit(1);
268 }
269 }
270
271 //
272 // Pass our data.
273 //
274 burst_all(make_dummy(transfd[1]));
275 send_queued_all();
276
277 write(transfd[1], "\001\r\n", 3);
278
279 DLINK_FOREACH(ptr, local_client_list.head)
280 introduce_socket(transfd[1], ptr->data);
281
282 DLINK_FOREACH(ptr, serv_list.head)
283 introduce_socket(transfd[1], ptr->data);
284
285 exit(0);
286 }
287
288 /*
289 * restore_socket()
290 *
291 * Restores socket related fields in struct LocalUser.
292 *
293 * inputs:
294 * client_p - client pointer
295 * fd - file descriptor
296 * output: none
297 */
298 static void
299 restore_socket(struct Client *client_p, int fd)
300 {
301 char buf[HOSTLEN+10];
302 struct irc_ssaddr addr;
303 int family, port;
304
305 snprintf(buf, sizeof(buf), IsServer(client_p) ? "Server: %s" : "Nick: %s",
306 client_p->name);
307
308 client_p->localClient = BlockHeapAlloc(lclient_heap);
309 attach_class(client_p, default_class);
310 fd_open(&client_p->localClient->fd, fd, 1, buf);
311 fcntl(fd, F_SETFD, FD_CLOEXEC);
312
313 addr.ss_len = sizeof(addr);
314 getsockname(fd, (struct sockaddr *) &addr, &addr.ss_len);
315 family = addr.ss.sin_family;
316 port = ntohs(addr.ss.sin_port);
317
318 client_p->localClient->ip.ss_len = sizeof(client_p->localClient->ip.ss);
319 getpeername(fd, (struct sockaddr *) &client_p->localClient->ip,
320 &client_p->localClient->ip.ss_len);
321 client_p->localClient->aftype = client_p->localClient->ip.ss.sin_family;
322
323 irc_getnameinfo((struct sockaddr *) &client_p->localClient->ip,
324 client_p->localClient->ip.ss_len, client_p->sockhost,
325 sizeof(client_p->sockhost), NULL, 0, NI_NUMERICHOST);
326
327 client_p->servptr = &me;
328 client_p->since = client_p->lasttime = client_p->firsttime =
329 client_p->localClient->last = CurrentTime;
330
331 client_p->localClient->allow_read = MAX_FLOOD;
332 comm_setflush(&client_p->localClient->fd, 1000, flood_recalc, client_p);
333
334 client_p->flags |= FLAGS_FINISHED_AUTH;
335 comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, read_packet,
336 client_p, 0);
337 }
338
339 /*
340 * restore_client()
341 * restore_server()
342 *
343 * Restores a local user/server entity.
344 *
345 * inputs:
346 * client_p - client pointer
347 * capabs - user/server capab string
348 * output: none
349 */
350 static void
351 restore_client(struct Client *client_p, char *capabs)
352 {
353 char userbuf[USERLEN+1];
354 struct Class *cptr;
355
356 if (client_p->username[0] != '~')
357 SetGotId(client_p);
358 strlcpy(userbuf, client_p->username + !IsGotId(client_p),
359 sizeof(userbuf));
360
361 if ((cptr = execute_callback(authorize_client, client_p, userbuf)))
362 attach_class(client_p, cptr);
363
364 Count.local++, Count.totalrestartcount++;
365 if (Count.local > Count.max_loc)
366 Count.max_loc = Count.local;
367
368 dlinkAdd(client_p, &client_p->localClient->lclient_node, &local_client_list);
369 dlinkAdd(client_p, &client_p->lnode, &me.serv->client_list);
370 }
371
372 static void
373 restore_server(struct Client *client_p, char *capabs)
374 {
375 char *p = NULL, *s = NULL;
376 int cap;
377
378 SetGotId(client_p);
379
380 for (s = strtoken(&p, capabs, " "); s; s = strtoken(&p, NULL, " "))
381 if ((cap = find_capability(s)) != 0)
382 SetCapable(client_p, cap);
383
384 if (check_server(client_p->name, client_p, NO) != 0)
385 serverize(client_p);
386
387 set_chcap_usage_counts(client_p);
388 Count.myserver++;
389
390 dlinkAdd(client_p, &client_p->localClient->lclient_node, &serv_list);
391 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
392 }
393
394 /*
395 * discover_from()
396 *
397 * Returns correct value of a client's from field.
398 *
399 * inputs: client pointer
400 * output: from
401 */
402 static struct Client *
403 discover_from(struct Client *client_p)
404 {
405 return IsMe(client_p->servptr) ? client_p : discover_from(client_p->servptr);
406 }
407
408 /*
409 * restore_dbuf()
410 *
411 * Loads a dbuf contents from a file stream.
412 *
413 * inputs:
414 * f - file stream
415 * dbuf - dbuf to fill or NULL
416 * cnt - number of bytes to read
417 * output: none
418 */
419 static void
420 restore_dbuf(FILE *f, struct dbuf_queue *dbuf, int cnt)
421 {
422 while (cnt > 0)
423 {
424 int nread = fread(readBuf, 1, sizeof(readBuf), f);
425
426 if (dbuf != NULL)
427 dbuf_put(dbuf, readBuf, nread);
428 cnt -= nread;
429 }
430 }
431
432 /*
433 * load_state()
434 *
435 * Loads ircd state from a socket stream.
436 *
437 * inputs: socket fd
438 * output: none
439 */
440 static void
441 load_state(int transfd)
442 {
443 FILE *f = fdopen(transfd, "r");
444 char buf[IRCD_BUFSIZE+1], *p;
445 struct Client *client_p;
446 struct SocketInfo si;
447 dlink_node *ptr;
448
449 //
450 // Read server burst from &me
451 //
452 fd_open(&me.localClient->fd, transfd, 1, "Softboot");
453 serverize(&me);
454
455 while (fgets(buf, sizeof(buf), f))
456 {
457 if ((p = strpbrk(buf, "\r\n")) != NULL)
458 *p = 0;
459 if (buf[0] == '\001')
460 break;
461 parse(&me, buf, buf + strlen(buf));
462 }
463
464 SetMe(&me);
465 unref_link(me.serv->sconf);
466 me.serv->sconf = NULL;
467
468 fd_close(&me.localClient->fd);
469
470 //
471 // Read local client information
472 //
473 while (fread(&si, sizeof(si), 1, f) == 1)
474 {
475 if (si.fd == -1)
476 break;
477
478 assert(si.namelen < IRCD_BUFSIZE);
479 assert(si.caplen < IRCD_BUFSIZE);
480
481 fread(buf, 1, si.namelen, f);
482 buf[si.namelen] = 0;
483
484 if ((client_p = find_client(buf)) != NULL)
485 restore_socket(client_p, si.fd);
486 else
487 close(si.fd);
488
489 fread(buf, 1, si.pwdlen, f);
490 if (client_p != NULL && si.pwdlen > 0)
491 {
492 buf[si.pwdlen] = 0;
493 DupString(client_p->localClient->passwd, buf);
494 }
495
496 fread(buf, 1, si.caplen, f);
497 buf[si.caplen] = 0;
498
499 if (client_p != NULL)
500 (IsServer(client_p) ? restore_server : restore_client) (client_p, buf);
501
502 restore_dbuf(f, client_p ? &client_p->localClient->buf_recvq : NULL,
503 si.recvqlen);
504 restore_dbuf(f, client_p ? &client_p->localClient->buf_sendq : NULL,
505 si.sendqlen);
506 }
507
508 //
509 // Finalization
510 //
511 DLINK_FOREACH(ptr, global_client_list.head)
512 ((struct Client *) ptr->data)->from = discover_from(ptr->data);
513
514 fclose(f);
515 send_queued_all();
516 }
517
518 /*
519 * do_verify_conf()
520 *
521 * Handles the conf verification callback.
522 *
523 * inputs: none
524 * output: none
525 */
526 static void *
527 do_verify_conf(va_list args)
528 {
529 pass_callback(h_verify);
530
531 if (conf_cold)
532 {
533 int i;
534
535 for (i = 0; myargv[i] != NULL; i++)
536 if (!ircncmp(myargv[i], "softboot_", 9))
537 {
538 load_state(atoi(myargv[i] + 9));
539 myargv[i] = NULL;
540 }
541 }
542
543 return NULL;
544 }
545
546 INIT_MODULE(soft_reboot, "$Revision$")
547 {
548 h_shutdown = install_hook(ircd_shutdown, do_shutdown);
549 h_verify = install_hook(verify_conf, do_verify_conf);
550 }
551
552 CLEANUP_MODULE
553 {
554 uninstall_hook(verify_conf, do_verify_conf);
555 uninstall_hook(ircd_shutdown, do_shutdown);
556 }

Properties

Name Value
svn:eol-style native
svn:keywords "Id Revision"