source: ipc.c @ 0b09da0

Last change on this file since 0b09da0 was 0b09da0, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-06T23:10:17Z

It works! Fragile like hell though, and without any confirmation or whatever.

  • Property mode set to 100644
File size: 19.5 KB
RevLine 
[0431ea1]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[54879ab]4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
[0431ea1]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"
[6dff9d4]30#ifndef _WIN32
31#include <sys/un.h>
32#endif
[0431ea1]33
34GSList *child_list = NULL;
[0b09da0]35static int ipc_child_recv_fd = -1;
[74c119d]36
[f73b969]37static void ipc_master_cmd_client( irc_t *data, char **cmd )
[2face62]38{
[5e713f6]39        /* Normally data points at an irc_t block, but for the IPC master
40           this is different. We think this scary cast is better than
41           creating a new command_t structure, just to make the compiler
42           happy. */
[2face62]43        struct bitlbee_child *child = (void*) data;
44       
[54879ab]45        if( child && cmd[1] )
[bd9b00f]46        {
47                child->host = g_strdup( cmd[1] );
48                child->nick = g_strdup( cmd[2] );
49                child->realname = g_strdup( cmd[3] );
50        }
[2face62]51       
[54879ab]52        if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 )
53                ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
[52744f8]54                                     (int) ( child ? child->pid : -1 ), cmd[2], cmd[1], cmd[3] );
[2face62]55}
56
[f73b969]57static void ipc_master_cmd_die( irc_t *data, char **cmd )
[0431ea1]58{
[74c119d]59        if( global.conf->runmode == RUNMODE_FORKDAEMON )
60                ipc_to_children_str( "DIE\r\n" );
61       
[ba9edaa]62        bitlbee_shutdown( NULL, -1, 0 );
[0431ea1]63}
64
[565a1ea]65static void ipc_master_cmd_deaf( irc_t *data, char **cmd )
66{
67        if( global.conf->runmode == RUNMODE_DAEMON )
68        {
69                b_event_remove( global.listen_watch_source_id );
70                close( global.listen_socket );
71               
72                global.listen_socket = global.listen_watch_source_id = -1;
73       
74                ipc_to_children_str( "OPERMSG :Closed listening socket, waiting "
75                                     "for all users to disconnect." );
76        }
77        else
78        {
79                ipc_to_children_str( "OPERMSG :The DEAF command only works in "
80                                     "normal daemon mode. Try DIE instead." );
81        }
82}
83
[f73b969]84void ipc_master_cmd_rehash( irc_t *data, char **cmd )
[0431ea1]85{
[f4a5940]86        runmode_t oldmode;
87       
88        oldmode = global.conf->runmode;
89       
90        g_free( global.conf );
91        global.conf = conf_load( 0, NULL );
92       
93        if( global.conf->runmode != oldmode )
94        {
95                log_message( LOGLVL_WARNING, "Can't change RunMode setting at runtime, restoring original setting" );
96                global.conf->runmode = oldmode;
97        }
98       
99        if( global.conf->runmode == RUNMODE_FORKDAEMON )
100                ipc_to_children( cmd );
[0431ea1]101}
102
[54879ab]103void ipc_master_cmd_restart( irc_t *data, char **cmd )
104{
105        if( global.conf->runmode != RUNMODE_FORKDAEMON )
106        {
107                /* Tell child that this is unsupported. */
108                return;
109        }
110       
111        global.restart = -1;
[ba9edaa]112        bitlbee_shutdown( NULL, -1, 0 );
[54879ab]113}
114
[6c2404e]115void ipc_master_cmd_identify( irc_t *data, char **cmd )
116{
117        struct bitlbee_child *child = (void*) data, *old = NULL;
[0b09da0]118        char *resp;
[6c2404e]119        GSList *l;
120       
121        if( strcmp( child->nick, cmd[1] ) != 0 )
122                return;
123       
124        g_free( child->password );
125        child->password = g_strdup( cmd[2] );
126       
127        for( l = child_list; l; l = l->next )
128        {
129                old = l->data;
130                if( nick_cmp( old->nick, child->nick ) == 0 && child != old &&
[0b09da0]131                    old->password && strcmp( old->password, child->password ) == 0 )
[6c2404e]132                        break;
133        }
134       
135        child->to_child = old;
[0b09da0]136       
137        if( l )
138        {
139                resp = "TAKEOVER INIT\r\n";
140        }
141        else
142        {
143                /* Won't need the fd since we can't send it anywhere. */
144                close( child->to_fd );
145                child->to_fd = -1;
146                resp = "TAKEOVER NO\r\n";
147        }
148       
149        if( write( child->ipc_fd, resp, strlen( resp ) ) != strlen( resp ) )
150        {
151                ipc_master_free_one( child );
152                child_list = g_slist_remove( child_list, child );
153        }
154}
155
156static gboolean ipc_send_fd( int fd, int send_fd );
157
158void ipc_master_cmd_takeover( irc_t *data, char **cmd )
159{
160        struct bitlbee_child *child = (void*) data;
161       
162        /* TODO: Check if child->to_child is still valid, etc. */
163        if( strcmp( cmd[1], "AUTH" ) == 0 )
164        {
165                if( child->to_child &&
166                    child->nick && child->to_child->nick && cmd[2] &&
167                    child->password && child->to_child->password && cmd[3] &&
168                    strcmp( child->nick, child->to_child->nick ) == 0 &&
169                    strcmp( child->nick, cmd[2] ) == 0 &&
170                    strcmp( child->password, child->to_child->password ) == 0 &&
171                    strcmp( child->password, cmd[3] ) == 0 )
172                {
173                        char *s;
174                       
175                        ipc_send_fd( child->to_child->ipc_fd, child->to_fd );
176                       
177                        s = irc_build_line( cmd );
178                        if( write( child->to_child->ipc_fd, s, strlen( s ) ) != strlen( s ) )
179                        {
180                                ipc_master_free_one( child );
181                                child_list = g_slist_remove( child_list, child );
182                        }
183                        g_free( s );
184                }
185        }
[6c2404e]186}
187
[0431ea1]188static const command_t ipc_master_commands[] = {
[2face62]189        { "client",     3, ipc_master_cmd_client,     0 },
[54879ab]190        { "hello",      0, ipc_master_cmd_client,     0 },
[0431ea1]191        { "die",        0, ipc_master_cmd_die,        0 },
[565a1ea]192        { "deaf",       0, ipc_master_cmd_deaf,       0 },
[f4a5940]193        { "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
[dfc8a46]194        { "wall",       1, NULL,                      IPC_CMD_TO_CHILDREN },
[2face62]195        { "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },
[f4a5940]196        { "rehash",     0, ipc_master_cmd_rehash,     0 },
[48721c3]197        { "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
[54879ab]198        { "restart",    0, ipc_master_cmd_restart,    0 },
[6c2404e]199        { "identify",   2, ipc_master_cmd_identify,   0 },
[0b09da0]200        { "takeover",   1, ipc_master_cmd_takeover,   0 },
[0431ea1]201        { NULL }
202};
203
[74c119d]204
[f73b969]205static void ipc_child_cmd_die( irc_t *irc, char **cmd )
[74c119d]206{
[87de505]207        irc_abort( irc, 0, "Shutdown requested by operator" );
[74c119d]208}
209
[f73b969]210static void ipc_child_cmd_wallops( irc_t *irc, char **cmd )
[0431ea1]211{
[3af70b0]212        if( !( irc->status & USTATUS_LOGGED_IN ) )
[f73b969]213                return;
[daa9e02]214       
[0431ea1]215        if( strchr( irc->umode, 'w' ) )
[3ddb7477]216                irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] );
[e0ca412]217}
218
[dfc8a46]219static void ipc_child_cmd_wall( irc_t *irc, char **cmd )
[e0ca412]220{
[3af70b0]221        if( !( irc->status & USTATUS_LOGGED_IN ) )
[f73b969]222                return;
[daa9e02]223       
[74c119d]224        if( strchr( irc->umode, 's' ) )
[3ddb7477]225                irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] );
[0431ea1]226}
227
[f73b969]228static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
[2face62]229{
[3af70b0]230        if( !( irc->status & USTATUS_LOGGED_IN ) )
[f73b969]231                return;
[2face62]232       
233        if( strchr( irc->umode, 'o' ) )
[3ddb7477]234                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] );
[2face62]235}
236
[f73b969]237static void ipc_child_cmd_rehash( irc_t *irc, char **cmd )
[f4a5940]238{
239        runmode_t oldmode;
240       
241        oldmode = global.conf->runmode;
242       
243        g_free( global.conf );
244        global.conf = conf_load( 0, NULL );
245       
246        global.conf->runmode = oldmode;
247}
248
[f73b969]249static void ipc_child_cmd_kill( irc_t *irc, char **cmd )
[48721c3]250{
[3af70b0]251        if( !( irc->status & USTATUS_LOGGED_IN ) )
[f73b969]252                return;
[48721c3]253       
[3ddb7477]254        if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
[f73b969]255                return;         /* It's not for us. */
[48721c3]256       
[3ddb7477]257        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] );
[f73b969]258        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
[48721c3]259}
260
[54879ab]261static void ipc_child_cmd_hello( irc_t *irc, char **cmd )
262{
[3af70b0]263        if( !( irc->status & USTATUS_LOGGED_IN ) )
[54879ab]264                ipc_to_master_str( "HELLO\r\n" );
265        else
[3ddb7477]266                ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
[54879ab]267}
268
[0b09da0]269static void ipc_child_cmd_takeover( irc_t *irc, char **cmd )
270{
271        if( strcmp( cmd[1], "NO" ) == 0 )
272        {
273                /* No takeover, finish the login. */
274        }
275        else if( strcmp( cmd[1], "INIT" ) == 0 )
276        {
277                ipc_to_master_str( "TAKEOVER AUTH %s :%s\r\n",
278                                   irc->user->nick, irc->password );
279               
280                /* Drop credentials, we'll shut down soon and shouldn't overwrite
281                   any settings. */
282                /* TODO: irc_setpass() should do all of this. */
283                irc_usermsg( irc, "Trying to take over existing session" );
284                /** NOT YET
285                irc_setpass( irc, NULL );
286                irc->status &= ~USTATUS_IDENTIFIED;
287                irc_umode_set( irc, "-R", 1 );
288                */
289        }
290        else if( strcmp( cmd[1], "AUTH" ) == 0 )
291        {
292                if( irc->password && cmd[2] && cmd[3] &&
293                    ipc_child_recv_fd != -1 &&
294                    strcmp( irc->user->nick, cmd[2] ) == 0 &&
295                    strcmp( irc->password, cmd[3] ) == 0 )
296                {
297                        fprintf( stderr, "TO\n" );
298                        b_event_remove( irc->r_watch_source_id );
299                        closesocket( irc->fd );
300                        irc->fd = ipc_child_recv_fd;
301                        irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc );
302                        ipc_child_recv_fd = -1;
303                }
304                fprintf( stderr, "%s %s %s\n", irc->password, cmd[2], cmd[3] );
305                fprintf( stderr, "%d %s %s\n", ipc_child_recv_fd, irc->user->nick, irc->password );
306        }
307}
308
[0431ea1]309static const command_t ipc_child_commands[] = {
[74c119d]310        { "die",        0, ipc_child_cmd_die,         0 },
311        { "wallops",    1, ipc_child_cmd_wallops,     0 },
[dfc8a46]312        { "wall",       1, ipc_child_cmd_wall,        0 },
[2face62]313        { "opermsg",    1, ipc_child_cmd_opermsg,     0 },
[48721c3]314        { "rehash",     0, ipc_child_cmd_rehash,      0 },
315        { "kill",       2, ipc_child_cmd_kill,        0 },
[54879ab]316        { "hello",      0, ipc_child_cmd_hello,       0 },
[0b09da0]317        { "takeover",   1, ipc_child_cmd_takeover,    0 },
[0431ea1]318        { NULL }
319};
320
[6c2404e]321gboolean ipc_child_identify( irc_t *irc )
322{
323        if( global.conf->runmode == RUNMODE_FORKDAEMON )
324        {
325                if( !ipc_send_fd( global.listen_socket, irc->fd ) )
326                        ipc_child_disable();
327       
328                ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password );
329               
330                return TRUE;
331        }
332        else
333                return FALSE;
334}
[74c119d]335
[0431ea1]336static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
337{
[f1d38f2]338        int i, j;
[0431ea1]339       
340        if( !cmd[0] )
341                return;
342       
343        for( i = 0; commands[i].command; i ++ )
344                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
345                {
[f1d38f2]346                        /* There is no typo in this line: */
347                        for( j = 1; cmd[j]; j ++ ); j --;
348                       
349                        if( j < commands[i].required_parameters )
350                                break;
351                       
[f4a5940]352                        if( commands[i].flags & IPC_CMD_TO_CHILDREN )
353                                ipc_to_children( cmd );
354                        else
355                                commands[i].execute( data, cmd );
356                       
[f1d38f2]357                        break;
[0431ea1]358                }
359}
360
[da7b484]361/* Return just one line. Returns NULL if something broke, an empty string
362   on temporary "errors" (EAGAIN and friends). */
[6c2404e]363static char *ipc_readline( int fd, int *recv_fd )
[0431ea1]364{
[6c2404e]365        struct msghdr msg;
366        struct iovec iov;
367        char ccmsg[CMSG_SPACE(sizeof(recv_fd))];
368        struct cmsghdr *cmsg;
[da7b484]369        char buf[513], *eol;
[0431ea1]370        int size;
371       
372        /* Because this is internal communication, it should be pretty safe
373           to just peek at the message, find its length (by searching for the
374           end-of-line) and then just read that message. With internal
375           sockets and limites message length, messages should always be
376           complete. Saves us quite a lot of code and buffering. */
[da7b484]377        size = recv( fd, buf, sizeof( buf ) - 1, MSG_PEEK );
[0431ea1]378        if( size == 0 || ( size < 0 && !sockerr_again() ) )
379                return NULL;
[1ea13be]380        else if( size < 0 ) /* && sockerr_again() */
381                return( g_strdup( "" ) );
[0431ea1]382        else
383                buf[size] = 0;
384       
[da7b484]385        if( ( eol = strstr( buf, "\r\n" ) ) == NULL )
[0431ea1]386                return NULL;
387        else
388                size = eol - buf + 2;
389       
[6c2404e]390        iov.iov_base = buf;
391        iov.iov_len = size;
392       
393        memset( &msg, 0, sizeof( msg ) );
394        msg.msg_iov = &iov;
395        msg.msg_iovlen = 1;
396        msg.msg_control = ccmsg;
397        msg.msg_controllen = sizeof( ccmsg );
398       
399        if( recvmsg( fd, &msg, 0 ) != size )
[0431ea1]400                return NULL;
[6c2404e]401       
402        if( recv_fd )
403                for( cmsg = CMSG_FIRSTHDR( &msg ); cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg ) )
404                        if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS )
405                        {
406                                /* Getting more than one shouldn't happen but if it does,
407                                   make sure we don't leave them around. */
408                                if( *recv_fd != -1 )
409                                        close( *recv_fd );
410                               
411                                *recv_fd = *(int*) CMSG_DATA( cmsg );
[0b09da0]412                                fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd );
[6c2404e]413                        }
414       
[0b09da0]415        fprintf( stderr, "pid %d received: %s", (int) getpid(), buf );
[6c2404e]416        return g_strndup( buf, size - 2 );
[0431ea1]417}
418
[ba9edaa]419gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond )
[0431ea1]420{
[6c2404e]421        struct bitlbee_child *child = data;
[0431ea1]422        char *buf, **cmd;
423       
[6c2404e]424        if( ( buf = ipc_readline( source, &child->to_fd ) ) )
[0431ea1]425        {
426                cmd = irc_parse_line( buf );
427                if( cmd )
[edc767b]428                {
[6c2404e]429                        ipc_command_exec( child, cmd, ipc_master_commands );
[edc767b]430                        g_free( cmd );
431                }
432                g_free( buf );
[0431ea1]433        }
434        else
435        {
[171ef85]436                ipc_master_free_fd( source );
[0431ea1]437        }
[ba9edaa]438       
439        return TRUE;
[0431ea1]440}
441
[ba9edaa]442gboolean ipc_child_read( gpointer data, gint source, b_input_condition cond )
[0431ea1]443{
444        char *buf, **cmd;
445       
[0b09da0]446        if( ( buf = ipc_readline( source, &ipc_child_recv_fd ) ) )
[0431ea1]447        {
448                cmd = irc_parse_line( buf );
449                if( cmd )
[edc767b]450                {
[0431ea1]451                        ipc_command_exec( data, cmd, ipc_child_commands );
[edc767b]452                        g_free( cmd );
453                }
454                g_free( buf );
[0431ea1]455        }
456        else
457        {
[171ef85]458                ipc_child_disable();
[0431ea1]459        }
[ba9edaa]460       
461        return TRUE;
[0431ea1]462}
463
464void ipc_to_master( char **cmd )
465{
466        if( global.conf->runmode == RUNMODE_FORKDAEMON )
467        {
[74c119d]468                char *s = irc_build_line( cmd );
[2face62]469                ipc_to_master_str( "%s", s );
[f4a5940]470                g_free( s );
471        }
472        else if( global.conf->runmode == RUNMODE_DAEMON )
473        {
474                ipc_command_exec( NULL, cmd, ipc_master_commands );
475        }
476}
477
[2face62]478void ipc_to_master_str( char *format, ... )
[f4a5940]479{
[2face62]480        char *msg_buf;
481        va_list params;
482
483        va_start( params, format );
484        msg_buf = g_strdup_vprintf( format, params );
485        va_end( params );
486       
487        if( strlen( msg_buf ) > 512 )
488        {
489                /* Don't send it, it's too long... */
490        }
491        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
[f4a5940]492        {
[171ef85]493                if( global.listen_socket >= 0 )
494                        if( write( global.listen_socket, msg_buf, strlen( msg_buf ) ) <= 0 )
495                                ipc_child_disable();
[f4a5940]496        }
497        else if( global.conf->runmode == RUNMODE_DAEMON )
498        {
[bd9b00f]499                char **cmd, *s;
500               
501                if( ( s = strchr( msg_buf, '\r' ) ) )
502                        *s = 0;
[f4a5940]503               
[2face62]504                cmd = irc_parse_line( msg_buf );
[f4a5940]505                ipc_command_exec( NULL, cmd, ipc_master_commands );
506                g_free( cmd );
[74c119d]507        }
[2face62]508       
509        g_free( msg_buf );
[74c119d]510}
511
512void ipc_to_children( char **cmd )
513{
514        if( global.conf->runmode == RUNMODE_FORKDAEMON )
515        {
516                char *msg_buf = irc_build_line( cmd );
[2face62]517                ipc_to_children_str( "%s", msg_buf );
[74c119d]518                g_free( msg_buf );
519        }
[f4a5940]520        else if( global.conf->runmode == RUNMODE_DAEMON )
521        {
522                GSList *l;
523               
524                for( l = irc_connection_list; l; l = l->next )
525                        ipc_command_exec( l->data, cmd, ipc_child_commands );
526        }
[74c119d]527}
528
[2face62]529void ipc_to_children_str( char *format, ... )
[74c119d]530{
[2face62]531        char *msg_buf;
532        va_list params;
533
534        va_start( params, format );
535        msg_buf = g_strdup_vprintf( format, params );
536        va_end( params );
537       
538        if( strlen( msg_buf ) > 512 )
539        {
540                /* Don't send it, it's too long... */
541        }
542        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
[74c119d]543        {
544                int msg_len = strlen( msg_buf );
[171ef85]545                GSList *l, *next;
[0431ea1]546               
[171ef85]547                for( l = child_list; l; l = next )
[0431ea1]548                {
[74c119d]549                        struct bitlbee_child *c = l->data;
[171ef85]550                       
551                        next = l->next;
552                        if( write( c->ipc_fd, msg_buf, msg_len ) <= 0 )
553                        {
554                                ipc_master_free_one( c );
555                                child_list = g_slist_remove( child_list, c );
556                        }
[0431ea1]557                }
558        }
[f4a5940]559        else if( global.conf->runmode == RUNMODE_DAEMON )
560        {
[bd9b00f]561                char **cmd, *s;
562               
563                if( ( s = strchr( msg_buf, '\r' ) ) )
564                        *s = 0;
[f4a5940]565               
[2face62]566                cmd = irc_parse_line( msg_buf );
[f4a5940]567                ipc_to_children( cmd );
568                g_free( cmd );
569        }
[2face62]570       
571        g_free( msg_buf );
572}
573
[6c2404e]574static gboolean ipc_send_fd( int fd, int send_fd )
575{
576        struct msghdr msg;
577        struct iovec iov;
578        char ccmsg[CMSG_SPACE(sizeof(fd))];
579        struct cmsghdr *cmsg;
580       
581        memset( &msg, 0, sizeof( msg ) );
582        iov.iov_base = "0x90\r\n";
583        iov.iov_len = 6;
584        msg.msg_iov = &iov;
585        msg.msg_iovlen = 1;
586       
587        msg.msg_control = ccmsg;
588        msg.msg_controllen = sizeof( ccmsg );
589        cmsg = CMSG_FIRSTHDR( &msg );
590        cmsg->cmsg_level = SOL_SOCKET;
591        cmsg->cmsg_type = SCM_RIGHTS;
592        cmsg->cmsg_len = CMSG_LEN( sizeof( send_fd ) );
593        *(int*)CMSG_DATA( cmsg ) = send_fd;
594        msg.msg_controllen = cmsg->cmsg_len;
595       
596        return sendmsg( fd, &msg, 0 ) == 6;
597}
598
[2face62]599void ipc_master_free_one( struct bitlbee_child *c )
600{
[ba9edaa]601        b_event_remove( c->ipc_inpa );
[2face62]602        closesocket( c->ipc_fd );
603       
[6c2404e]604        if( c->to_fd != -1 )
605                close( c->to_fd );
606       
[2face62]607        g_free( c->host );
608        g_free( c->nick );
609        g_free( c->realname );
[6c2404e]610        g_free( c->password );
[2face62]611        g_free( c );
612}
613
[171ef85]614void ipc_master_free_fd( int fd )
615{
616        GSList *l;
617        struct bitlbee_child *c;
618       
619        for( l = child_list; l; l = l->next )
620        {
621                c = l->data;
622                if( c->ipc_fd == fd )
623                {
624                        ipc_master_free_one( c );
625                        child_list = g_slist_remove( child_list, c );
626                        break;
627                }
628        }
629}
630
[2face62]631void ipc_master_free_all()
632{
633        GSList *l;
634       
635        for( l = child_list; l; l = l->next )
636                ipc_master_free_one( l->data );
637       
638        g_slist_free( child_list );
639        child_list = NULL;
[0431ea1]640}
[54879ab]641
[171ef85]642void ipc_child_disable()
643{
644        b_event_remove( global.listen_watch_source_id );
645        close( global.listen_socket );
646       
647        global.listen_socket = -1;
648}
649
[80c1e4d]650#ifndef _WIN32
[54879ab]651char *ipc_master_save_state()
652{
653        char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" );
654        int fd = mkstemp( fn );
655        GSList *l;
656        FILE *fp;
657        int i;
658       
659        if( fd == -1 )
660        {
661                log_message( LOGLVL_ERROR, "Could not create temporary file: %s", strerror( errno ) );
662                g_free( fn );
663                return NULL;
664        }
665       
666        /* This is more convenient now. */
667        fp = fdopen( fd, "w" );
668       
669        for( l = child_list, i = 0; l; l = l->next )
670                i ++;
671       
672        /* Number of client processes. */
673        fprintf( fp, "%d\n", i );
674       
675        for( l = child_list; l; l = l->next )
[52744f8]676                fprintf( fp, "%d %d\n", (int) ((struct bitlbee_child*)l->data)->pid,
[54879ab]677                                        ((struct bitlbee_child*)l->data)->ipc_fd );
678       
679        if( fclose( fp ) == 0 )
680        {
681                return fn;
682        }
683        else
684        {
685                unlink( fn );
686                g_free( fn );
687                return NULL;
688        }
689}
690
[6dff9d4]691
[ba9edaa]692static gboolean new_ipc_client( gpointer data, gint serversock, b_input_condition cond )
[6dff9d4]693{
694        struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 );
[a0d04d6]695       
[6c2404e]696        child->to_fd = -1;
[a0d04d6]697        child->ipc_fd = accept( serversock, NULL, 0 );
698        if( child->ipc_fd == -1 )
699        {
[8a56e52]700                log_message( LOGLVL_WARNING, "Unable to accept connection on UNIX domain socket: %s", strerror(errno) );
701                return TRUE;
702        }
[6dff9d4]703               
[e046390]704        child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
[a0d04d6]705       
[6c2404e]706        child_list = g_slist_prepend( child_list, child );
[ba9edaa]707       
[6dff9d4]708        return TRUE;
709}
710
711int ipc_master_listen_socket()
712{
713        struct sockaddr_un un_addr;
714        int serversock;
715
716        /* Clean up old socket files that were hanging around.. */
[8a56e52]717        if (unlink(IPCSOCKET) == -1 && errno != ENOENT) {
718                log_message( LOGLVL_ERROR, "Could not remove old IPC socket at %s: %s", IPCSOCKET, strerror(errno) );
719                return 0;
720        }
[6dff9d4]721
722        un_addr.sun_family = AF_UNIX;
723        strcpy(un_addr.sun_path, IPCSOCKET);
724
725        serversock = socket(AF_UNIX, SOCK_STREAM, PF_UNIX);
726
[8a56e52]727        if (serversock == -1) {
728                log_message( LOGLVL_WARNING, "Unable to create UNIX socket: %s", strerror(errno) );
729                return 0;
730        }
[6dff9d4]731
[5d6c178]732        if (bind(serversock, (struct sockaddr *)&un_addr, sizeof(un_addr)) == -1) {
[8a56e52]733                log_message( LOGLVL_WARNING, "Unable to bind UNIX socket to %s: %s", IPCSOCKET, strerror(errno) );
734                return 0;
735        }
736
737        if (listen(serversock, 5) == -1) {
738                log_message( LOGLVL_WARNING, "Unable to listen on UNIX socket: %s", strerror(errno) );
739                return 0;
740        }
[6dff9d4]741       
[e046390]742        b_input_add( serversock, B_EV_IO_READ, new_ipc_client, NULL );
[8a56e52]743       
[6dff9d4]744        return 1;
745}
746#else
[1cda4f3]747int ipc_master_listen_socket()
748{
[6dff9d4]749        /* FIXME: Open named pipe \\.\BITLBEE */
[1cda4f3]750        return 0;
751}
[6dff9d4]752#endif
753
[cd63d58]754int ipc_master_load_state( char *statefile )
[54879ab]755{
756        struct bitlbee_child *child;
757        FILE *fp;
758        int i, n;
759       
760        if( statefile == NULL )
761                return 0;
[cd63d58]762       
[54879ab]763        fp = fopen( statefile, "r" );
764        unlink( statefile );    /* Why do it later? :-) */
765        if( fp == NULL )
766                return 0;
767       
768        if( fscanf( fp, "%d", &n ) != 1 )
769        {
770                log_message( LOGLVL_WARNING, "Could not import state information for child processes." );
771                fclose( fp );
772                return 0;
773        }
774       
775        log_message( LOGLVL_INFO, "Importing information for %d child processes.", n );
776        for( i = 0; i < n; i ++ )
777        {
778                child = g_new0( struct bitlbee_child, 1 );
779               
[52744f8]780                if( fscanf( fp, "%d %d", (int *) &child->pid, &child->ipc_fd ) != 2 )
[54879ab]781                {
782                        log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i );
783                        g_free( child );
784                        fclose( fp );
785                        return 0;
786                }
[e046390]787                child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
[6c2404e]788                child->to_fd = -1;
[54879ab]789               
[6c2404e]790                child_list = g_slist_prepend( child_list, child );
[54879ab]791        }
792       
793        ipc_to_children_str( "HELLO\r\n" );
794        ipc_to_children_str( "OPERMSG :New BitlBee master process started (version " BITLBEE_VERSION ")\r\n" );
795       
[dd89a55]796        fclose( fp );
[54879ab]797        return 1;
798}
Note: See TracBrowser for help on using the repository browser.