aboutsummaryrefslogtreecommitdiffstats
path: root/bitlbee.c
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2006-03-01 23:48:37 +0100
committerJelmer Vernooij <jelmer@samba.org>2006-03-01 23:48:37 +0100
commita4dc9f77de03eb46ecabed02dbd1b678319cf11d (patch)
tree71a8dfa927ea2ac4bfc30a36b4d9324a51247aeb /bitlbee.c
parent8e419cb4f86679636b2d96618e1bec4853636c11 (diff)
parent9a1555dc8521f0973347911bcb26d1038259f967 (diff)
[merge] Wilmer
Diffstat (limited to 'bitlbee.c')
-rw-r--r--bitlbee.c182
1 files changed, 124 insertions, 58 deletions
diff --git a/bitlbee.c b/bitlbee.c
index 08c83d91..752ed659 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()
{
@@ -78,6 +44,7 @@ int bitlbee_daemon_init()
#endif
int i;
GIOChannel *ch;
+ FILE *fp;
log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );
log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG );
@@ -89,6 +56,10 @@ int bitlbee_daemon_init()
return( -1 );
}
+ /* TIME_WAIT (?) sucks.. */
+ i = 1;
+ setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) );
+
#ifdef IPV6
listen_addr.sin6_family = AF_INETx;
listen_addr.sin6_port = htons( global.conf->port );
@@ -133,13 +104,34 @@ int bitlbee_daemon_init()
}
else if( i != 0 )
exit( 0 );
- close( 0 );
- close( 1 );
- close( 2 );
+
chdir( "/" );
+
+ /* Sometimes std* are already closed (for example when we're in a RESTARTed
+ BitlBee process. So let's only close TTY-fds. */
+ if( isatty( 0 ) ) close( 0 );
+ if( isatty( 0 ) ) close( 1 );
+ if( isatty( 0 ) ) close( 2 );
}
#endif
+ if( global.conf->runmode == RUNMODE_FORKDAEMON )
+ ipc_master_load_state();
+
+ if( global.conf->runmode == RUNMODE_DAEMON ||
+ global.conf->runmode == RUNMODE_FORKDAEMON )
+ ipc_master_listen_socket();
+
+ if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
+ {
+ fprintf( fp, "%d\n", (int) getpid() );
+ fclose( fp );
+ }
+ else
+ {
+ log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile );
+ }
+
return( 0 );
}
@@ -159,14 +151,14 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit
if( condition & G_IO_ERR || condition & G_IO_HUP )
{
- irc_free( irc );
+ irc_abort( irc, 1, "Read error" );
return FALSE;
}
st = read( irc->fd, line, sizeof( line ) - 1 );
if( st == 0 )
{
- irc_free( irc );
+ irc_abort( irc, 1, "Connection reset by peer" );
return FALSE;
}
else if( st < 0 )
@@ -177,7 +169,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit
}
else
{
- irc_free( irc );
+ irc_abort( irc, 1, "Read error: %s", strerror( errno ) );
return FALSE;
}
}
@@ -193,18 +185,19 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit
strcpy( ( irc->readbuffer + strlen( irc->readbuffer ) ), line );
}
- if( !irc_process( irc ) )
+ irc_process( irc );
+
+ /* Normally, irc_process() shouldn't call irc_free() but irc_abort(). Just in case: */
+ if( !g_slist_find( irc_connection_list, irc ) )
{
- log_message( LOGLVL_INFO, "Destroying connection with fd %d.", irc->fd );
- irc_free( irc );
+ log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", irc->fd );
return FALSE;
}
/* Very naughty, go read the RFCs! >:) */
if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) )
{
- log_message( LOGLVL_ERROR, "Maximum line length exceeded." );
- irc_free( irc );
+ irc_abort( irc, 0, "Maximum line length exceeded" );
return FALSE;
}
@@ -223,25 +216,25 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi
size = strlen( irc->sendbuffer );
st = write( irc->fd, irc->sendbuffer, size );
- if( st <= 0 )
+ if( st == 0 || ( st < 0 && !sockerr_again() ) )
{
- if( sockerr_again() )
- {
- return TRUE;
- }
- else
- {
- irc_free( irc );
- return FALSE;
- }
+ irc_abort( irc, 1, "Write error: %s", strerror( errno ) );
+ return FALSE;
+ }
+ else if( st < 0 ) /* && sockerr_again() */
+ {
+ return TRUE;
}
if( st == size )
{
g_free( irc->sendbuffer );
irc->sendbuffer = NULL;
-
irc->w_watch_source_id = 0;
+
+ if( irc->status == USTATUS_SHUTDOWN )
+ irc_free( irc );
+
return( FALSE );
}
else
@@ -254,6 +247,79 @@ 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( new_socket == -1 )
+ {
+ log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) );
+ return TRUE;
+ }
+
+ 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] );
+
+ ipc_master_free_all();
+ }
+ }
+ 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). */