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 ); } |