diff options
| author | Jelmer Vernooij <jelmer@samba.org> | 2006-01-24 12:28:13 +1300 | 
|---|---|---|
| committer | Jelmer Vernooij <jelmer@samba.org> | 2006-01-24 12:28:13 +1300 | 
| commit | 9fae35c9cf2d5a319623946705e5d7179ea5c338 (patch) | |
| tree | c489bfe332588c4fb918b4759c3f89f8b4c0a75f /bitlbee.c | |
| parent | 7308b63f3300d5b2a326edfde6c50a18bc05e3e5 (diff) | |
| parent | 68c7c145c281fe3ae734b345bf133d70d1ef8652 (diff) | |
Merge from Wilmer
Diffstat (limited to 'bitlbee.c')
| -rw-r--r-- | bitlbee.c | 300 | 
1 files changed, 111 insertions, 189 deletions
| @@ -28,61 +28,70 @@  #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 ); -	 -	log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); -	irc_new( new_socket ); - -	return TRUE; -} -  - +gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data );  int bitlbee_daemon_init()  { +#ifdef IPV6 +	struct sockaddr_in6 listen_addr; +#else  	struct sockaddr_in listen_addr; +#endif  	int i;  	GIOChannel *ch;  	log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );  	log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG ); -	global.listen_socket = socket( AF_INET, SOCK_STREAM, 0 ); +	global.listen_socket = socket( AF_INETx, SOCK_STREAM, 0 );  	if( global.listen_socket == -1 )  	{  		log_error( "socket" );  		return( -1 );  	} -	listen_addr.sin_family = AF_INET; +	 +	/* 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 ); +	i = inet_pton( AF_INETx, ipv6_wrap( global.conf->iface ), &listen_addr.sin6_addr ); +#else +	listen_addr.sin_family = AF_INETx;  	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 ) ); +	i = inet_pton( AF_INETx, global.conf->iface, &listen_addr.sin_addr ); +#endif +	 +	if( i != 1 ) +	{ +		log_message( LOGLVL_ERROR, "Couldn't parse address `%s'", global.conf->iface ); +		return( -1 ); +	} +	 +	i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( listen_addr ) );  	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 )  	{ @@ -123,14 +132,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 ) @@ -141,7 +150,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;  		}  	} @@ -157,18 +166,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;  	} @@ -180,56 +190,32 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi  	irc_t *irc = data;  	int st, size;  	char *temp; -#ifdef FLOOD_SEND -	time_t newtime; -#endif -#ifdef FLOOD_SEND	 -	newtime = time( NULL ); -	if( ( newtime - irc->oldtime ) > FLOOD_SEND_INTERVAL ) -	{ -		irc->sentbytes = 0; -		irc->oldtime = newtime; -	} -#endif -	  	if( irc->sendbuffer == NULL )  		return( FALSE );  	size = strlen( irc->sendbuffer ); -	 -#ifdef FLOOD_SEND -	if( ( FLOOD_SEND_BYTES - irc->sentbytes ) > size ) -		st = write( irc->fd, irc->sendbuffer, size ); -	else -		st = write( irc->fd, irc->sendbuffer, ( FLOOD_SEND_BYTES - irc->sentbytes ) ); -#else  	st = write( irc->fd, irc->sendbuffer, size ); -#endif -	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;  	} -	 -#ifdef FLOOD_SEND -	irc->sentbytes += st; -#endif		  	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 @@ -242,143 +228,79 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi  	}  } -void bitlbee_shutdown( gpointer data ) -{ -	/* Try to save data for all active connections (if desired). */ -	while( irc_connection_list != NULL ) -		irc_free( irc_connection_list->data ); -	 -	/* We'll only reach this point when not running in inetd mode: */ -	g_main_quit( global.loop ); -} - -int root_command_string( irc_t *irc, user_t *u, char *command, int flags ) +gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data )  { -	char *cmd[IRC_MAX_ARGS]; -	char *s; -	int k; -	char q = 0; -	 -	memset( cmd, 0, sizeof( cmd ) ); -	cmd[0] = command; -	k = 1; -	for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ ) -		if( *s == ' ' && !q ) -		{ -			*s = 0; -			while( *++s == ' ' ); -			if( *s == '"' || *s == '\'' ) -			{ -				q = *s; -				s ++; -			} -			if( *s ) -			{ -				cmd[k++] = s; -				s --; -			} -		} -		else if( *s == q ) -		{ -			q = *s = 0; -		} -	cmd[k] = NULL; -	 -	return( root_command( irc, cmd ) ); -} - -int root_command( irc_t *irc, char *cmd[] ) -{	 -	int i; -	 -	if( !cmd[0] ) -		return( 0 ); +	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; -	for( i = 0; commands[i].command; i++ ) -		if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) +	if( global.conf->runmode == RUNMODE_FORKDAEMON ) +	{ +		int fds[2]; +		 +		if( socketpair( AF_UNIX, SOCK_STREAM, 0, fds ) == -1 )  		{ -			if( !cmd[commands[i].required_parameters] ) -			{ -				irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters ); -				return( 0 ); -			} -			commands[i].execute( irc, cmd ); -			return( 1 ); +			log_message( LOGLVL_WARNING, "Could not create IPC socket for client: %s", strerror( errno ) ); +			fds[0] = fds[1] = -1;  		} -	 -	irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] ); -	 -	return( 1 ); -} - -/* Decode%20a%20file%20name						*/ -void http_decode( char *s ) -{ -	char *t; -	int i, j, k; -	 -	t = g_new( char, strlen( s ) + 1 ); -	 -	for( i = j = 0; s[i]; i ++, j ++ ) -	{ -		if( s[i] == '%' ) +		 +		sock_make_nonblocking( fds[0] ); +		sock_make_nonblocking( fds[1] ); +		 +		client_pid = fork(); +		 +		if( client_pid > 0 && fds[0] != -1 )  		{ -			if( sscanf( s + i + 1, "%2x", &k ) ) -			{ -				t[j] = k; -				i += 2; -			} -			else -			{ -				*t = 0; -				break; -			} +			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 +		else if( client_pid == 0 )  		{ -			t[j] = s[i]; +			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();  		}  	} -	t[j] = 0; -	 -	strcpy( s, t ); -	g_free( t ); -} - -/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */ -/* This fuction is safe, but make sure you call it safely as well! */ -void http_encode( char *s ) -{ -	char *t; -	int i, j; -	 -	t = g_strdup( s ); -	 -	for( i = j = 0; t[i]; i ++, j ++ ) +	else  	{ -		if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) -		{ -			sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); -			j += 2; -		} -		else -		{ -			s[j] = t[i]; -		} +		log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); +		irc_new( new_socket );  	} -	s[j] = 0; -	g_free( t ); +	return TRUE;  } -/* Strip newlines from a string. Modifies the string passed to it. */  -char *strip_newlines( char *source ) +void bitlbee_shutdown( gpointer data )  { -	int i;	 - -	for( i = 0; source[i] != '\0'; i ++ ) -		if( source[i] == '\n' || source[i] == '\r' ) -			source[i] = 32; +	/* Try to save data for all active connections (if desired). */ +	while( irc_connection_list != NULL ) +		irc_free( irc_connection_list->data ); -	return source; +	/* We'll only reach this point when not running in inetd mode: */ +	g_main_quit( global.loop );  } | 
