diff options
Diffstat (limited to 'bitlbee.c')
-rw-r--r-- | bitlbee.c | 393 |
1 files changed, 184 insertions, 209 deletions
@@ -1,4 +1,4 @@ - /********************************************************************\ +/********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * * Copyright 2002-2004 Wilmer van der Gaast and others * @@ -33,42 +33,39 @@ #include <stdio.h> #include <errno.h> -static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition ); +static gboolean bitlbee_io_new_client(gpointer data, gint fd, b_input_condition condition); -static gboolean try_listen( struct addrinfo *res ) +static gboolean try_listen(struct addrinfo *res) { int i; - - global.listen_socket = socket( res->ai_family, res->ai_socktype, res->ai_protocol ); - if( global.listen_socket < 0 ) - { - log_error( "socket" ); + + global.listen_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (global.listen_socket < 0) { + log_error("socket"); return FALSE; } -#ifdef IPV6_V6ONLY - if( res->ai_family == AF_INET6 ) - { +#ifdef IPV6_V6ONLY + if (res->ai_family == AF_INET6) { i = 0; - setsockopt( global.listen_socket, IPPROTO_IPV6, IPV6_V6ONLY, - (char *) &i, sizeof( i ) ); + setsockopt(global.listen_socket, IPPROTO_IPV6, IPV6_V6ONLY, + (char *) &i, sizeof(i)); } #endif /* TIME_WAIT (?) sucks.. */ i = 1; - setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) ); + setsockopt(global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); - i = bind( global.listen_socket, res->ai_addr, res->ai_addrlen ); - if( i == -1 ) - { - closesocket( global.listen_socket ); + i = bind(global.listen_socket, res->ai_addr, res->ai_addrlen); + if (i == -1) { + closesocket(global.listen_socket); global.listen_socket = -1; - - log_error( "bind" ); + + log_error("bind"); return FALSE; } - + return TRUE; } @@ -77,295 +74,273 @@ int bitlbee_daemon_init() struct addrinfo *res, hints, *addrinfo_bind; int i; FILE *fp; - - log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE ); - log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE ); - - memset( &hints, 0, sizeof( hints ) ); + + log_link(LOGLVL_ERROR, LOGOUTPUT_CONSOLE); + log_link(LOGLVL_WARNING, LOGOUTPUT_CONSOLE); + + memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE #ifdef AI_ADDRCONFIG - /* Disabled as it may be doing more harm than good: this flag - ignores IPv6 addresses on lo (which seems reasonable), but - the result is that some clients (including irssi) try to - connect to ::1 and fail. - | AI_ADDRCONFIG */ + /* Disabled as it may be doing more harm than good: this flag + ignores IPv6 addresses on lo (which seems reasonable), but + the result is that some clients (including irssi) try to + connect to ::1 and fail. + | AI_ADDRCONFIG */ #endif ; - i = getaddrinfo( global.conf->iface_in, global.conf->port, &hints, &addrinfo_bind ); - if( i ) - { - log_message( LOGLVL_ERROR, "Couldn't parse address `%s': %s", - global.conf->iface_in, gai_strerror(i) ); + i = getaddrinfo(global.conf->iface_in, global.conf->port, &hints, &addrinfo_bind); + if (i) { + log_message(LOGLVL_ERROR, "Couldn't parse address `%s': %s", + global.conf->iface_in, gai_strerror(i)); return -1; } global.listen_socket = -1; - + /* Try IPv6 first (which will become an IPv6+IPv4 socket). */ - for( res = addrinfo_bind; res; res = res->ai_next ) - if( res->ai_family == AF_INET6 && try_listen( res ) ) + for (res = addrinfo_bind; res; res = res->ai_next) { + if (res->ai_family == AF_INET6 && try_listen(res)) { break; - + } + } + /* The rest (so IPv4, I guess). */ - if( res == NULL ) - for( res = addrinfo_bind; res; res = res->ai_next ) - if( res->ai_family != AF_INET6 && try_listen( res ) ) + if (res == NULL) { + for (res = addrinfo_bind; res; res = res->ai_next) { + if (res->ai_family != AF_INET6 && try_listen(res)) { break; - - freeaddrinfo( addrinfo_bind ); - - i = listen( global.listen_socket, 10 ); - if( i == -1 ) - { - log_error( "listen" ); - return( -1 ); + } + } + } + + freeaddrinfo(addrinfo_bind); + + i = listen(global.listen_socket, 10); + if (i == -1) { + log_error("listen"); + return(-1); } - - global.listen_watch_source_id = b_input_add( global.listen_socket, B_EV_IO_READ, bitlbee_io_new_client, NULL ); - - if( !global.conf->nofork ) - { + + global.listen_watch_source_id = b_input_add(global.listen_socket, B_EV_IO_READ, bitlbee_io_new_client, NULL); + + if (!global.conf->nofork) { i = fork(); - if( i == -1 ) - { - log_error( "fork" ); - return( -1 ); + if (i == -1) { + log_error("fork"); + return(-1); + } else if (i != 0) { + exit(0); } - else if( i != 0 ) - exit( 0 ); - + setsid(); - i = chdir( "/" ); + i = chdir("/"); /* Don't use i, just make gcc happy. :-/ */ - - if( getenv( "_BITLBEE_RESTART_STATE" ) == NULL ) - for( i = 0; i < 3; i ++ ) - if( close( i ) == 0 ) - { + + if (getenv("_BITLBEE_RESTART_STATE") == NULL) { + for (i = 0; i < 3; i++) { + if (close(i) == 0) { /* Keep something bogus on those fd's just in case. */ - open( "/dev/null", O_WRONLY ); + open("/dev/null", O_WRONLY); } + } + } + } + + if (global.conf->runmode == RUNMODE_FORKDAEMON) { + ipc_master_load_state(getenv("_BITLBEE_RESTART_STATE")); } - - if( global.conf->runmode == RUNMODE_FORKDAEMON ) - ipc_master_load_state( getenv( "_BITLBEE_RESTART_STATE" ) ); - if( global.conf->runmode == RUNMODE_DAEMON || global.conf->runmode == RUNMODE_FORKDAEMON ) + 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 ); + + 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); } - - if( !global.conf->nofork ) - { - log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG ); - log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG ); + + if (!global.conf->nofork) { + log_link(LOGLVL_ERROR, LOGOUTPUT_SYSLOG); + log_link(LOGLVL_WARNING, LOGOUTPUT_SYSLOG); } - - return( 0 ); + + return(0); } - + int bitlbee_inetd_init() { - if( !irc_new( 0 ) ) - return( 1 ); - - return( 0 ); + if (!irc_new(0)) { + return(1); + } + + return(0); } -gboolean bitlbee_io_current_client_read( gpointer data, gint fd, b_input_condition cond ) +gboolean bitlbee_io_current_client_read(gpointer data, gint fd, b_input_condition cond) { irc_t *irc = data; char line[513]; int st; - - st = read( irc->fd, line, sizeof( line ) - 1 ); - if( st == 0 ) - { - irc_abort( irc, 1, "Connection reset by peer" ); + + st = read(irc->fd, line, sizeof(line) - 1); + if (st == 0) { + irc_abort(irc, 1, "Connection reset by peer"); return FALSE; - } - else if( st < 0 ) - { - if( sockerr_again() ) - { + } else if (st < 0) { + if (sockerr_again()) { return TRUE; - } - else - { - irc_abort( irc, 1, "Read error: %s", strerror( errno ) ); + } else { + irc_abort(irc, 1, "Read error: %s", strerror(errno)); return FALSE; } } - + line[st] = '\0'; - if( irc->readbuffer == NULL ) - { - irc->readbuffer = g_strdup( line ); - } - else - { - irc->readbuffer = g_renew( char, irc->readbuffer, strlen( irc->readbuffer ) + strlen ( line ) + 1 ); - strcpy( ( irc->readbuffer + strlen( irc->readbuffer ) ), line ); + if (irc->readbuffer == NULL) { + irc->readbuffer = g_strdup(line); + } else { + irc->readbuffer = g_renew(char, irc->readbuffer, strlen(irc->readbuffer) + strlen(line) + 1); + strcpy((irc->readbuffer + strlen(irc->readbuffer)), line); } - - 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_WARNING, "Abnormal termination of connection with fd %d.", fd ); + if (!g_slist_find(irc_connection_list, irc)) { + log_message(LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", fd); return FALSE; - } - + } + /* Very naughty, go read the RFCs! >:) */ - if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) ) - { - irc_abort( irc, 0, "Maximum line length exceeded" ); + if (irc->readbuffer && (strlen(irc->readbuffer) > 1024)) { + irc_abort(irc, 0, "Maximum line length exceeded"); return FALSE; } - + return TRUE; } -gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condition cond ) +gboolean bitlbee_io_current_client_write(gpointer data, gint fd, b_input_condition cond) { irc_t *irc = data; int st, size; char *temp; - if( irc->sendbuffer == NULL ) - return FALSE; - - size = strlen( irc->sendbuffer ); - st = write( irc->fd, irc->sendbuffer, size ); - - if( st == 0 || ( st < 0 && !sockerr_again() ) ) - { - irc_abort( irc, 1, "Write error: %s", strerror( errno ) ); + if (irc->sendbuffer == NULL) { return FALSE; } - else if( st < 0 ) /* && sockerr_again() */ - { + + size = strlen(irc->sendbuffer); + st = write(irc->fd, irc->sendbuffer, size); + + if (st == 0 || (st < 0 && !sockerr_again())) { + 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 ); + + if (st == size) { + g_free(irc->sendbuffer); irc->sendbuffer = NULL; irc->w_watch_source_id = 0; - + return FALSE; - } - else - { - temp = g_strdup( irc->sendbuffer + st ); - g_free( irc->sendbuffer ); + } else { + temp = g_strdup(irc->sendbuffer + st); + g_free(irc->sendbuffer); irc->sendbuffer = temp; - + return TRUE; } } -static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition ) +static gboolean bitlbee_io_new_client(gpointer data, gint fd, b_input_condition condition) { - socklen_t size = sizeof( struct sockaddr_in ); + socklen_t size = sizeof(struct sockaddr_in); struct sockaddr_in conn_info; - int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size ); - - if( new_socket == -1 ) - { - log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) ); + int new_socket = accept(global.listen_socket, (struct sockaddr *) &conn_info, &size); + + if (new_socket == -1) { + log_message(LOGLVL_WARNING, "Could not accept new connection: %s", strerror(errno)); return TRUE; } - - if( global.conf->runmode == RUNMODE_FORKDAEMON ) - { + + if (global.conf->runmode == RUNMODE_FORKDAEMON) { pid_t client_pid = 0; 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 ) ); + + 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] ); - + + sock_make_nonblocking(fds[0]); + sock_make_nonblocking(fds[1]); + client_pid = fork(); - - if( client_pid > 0 && fds[0] != -1 ) - { + + if (client_pid > 0 && fds[0] != -1) { struct bitlbee_child *child; - + /* TODO: Stuff like this belongs in ipc.c. */ - child = g_new0( struct bitlbee_child, 1 ); + child = g_new0(struct bitlbee_child, 1); child->pid = client_pid; child->ipc_fd = fds[0]; - child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); + child->ipc_inpa = b_input_add(child->ipc_fd, B_EV_IO_READ, ipc_master_read, child); child->to_fd = -1; - child_list = g_slist_append( child_list, child ); - - log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", (int) client_pid ); - + child_list = g_slist_append(child_list, child); + + log_message(LOGLVL_INFO, "Creating new subprocess with pid %d.", (int) client_pid); + /* Close some things we don't need in the parent process. */ - close( new_socket ); - close( fds[1] ); - } - else if( client_pid == 0 ) - { + close(new_socket); + close(fds[1]); + } else if (client_pid == 0) { irc_t *irc; - + b_main_init(); - + /* Close the listening socket, we're a client. */ - close( global.listen_socket ); - b_event_remove( global.listen_watch_source_id ); - + close(global.listen_socket); + b_event_remove(global.listen_watch_source_id); + /* Make the connection. */ - irc = irc_new( new_socket ); - + irc = irc_new(new_socket); + /* We can store the IPC fd there now. */ global.listen_socket = fds[1]; - global.listen_watch_source_id = b_input_add( fds[1], B_EV_IO_READ, ipc_child_read, irc ); - - close( fds[0] ); - + global.listen_watch_source_id = b_input_add(fds[1], B_EV_IO_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); } - else - { - log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); - irc_new( new_socket ); - } - + return TRUE; } -gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond ) +gboolean bitlbee_shutdown(gpointer data, gint fd, b_input_condition cond) { /* Send the message here with now=TRUE to ensure it arrives */ - irc_write_all( TRUE, "ERROR :Closing link: BitlBee server shutting down" ); + irc_write_all(TRUE, "ERROR :Closing link: BitlBee server shutting down"); /* Try to save data for all active connections (if desired). */ - while( irc_connection_list != NULL ) - irc_abort( irc_connection_list->data, TRUE, NULL ); - + while (irc_connection_list != NULL) { + irc_abort(irc_connection_list->data, TRUE, NULL); + } + /* We'll only reach this point when not running in inetd mode: */ b_main_quit(); - + return FALSE; } |