source: ipc.c @ 74c119d

Last change on this file since 74c119d was 74c119d, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-01-15T15:42:20Z

Better DIE implementation, added SO_REUSEADDR to listening socket.

  • Property mode set to 100644
File size: 5.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_die( irc_t *data, char **cmd )
35{
36        if( global.conf->runmode == RUNMODE_FORKDAEMON )
37                ipc_to_children_str( "DIE\r\n" );
38       
39        bitlbee_shutdown( NULL );
40       
41        return 1;
42}
43
44static int ipc_master_cmd_wallops( irc_t *data, char **cmd )
45{
46        ipc_to_children( cmd );
47       
48        return 1;
49}
50
51static const command_t ipc_master_commands[] = {
52        { "die",        0, ipc_master_cmd_die,        0 },
53        { "wallops",    1, ipc_master_cmd_wallops,    0 },
54        { "lilo",       1, ipc_master_cmd_wallops,    0 },
55        { NULL }
56};
57
58
59static int ipc_child_cmd_die( irc_t *data, char **cmd )
60{
61        bitlbee_shutdown( NULL );
62       
63        return 1;
64}
65
66static int ipc_child_cmd_wallops( irc_t *data, char **cmd )
67{
68        irc_t *irc = data;
69       
70        if( strchr( irc->umode, 'w' ) )
71                irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
72       
73        return 1;
74}
75
76static int ipc_child_cmd_lilo( irc_t *data, char **cmd )
77{
78        irc_t *irc = data;
79       
80        if( strchr( irc->umode, 's' ) )
81                irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
82       
83        return 1;
84}
85
86static const command_t ipc_child_commands[] = {
87        { "die",        0, ipc_child_cmd_die,         0 },
88        { "wallops",    1, ipc_child_cmd_wallops,     0 },
89        { "lilo",       1, ipc_child_cmd_lilo,        0 },
90        { NULL }
91};
92
93
94static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
95{
96        int i;
97       
98        if( !cmd[0] )
99                return;
100       
101        for( i = 0; commands[i].command; i ++ )
102                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
103                {
104                        commands[i].execute( data, cmd );
105                        return;
106                }
107}
108
109static char *ipc_readline( int fd )
110{
111        char *buf, *eol;
112        int size;
113       
114        buf = g_new0( char, 513 );
115       
116        /* Because this is internal communication, it should be pretty safe
117           to just peek at the message, find its length (by searching for the
118           end-of-line) and then just read that message. With internal
119           sockets and limites message length, messages should always be
120           complete. Saves us quite a lot of code and buffering. */
121        size = recv( fd, buf, 512, MSG_PEEK );
122        if( size == 0 || ( size < 0 && !sockerr_again() ) )
123                return NULL;
124        else
125                buf[size] = 0;
126       
127        eol = strstr( buf, "\r\n" );
128        if( eol == NULL )
129                return NULL;
130        else
131                size = eol - buf + 2;
132       
133        g_free( buf );
134        buf = g_new0( char, size + 1 );
135       
136        if( recv( fd, buf, size, 0 ) != size )
137                return NULL;
138        else
139                buf[size-2] = 0;
140       
141        return buf;
142}
143
144void ipc_master_read( gpointer data, gint source, GaimInputCondition cond )
145{
146        char *buf, **cmd;
147       
148        if( ( buf = ipc_readline( source ) ) )
149        {
150                cmd = irc_parse_line( buf );
151                if( cmd )
152                        ipc_command_exec( data, cmd, ipc_master_commands );
153        }
154        else
155        {
156                GSList *l;
157                struct bitlbee_child *c;
158               
159                for( l = child_list; l; l = l->next )
160                {
161                        c = l->data;
162                        if( c->ipc_fd == source )
163                        {
164                                close( c->ipc_fd );
165                                gaim_input_remove( c->ipc_inpa );
166                                g_free( c );
167                               
168                                child_list = g_slist_remove( child_list, l );
169                               
170                                break;
171                        }
172                }
173        }
174}
175
176void ipc_child_read( gpointer data, gint source, GaimInputCondition cond )
177{
178        char *buf, **cmd;
179       
180        if( ( buf = ipc_readline( source ) ) )
181        {
182                cmd = irc_parse_line( buf );
183                if( cmd )
184                        ipc_command_exec( data, cmd, ipc_child_commands );
185        }
186        else
187        {
188                gaim_input_remove( global.listen_watch_source_id );
189                close( global.listen_socket );
190               
191                global.listen_socket = -1;
192        }
193}
194
195void ipc_to_master( char **cmd )
196{
197        if( global.conf->runmode == RUNMODE_FORKDAEMON )
198        {
199                char *s = irc_build_line( cmd );
200                write( global.listen_socket, s, strlen( s ) );
201                g_free( s );
202        }
203}
204
205void ipc_to_children( char **cmd )
206{
207        if( global.conf->runmode == RUNMODE_FORKDAEMON )
208        {
209                char *msg_buf = irc_build_line( cmd );
210                ipc_to_children_str( msg_buf );
211                g_free( msg_buf );
212        }
213}
214
215void ipc_to_children_str( char *msg_buf )
216{
217        if( global.conf->runmode == RUNMODE_FORKDAEMON )
218        {
219                int msg_len = strlen( msg_buf );
220                GSList *l;
221               
222                for( l = child_list; l; l = l->next )
223                {
224                        struct bitlbee_child *c = l->data;
225                        write( c->ipc_fd, msg_buf, msg_len );
226                }
227        }
228}
Note: See TracBrowser for help on using the repository browser.