From 5c577bd5e2ee33dbe7389df6f4baf659c34de365 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 13 Jan 2006 23:10:29 +0100 Subject: IPC code (by no means final) --- bitlbee.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 30 deletions(-) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index 6e36bd12..0e90b912 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -32,39 +32,17 @@ #include #include -gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ) +struct bitlbee_child { - 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 ); - } - - return TRUE; -} - + pid_t pid; + int ipc_fd; + gint ipc_inpa; +}; +static GSList *child_list = NULL; +gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ); + int bitlbee_daemon_init() { #ifdef IPV6 @@ -277,6 +255,71 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi } } +gboolean bitlbee_io_master_ipc_read( gpointer data, gint source, GaimInputCondition cond ); +gboolean bitlbee_io_child_ipc_read( gpointer data, gint source, GaimInputCondition cond ); + +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, bitlbee_io_master_ipc_read, child ); + child_list = g_slist_append( child_list, child ); + + close( fds[1] ); + } + else if( client_pid == 0 ) + { + /* Close the listening socket, we're a client. */ + close( global.listen_socket ); + g_source_remove( global.listen_watch_source_id ); + + /* 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, bitlbee_io_child_ipc_read, NULL ); + + close( fds[0] ); + } + } + + if( client_pid == 0 ) + { + log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); + irc_new( new_socket ); + } + else + { + /* We don't need this one, only the client does. */ + close( new_socket ); + } + + return TRUE; +} + void bitlbee_shutdown( gpointer data ) { /* Try to save data for all active connections (if desired). */ @@ -286,3 +329,60 @@ void bitlbee_shutdown( gpointer data ) /* We'll only reach this point when not running in inetd mode: */ g_main_quit( global.loop ); } + +gboolean bitlbee_io_master_ipc_read( gpointer data, gint source, GaimInputCondition cond ) +{ + struct bitlbee_child *child = data; + char buf[513], *eol; + int size; + + size = recv( child->ipc_fd, buf, sizeof( buf ) - 1, MSG_PEEK ); + + if( size < 0 || ( size < 0 && !sockerr_again() ) ) + goto error_abort; + else + buf[size] = 0; + + eol = strstr( buf, "\r\n" ); + if( eol == NULL ) + goto error_abort; + + size = recv( child->ipc_fd, buf, eol - buf + 2, 0 ); + buf[size] = 0; + + if( strcmp( buf, "DIE\r\n" ) == 0 ) + { + printf( "Bye...\n" ); + exit( 0 ); + } + + return TRUE; + +error_abort: + { + 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; + } + } + + return FALSE; + } +} + +gboolean bitlbee_io_child_ipc_read( gpointer data, gint source, GaimInputCondition cond ) +{ + return TRUE; +} -- cgit v1.2.3 From 74c119dd1b066329eba59d057935ba7ec7249555 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jan 2006 16:42:20 +0100 Subject: Better DIE implementation, added SO_REUSEADDR to listening socket. --- bitlbee.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index f6605552..dc6b8261 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -55,6 +55,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 ); -- cgit v1.2.3 From c1826c6f72d1fe85e1c5decf5207601dac2c23e7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 18 Jan 2006 19:25:31 +0100 Subject: BitlBee now tries to empty sendbuffer before closing the connection. --- bitlbee.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index f4eba866..d8bf12d7 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -199,7 +199,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit if( !irc_process( irc ) ) { log_message( LOGLVL_INFO, "Destroying connection with fd %d.", irc->fd ); - irc_free( irc ); + irc_abort( irc ); return FALSE; } @@ -207,7 +207,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) ) { log_message( LOGLVL_ERROR, "Maximum line length exceeded." ); - irc_free( irc ); + irc_abort( irc ); return FALSE; } @@ -226,25 +226,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_free( irc ); + 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 -- cgit v1.2.3 From fc50d482ae5a7836fbf7c72df168b51d1cf714a5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 20 Jan 2006 13:21:24 +0100 Subject: irc_abort() does logging (including a reason) now. --- bitlbee.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index d8bf12d7..891bd195 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -162,14 +162,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 ) @@ -180,7 +180,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; } } @@ -206,8 +206,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit /* Very naughty, go read the RFCs! >:) */ if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) ) { - log_message( LOGLVL_ERROR, "Maximum line length exceeded." ); - irc_abort( irc ); + irc_abort( irc, 0, "Maximum line length exceeded" ); return FALSE; } @@ -228,7 +227,7 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi if( st == 0 || ( st < 0 && !sockerr_again() ) ) { - irc_free( irc ); + irc_abort( irc, 1, "Write error: %s", strerror( errno ) ); return FALSE; } else if( st < 0 ) /* && sockerr_again() */ -- cgit v1.2.3 From f73b9697f9be18e04ec7458634520f9dd2e2432f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 20 Jan 2006 16:15:49 +0100 Subject: Renamed commands.c, got rid of return values in all command functions. --- bitlbee.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index 218caf01..9a4688d8 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -166,10 +166,12 @@ 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_abort( irc ); + log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", irc->fd ); return FALSE; } -- cgit v1.2.3 From a49dcd5c3c6b79470ad71dc45ccf29f65ba2a7f9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jan 2006 21:33:56 +0100 Subject: Fixed the bug that caused a fork() bomb last night. --- bitlbee.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index 5da5d6e1..2f757f53 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -103,10 +103,14 @@ 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 -- cgit v1.2.3 From 34b17d9b8901b72439167b99d780c481ce420e33 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 2 Feb 2006 14:21:44 +0100 Subject: Added PID-file code. --- bitlbee.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index 9a4688d8..ac7823a4 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -44,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 ); @@ -110,6 +111,16 @@ int bitlbee_daemon_init() } #endif + 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 ); } -- cgit v1.2.3 From 6dff9d4ac2cbd279e25db60ae26086c830764682 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 1 Mar 2006 22:08:03 +0100 Subject: Also listen for admin connections on a unix domain socket at /var/run/bitlbee --- bitlbee.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'bitlbee.c') diff --git a/bitlbee.c b/bitlbee.c index ddd8d2ea..47064382 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -117,6 +117,10 @@ int bitlbee_daemon_init() 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" ) ) ) { -- cgit v1.2.3