Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • ipc.c

    rc5bff81 r3ddb7477  
    3333
    3434GSList *child_list = NULL;
    35 static int ipc_child_recv_fd = -1;
    36 
    37 static void ipc_master_takeover_fail( struct bitlbee_child *child, gboolean both );
    38 static gboolean ipc_send_fd( int fd, int send_fd );
    3935
    4036static void ipc_master_cmd_client( irc_t *data, char **cmd )
     
    5349        }
    5450       
    55         /* CLIENT == On initial connects, HELLO is after /RESTARTs. */
    5651        if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 )
    5752                ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
     
    5954}
    6055
    61 static void ipc_master_cmd_nick( irc_t *data, char **cmd )
    62 {
    63         struct bitlbee_child *child = (void*) data;
    64        
    65         if( child && cmd[1] )
    66         {
    67                 g_free( child->nick );
    68                 child->nick = g_strdup( cmd[1] );
    69         }
    70 }
    71 
    7256static void ipc_master_cmd_die( irc_t *data, char **cmd )
    7357{
     
    126110        global.restart = -1;
    127111        bitlbee_shutdown( NULL, -1, 0 );
    128 }
    129 
    130 void ipc_master_cmd_identify( irc_t *data, char **cmd )
    131 {
    132         struct bitlbee_child *child = (void*) data, *old = NULL;
    133         char *resp;
    134         GSList *l;
    135        
    136         if( strcmp( child->nick, cmd[1] ) != 0 )
    137                 return;
    138        
    139         g_free( child->password );
    140         child->password = g_strdup( cmd[2] );
    141        
    142         for( l = child_list; l; l = l->next )
    143         {
    144                 old = l->data;
    145                 if( nick_cmp( old->nick, child->nick ) == 0 && child != old &&
    146                     old->password && strcmp( old->password, child->password ) == 0 )
    147                         break;
    148         }
    149        
    150         if( l && !child->to_child && !old->to_child )
    151         {
    152                 resp = "TAKEOVER INIT\r\n";
    153                 child->to_child = old;
    154                 old->to_child = child;
    155         }
    156         else
    157         {
    158                 /* Won't need the fd since we can't send it anywhere. */
    159                 closesocket( child->to_fd );
    160                 child->to_fd = -1;
    161                 resp = "TAKEOVER NO\r\n";
    162         }
    163        
    164         if( write( child->ipc_fd, resp, strlen( resp ) ) != strlen( resp ) )
    165                 ipc_master_free_one( child );
    166 }
    167 
    168 
    169 void ipc_master_cmd_takeover( irc_t *data, char **cmd )
    170 {
    171         struct bitlbee_child *child = (void*) data;
    172         char *fwd = NULL;
    173        
    174         if( child->to_child == NULL ||
    175             g_slist_find( child_list, child->to_child ) == NULL )
    176                 return ipc_master_takeover_fail( child, FALSE );
    177        
    178         if( strcmp( cmd[1], "AUTH" ) == 0 )
    179         {
    180                 /* New connection -> Master */
    181                 if( child->to_child &&
    182                     child->nick && child->to_child->nick && cmd[2] &&
    183                     child->password && child->to_child->password && cmd[3] &&
    184                     strcmp( child->nick, child->to_child->nick ) == 0 &&
    185                     strcmp( child->nick, cmd[2] ) == 0 &&
    186                     strcmp( child->password, child->to_child->password ) == 0 &&
    187                     strcmp( child->password, cmd[3] ) == 0 )
    188                 {
    189                         ipc_send_fd( child->to_child->ipc_fd, child->to_fd );
    190                        
    191                         fwd = irc_build_line( cmd );
    192                         if( write( child->to_child->ipc_fd, fwd, strlen( fwd ) ) != strlen( fwd ) )
    193                                 ipc_master_free_one( child );
    194                         g_free( fwd );
    195                 }
    196                 else
    197                         return ipc_master_takeover_fail( child, TRUE );
    198         }
    199         else if( strcmp( cmd[1], "DONE" ) == 0 || strcmp( cmd[1], "FAIL" ) == 0 )
    200         {
    201                 /* Old connection -> Master */
    202                 int fd;
    203                
    204                 /* The copy was successful (or not), we don't need it anymore. */
    205                 closesocket( child->to_fd );
    206                 child->to_fd = -1;
    207                
    208                 /* Pass it through to the other party, and flush all state. */
    209                 fwd = irc_build_line( cmd );
    210                 fd = child->to_child->ipc_fd;
    211                 child->to_child->to_child = NULL;
    212                 child->to_child = NULL;
    213                 if( write( fd, fwd, strlen( fwd ) ) != strlen( fwd ) )
    214                         ipc_master_free_one( child );
    215                 g_free( fwd );
    216         }
    217112}
    218113
     
    220115        { "client",     3, ipc_master_cmd_client,     0 },
    221116        { "hello",      0, ipc_master_cmd_client,     0 },
    222         { "nick",       1, ipc_master_cmd_nick,       0 },
    223117        { "die",        0, ipc_master_cmd_die,        0 },
    224118        { "deaf",       0, ipc_master_cmd_deaf,       0 },
     
    229123        { "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
    230124        { "restart",    0, ipc_master_cmd_restart,    0 },
    231         { "identify",   2, ipc_master_cmd_identify,   0 },
    232         { "takeover",   1, ipc_master_cmd_takeover,   0 },
    233125        { NULL }
    234126};
     
    297189        else
    298190                ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
    299 }
    300 
    301 static void ipc_child_cmd_takeover_yes( void *data );
    302 static void ipc_child_cmd_takeover_no( void *data );
    303 
    304 static void ipc_child_cmd_takeover( irc_t *irc, char **cmd )
    305 {
    306         if( strcmp( cmd[1], "NO" ) == 0 )
    307         {
    308                 /* Master->New connection */
    309                 /* No takeover, finish the login. */
    310         }
    311         else if( strcmp( cmd[1], "INIT" ) == 0 )
    312         {
    313                 /* Master->New connection */
    314                 /* Offer to take over the old session, unless for some reason
    315                    we're already logging into IM connections. */
    316                 if( irc->login_source_id != -1 )
    317                         query_add( irc, NULL,
    318                                    "You're already connected to this server. "
    319                                    "Would you like to take over this session?",
    320                                    ipc_child_cmd_takeover_yes,
    321                                    ipc_child_cmd_takeover_no, irc );
    322                
    323                 /* This one's going to connect to accounts, avoid that. */
    324                 b_event_remove( irc->login_source_id );
    325                 irc->login_source_id = -1;
    326         }
    327         else if( strcmp( cmd[1], "AUTH" ) == 0 )
    328         {
    329                 /* Master->Old connection */
    330                 if( irc->password && cmd[2] && cmd[3] &&
    331                     ipc_child_recv_fd != -1 &&
    332                     strcmp( irc->user->nick, cmd[2] ) == 0 &&
    333                     strcmp( irc->password, cmd[3] ) == 0 )
    334                 {
    335                         GSList *l;
    336                        
    337                         /* TODO: Move this all into irc_switch_fd() or so and
    338                            irc_sync() */
    339                         b_event_remove( irc->r_watch_source_id );
    340                         closesocket( irc->fd );
    341                         irc->fd = ipc_child_recv_fd;
    342                         irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc );
    343                         ipc_child_recv_fd = -1;
    344                        
    345                         irc_write( irc, ":%s!%s@%s MODE %s :+%s", irc->user->nick,
    346                                    irc->user->user, irc->user->host, irc->user->nick,
    347                                    irc->umode );
    348                        
    349                         for( l = irc->channels; l; l = l->next )
    350                         {
    351                                 irc_channel_t *ic = l->data;
    352                                 if( ic->flags & IRC_CHANNEL_JOINED )
    353                                         irc_send_join( ic, irc->user );
    354                         }
    355                         irc_usermsg( irc, "You've successfully taken over your old session" );
    356                        
    357                         ipc_to_master_str( "TAKEOVER DONE\r\n" );
    358                 }
    359                 else
    360                 {
    361                         ipc_to_master_str( "TAKEOVER FAIL\r\n" );
    362                 }
    363         }
    364         else if( strcmp( cmd[1], "DONE" ) == 0 )
    365         {
    366                 /* Master->New connection (now taken over by old process) */
    367                 irc_free( irc );
    368         }
    369         else if( strcmp( cmd[1], "FAIL" ) == 0 )
    370         {
    371                 /* Master->New connection */
    372                 irc_usermsg( irc, "Could not take over old session" );
    373         }
    374 }
    375 
    376 static void ipc_child_cmd_takeover_yes( void *data )
    377 {
    378         irc_t *irc = data;
    379         GSList *l;
    380        
    381         /* Master->New connection */
    382         ipc_to_master_str( "TAKEOVER AUTH %s :%s\r\n",
    383                            irc->user->nick, irc->password );
    384        
    385         /* Drop credentials, we'll shut down soon and shouldn't overwrite
    386            any settings. */
    387         irc_usermsg( irc, "Trying to take over existing session" );
    388        
    389         /* TODO: irc_setpass() should do all of this. */
    390         irc_setpass( irc, NULL );
    391         irc->status &= ~USTATUS_IDENTIFIED;
    392         irc_umode_set( irc, "-R", 1 );
    393        
    394         for( l = irc->channels; l; l = l->next )
    395                 irc_channel_del_user( l->data, irc->user, IRC_CDU_KICK,
    396                                       "Switching to old session" );
    397        
    398         irc_write( irc, ":%s!%s@%s MODE %s :-%s", irc->user->nick,
    399                    irc->user->user, irc->user->host, irc->user->nick,
    400                    irc->umode );
    401 }
    402 
    403 static void ipc_child_cmd_takeover_no( void *data )
    404 {
    405         ipc_to_master_str( "TAKEOVER NO\r\n" );
    406         cmd_identify_finish( data, 0, 0 );
    407191}
    408192
     
    415199        { "kill",       2, ipc_child_cmd_kill,        0 },
    416200        { "hello",      0, ipc_child_cmd_hello,       0 },
    417         { "takeover",   1, ipc_child_cmd_takeover,    0 },
    418201        { NULL }
    419202};
    420203
    421 gboolean ipc_child_identify( irc_t *irc )
    422 {
    423         if( global.conf->runmode == RUNMODE_FORKDAEMON )
    424         {
    425                 if( !ipc_send_fd( global.listen_socket, irc->fd ) )
    426                         ipc_child_disable();
    427        
    428                 ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password );
    429                
    430                 return TRUE;
    431         }
    432         else
    433                 return FALSE;
    434 }
    435 
    436 static void ipc_master_takeover_fail( struct bitlbee_child *child, gboolean both )
    437 {
    438         if( child == NULL || g_slist_find( child_list, child ) == NULL )
    439                 return;
    440        
    441         if( both && child->to_child != NULL )
    442                 ipc_master_takeover_fail( child->to_child, FALSE );
    443        
    444         if( child->to_fd > -1 )
    445         {
    446                 /* Send this error only to the new connection, which can be
    447                    recognised by to_fd being set. */
    448                 if( write( child->ipc_fd, "TAKEOVER FAIL\r\n", 15 ) != 15 )
    449                 {
    450                         ipc_master_free_one( child );
    451                         return;
    452                 }
    453                 close( child->to_fd );
    454                 child->to_fd = -1;
    455         }
    456         child->to_child = NULL;
    457 }
    458204
    459205static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
     
    484230/* Return just one line. Returns NULL if something broke, an empty string
    485231   on temporary "errors" (EAGAIN and friends). */
    486 static char *ipc_readline( int fd, int *recv_fd )
    487 {
    488         struct msghdr msg;
    489         struct iovec iov;
    490         char ccmsg[CMSG_SPACE(sizeof(recv_fd))];
    491         struct cmsghdr *cmsg;
     232static char *ipc_readline( int fd )
     233{
    492234        char buf[513], *eol;
    493235        int size;
     
    511253                size = eol - buf + 2;
    512254       
    513         iov.iov_base = buf;
    514         iov.iov_len = size;
    515        
    516         memset( &msg, 0, sizeof( msg ) );
    517         msg.msg_iov = &iov;
    518         msg.msg_iovlen = 1;
    519         msg.msg_control = ccmsg;
    520         msg.msg_controllen = sizeof( ccmsg );
    521        
    522         if( recvmsg( fd, &msg, 0 ) != size )
     255        if( recv( fd, buf, size, 0 ) != size )
    523256                return NULL;
    524        
    525         if( recv_fd )
    526                 for( cmsg = CMSG_FIRSTHDR( &msg ); cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg ) )
    527                         if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS )
    528                         {
    529                                 /* Getting more than one shouldn't happen but if it does,
    530                                    make sure we don't leave them around. */
    531                                 if( *recv_fd != -1 )
    532                                         close( *recv_fd );
    533                                
    534                                 *recv_fd = *(int*) CMSG_DATA( cmsg );
    535                                 fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd );
    536                         }
    537        
    538         fprintf( stderr, "pid %d received: %s", (int) getpid(), buf );
    539         return g_strndup( buf, size - 2 );
     257        else
     258                return g_strndup( buf, size - 2 );
    540259}
    541260
    542261gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond )
    543262{
    544         struct bitlbee_child *child = data;
    545263        char *buf, **cmd;
    546264       
    547         if( ( buf = ipc_readline( source, &child->to_fd ) ) )
     265        if( ( buf = ipc_readline( source ) ) )
    548266        {
    549267                cmd = irc_parse_line( buf );
    550268                if( cmd )
    551269                {
    552                         ipc_command_exec( child, cmd, ipc_master_commands );
     270                        ipc_command_exec( data, cmd, ipc_master_commands );
    553271                        g_free( cmd );
    554272                }
     
    567285        char *buf, **cmd;
    568286       
    569         if( ( buf = ipc_readline( source, &ipc_child_recv_fd ) ) )
     287        if( ( buf = ipc_readline( source ) ) )
    570288        {
    571289                cmd = irc_parse_line( buf );
     
    674392                        next = l->next;
    675393                        if( write( c->ipc_fd, msg_buf, msg_len ) <= 0 )
     394                        {
    676395                                ipc_master_free_one( c );
     396                                child_list = g_slist_remove( child_list, c );
     397                        }
    677398                }
    678399        }
     
    692413}
    693414
    694 static gboolean ipc_send_fd( int fd, int send_fd )
    695 {
    696         struct msghdr msg;
    697         struct iovec iov;
    698         char ccmsg[CMSG_SPACE(sizeof(fd))];
    699         struct cmsghdr *cmsg;
    700        
    701         memset( &msg, 0, sizeof( msg ) );
    702         iov.iov_base = "0x90\r\n";         /* Ja, noppes */
    703         iov.iov_len = 6;
    704         msg.msg_iov = &iov;
    705         msg.msg_iovlen = 1;
    706        
    707         msg.msg_control = ccmsg;
    708         msg.msg_controllen = sizeof( ccmsg );
    709         cmsg = CMSG_FIRSTHDR( &msg );
    710         cmsg->cmsg_level = SOL_SOCKET;
    711         cmsg->cmsg_type = SCM_RIGHTS;
    712         cmsg->cmsg_len = CMSG_LEN( sizeof( send_fd ) );
    713         *(int*)CMSG_DATA( cmsg ) = send_fd;
    714         msg.msg_controllen = cmsg->cmsg_len;
    715        
    716         return sendmsg( fd, &msg, 0 ) == 6;
    717 }
    718 
    719415void ipc_master_free_one( struct bitlbee_child *c )
    720416{
    721         GSList *l;
    722        
    723417        b_event_remove( c->ipc_inpa );
    724418        closesocket( c->ipc_fd );
    725        
    726         if( c->to_fd != -1 )
    727                 close( c->to_fd );
    728419       
    729420        g_free( c->host );
    730421        g_free( c->nick );
    731422        g_free( c->realname );
    732         g_free( c->password );
    733423        g_free( c );
    734        
    735         child_list = g_slist_remove( child_list, c );
    736        
    737         /* Also, if any child has a reference to this one, remove it. */
    738         for( l = child_list; l; l = l->next )
    739         {
    740                 struct bitlbee_child *oc = l->data;
    741                
    742                 if( oc->to_child == c )
    743                         ipc_master_takeover_fail( oc, FALSE );
    744         }
    745424}
    746425
     
    756435                {
    757436                        ipc_master_free_one( c );
     437                        child_list = g_slist_remove( child_list, c );
    758438                        break;
    759439                }
     
    763443void ipc_master_free_all()
    764444{
    765         while( child_list )
    766                 ipc_master_free_one( child_list->data );
     445        GSList *l;
     446       
     447        for( l = child_list; l; l = l->next )
     448                ipc_master_free_one( l->data );
     449       
     450        g_slist_free( child_list );
     451        child_list = NULL;
    767452}
    768453
     
    821506        struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 );
    822507       
    823         child->to_fd = -1;
    824508        child->ipc_fd = accept( serversock, NULL, 0 );
     509       
    825510        if( child->ipc_fd == -1 )
    826511        {
     
    829514        }
    830515               
    831         child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
    832        
    833         child_list = g_slist_prepend( child_list, child );
     516        child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
     517       
     518        child_list = g_slist_append( child_list, child );
    834519       
    835520        return TRUE;
     
    867552        }
    868553       
    869         b_input_add( serversock, B_EV_IO_READ, new_ipc_client, NULL );
     554        b_input_add( serversock, GAIM_INPUT_READ, new_ipc_client, NULL );
    870555       
    871556        return 1;
     
    912597                        return 0;
    913598                }
    914                 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
    915                 child->to_fd = -1;
    916                
    917                 child_list = g_slist_prepend( child_list, child );
     599                child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
     600               
     601                child_list = g_slist_append( child_list, child );
    918602        }
    919603       
Note: See TracChangeset for help on using the changeset viewer.