source: ipc.c @ 2face62

Last change on this file since 2face62 was 2face62, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-01-19T16:34:41Z

A bit too much for one commit, but well: Client processes didn't clean up
some master structs (bitlbee_child list) yet, and added the IPC CLIENT
command to inform the master process about host- and nickname. Can be useful
later.

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