aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitlbee.c40
-rw-r--r--bitlbee.conf9
-rw-r--r--bitlbee.h1
-rw-r--r--conf.c16
-rw-r--r--conf.h5
-rw-r--r--irc.c13
-rw-r--r--irc.h2
-rw-r--r--storage_text.c2
-rw-r--r--unix.c27
9 files changed, 92 insertions, 23 deletions
diff --git a/bitlbee.c b/bitlbee.c
index e920f2cb..45cb388d 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -36,12 +36,30 @@ gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpoi
{
size_t size = sizeof( struct sockaddr_in );
struct sockaddr_in conn_info;
- int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info,
- &size );
+ 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 );
+ }
- log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
- irc_new( new_socket );
-
return TRUE;
}
@@ -65,24 +83,24 @@ int bitlbee_daemon_init()
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons( global.conf->port );
listen_addr.sin_addr.s_addr = inet_addr( global.conf->iface );
-
+
i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( struct sockaddr ) );
if( i == -1 )
{
log_error( "bind" );
return( -1 );
}
-
+
i = listen( global.listen_socket, 10 );
if( i == -1 )
{
log_error( "listen" );
return( -1 );
}
-
+
ch = g_io_channel_unix_new( global.listen_socket );
- g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL );
-
+ global.listen_watch_source_id = g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL );
+
#ifndef _WIN32
if( !global.conf->nofork )
{
@@ -164,6 +182,8 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit
return FALSE;
}
+ return TRUE;
+
/* Very naughty, go read the RFCs! >:) */
if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) )
{
diff --git a/bitlbee.conf b/bitlbee.conf
index b0de328d..919cee9d 100644
--- a/bitlbee.conf
+++ b/bitlbee.conf
@@ -13,6 +13,9 @@
## stable enough to serve lots of users from one process. Because of this
## and other reasons, the use of daemon-mode is *STRONGLY* discouraged,
## don't even *think* of reporting bugs when you use this.
+## ForkDaemon -- Run as a stand-alone daemon, but keep all clients in separate
+## child processes. This should be pretty safe and reliable to use instead
+## of inetd mode.
##
# RunMode = Inetd
@@ -41,6 +44,12 @@
##
# AuthPassword = ItllBeBitlBee ## Heh.. Our slogan. ;-)
+## OperPassword
+##
+## Password that unlocks access to special operator commands.
+##
+# OperPassword = ChangeMe!
+
## HostName
##
## Normally, BitlBee gets a hostname using getsockname(). If you have a nicer
diff --git a/bitlbee.h b/bitlbee.h
index 41247270..be58ad07 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -113,6 +113,7 @@ extern char *CONF_FILE;
typedef struct global_t {
int listen_socket;
+ gint listen_watch_source_id;
help_t *help;
conf_t *conf;
GList *storage; /* The first backend in the list will be used for saving */
diff --git a/conf.c b/conf.c
index 15055ca3..81340e3f 100644
--- a/conf.c
+++ b/conf.c
@@ -52,7 +52,8 @@ conf_t *conf_load( int argc, char *argv[] )
conf->primary_storage = "text";
conf->runmode = RUNMODE_INETD;
conf->authmode = AUTHMODE_OPEN;
- conf->password = NULL;
+ conf->auth_pass = NULL;
+ conf->oper_pass = NULL;
conf->configdir = g_strdup( CONFIG );
conf->plugindir = g_strdup( PLUGINDIR );
conf->motdfile = g_strdup( ETCDIR "/motd.txt" );
@@ -70,7 +71,7 @@ conf_t *conf_load( int argc, char *argv[] )
fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE );
}
- while( ( opt = getopt( argc, argv, "i:p:nvIDc:d:h" ) ) >= 0 )
+ while( ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 )
{
if( opt == 'i' )
{
@@ -93,6 +94,8 @@ conf_t *conf_load( int argc, char *argv[] )
conf->runmode=RUNMODE_INETD;
else if( opt == 'D' )
conf->runmode=RUNMODE_DAEMON;
+ else if( opt == 'F' )
+ conf->runmode=RUNMODE_FORKDAEMON;
else if( opt == 'c' )
{
if( strcmp( CONF_FILE, optarg ) != 0 )
@@ -117,6 +120,7 @@ conf_t *conf_load( int argc, char *argv[] )
"\n"
" -I Classic/InetD mode. (Default)\n"
" -D Daemon mode. (Still EXPERIMENTAL!)\n"
+ " -F Forking daemon. (one process per client)\n"
" -i Specify the interface (by IP address) to listen on.\n"
" (Default: 0.0.0.0 (any interface))\n"
" -p Port number to listen on. (Default: 6667)\n"
@@ -156,6 +160,8 @@ static int conf_loadini( conf_t *conf, char *file )
{
if( g_strcasecmp( ini->value, "daemon" ) == 0 )
conf->runmode = RUNMODE_DAEMON;
+ else if( g_strcasecmp( ini->value, "forkdaemon" ) == 0 )
+ conf->runmode = RUNMODE_FORKDAEMON;
else
conf->runmode = RUNMODE_INETD;
}
@@ -183,7 +189,11 @@ static int conf_loadini( conf_t *conf, char *file )
}
else if( g_strcasecmp( ini->key, "authpassword" ) == 0 )
{
- conf->password = g_strdup( ini->value );
+ conf->auth_pass = g_strdup( ini->value );
+ }
+ else if( g_strcasecmp( ini->key, "operpassword" ) == 0 )
+ {
+ conf->oper_pass = g_strdup( ini->value );
}
else if( g_strcasecmp( ini->key, "hostname" ) == 0 )
{
diff --git a/conf.h b/conf.h
index c5b2455f..d6460901 100644
--- a/conf.h
+++ b/conf.h
@@ -26,7 +26,7 @@
#ifndef __CONF_H
#define __CONF_H
-typedef enum runmode { RUNMODE_DAEMON, RUNMODE_INETD } runmode_t;
+typedef enum runmode { RUNMODE_DAEMON, RUNMODE_FORKDAEMON, RUNMODE_INETD } runmode_t;
typedef enum authmode { AUTHMODE_OPEN, AUTHMODE_CLOSED, AUTHMODE_REGISTERED } authmode_t;
typedef struct conf
@@ -37,7 +37,8 @@ typedef struct conf
int verbose;
runmode_t runmode;
authmode_t authmode;
- char *password;
+ char *auth_pass;
+ char *oper_pass;
char *hostname;
char *configdir;
char *plugindir;
diff --git a/irc.c b/irc.c
index 19b14668..f9dfea8a 100644
--- a/irc.c
+++ b/irc.c
@@ -263,7 +263,7 @@ void irc_free(irc_t * irc)
}
g_free(irc);
- if( global.conf->runmode == RUNMODE_INETD )
+ if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
g_main_quit( global.loop );
}
@@ -421,7 +421,7 @@ int irc_exec( irc_t *irc, char **cmd )
{
irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
}
- else if( strcmp( cmd[1], (global.conf)->password ) == 0 )
+ else if( strcmp( cmd[1], (global.conf)->auth_pass ) == 0 )
{
irc->status = USTATUS_AUTHORIZED;
}
@@ -500,6 +500,15 @@ int irc_exec( irc_t *irc, char **cmd )
{
irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
}
+ else if( g_strcasecmp( cmd[0], "OPER" ) == 0 )
+ {
+ if( !cmd[2] )
+ irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
+ else if( strcmp( cmd[2], global.conf->oper_pass ) == 0 )
+ irc_umode_set( irc, irc->nick, "+o" );
+ // else
+ /* FIXME/TODO: Find out which reply to send now. */
+ }
else if( g_strcasecmp( cmd[0], "MODE" ) == 0 )
{
if( !cmd[1] )
diff --git a/irc.h b/irc.h
index 9e0500f9..21ef63db 100644
--- a/irc.h
+++ b/irc.h
@@ -39,7 +39,7 @@
#define FLOOD_SEND_BYTES (1024*10)
#define FLOOD_SEND_MAXBUFFER (1024*20)
-#define UMODES "ais"
+#define UMODES "aiso"
#define CMODES "nt"
#define CMODE "t"
#define UMODE "s"
diff --git a/storage_text.c b/storage_text.c
index 1bf2dcf3..f807cb3e 100644
--- a/storage_text.c
+++ b/storage_text.c
@@ -70,7 +70,7 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i
FILE *fp;
user_t *ru = user_find( irc, ROOT_NICK );
- if( irc->status == USTATUS_IDENTIFIED )
+ if( irc->status >= USTATUS_IDENTIFIED )
return( 1 );
g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" );
diff --git a/unix.c b/unix.c
index a1f39753..fafa828e 100644
--- a/unix.c
+++ b/unix.c
@@ -31,6 +31,7 @@
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
+#include <sys/wait.h>
global_t global; /* Against global namespace pollution */
@@ -45,7 +46,7 @@ int main( int argc, char *argv[] )
global.loop = g_main_new( FALSE );
- log_init( );
+ log_init();
nogaim_init();
@@ -69,11 +70,15 @@ int main( int argc, char *argv[] )
i = bitlbee_daemon_init();
log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION );
}
+ else if( global.conf->runmode == RUNMODE_FORKDAEMON )
+ {
+ i = bitlbee_daemon_init();
+ log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );
+ }
if( i != 0 )
return( i );
- global.storage = storage_init( global.conf->primary_storage,
- global.conf->migrate_storage );
+ global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
if ( global.storage == NULL) {
log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
return( 1 );
@@ -83,6 +88,7 @@ int main( int argc, char *argv[] )
/* Catch some signals to tell the user what's happening before quitting */
memset( &sig, 0, sizeof( sig ) );
sig.sa_handler = sighandler;
+ sigaction( SIGCHLD, &sig, &old );
sigaction( SIGPIPE, &sig, &old );
sig.sa_flags = SA_RESETHAND;
sigaction( SIGINT, &sig, &old );
@@ -106,7 +112,7 @@ int main( int argc, char *argv[] )
static void sighandler( int signal )
{
- /* FIXME: In fact, calling log_message() here can be dangerous. But well, let's take the risk for now. */
+ /* FIXME: Calling log_message() here is not a very good idea! */
if( signal == SIGTERM )
{
@@ -132,6 +138,19 @@ static void sighandler( int signal )
raise( signal );
}
}
+ else if( signal == SIGCHLD )
+ {
+ pid_t pid;
+ int st;
+
+ while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 )
+ {
+ if( WIFSIGNALED( st ) )
+ log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", pid, WEXITSTATUS( st ) );
+ else if( WIFEXITED( st ) )
+ log_message( LOGLVL_INFO, "Client %d killed by signal %d.", pid, WTERMSIG( st ) );
+ }
+ }
else if( signal != SIGPIPE )
{
log_message( LOGLVL_ERROR, "Fatal signal received: %d. That's probably a bug.", signal );