Scan media entities as well, not just url entities. This should expand more
[bitlbee.git] / ipc.c
blobfa23d9871f32a083e27d5f769327327e15c60290
1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2010 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* IPC - communication between BitlBee processes */
9 /*
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License with
21 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23 Suite 330, Boston, MA 02111-1307 USA
26 #define BITLBEE_CORE
27 #include "bitlbee.h"
28 #include "ipc.h"
29 #include "commands.h"
30 #ifndef _WIN32
31 #include <sys/uio.h>
32 #include <sys/un.h>
33 #endif
35 GSList *child_list = NULL;
36 static int ipc_child_recv_fd = -1;
38 static void ipc_master_takeover_fail( struct bitlbee_child *child, gboolean both );
39 static gboolean ipc_send_fd( int fd, int send_fd );
41 /* On Solaris and possibly other systems passing FDs between processes is
42 * not possible (or at least not using the method used in this file.
43 * Just disable that code, the functionality is not that important. */
44 #if defined(NO_FD_PASSING) && !defined(CMSG_SPACE)
45 #define CMSG_SPACE(len) 1
46 #endif
48 static void ipc_master_cmd_client( irc_t *data, char **cmd )
50 /* Normally data points at an irc_t block, but for the IPC master
51 this is different. We think this scary cast is better than
52 creating a new command_t structure, just to make the compiler
53 happy. */
54 struct bitlbee_child *child = (void*) data;
56 if( child && cmd[1] )
58 child->host = g_strdup( cmd[1] );
59 child->nick = g_strdup( cmd[2] );
60 child->realname = g_strdup( cmd[3] );
63 /* CLIENT == On initial connects, HELLO is after /RESTARTs. */
64 if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 )
65 ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
66 (int) ( child ? child->pid : -1 ), cmd[2], cmd[1], cmd[3] );
69 static void ipc_master_cmd_nick( irc_t *data, char **cmd )
71 struct bitlbee_child *child = (void*) data;
73 if( child && cmd[1] )
75 g_free( child->nick );
76 child->nick = g_strdup( cmd[1] );
80 static void ipc_master_cmd_die( irc_t *data, char **cmd )
82 if( global.conf->runmode == RUNMODE_FORKDAEMON )
83 ipc_to_children_str( "DIE\r\n" );
85 bitlbee_shutdown( NULL, -1, 0 );
88 static void ipc_master_cmd_deaf( irc_t *data, char **cmd )
90 if( global.conf->runmode == RUNMODE_DAEMON )
92 b_event_remove( global.listen_watch_source_id );
93 close( global.listen_socket );
95 global.listen_socket = global.listen_watch_source_id = -1;
97 ipc_to_children_str( "OPERMSG :Closed listening socket, waiting "
98 "for all users to disconnect." );
100 else
102 ipc_to_children_str( "OPERMSG :The DEAF command only works in "
103 "normal daemon mode. Try DIE instead." );
107 void ipc_master_cmd_rehash( irc_t *data, char **cmd )
109 runmode_t oldmode;
111 oldmode = global.conf->runmode;
113 g_free( global.conf );
114 global.conf = conf_load( 0, NULL );
116 if( global.conf->runmode != oldmode )
118 log_message( LOGLVL_WARNING, "Can't change RunMode setting at runtime, restoring original setting" );
119 global.conf->runmode = oldmode;
122 if( global.conf->runmode == RUNMODE_FORKDAEMON )
123 ipc_to_children( cmd );
126 void ipc_master_cmd_restart( irc_t *data, char **cmd )
128 if( global.conf->runmode != RUNMODE_FORKDAEMON )
130 /* Tell child that this is unsupported. */
131 return;
134 global.restart = -1;
135 bitlbee_shutdown( NULL, -1, 0 );
138 void ipc_master_cmd_identify( irc_t *data, char **cmd )
140 struct bitlbee_child *child = (void*) data, *old = NULL;
141 char *resp;
142 GSList *l;
144 if( !child || !child->nick || strcmp( child->nick, cmd[1] ) != 0 )
145 return;
147 g_free( child->password );
148 child->password = g_strdup( cmd[2] );
150 for( l = child_list; l; l = l->next )
152 old = l->data;
153 if( child != old &&
154 old->nick && nick_cmp( old->nick, child->nick ) == 0 &&
155 old->password && strcmp( old->password, child->password ) == 0 )
156 break;
159 if( l && !child->to_child && !old->to_child )
161 resp = "TAKEOVER INIT\r\n";
162 child->to_child = old;
163 old->to_child = child;
165 else
167 /* Won't need the fd since we can't send it anywhere. */
168 closesocket( child->to_fd );
169 child->to_fd = -1;
170 resp = "TAKEOVER NO\r\n";
173 if( write( child->ipc_fd, resp, strlen( resp ) ) != strlen( resp ) )
174 ipc_master_free_one( child );
178 void ipc_master_cmd_takeover( irc_t *data, char **cmd )
180 struct bitlbee_child *child = (void*) data;
181 char *fwd = NULL;
183 /* Normal daemon mode doesn't keep these and has simplified code for
184 takeovers. */
185 if( child == NULL )
186 return;
188 if( child->to_child == NULL ||
189 g_slist_find( child_list, child->to_child ) == NULL )
190 return ipc_master_takeover_fail( child, FALSE );
192 if( strcmp( cmd[1], "AUTH" ) == 0 )
194 /* New connection -> Master */
195 if( child->to_child &&
196 child->nick && child->to_child->nick && cmd[2] &&
197 child->password && child->to_child->password && cmd[3] &&
198 strcmp( child->nick, child->to_child->nick ) == 0 &&
199 strcmp( child->nick, cmd[2] ) == 0 &&
200 strcmp( child->password, child->to_child->password ) == 0 &&
201 strcmp( child->password, cmd[3] ) == 0 )
203 ipc_send_fd( child->to_child->ipc_fd, child->to_fd );
205 fwd = irc_build_line( cmd );
206 if( write( child->to_child->ipc_fd, fwd, strlen( fwd ) ) != strlen( fwd ) )
207 ipc_master_free_one( child );
208 g_free( fwd );
210 else
211 return ipc_master_takeover_fail( child, TRUE );
213 else if( strcmp( cmd[1], "DONE" ) == 0 || strcmp( cmd[1], "FAIL" ) == 0 )
215 /* Old connection -> Master */
216 int fd;
218 /* The copy was successful (or not), we don't need it anymore. */
219 closesocket( child->to_fd );
220 child->to_fd = -1;
222 /* Pass it through to the other party, and flush all state. */
223 fwd = irc_build_line( cmd );
224 fd = child->to_child->ipc_fd;
225 child->to_child->to_child = NULL;
226 child->to_child = NULL;
227 if( write( fd, fwd, strlen( fwd ) ) != strlen( fwd ) )
228 ipc_master_free_one( child );
229 g_free( fwd );
233 static const command_t ipc_master_commands[] = {
234 { "client", 3, ipc_master_cmd_client, 0 },
235 { "hello", 0, ipc_master_cmd_client, 0 },
236 { "nick", 1, ipc_master_cmd_nick, 0 },
237 { "die", 0, ipc_master_cmd_die, 0 },
238 { "deaf", 0, ipc_master_cmd_deaf, 0 },
239 { "wallops", 1, NULL, IPC_CMD_TO_CHILDREN },
240 { "wall", 1, NULL, IPC_CMD_TO_CHILDREN },
241 { "opermsg", 1, NULL, IPC_CMD_TO_CHILDREN },
242 { "rehash", 0, ipc_master_cmd_rehash, 0 },
243 { "kill", 2, NULL, IPC_CMD_TO_CHILDREN },
244 { "restart", 0, ipc_master_cmd_restart, 0 },
245 { "identify", 2, ipc_master_cmd_identify, 0 },
246 { "takeover", 1, ipc_master_cmd_takeover, 0 },
247 { NULL }
251 static void ipc_child_cmd_die( irc_t *irc, char **cmd )
253 irc_abort( irc, 0, "Shutdown requested by operator" );
256 static void ipc_child_cmd_wallops( irc_t *irc, char **cmd )
258 if( !( irc->status & USTATUS_LOGGED_IN ) )
259 return;
261 if( strchr( irc->umode, 'w' ) )
262 irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] );
265 static void ipc_child_cmd_wall( irc_t *irc, char **cmd )
267 if( !( irc->status & USTATUS_LOGGED_IN ) )
268 return;
270 if( strchr( irc->umode, 's' ) )
271 irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] );
274 static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
276 if( !( irc->status & USTATUS_LOGGED_IN ) )
277 return;
279 if( strchr( irc->umode, 'o' ) )
280 irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] );
283 static void ipc_child_cmd_rehash( irc_t *irc, char **cmd )
285 runmode_t oldmode;
287 oldmode = global.conf->runmode;
289 g_free( global.conf );
290 global.conf = conf_load( 0, NULL );
292 global.conf->runmode = oldmode;
295 static void ipc_child_cmd_kill( irc_t *irc, char **cmd )
297 if( !( irc->status & USTATUS_LOGGED_IN ) )
298 return;
300 if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
301 return; /* It's not for us. */
303 irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] );
304 irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
307 static void ipc_child_cmd_hello( irc_t *irc, char **cmd )
309 if( !( irc->status & USTATUS_LOGGED_IN ) )
310 ipc_to_master_str( "HELLO\r\n" );
311 else
312 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
315 static void ipc_child_cmd_takeover_yes( void *data );
316 static void ipc_child_cmd_takeover_no( void *data );
318 static void ipc_child_cmd_takeover( irc_t *irc, char **cmd )
320 if( strcmp( cmd[1], "NO" ) == 0 )
322 /* Master->New connection */
323 /* No takeover, finish the login. */
325 else if( strcmp( cmd[1], "INIT" ) == 0 )
327 /* Master->New connection */
328 if( !set_getbool( &irc->b->set, "allow_takeover" ) )
330 ipc_child_cmd_takeover_no( irc );
331 return;
334 /* Offer to take over the old session, unless for some reason
335 we're already logging into IM connections. */
336 if( irc->login_source_id != -1 )
337 query_add( irc, NULL,
338 "You're already connected to this server. "
339 "Would you like to take over this session?",
340 ipc_child_cmd_takeover_yes,
341 ipc_child_cmd_takeover_no, NULL, irc );
343 /* This one's going to connect to accounts, avoid that. */
344 b_event_remove( irc->login_source_id );
345 irc->login_source_id = -1;
347 else if( strcmp( cmd[1], "AUTH" ) == 0 )
349 /* Master->Old connection */
350 if( irc->password && cmd[2] && cmd[3] &&
351 ipc_child_recv_fd != -1 &&
352 strcmp( irc->user->nick, cmd[2] ) == 0 &&
353 strcmp( irc->password, cmd[3] ) == 0 &&
354 set_getbool( &irc->b->set, "allow_takeover" ) )
356 irc_switch_fd( irc, ipc_child_recv_fd );
357 irc_sync( irc );
358 irc_rootmsg( irc, "You've successfully taken over your old session" );
359 ipc_child_recv_fd = -1;
361 ipc_to_master_str( "TAKEOVER DONE\r\n" );
363 else
365 ipc_to_master_str( "TAKEOVER FAIL\r\n" );
368 else if( strcmp( cmd[1], "DONE" ) == 0 )
370 /* Master->New connection (now taken over by old process) */
371 irc_free( irc );
373 else if( strcmp( cmd[1], "FAIL" ) == 0 )
375 /* Master->New connection */
376 irc_rootmsg( irc, "Could not take over old session" );
380 static void ipc_child_cmd_takeover_yes( void *data )
382 irc_t *irc = data, *old = NULL;
383 char *to_auth[] = { "TAKEOVER", "AUTH", irc->user->nick, irc->password, NULL };
385 /* Master->New connection */
386 ipc_to_master_str( "TAKEOVER AUTH %s :%s\r\n",
387 irc->user->nick, irc->password );
389 if( global.conf->runmode == RUNMODE_DAEMON )
391 GSList *l;
393 for( l = irc_connection_list; l; l = l->next )
395 old = l->data;
397 if( irc != old &&
398 irc->user->nick && old->user->nick &&
399 irc->password && old->password &&
400 strcmp( irc->user->nick, old->user->nick ) == 0 &&
401 strcmp( irc->password, old->password ) == 0 )
402 break;
404 if( l == NULL )
406 to_auth[1] = "FAIL";
407 ipc_child_cmd_takeover( irc, to_auth );
408 return;
412 /* Drop credentials, we'll shut down soon and shouldn't overwrite
413 any settings. */
414 irc_rootmsg( irc, "Trying to take over existing session" );
416 irc_desync( irc );
418 if( old )
420 ipc_child_recv_fd = dup( irc->fd );
421 ipc_child_cmd_takeover( old, to_auth );
424 /* TODO: irc_setpass() should do all of this. */
425 irc_setpass( irc, NULL );
426 irc->status &= ~USTATUS_IDENTIFIED;
427 irc_umode_set( irc, "-R", 1 );
429 if( old )
430 irc_abort( irc, FALSE, NULL );
433 static void ipc_child_cmd_takeover_no( void *data )
435 ipc_to_master_str( "TAKEOVER NO\r\n" );
436 cmd_identify_finish( data, 0, 0 );
439 static const command_t ipc_child_commands[] = {
440 { "die", 0, ipc_child_cmd_die, 0 },
441 { "wallops", 1, ipc_child_cmd_wallops, 0 },
442 { "wall", 1, ipc_child_cmd_wall, 0 },
443 { "opermsg", 1, ipc_child_cmd_opermsg, 0 },
444 { "rehash", 0, ipc_child_cmd_rehash, 0 },
445 { "kill", 2, ipc_child_cmd_kill, 0 },
446 { "hello", 0, ipc_child_cmd_hello, 0 },
447 { "takeover", 1, ipc_child_cmd_takeover, 0 },
448 { NULL }
451 gboolean ipc_child_identify( irc_t *irc )
453 if( global.conf->runmode == RUNMODE_FORKDAEMON )
455 #ifndef NO_FD_PASSING
456 if( !ipc_send_fd( global.listen_socket, irc->fd ) )
457 ipc_child_disable();
459 ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password );
460 #endif
462 return TRUE;
464 else if( global.conf->runmode == RUNMODE_DAEMON )
466 GSList *l;
467 irc_t *old;
468 char *to_init[] = { "TAKEOVER", "INIT", NULL };
470 for( l = irc_connection_list; l; l = l->next )
472 old = l->data;
474 if( irc != old &&
475 irc->user->nick && old->user->nick &&
476 irc->password && old->password &&
477 strcmp( irc->user->nick, old->user->nick ) == 0 &&
478 strcmp( irc->password, old->password ) == 0 )
479 break;
481 if( l == NULL ||
482 !set_getbool( &irc->b->set, "allow_takeover" ) ||
483 !set_getbool( &old->b->set, "allow_takeover" ) )
484 return FALSE;
486 ipc_child_cmd_takeover( irc, to_init );
488 return TRUE;
490 else
491 return FALSE;
494 static void ipc_master_takeover_fail( struct bitlbee_child *child, gboolean both )
496 if( child == NULL || g_slist_find( child_list, child ) == NULL )
497 return;
499 if( both && child->to_child != NULL )
500 ipc_master_takeover_fail( child->to_child, FALSE );
502 if( child->to_fd > -1 )
504 /* Send this error only to the new connection, which can be
505 recognised by to_fd being set. */
506 if( write( child->ipc_fd, "TAKEOVER FAIL\r\n", 15 ) != 15 )
508 ipc_master_free_one( child );
509 return;
511 close( child->to_fd );
512 child->to_fd = -1;
514 child->to_child = NULL;
517 static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
519 int i, j;
521 if( !cmd[0] )
522 return;
524 for( i = 0; commands[i].command; i ++ )
525 if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
527 /* There is no typo in this line: */
528 for( j = 1; cmd[j]; j ++ ); j --;
530 if( j < commands[i].required_parameters )
531 break;
533 if( commands[i].flags & IPC_CMD_TO_CHILDREN )
534 ipc_to_children( cmd );
535 else
536 commands[i].execute( data, cmd );
538 break;
542 /* Return just one line. Returns NULL if something broke, an empty string
543 on temporary "errors" (EAGAIN and friends). */
544 static char *ipc_readline( int fd, int *recv_fd )
546 struct msghdr msg;
547 struct iovec iov;
548 char ccmsg[CMSG_SPACE(sizeof(recv_fd))];
549 struct cmsghdr *cmsg;
550 char buf[513], *eol;
551 int size;
553 /* Because this is internal communication, it should be pretty safe
554 to just peek at the message, find its length (by searching for the
555 end-of-line) and then just read that message. With internal
556 sockets and limites message length, messages should always be
557 complete. Saves us quite a lot of code and buffering. */
558 size = recv( fd, buf, sizeof( buf ) - 1, MSG_PEEK );
559 if( size == 0 || ( size < 0 && !sockerr_again() ) )
560 return NULL;
561 else if( size < 0 ) /* && sockerr_again() */
562 return( g_strdup( "" ) );
563 else
564 buf[size] = 0;
566 if( ( eol = strstr( buf, "\r\n" ) ) == NULL )
567 return NULL;
568 else
569 size = eol - buf + 2;
571 iov.iov_base = buf;
572 iov.iov_len = size;
574 memset( &msg, 0, sizeof( msg ) );
575 msg.msg_iov = &iov;
576 msg.msg_iovlen = 1;
577 #ifndef NO_FD_PASSING
578 msg.msg_control = ccmsg;
579 msg.msg_controllen = sizeof( ccmsg );
580 #endif
582 if( recvmsg( fd, &msg, 0 ) != size )
583 return NULL;
585 #ifndef NO_FD_PASSING
586 if( recv_fd )
587 for( cmsg = CMSG_FIRSTHDR( &msg ); cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg ) )
588 if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS )
590 /* Getting more than one shouldn't happen but if it does,
591 make sure we don't leave them around. */
592 if( *recv_fd != -1 )
593 close( *recv_fd );
595 *recv_fd = *(int*) CMSG_DATA( cmsg );
597 fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd );
600 #endif
603 fprintf( stderr, "pid %d received: %s", (int) getpid(), buf );
605 return g_strndup( buf, size - 2 );
608 gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond )
610 struct bitlbee_child *child = data;
611 char *buf, **cmd;
613 if( ( buf = ipc_readline( source, &child->to_fd ) ) )
615 cmd = irc_parse_line( buf );
616 if( cmd )
618 ipc_command_exec( child, cmd, ipc_master_commands );
619 g_free( cmd );
621 g_free( buf );
623 else
625 ipc_master_free_fd( source );
628 return TRUE;
631 gboolean ipc_child_read( gpointer data, gint source, b_input_condition cond )
633 char *buf, **cmd;
635 if( ( buf = ipc_readline( source, &ipc_child_recv_fd ) ) )
637 cmd = irc_parse_line( buf );
638 if( cmd )
640 ipc_command_exec( data, cmd, ipc_child_commands );
641 g_free( cmd );
643 g_free( buf );
645 else
647 ipc_child_disable();
650 return TRUE;
653 void ipc_to_master( char **cmd )
655 if( global.conf->runmode == RUNMODE_FORKDAEMON )
657 char *s = irc_build_line( cmd );
658 ipc_to_master_str( "%s", s );
659 g_free( s );
661 else if( global.conf->runmode == RUNMODE_DAEMON )
663 ipc_command_exec( NULL, cmd, ipc_master_commands );
667 void ipc_to_master_str( char *format, ... )
669 char *msg_buf;
670 va_list params;
672 va_start( params, format );
673 msg_buf = g_strdup_vprintf( format, params );
674 va_end( params );
676 if( strlen( msg_buf ) > 512 )
678 /* Don't send it, it's too long... */
680 else if( global.conf->runmode == RUNMODE_FORKDAEMON )
682 if( global.listen_socket >= 0 )
683 if( write( global.listen_socket, msg_buf, strlen( msg_buf ) ) <= 0 )
684 ipc_child_disable();
686 else if( global.conf->runmode == RUNMODE_DAEMON )
688 char **cmd, *s;
690 if( ( s = strchr( msg_buf, '\r' ) ) )
691 *s = 0;
693 cmd = irc_parse_line( msg_buf );
694 ipc_command_exec( NULL, cmd, ipc_master_commands );
695 g_free( cmd );
698 g_free( msg_buf );
701 void ipc_to_children( char **cmd )
703 if( global.conf->runmode == RUNMODE_FORKDAEMON )
705 char *msg_buf = irc_build_line( cmd );
706 ipc_to_children_str( "%s", msg_buf );
707 g_free( msg_buf );
709 else if( global.conf->runmode == RUNMODE_DAEMON )
711 GSList *l;
713 for( l = irc_connection_list; l; l = l->next )
714 ipc_command_exec( l->data, cmd, ipc_child_commands );
718 void ipc_to_children_str( char *format, ... )
720 char *msg_buf;
721 va_list params;
723 va_start( params, format );
724 msg_buf = g_strdup_vprintf( format, params );
725 va_end( params );
727 if( strlen( msg_buf ) > 512 )
729 /* Don't send it, it's too long... */
731 else if( global.conf->runmode == RUNMODE_FORKDAEMON )
733 int msg_len = strlen( msg_buf );
734 GSList *l, *next;
736 for( l = child_list; l; l = next )
738 struct bitlbee_child *c = l->data;
740 next = l->next;
741 if( write( c->ipc_fd, msg_buf, msg_len ) <= 0 )
742 ipc_master_free_one( c );
745 else if( global.conf->runmode == RUNMODE_DAEMON )
747 char **cmd, *s;
749 if( ( s = strchr( msg_buf, '\r' ) ) )
750 *s = 0;
752 cmd = irc_parse_line( msg_buf );
753 ipc_to_children( cmd );
754 g_free( cmd );
757 g_free( msg_buf );
760 static gboolean ipc_send_fd( int fd, int send_fd )
762 struct msghdr msg;
763 struct iovec iov;
764 char ccmsg[CMSG_SPACE(sizeof(fd))];
765 struct cmsghdr *cmsg;
767 memset( &msg, 0, sizeof( msg ) );
768 iov.iov_base = "0x90\r\n"; /* Ja, noppes */
769 iov.iov_len = 6;
770 msg.msg_iov = &iov;
771 msg.msg_iovlen = 1;
773 #ifndef NO_FD_PASSING
774 msg.msg_control = ccmsg;
775 msg.msg_controllen = sizeof( ccmsg );
776 cmsg = CMSG_FIRSTHDR( &msg );
777 cmsg->cmsg_level = SOL_SOCKET;
778 cmsg->cmsg_type = SCM_RIGHTS;
779 cmsg->cmsg_len = CMSG_LEN( sizeof( send_fd ) );
780 *(int*)CMSG_DATA( cmsg ) = send_fd;
781 msg.msg_controllen = cmsg->cmsg_len;
782 #endif
784 return sendmsg( fd, &msg, 0 ) == 6;
787 void ipc_master_free_one( struct bitlbee_child *c )
789 GSList *l;
791 b_event_remove( c->ipc_inpa );
792 closesocket( c->ipc_fd );
794 if( c->to_fd != -1 )
795 close( c->to_fd );
797 g_free( c->host );
798 g_free( c->nick );
799 g_free( c->realname );
800 g_free( c->password );
801 g_free( c );
803 child_list = g_slist_remove( child_list, c );
805 /* Also, if any child has a reference to this one, remove it. */
806 for( l = child_list; l; l = l->next )
808 struct bitlbee_child *oc = l->data;
810 if( oc->to_child == c )
811 ipc_master_takeover_fail( oc, FALSE );
815 void ipc_master_free_fd( int fd )
817 GSList *l;
818 struct bitlbee_child *c;
820 for( l = child_list; l; l = l->next )
822 c = l->data;
823 if( c->ipc_fd == fd )
825 ipc_master_free_one( c );
826 break;
831 void ipc_master_free_all()
833 while( child_list )
834 ipc_master_free_one( child_list->data );
837 void ipc_child_disable()
839 b_event_remove( global.listen_watch_source_id );
840 close( global.listen_socket );
842 global.listen_socket = -1;
845 #ifndef _WIN32
846 char *ipc_master_save_state()
848 char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" );
849 int fd = mkstemp( fn );
850 GSList *l;
851 FILE *fp;
852 int i;
854 if( fd == -1 )
856 log_message( LOGLVL_ERROR, "Could not create temporary file: %s", strerror( errno ) );
857 g_free( fn );
858 return NULL;
861 /* This is more convenient now. */
862 fp = fdopen( fd, "w" );
864 for( l = child_list, i = 0; l; l = l->next )
865 i ++;
867 /* Number of client processes. */
868 fprintf( fp, "%d\n", i );
870 for( l = child_list; l; l = l->next )
871 fprintf( fp, "%d %d\n", (int) ((struct bitlbee_child*)l->data)->pid,
872 ((struct bitlbee_child*)l->data)->ipc_fd );
874 if( fclose( fp ) == 0 )
876 return fn;
878 else
880 unlink( fn );
881 g_free( fn );
882 return NULL;
887 static gboolean new_ipc_client( gpointer data, gint serversock, b_input_condition cond )
889 struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 );
891 child->to_fd = -1;
892 child->ipc_fd = accept( serversock, NULL, 0 );
893 if( child->ipc_fd == -1 )
895 log_message( LOGLVL_WARNING, "Unable to accept connection on UNIX domain socket: %s", strerror(errno) );
896 return TRUE;
899 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
901 child_list = g_slist_prepend( child_list, child );
903 return TRUE;
906 int ipc_master_listen_socket()
908 struct sockaddr_un un_addr;
909 int serversock;
911 if (!IPCSOCKET || !*IPCSOCKET)
912 return 1;
914 /* Clean up old socket files that were hanging around.. */
915 if (unlink(IPCSOCKET) == -1 && errno != ENOENT) {
916 log_message( LOGLVL_ERROR, "Could not remove old IPC socket at %s: %s", IPCSOCKET, strerror(errno) );
917 return 0;
920 un_addr.sun_family = AF_UNIX;
921 strcpy(un_addr.sun_path, IPCSOCKET);
923 serversock = socket(AF_UNIX, SOCK_STREAM, PF_UNIX);
925 if (serversock == -1) {
926 log_message( LOGLVL_WARNING, "Unable to create UNIX socket: %s", strerror(errno) );
927 return 0;
930 if (bind(serversock, (struct sockaddr *)&un_addr, sizeof(un_addr)) == -1) {
931 log_message( LOGLVL_WARNING, "Unable to bind UNIX socket to %s: %s", IPCSOCKET, strerror(errno) );
932 return 0;
935 if (listen(serversock, 5) == -1) {
936 log_message( LOGLVL_WARNING, "Unable to listen on UNIX socket: %s", strerror(errno) );
937 return 0;
940 b_input_add( serversock, B_EV_IO_READ, new_ipc_client, NULL );
942 return 1;
944 #else
945 int ipc_master_listen_socket()
947 /* FIXME: Open named pipe \\.\BITLBEE */
948 return 0;
950 #endif
952 int ipc_master_load_state( char *statefile )
954 struct bitlbee_child *child;
955 FILE *fp;
956 int i, n;
958 if( statefile == NULL )
959 return 0;
961 fp = fopen( statefile, "r" );
962 unlink( statefile ); /* Why do it later? :-) */
963 if( fp == NULL )
964 return 0;
966 if( fscanf( fp, "%d", &n ) != 1 )
968 log_message( LOGLVL_WARNING, "Could not import state information for child processes." );
969 fclose( fp );
970 return 0;
973 log_message( LOGLVL_INFO, "Importing information for %d child processes.", n );
974 for( i = 0; i < n; i ++ )
976 child = g_new0( struct bitlbee_child, 1 );
978 if( fscanf( fp, "%d %d", (int *) &child->pid, &child->ipc_fd ) != 2 )
980 log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i );
981 g_free( child );
982 fclose( fp );
983 return 0;
985 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
986 child->to_fd = -1;
988 child_list = g_slist_prepend( child_list, child );
991 ipc_to_children_str( "HELLO\r\n" );
992 ipc_to_children_str( "OPERMSG :New %s master process started (version %s)\r\n", PACKAGE, BITLBEE_VERSION );
994 fclose( fp );
995 return 1;