aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bitlbee.c103
-rw-r--r--bitlbee.h3
-rw-r--r--commands.h1
-rw-r--r--ipc.c207
-rw-r--r--ipc.h40
-rw-r--r--irc.c6
-rw-r--r--irc.h4
-rw-r--r--irc_commands.c8
9 files changed, 330 insertions, 44 deletions
diff --git a/Makefile b/Makefile
index c9c396ee..26dd3d0f 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@
-include Makefile.settings
# Program variables
-objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o irc.o irc_commands.o log.o nick.o query.o set.o storage.o storage_text.o unix.o url.o user.o util.o
+objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o set.o storage.o storage_text.o unix.o url.o user.o util.o
subdirs = protocols
# Expansion of variables
diff --git a/bitlbee.c b/bitlbee.c
index f4eba866..f6605552 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -28,46 +28,12 @@
#include "commands.h"
#include "protocols/nogaim.h"
#include "help.h"
+#include "ipc.h"
#include <signal.h>
#include <stdio.h>
#include <errno.h>
-gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data )
-{
- size_t size = sizeof( struct sockaddr_in );
- struct sockaddr_in conn_info;
- int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
- pid_t client_pid = 0;
-
- if( global.conf->runmode == RUNMODE_FORKDAEMON )
- client_pid = fork();
-
- if( client_pid == 0 )
- {
- log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
- irc_new( new_socket );
-
- if( global.conf->runmode == RUNMODE_FORKDAEMON )
- {
- /* Close the listening socket, we're a client. */
- close( global.listen_socket );
- g_source_remove( global.listen_watch_source_id );
- }
- }
- else
- {
- /* We don't need this one, only the client does. */
- close( new_socket );
-
- /* Or maybe we didn't even get a child process... */
- if( client_pid == -1 )
- log_message( LOGLVL_ERROR, "Failed to fork() subprocess for client: %s", strerror( errno ) );
- }
-
- return TRUE;
-}
-
-
+gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data );
int bitlbee_daemon_init()
{
@@ -257,6 +223,71 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi
}
}
+gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data )
+{
+ size_t size = sizeof( struct sockaddr_in );
+ struct sockaddr_in conn_info;
+ int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
+ pid_t client_pid = 0;
+
+ if( global.conf->runmode == RUNMODE_FORKDAEMON )
+ {
+ int fds[2];
+
+ if( socketpair( AF_UNIX, SOCK_STREAM, 0, fds ) == -1 )
+ {
+ log_message( LOGLVL_WARNING, "Could not create IPC socket for client: %s", strerror( errno ) );
+ fds[0] = fds[1] = -1;
+ }
+
+ sock_make_nonblocking( fds[0] );
+ sock_make_nonblocking( fds[1] );
+
+ client_pid = fork();
+
+ if( client_pid > 0 && fds[0] != -1 )
+ {
+ struct bitlbee_child *child;
+
+ child = g_new0( struct bitlbee_child, 1 );
+ child->pid = client_pid;
+ child->ipc_fd = fds[0];
+ child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
+ child_list = g_slist_append( child_list, child );
+
+ log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", client_pid );
+
+ /* Close some things we don't need in the parent process. */
+ close( new_socket );
+ close( fds[1] );
+ }
+ else if( client_pid == 0 )
+ {
+ irc_t *irc;
+
+ /* Close the listening socket, we're a client. */
+ close( global.listen_socket );
+ g_source_remove( global.listen_watch_source_id );
+
+ /* Make the connection. */
+ irc = irc_new( new_socket );
+
+ /* We can store the IPC fd there now. */
+ global.listen_socket = fds[1];
+ global.listen_watch_source_id = gaim_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc );
+
+ close( fds[0] );
+ }
+ }
+ else
+ {
+ log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
+ irc_new( new_socket );
+ }
+
+ return TRUE;
+}
+
void bitlbee_shutdown( gpointer data )
{
/* Try to save data for all active connections (if desired). */
diff --git a/bitlbee.h b/bitlbee.h
index be58ad07..0bd7c90e 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -111,7 +111,8 @@ extern char *CONF_FILE;
#include "query.h"
#include "sock.h"
-typedef struct global_t {
+typedef struct global {
+ /* In forked mode, child processes store the fd of the IPC socket here. */
int listen_socket;
gint listen_watch_source_id;
help_t *help;
diff --git a/commands.h b/commands.h
index 69514a67..e43d275a 100644
--- a/commands.h
+++ b/commands.h
@@ -41,5 +41,6 @@ extern const command_t commands[];
#define IRC_CMD_PRE_LOGIN 1
#define IRC_CMD_LOGGED_IN 2
#define IRC_CMD_OPER_ONLY 4
+#define IRC_CMD_TO_MASTER 8
#endif
diff --git a/ipc.c b/ipc.c
new file mode 100644
index 00000000..81ef4ce8
--- /dev/null
+++ b/ipc.c
@@ -0,0 +1,207 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* IPC - communication between BitlBee processes */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "ipc.h"
+#include "commands.h"
+
+GSList *child_list = NULL;
+
+static int ipc_master_cmd_die( irc_t *data, char **cmd )
+{
+ exit( 0 );
+}
+
+static int ipc_master_cmd_wallop( irc_t *data, char **cmd )
+{
+ GSList *l;
+ char msg_buf[513];
+ int msg_len;
+
+ if( ( msg_len = g_snprintf( msg_buf, sizeof( msg_buf ) - 1, "WALLOP :%s\r\n", cmd[1] ) ) > ( sizeof( msg_buf ) - 1 ) )
+ return 0;
+
+ for( l = child_list; l; l = l->next )
+ {
+ struct bitlbee_child *c = l->data;
+ write( c->ipc_fd, msg_buf, msg_len );
+ }
+
+ return 1;
+}
+
+static const command_t ipc_master_commands[] = {
+ { "die", 0, ipc_master_cmd_die, 0 },
+ { "wallop", 1, ipc_master_cmd_wallop, 1 },
+ { NULL }
+};
+
+static int ipc_child_cmd_wallop( irc_t *data, char **cmd )
+{
+ irc_t *irc = data;
+
+ if( strchr( irc->umode, 'w' ) )
+ irc_write( irc, ":%s WALLOP :%s", irc->myhost, cmd[1] );
+
+ return 1;
+}
+
+static const command_t ipc_child_commands[] = {
+ { "wallop", 1, ipc_child_cmd_wallop, 1 },
+ { NULL }
+};
+
+static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
+{
+ int i;
+
+ if( !cmd[0] )
+ return;
+
+ for( i = 0; commands[i].command; i ++ )
+ if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
+ {
+ commands[i].execute( data, cmd );
+ return;
+ }
+}
+
+static char *ipc_readline( int fd )
+{
+ char *buf, *eol;
+ int size;
+
+ buf = g_new0( char, 513 );
+
+ /* Because this is internal communication, it should be pretty safe
+ to just peek at the message, find its length (by searching for the
+ end-of-line) and then just read that message. With internal
+ sockets and limites message length, messages should always be
+ complete. Saves us quite a lot of code and buffering. */
+ size = recv( fd, buf, 512, MSG_PEEK );
+ if( size == 0 || ( size < 0 && !sockerr_again() ) )
+ return NULL;
+ else
+ buf[size] = 0;
+
+ eol = strstr( buf, "\r\n" );
+ if( eol == NULL )
+ return NULL;
+ else
+ size = eol - buf + 2;
+
+ g_free( buf );
+ buf = g_new0( char, size + 1 );
+
+ if( recv( fd, buf, size, 0 ) != size )
+ return NULL;
+ else
+ buf[size-2] = 0;
+
+ return buf;
+}
+
+void ipc_master_read( gpointer data, gint source, GaimInputCondition cond )
+{
+ char *buf, **cmd;
+
+ if( ( buf = ipc_readline( source ) ) )
+ {
+ cmd = irc_parse_line( buf );
+ if( cmd )
+ ipc_command_exec( data, cmd, ipc_master_commands );
+ }
+ else
+ {
+ GSList *l;
+ struct bitlbee_child *c;
+
+ for( l = child_list; l; l = l->next )
+ {
+ c = l->data;
+ if( c->ipc_fd == source )
+ {
+ close( c->ipc_fd );
+ gaim_input_remove( c->ipc_inpa );
+ g_free( c );
+
+ child_list = g_slist_remove( child_list, l );
+
+ break;
+ }
+ }
+ }
+}
+
+void ipc_child_read( gpointer data, gint source, GaimInputCondition cond )
+{
+ char *buf, **cmd;
+
+ if( ( buf = ipc_readline( source ) ) )
+ {
+ cmd = irc_parse_line( buf );
+ if( cmd )
+ ipc_command_exec( data, cmd, ipc_child_commands );
+ }
+ else
+ {
+ gaim_input_remove( global.listen_watch_source_id );
+ close( global.listen_socket );
+
+ global.listen_socket = -1;
+ }
+}
+
+void ipc_to_master( char **cmd )
+{
+ if( global.conf->runmode == RUNMODE_FORKDAEMON )
+ {
+ int i, len;
+ char *s;
+
+ len = 1;
+ for( i = 0; cmd[i]; i ++ )
+ len += strlen( cmd[i] ) + 1;
+
+ if( strchr( cmd[i-1], ' ' ) != NULL )
+ len ++;
+
+ s = g_new0( char, len + 1 );
+ for( i = 0; cmd[i]; i ++ )
+ {
+ if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL )
+ strcat( s, ":" );
+
+ strcat( s, cmd[i] );
+
+ if( cmd[i+1] )
+ strcat( s, " " );
+ }
+ strcat( s, "\r\n" );
+
+ write( global.listen_socket, s, len );
+ }
+}
diff --git a/ipc.h b/ipc.h
new file mode 100644
index 00000000..8c48147c
--- /dev/null
+++ b/ipc.h
@@ -0,0 +1,40 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* IPC - communication between BitlBee processes */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+
+void ipc_master_read( gpointer data, gint source, GaimInputCondition cond );
+void ipc_child_read( gpointer data, gint source, GaimInputCondition cond );
+void ipc_to_master( char **cmd );
+
+struct bitlbee_child
+{
+ pid_t pid;
+ int ipc_fd;
+ gint ipc_inpa;
+};
+
+extern GSList *child_list;
diff --git a/irc.c b/irc.c
index 86bcba35..a00c4192 100644
--- a/irc.c
+++ b/irc.c
@@ -310,7 +310,7 @@ int irc_process( irc_t *irc )
break;
}
- if( ( cmd = irc_parse_line( irc, lines[i] ) ) == NULL )
+ if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
continue;
if( !irc_exec( irc, cmd ) )
{
@@ -325,7 +325,7 @@ int irc_process( irc_t *irc )
if( lines[i] != NULL )
{
g_free( irc->readbuffer );
- irc->readbuffer = NULL;
+ irc->readbuffer = NULL;
}
g_free( lines );
@@ -374,7 +374,7 @@ char **irc_tokenize( char *buffer )
return( lines );
}
-char **irc_parse_line( irc_t *irc, char *line )
+char **irc_parse_line( char *line )
{
int i, j;
char **cmd;
diff --git a/irc.h b/irc.h
index e5b90ea5..8517bb7e 100644
--- a/irc.h
+++ b/irc.h
@@ -32,7 +32,7 @@
#define IRC_LOGIN_TIMEOUT 60
#define IRC_PING_STRING "PinglBee"
-#define UMODES "ias"
+#define UMODES "iasw"
#define UMODES_PRIV "Ro"
#define CMODES "nt"
#define CMODE "t"
@@ -107,7 +107,7 @@ void irc_free( irc_t *irc );
int irc_exec( irc_t *irc, char **cmd );
int irc_process( irc_t *irc );
-char **irc_parse_line( irc_t *irc, char *line );
+char **irc_parse_line( char *line );
void irc_vawrite( irc_t *irc, char *format, va_list params );
void irc_write( irc_t *irc, char *format, ... );
diff --git a/irc_commands.c b/irc_commands.c
index a7cb9963..3ef5566e 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -25,6 +25,7 @@
#define BITLBEE_CORE
#include "bitlbee.h"
+#include "ipc.h"
static int irc_cmd_pass( irc_t *irc, char **cmd )
{
@@ -605,6 +606,8 @@ static const command_t irc_commands[] = {
{ "motd", 0, irc_cmd_motd, IRC_CMD_LOGGED_IN },
{ "pong", 0, irc_cmd_pong, IRC_CMD_LOGGED_IN },
{ "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
+ { "die", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+ { "wallop", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
{ NULL }
};
@@ -641,7 +644,10 @@ int irc_exec( irc_t *irc, char *cmd[] )
return( 1 );
}
- return irc_commands[i].execute( irc, cmd );
+ if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
+ ipc_to_master( cmd );
+ else
+ return irc_commands[i].execute( irc, cmd );
}
return( 1 );