source: ipc.c @ 5424c76

Last change on this file since 5424c76 was 5424c76, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-01-19T17:52:19Z

Rehash command now also works in inetd mode. Other "IPC" commands only make
sense in daemon mode.

  • Property mode set to 100644
File size: 9.1 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* IPC - communication between BitlBee processes                        */
8
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.
14
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.
19
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
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28#include "ipc.h"
29#include "commands.h"
30
31GSList *child_list = NULL;
32
33
34static int ipc_master_cmd_client( irc_t *data, char **cmd )
35{
36        struct bitlbee_child *child = (void*) data;
37       
38        if( child )
39        {
40                child->host = g_strdup( cmd[1] );
41                child->nick = g_strdup( cmd[2] );
42                child->realname = g_strdup( cmd[3] );
43        }
44       
45        ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
46                             child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
47       
48        return 1;
49}
50
51static int ipc_master_cmd_die( irc_t *data, char **cmd )
52{
53        if( global.conf->runmode == RUNMODE_FORKDAEMON )
54                ipc_to_children_str( "DIE\r\n" );
55       
56        bitlbee_shutdown( NULL );
57       
58        return 1;
59}
60
61int ipc_master_cmd_rehash( irc_t *data, char **cmd )
62{
63        runmode_t oldmode;
64       
65        oldmode = global.conf->runmode;
66       
67        g_free( global.conf );
68        global.conf = conf_load( 0, NULL );
69       
70        if( global.conf->runmode != oldmode )
71        {
72                log_message( LOGLVL_WARNING, "Can't change RunMode setting at runtime, restoring original setting" );
73                global.conf->runmode = oldmode;
74        }
75       
76        if( global.conf->runmode == RUNMODE_FORKDAEMON )
77                ipc_to_children( cmd );
78       
79        return 1;
80}
81
82static const command_t ipc_master_commands[] = {
83        { "client",     3, ipc_master_cmd_client,     0 },
84        { "die",        0, ipc_master_cmd_die,        0 },
85        { "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
86        { "lilo",       1, NULL,                      IPC_CMD_TO_CHILDREN },
87        { "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },
88        { "rehash",     0, ipc_master_cmd_rehash,     0 },
89        { "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
90        { NULL }
91};
92
93
94static int ipc_child_cmd_die( irc_t *irc, char **cmd )
95{
96        if( irc->status >= USTATUS_LOGGED_IN )
97                irc_write( irc, "ERROR :Operator requested server shutdown, bye bye!" );
98       
99        irc_abort( irc );
100       
101        return 1;
102}
103
104static int ipc_child_cmd_wallops( irc_t *irc, char **cmd )
105{
106        if( irc->status < USTATUS_LOGGED_IN )
107                return 1;
108       
109        if( strchr( irc->umode, 'w' ) )
110                irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
111       
112        return 1;
113}
114
115static int ipc_child_cmd_lilo( irc_t *irc, char **cmd )
116{
117        if( irc->status < USTATUS_LOGGED_IN )
118                return 1;
119       
120        if( strchr( irc->umode, 's' ) )
121                irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
122       
123        return 1;
124}
125
126static int ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
127{
128        if( irc->status < USTATUS_LOGGED_IN )
129                return 1;
130       
131        if( strchr( irc->umode, 'o' ) )
132                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
133       
134        return 1;
135}
136
137static int ipc_child_cmd_rehash( irc_t *irc, char **cmd )
138{
139        runmode_t oldmode;
140       
141        oldmode = global.conf->runmode;
142       
143        g_free( global.conf );
144        global.conf = conf_load( 0, NULL );
145       
146        global.conf->runmode = oldmode;
147       
148        return 1;
149}
150
151static int ipc_child_cmd_kill( irc_t *irc, char **cmd )
152{
153        if( irc->status < USTATUS_LOGGED_IN )
154                return 1;
155       
156        if( nick_cmp( cmd[1], irc->nick ) != 0 )
157                return 1;       /* It's not for us. */
158       
159        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
160        irc_abort( irc );
161        /* g_io_channel_close( irc->io_channel ); */
162       
163        return 0;
164}
165
166static const command_t ipc_child_commands[] = {
167        { "die",        0, ipc_child_cmd_die,         0 },
168        { "wallops",    1, ipc_child_cmd_wallops,     0 },
169        { "lilo",       1, ipc_child_cmd_lilo,        0 },
170        { "opermsg",    1, ipc_child_cmd_opermsg,     0 },
171        { "rehash",     0, ipc_child_cmd_rehash,      0 },
172        { "kill",       2, ipc_child_cmd_kill,        0 },
173        { NULL }
174};
175
176
177static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
178{
179        int i;
180       
181        if( !cmd[0] )
182                return;
183       
184        for( i = 0; commands[i].command; i ++ )
185                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
186                {
187                        if( commands[i].flags & IPC_CMD_TO_CHILDREN )
188                                ipc_to_children( cmd );
189                        else
190                                commands[i].execute( data, cmd );
191                       
192                        return;
193                }
194}
195
196static char *ipc_readline( int fd )
197{
198        char *buf, *eol;
199        int size;
200       
201        buf = g_new0( char, 513 );
202       
203        /* Because this is internal communication, it should be pretty safe
204           to just peek at the message, find its length (by searching for the
205           end-of-line) and then just read that message. With internal
206           sockets and limites message length, messages should always be
207           complete. Saves us quite a lot of code and buffering. */
208        size = recv( fd, buf, 512, MSG_PEEK );
209        if( size == 0 || ( size < 0 && !sockerr_again() ) )
210                return NULL;
211        else if( size < 0 ) /* && sockerr_again() */
212                return( g_strdup( "" ) );
213        else
214                buf[size] = 0;
215       
216        eol = strstr( buf, "\r\n" );
217        if( eol == NULL )
218                return NULL;
219        else
220                size = eol - buf + 2;
221       
222        g_free( buf );
223        buf = g_new0( char, size + 1 );
224       
225        if( recv( fd, buf, size, 0 ) != size )
226                return NULL;
227        else
228                buf[size-2] = 0;
229       
230        return buf;
231}
232
233void ipc_master_read( gpointer data, gint source, GaimInputCondition cond )
234{
235        char *buf, **cmd;
236       
237        if( ( buf = ipc_readline( source ) ) )
238        {
239                cmd = irc_parse_line( buf );
240                if( cmd )
241                        ipc_command_exec( data, cmd, ipc_master_commands );
242        }
243        else
244        {
245                GSList *l;
246                struct bitlbee_child *c;
247               
248                for( l = child_list; l; l = l->next )
249                {
250                        c = l->data;
251                        if( c->ipc_fd == source )
252                        {
253                                ipc_master_free_one( c );
254                                child_list = g_slist_remove( child_list, c );
255                                break;
256                        }
257                }
258        }
259}
260
261void ipc_child_read( gpointer data, gint source, GaimInputCondition cond )
262{
263        char *buf, **cmd;
264       
265        if( ( buf = ipc_readline( source ) ) )
266        {
267                cmd = irc_parse_line( buf );
268                if( cmd )
269                        ipc_command_exec( data, cmd, ipc_child_commands );
270        }
271        else
272        {
273                gaim_input_remove( global.listen_watch_source_id );
274                close( global.listen_socket );
275               
276                global.listen_socket = -1;
277        }
278}
279
280void ipc_to_master( char **cmd )
281{
282        if( global.conf->runmode == RUNMODE_FORKDAEMON )
283        {
284                char *s = irc_build_line( cmd );
285                ipc_to_master_str( "%s", s );
286                g_free( s );
287        }
288        else if( global.conf->runmode == RUNMODE_DAEMON )
289        {
290                ipc_command_exec( NULL, cmd, ipc_master_commands );
291        }
292}
293
294void ipc_to_master_str( char *format, ... )
295{
296        char *msg_buf;
297        va_list params;
298
299        va_start( params, format );
300        msg_buf = g_strdup_vprintf( format, params );
301        va_end( params );
302       
303        if( strlen( msg_buf ) > 512 )
304        {
305                /* Don't send it, it's too long... */
306        }
307        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
308        {
309                write( global.listen_socket, msg_buf, strlen( msg_buf ) );
310        }
311        else if( global.conf->runmode == RUNMODE_DAEMON )
312        {
313                char **cmd, *s;
314               
315                if( ( s = strchr( msg_buf, '\r' ) ) )
316                        *s = 0;
317               
318                cmd = irc_parse_line( msg_buf );
319                ipc_command_exec( NULL, cmd, ipc_master_commands );
320                g_free( cmd );
321        }
322       
323        g_free( msg_buf );
324}
325
326void ipc_to_children( char **cmd )
327{
328        if( global.conf->runmode == RUNMODE_FORKDAEMON )
329        {
330                char *msg_buf = irc_build_line( cmd );
331                ipc_to_children_str( "%s", msg_buf );
332                g_free( msg_buf );
333        }
334        else if( global.conf->runmode == RUNMODE_DAEMON )
335        {
336                GSList *l;
337               
338                for( l = irc_connection_list; l; l = l->next )
339                        ipc_command_exec( l->data, cmd, ipc_child_commands );
340        }
341}
342
343void ipc_to_children_str( char *format, ... )
344{
345        char *msg_buf;
346        va_list params;
347
348        va_start( params, format );
349        msg_buf = g_strdup_vprintf( format, params );
350        va_end( params );
351       
352        if( strlen( msg_buf ) > 512 )
353        {
354                /* Don't send it, it's too long... */
355        }
356        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
357        {
358                int msg_len = strlen( msg_buf );
359                GSList *l;
360               
361                for( l = child_list; l; l = l->next )
362                {
363                        struct bitlbee_child *c = l->data;
364                        write( c->ipc_fd, msg_buf, msg_len );
365                }
366        }
367        else if( global.conf->runmode == RUNMODE_DAEMON )
368        {
369                char **cmd, *s;
370               
371                if( ( s = strchr( msg_buf, '\r' ) ) )
372                        *s = 0;
373               
374                cmd = irc_parse_line( msg_buf );
375                ipc_to_children( cmd );
376                g_free( cmd );
377        }
378       
379        g_free( msg_buf );
380}
381
382void ipc_master_free_one( struct bitlbee_child *c )
383{
384        gaim_input_remove( c->ipc_inpa );
385        closesocket( c->ipc_fd );
386       
387        g_free( c->host );
388        g_free( c->nick );
389        g_free( c->realname );
390        g_free( c );
391}
392
393void ipc_master_free_all()
394{
395        GSList *l;
396       
397        for( l = child_list; l; l = l->next )
398                ipc_master_free_one( l->data );
399       
400        g_slist_free( child_list );
401        child_list = NULL;
402}
Note: See TracBrowser for help on using the repository browser.