Changes in / [b556e46:9a9b520]
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
bitlbee.c
rb556e46 r9a9b520 318 318 struct bitlbee_child *child; 319 319 320 /* TODO: Stuff like this belongs in ipc.c. */321 320 child = g_new0( struct bitlbee_child, 1 ); 322 321 child->pid = client_pid; 323 322 child->ipc_fd = fds[0]; 324 323 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); 325 child->to_fd = -1;326 324 child_list = g_slist_append( child_list, child ); 327 325 -
bitlbee.h
rb556e46 r9a9b520 163 163 void root_command_string( irc_t *irc, char *command ); 164 164 void root_command( irc_t *irc, char *command[] ); 165 gboolean cmd_identify_finish( gpointer data, gint fd, b_input_condition cond );166 165 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond ); 167 166 -
ipc.c
rb556e46 r9a9b520 33 33 34 34 GSList *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 );39 35 40 36 static void ipc_master_cmd_client( irc_t *data, char **cmd ) … … 53 49 } 54 50 55 /* CLIENT == On initial connects, HELLO is after /RESTARTs. */56 51 if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 ) 57 52 ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", … … 59 54 } 60 55 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 72 56 static void ipc_master_cmd_die( irc_t *data, char **cmd ) 73 57 { … … 126 110 global.restart = -1; 127 111 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 else157 {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 else197 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 }217 112 } 218 113 … … 220 115 { "client", 3, ipc_master_cmd_client, 0 }, 221 116 { "hello", 0, ipc_master_cmd_client, 0 }, 222 { "nick", 1, ipc_master_cmd_nick, 0 },223 117 { "die", 0, ipc_master_cmd_die, 0 }, 224 118 { "deaf", 0, ipc_master_cmd_deaf, 0 }, … … 229 123 { "kill", 2, NULL, IPC_CMD_TO_CHILDREN }, 230 124 { "restart", 0, ipc_master_cmd_restart, 0 }, 231 { "identify", 2, ipc_master_cmd_identify, 0 },232 { "takeover", 1, ipc_master_cmd_takeover, 0 },233 125 { NULL } 234 126 }; … … 297 189 else 298 190 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 reason315 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 and338 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 else360 {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 overwrite386 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 );407 191 } 408 192 … … 415 199 { "kill", 2, ipc_child_cmd_kill, 0 }, 416 200 { "hello", 0, ipc_child_cmd_hello, 0 }, 417 { "takeover", 1, ipc_child_cmd_takeover, 0 },418 201 { NULL } 419 202 }; 420 203 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 else433 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 be447 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 }458 204 459 205 static void ipc_command_exec( void *data, char **cmd, const command_t *commands ) … … 484 230 /* Return just one line. Returns NULL if something broke, an empty string 485 231 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; 232 static char *ipc_readline( int fd ) 233 { 492 234 char buf[513], *eol; 493 235 int size; … … 511 253 size = eol - buf + 2; 512 254 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 ) 523 256 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 ); 540 259 } 541 260 542 261 gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond ) 543 262 { 544 struct bitlbee_child *child = data;545 263 char *buf, **cmd; 546 264 547 if( ( buf = ipc_readline( source , &child->to_fd) ) )265 if( ( buf = ipc_readline( source ) ) ) 548 266 { 549 267 cmd = irc_parse_line( buf ); 550 268 if( cmd ) 551 269 { 552 ipc_command_exec( child, cmd, ipc_master_commands );270 ipc_command_exec( data, cmd, ipc_master_commands ); 553 271 g_free( cmd ); 554 272 } … … 567 285 char *buf, **cmd; 568 286 569 if( ( buf = ipc_readline( source , &ipc_child_recv_fd) ) )287 if( ( buf = ipc_readline( source ) ) ) 570 288 { 571 289 cmd = irc_parse_line( buf ); … … 674 392 next = l->next; 675 393 if( write( c->ipc_fd, msg_buf, msg_len ) <= 0 ) 394 { 676 395 ipc_master_free_one( c ); 396 child_list = g_slist_remove( child_list, c ); 397 } 677 398 } 678 399 } … … 692 413 } 693 414 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 719 415 void ipc_master_free_one( struct bitlbee_child *c ) 720 416 { 721 GSList *l;722 723 417 b_event_remove( c->ipc_inpa ); 724 418 closesocket( c->ipc_fd ); 725 726 if( c->to_fd != -1 )727 close( c->to_fd );728 419 729 420 g_free( c->host ); 730 421 g_free( c->nick ); 731 422 g_free( c->realname ); 732 g_free( c->password );733 423 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 }745 424 } 746 425 … … 756 435 { 757 436 ipc_master_free_one( c ); 437 child_list = g_slist_remove( child_list, c ); 758 438 break; 759 439 } … … 763 443 void ipc_master_free_all() 764 444 { 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; 767 452 } 768 453 … … 821 506 struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 ); 822 507 823 child->to_fd = -1;824 508 child->ipc_fd = accept( serversock, NULL, 0 ); 509 825 510 if( child->ipc_fd == -1 ) 826 511 { … … 831 516 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); 832 517 833 child_list = g_slist_ prepend( child_list, child );518 child_list = g_slist_append( child_list, child ); 834 519 835 520 return TRUE; … … 913 598 } 914 599 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 ); 600 601 child_list = g_slist_append( child_list, child ); 918 602 } 919 603 -
ipc.h
rb556e46 r9a9b520 37 37 char *nick; 38 38 char *realname; 39 40 char *password;41 42 /* For takeovers: */43 struct bitlbee_child *to_child;44 int to_fd;45 39 }; 46 40 -
irc.h
rb556e46 r9a9b520 87 87 gint w_watch_source_id; 88 88 gint ping_source_id; 89 gint login_source_id; /* To slightly delay some events at login time. */90 89 91 90 struct bee *b; -
irc_user.c
rb556e46 r9a9b520 25 25 26 26 #include "bitlbee.h" 27 #include "ipc.h"28 27 29 28 irc_user_t *irc_user_new( irc_t *irc, const char *nick ) … … 161 160 irc->users = g_slist_insert_sorted( irc->users, iu, irc_user_cmp ); 162 161 163 if( iu == irc->user )164 ipc_to_master_str( "NICK :%s\r\n", new );165 166 162 return 1; 167 163 } -
root_commands.c
rb556e46 r9a9b520 105 105 { 106 106 storage_status_t status; 107 char *account_on[] = { "account", "on", NULL }; 107 108 gboolean load = TRUE; 108 109 char *password = cmd[1]; … … 157 158 irc_umode_set( irc, "+R", 1 ); 158 159 irc_channel_auto_joins( irc, NULL ); 159 160 if( ipc_child_identify( irc ) ) 161 { 162 if( load && set_getbool( &irc->b->set, "auto_connect" ) ) 163 irc->login_source_id = b_timeout_add( 200, 164 cmd_identify_finish, irc ); 165 } 166 else if( load && set_getbool( &irc->b->set, "auto_connect" ) ) 167 cmd_identify_finish( irc, 0, 0 ); 168 160 if( load && set_getbool( &irc->b->set, "auto_connect" ) ) 161 cmd_account( irc, account_on ); 169 162 break; 170 163 case STORAGE_OTHER_ERROR: … … 173 166 break; 174 167 } 175 }176 177 gboolean cmd_identify_finish( gpointer data, gint fd, b_input_condition cond )178 {179 char *account_on[] = { "account", "on", NULL };180 irc_t *irc = data;181 182 cmd_account( irc, account_on );183 184 irc->login_source_id = -1;185 return FALSE;186 168 } 187 169 … … 690 672 else if( iu == irc->user ) 691 673 { 692 irc_usermsg( irc, " Use /nick to change your own nickname");674 irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] ); 693 675 } 694 676 else if( !nick_ok( cmd[2] ) )
Note: See TracChangeset
for help on using the changeset viewer.