Debian package changelog entry.
[bitlbee.git] / bitlbee.c
blob89e332232b9985bbe95d4ac9102b0c084aa6053c
1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2004 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* Main file */
9 /*
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License with
21 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23 Suite 330, Boston, MA 02111-1307 USA
26 #define BITLBEE_CORE
27 #include "bitlbee.h"
28 #include "commands.h"
29 #include "protocols/nogaim.h"
30 #include "help.h"
31 #include "ipc.h"
32 #include <signal.h>
33 #include <stdio.h>
34 #include <errno.h>
36 static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition );
38 static gboolean try_listen( struct addrinfo *res )
40 int i;
42 global.listen_socket = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
43 if( global.listen_socket < 0 )
45 log_error( "socket" );
46 return FALSE;
49 #ifdef IPV6_V6ONLY
50 if( res->ai_family == AF_INET6 )
52 i = 0;
53 setsockopt( global.listen_socket, IPPROTO_IPV6, IPV6_V6ONLY,
54 (char *) &i, sizeof( i ) );
56 #endif
58 /* TIME_WAIT (?) sucks.. */
59 i = 1;
60 setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) );
62 i = bind( global.listen_socket, res->ai_addr, res->ai_addrlen );
63 if( i == -1 )
65 closesocket( global.listen_socket );
66 global.listen_socket = -1;
68 log_error( "bind" );
69 return FALSE;
72 return TRUE;
75 int bitlbee_daemon_init()
77 struct addrinfo *res, hints, *addrinfo_bind;
78 int i;
79 FILE *fp;
81 log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
82 log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );
84 memset( &hints, 0, sizeof( hints ) );
85 hints.ai_family = PF_UNSPEC;
86 hints.ai_socktype = SOCK_STREAM;
87 hints.ai_flags = AI_PASSIVE
88 #ifdef AI_ADDRCONFIG
89 | AI_ADDRCONFIG
90 #endif
93 i = getaddrinfo( global.conf->iface_in, global.conf->port, &hints, &addrinfo_bind );
94 if( i )
96 log_message( LOGLVL_ERROR, "Couldn't parse address `%s': %s",
97 global.conf->iface_in, gai_strerror(i) );
98 return -1;
101 global.listen_socket = -1;
103 /* Try IPv6 first (which will become an IPv6+IPv4 socket). */
104 for( res = addrinfo_bind; res; res = res->ai_next )
105 if( res->ai_family == AF_INET6 && try_listen( res ) )
106 break;
108 /* The rest (so IPv4, I guess). */
109 if( res == NULL )
110 for( res = addrinfo_bind; res; res = res->ai_next )
111 if( res->ai_family != AF_INET6 && try_listen( res ) )
112 break;
114 freeaddrinfo( addrinfo_bind );
116 i = listen( global.listen_socket, 10 );
117 if( i == -1 )
119 log_error( "listen" );
120 return( -1 );
123 global.listen_watch_source_id = b_input_add( global.listen_socket, GAIM_INPUT_READ, bitlbee_io_new_client, NULL );
125 #ifndef _WIN32
126 if( !global.conf->nofork )
128 i = fork();
129 if( i == -1 )
131 log_error( "fork" );
132 return( -1 );
134 else if( i != 0 )
135 exit( 0 );
137 setsid();
138 chdir( "/" );
140 if( getenv( "_BITLBEE_RESTART_STATE" ) == NULL )
141 for( i = 0; i < 3; i ++ )
142 if( close( i ) == 0 )
144 /* Keep something bogus on those fd's just in case. */
145 open( "/dev/null", O_WRONLY );
148 #endif
150 if( global.conf->runmode == RUNMODE_FORKDAEMON )
151 ipc_master_load_state( getenv( "_BITLBEE_RESTART_STATE" ) );
153 if( global.conf->runmode == RUNMODE_DAEMON || global.conf->runmode == RUNMODE_FORKDAEMON )
154 ipc_master_listen_socket();
156 #ifndef _WIN32
157 if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
159 fprintf( fp, "%d\n", (int) getpid() );
160 fclose( fp );
162 else
164 log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile );
166 #endif
168 if( !global.conf->nofork )
170 log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );
171 log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG );
174 return( 0 );
177 int bitlbee_inetd_init()
179 if( !irc_new( 0 ) )
180 return( 1 );
182 return( 0 );
185 gboolean bitlbee_io_current_client_read( gpointer data, gint fd, b_input_condition cond )
187 irc_t *irc = data;
188 char line[513];
189 int st;
191 st = read( irc->fd, line, sizeof( line ) - 1 );
192 if( st == 0 )
194 irc_abort( irc, 1, "Connection reset by peer" );
195 return FALSE;
197 else if( st < 0 )
199 if( sockerr_again() )
201 return TRUE;
203 else
205 irc_abort( irc, 1, "Read error: %s", strerror( errno ) );
206 return FALSE;
210 line[st] = '\0';
211 if( irc->readbuffer == NULL )
213 irc->readbuffer = g_strdup( line );
215 else
217 irc->readbuffer = g_renew( char, irc->readbuffer, strlen( irc->readbuffer ) + strlen ( line ) + 1 );
218 strcpy( ( irc->readbuffer + strlen( irc->readbuffer ) ), line );
221 irc_process( irc );
223 /* Normally, irc_process() shouldn't call irc_free() but irc_abort(). Just in case: */
224 if( !g_slist_find( irc_connection_list, irc ) )
226 log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", fd );
227 return FALSE;
230 /* Very naughty, go read the RFCs! >:) */
231 if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) )
233 irc_abort( irc, 0, "Maximum line length exceeded" );
234 return FALSE;
237 return TRUE;
240 gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condition cond )
242 irc_t *irc = data;
243 int st, size;
244 char *temp;
246 if( irc->sendbuffer == NULL )
247 return FALSE;
249 size = strlen( irc->sendbuffer );
250 st = write( irc->fd, irc->sendbuffer, size );
252 if( st == 0 || ( st < 0 && !sockerr_again() ) )
254 irc_abort( irc, 1, "Write error: %s", strerror( errno ) );
255 return FALSE;
257 else if( st < 0 ) /* && sockerr_again() */
259 return TRUE;
262 if( st == size )
264 if( irc->status & USTATUS_SHUTDOWN )
266 irc_free( irc );
268 else
270 g_free( irc->sendbuffer );
271 irc->sendbuffer = NULL;
272 irc->w_watch_source_id = 0;
275 return FALSE;
277 else
279 temp = g_strdup( irc->sendbuffer + st );
280 g_free( irc->sendbuffer );
281 irc->sendbuffer = temp;
283 return TRUE;
287 static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition )
289 socklen_t size = sizeof( struct sockaddr_in );
290 struct sockaddr_in conn_info;
291 int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
293 if( new_socket == -1 )
295 log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) );
296 return TRUE;
299 #ifndef _WIN32
300 if( global.conf->runmode == RUNMODE_FORKDAEMON )
302 pid_t client_pid = 0;
303 int fds[2];
305 if( socketpair( AF_UNIX, SOCK_STREAM, 0, fds ) == -1 )
307 log_message( LOGLVL_WARNING, "Could not create IPC socket for client: %s", strerror( errno ) );
308 fds[0] = fds[1] = -1;
311 sock_make_nonblocking( fds[0] );
312 sock_make_nonblocking( fds[1] );
314 client_pid = fork();
316 if( client_pid > 0 && fds[0] != -1 )
318 struct bitlbee_child *child;
320 child = g_new0( struct bitlbee_child, 1 );
321 child->pid = client_pid;
322 child->ipc_fd = fds[0];
323 child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
324 child_list = g_slist_append( child_list, child );
326 log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", (int) client_pid );
328 /* Close some things we don't need in the parent process. */
329 close( new_socket );
330 close( fds[1] );
332 else if( client_pid == 0 )
334 irc_t *irc;
336 /* Since we're fork()ing here, let's make sure we won't
337 get the same random numbers as the parent/siblings. */
338 srand( time( NULL ) ^ getpid() );
340 b_main_init();
342 /* Close the listening socket, we're a client. */
343 close( global.listen_socket );
344 b_event_remove( global.listen_watch_source_id );
346 /* Make the connection. */
347 irc = irc_new( new_socket );
349 /* We can store the IPC fd there now. */
350 global.listen_socket = fds[1];
351 global.listen_watch_source_id = b_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc );
353 close( fds[0] );
355 ipc_master_free_all();
358 else
359 #endif
361 log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
362 irc_new( new_socket );
365 return TRUE;
368 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond )
370 /* Try to save data for all active connections (if desired). */
371 while( irc_connection_list != NULL )
372 irc_free( irc_connection_list->data );
374 /* We'll only reach this point when not running in inetd mode: */
375 b_main_quit();
377 return FALSE;