Пример #1
0
/**
   Event handler. Broadcasts updates to all clients.
*/
static void broadcast(fish_message_type_t type, const wchar_t *key, const wchar_t *val)
{
    message_t *msg;

    if (connections.empty())
        return;

    msg = create_message(type, key, val);

    /*
      Don't merge these loops, or try_send_all can free the message
      prematurely
    */

    for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
    {
        msg->count++;
        iter->unsent.push(msg);
    }

    for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
    {
        try_send_all(&*iter);
    }
}
Пример #2
0
/**
   Event handler. Broadcasts updates to all clients.
*/
static void broadcast( fish_message_type_t type, const wchar_t *key, const wchar_t *val )
{
	connection_t *c;
	message_t *msg;

	if( !conn )
		return;
	
	msg = create_message( type, key, val );
	
	/*
	  Don't merge these loops, or try_send_all can free the message
	  prematurely
	*/
	
	for( c = conn; c; c=c->next )
	{
		msg->count++;
        c->unsent->push(msg);
	}	
	
	for( c = conn; c; c=c->next )
	{
		try_send_all( c );
	}	
}
Пример #3
0
void enqueue_all(connection_t *c)
{
    env_var_table_t::const_iterator iter;

    for (iter = env_universal_var.begin(); iter != env_universal_var.end(); ++iter)
    {
        const wcstring &key = iter->first;
        const var_uni_entry_t *val = iter->second;

        message_t *msg = create_message(val->exportv?SET_EXPORT:SET, key.c_str(), val->val.c_str());
        msg->count=1;
        c->unsent->push(msg);
    }

    try_send_all(c);
}
Пример #4
0
void env_universal_destroy()
{
    /*
      Go into blocking mode and send all data before exiting
    */
    if (env_universal_server.fd >= 0)
    {
        if (fcntl(env_universal_server.fd, F_SETFL, 0) != 0)
        {
            wperror(L"fcntl");
        }
        try_send_all(&env_universal_server);
    }

    connection_destroy(&env_universal_server);
    env_universal_server.fd =-1;
    s_env_univeral_inited = false;
}
Пример #5
0
/**
   Main function for fishd
*/
int main( int argc, char ** argv )
{
	int child_socket;
	struct sockaddr_un remote;
	socklen_t t;
	int max_fd;
	int update_count=0;
	
	fd_set read_fd, write_fd;

	set_main_thread();
    setup_fork_guards();
	
	program_name=L"fishd";
	wsetlocale( LC_ALL, L"" );	

	/*
	  Parse options
	*/
	while( 1 )
	{
		static struct option
			long_options[] =
			{
				{
					"help", no_argument, 0, 'h' 
				}
				,
				{
					"version", no_argument, 0, 'v' 
				}
				,
				{ 
					0, 0, 0, 0 
				}
			}
		;
		
		int opt_index = 0;
		
		int opt = getopt_long( argc,
							   argv, 
							   GETOPT_STRING,
							   long_options, 
							   &opt_index );
		
		if( opt == -1 )
			break;
		
		switch( opt )
		{
			case 0:
				break;				

			case 'h':
				print_help( argv[0], 1 );
				exit(0);				
								
			case 'v':
				debug( 0, L"%ls, version %s\n", program_name, PACKAGE_VERSION );
				exit( 0 );				
				
			case '?':
				return 1;
				
		}		
	}
	
	init();
	while(1) 
	{
		connection_t *c;
		int res;

		t = sizeof( remote );		
		
		FD_ZERO( &read_fd );
		FD_ZERO( &write_fd );
		FD_SET( sock, &read_fd );
		max_fd = sock+1;
		for( c=conn; c; c=c->next )
		{
			FD_SET( c->fd, &read_fd );
			max_fd = maxi( max_fd, c->fd+1);
			
			if( ! c->unsent->empty() )
			{
				FD_SET( c->fd, &write_fd );
			}
		}

		while( 1 )
		{
			res=select( max_fd, &read_fd, &write_fd, 0, 0 );

			if( quit )
			{
				save();
				exit(0);
			}
			
			if( res != -1 )
				break;
			
			if( errno != EINTR )
			{
				wperror( L"select" );
				exit(1);
			}
		}
				
		if( FD_ISSET( sock, &read_fd ) )
		{
			if( (child_socket = 
				 accept( sock, 
						 (struct sockaddr *)&remote, 
						 &t) ) == -1) {
				wperror( L"accept" );
				exit(1);
			}
			else
			{
				debug( 4, L"Connected with new child on fd %d", child_socket );

				if( fcntl( child_socket, F_SETFL, O_NONBLOCK ) != 0 )
				{
					wperror( L"fcntl" );
					close( child_socket );		
				}
				else
				{
					connection_t *newc = (connection_t *)malloc( sizeof(connection_t));
					connection_init( newc, child_socket );					
					newc->next = conn;
					send( newc->fd, GREETING, strlen(GREETING), MSG_DONTWAIT );
					enqueue_all( newc );				
					conn=newc;
				}
			}
		}
		
		for( c=conn; c; c=c->next )
		{
			if( FD_ISSET( c->fd, &write_fd ) )
			{
				try_send_all( c );
			}
		}
		
		for( c=conn; c; c=c->next )
		{
			if( FD_ISSET( c->fd, &read_fd ) )
			{
				read_message( c );

				/*
				  Occasionally we save during normal use, so that we
				  won't lose everything on a system crash
				*/
				update_count++;
				if( update_count >= 64 )
				{
					save();
					update_count = 0;
				}
			}
		}
		
		connection_t *prev=0;
		c=conn;
		
		while( c )
		{
			if( c->killme )
			{
				debug( 4, L"Close connection %d", c->fd );

				while( ! c->unsent->empty() )
				{
					message_t *msg = c->unsent->front();
                    c->unsent->pop();
					msg->count--;
					if( !msg->count )
						free( msg );
				}
				
				connection_destroy( c );
				if( prev )
				{
					prev->next=c->next;
				}
				else
				{
					conn=c->next;
				}
				
				free(c);
				
				c=(prev?prev->next:conn);
				
			}
			else
			{
				prev=c;
				c=c->next;
			}
		}

		if( !conn )
		{
			debug( 0, L"No more clients. Quitting" );
			save();			
			env_universal_common_destroy();
			break;
		}		

	}
}
Пример #6
0
void env_universal_barrier()
{
    ASSERT_IS_MAIN_THREAD();
	message_t *msg;
	fd_set fds;

	if( !init || is_dead() )
		return;

	barrier_reply = 0;

	/*
	  Create barrier request
	*/
	msg= create_message( BARRIER, 0, 0);
	msg->count=1;
    env_universal_server.unsent->push(msg);

	/*
	  Wait until barrier request has been sent
	*/
	debug( 3, L"Create barrier" );
	while( 1 )
	{
		try_send_all( &env_universal_server );	
		check_connection();		
		
		if( env_universal_server.unsent->empty() )
			break;
		
		if( env_universal_server.fd == -1 )
		{
			reconnect();
			debug( 2, L"barrier interrupted, exiting" );
			return;			
		}
		
		FD_ZERO( &fds );
		FD_SET( env_universal_server.fd, &fds );
		select( env_universal_server.fd+1, 0, &fds, 0, 0 );
	}

	/*
	  Wait for barrier reply
	*/
	debug( 3, L"Sent barrier request" );
	while( !barrier_reply )
	{
		if( env_universal_server.fd == -1 )
		{
			reconnect();
			debug( 2, L"barrier interrupted, exiting (2)" );
			return;			
		}		
		FD_ZERO( &fds );
        FD_SET( env_universal_server.fd, &fds );		
        select( env_universal_server.fd+1, &fds, 0, 0, 0 );
		env_universal_read_all();
	}
	debug( 3, L"End barrier" );
}
Пример #7
0
/**
   Parse message msg
*/
static void parse_message(wchar_t *msg,
                          connection_t *src)
{
//  debug( 3, L"parse_message( %ls );", msg );

    if (msg[0] == L'#')
        return;

    if (match(msg, SET_STR) || match(msg, SET_EXPORT_STR))
    {
        wchar_t *name, *tmp;
        int exportv = match(msg, SET_EXPORT_STR);

        name = msg+(exportv?wcslen(SET_EXPORT_STR):wcslen(SET_STR));
        while (wcschr(L"\t ", *name))
            name++;

        tmp = wcschr(name, L':');
        if (tmp)
        {
            wchar_t *key;
            wchar_t *val;

            key = (wchar_t *)malloc(sizeof(wchar_t)*(tmp-name+1));
            memcpy(key, name, sizeof(wchar_t)*(tmp-name));
            key[tmp-name]=0;

            val = tmp+1;
            val = unescape(val, 0);

            if (key && val)
                env_universal_common_set(key, val, exportv);

            free(val);
            free(key);
        }
        else
        {
            debug(1, PARSE_ERR, msg);
        }
    }
    else if (match(msg, ERASE_STR))
    {
        wchar_t *name, *tmp;

        name = msg+wcslen(ERASE_STR);
        while (wcschr(L"\t ", *name))
            name++;

        tmp = name;
        while (iswalnum(*tmp) || *tmp == L'_')
            tmp++;

        *tmp = 0;

        if (!wcslen(name))
        {
            debug(1, PARSE_ERR, msg);
        }

        env_universal_common_remove(name);

        if (callback)
        {
            callback(ERASE, name, 0);
        }
    }
    else if (match(msg, BARRIER_STR))
    {
        message_t *msg = create_message(BARRIER_REPLY, 0, 0);
        msg->count = 1;
        src->unsent->push(msg);
        try_send_all(src);
    }
    else if (match(msg, BARRIER_REPLY_STR))
    {
        if (callback)
        {
            callback(BARRIER_REPLY, 0, 0);
        }
    }
    else
    {
        debug(1, PARSE_ERR, msg);
    }
}
Пример #8
0
/**
   Main function for fishd
*/
int main(int argc, char ** argv)
{
    int child_socket;
    struct sockaddr_un remote;
    socklen_t t;
    uid_t sock_euid;
    gid_t sock_egid;
    int max_fd;
    int update_count=0;

    fd_set read_fd, write_fd;

    set_main_thread();
    setup_fork_guards();

    program_name=L"fishd";
    wsetlocale(LC_ALL, L"");

    /*
      Parse options
    */
    while (1)
    {
        static struct option
                long_options[] =
        {
            {
                "help", no_argument, 0, 'h'
            }
            ,
            {
                "version", no_argument, 0, 'v'
            }
            ,
            {
                0, 0, 0, 0
            }
        }
        ;

        int opt_index = 0;

        int opt = getopt_long(argc,
                              argv,
                              GETOPT_STRING,
                              long_options,
                              &opt_index);

        if (opt == -1)
            break;

        switch (opt)
        {
            case 0:
                break;

            case 'h':
                print_help(argv[0], 1);
                exit(0);

            case 'v':
                debug(0, L"%ls, version %s\n", program_name, FISH_BUILD_VERSION);
                exit(0);

            case '?':
                return 1;

        }
    }

    init();
    while (1)
    {
        int res;

        t = sizeof(remote);

        FD_ZERO(&read_fd);
        FD_ZERO(&write_fd);
        FD_SET(sock, &read_fd);
        max_fd = sock+1;
        for (connection_list_t::const_iterator iter = connections.begin(); iter != connections.end(); ++iter)
        {
            const connection_t &c = *iter;
            FD_SET(c.fd, &read_fd);
            max_fd = maxi(max_fd, c.fd+1);

            if (! c.unsent.empty())
            {
                FD_SET(c.fd, &write_fd);
            }
        }

        while (1)
        {
            res=select(max_fd, &read_fd, &write_fd, 0, 0);

            if (quit)
            {
                save();
                exit(0);
            }

            if (res != -1)
                break;

            if (errno != EINTR)
            {
                wperror(L"select");
                exit(1);
            }
        }

        if (FD_ISSET(sock, &read_fd))
        {
            if ((child_socket =
                        accept(sock,
                               (struct sockaddr *)&remote,
                               &t)) == -1)
            {
                wperror(L"accept");
                exit(1);
            }
            else
            {
                debug(4, L"Connected with new child on fd %d", child_socket);

                if (((getpeereid(child_socket, &sock_euid, &sock_egid) != 0) || sock_euid != geteuid()))
                {
                    debug(1, L"Wrong credentials for child on fd %d", child_socket);
                    close(child_socket);
                }
                else if (make_fd_nonblocking(child_socket) != 0)
                {
                    wperror(L"fcntl");
                    close(child_socket);
                }
                else
                {
                    connections.push_front(connection_t(child_socket));
                    connection_t &newc = connections.front();
                    send(newc.fd, GREETING, strlen(GREETING), MSG_DONTWAIT);
                    enqueue_all(&newc);
                }
            }
        }

        for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        {
            if (FD_ISSET(iter->fd, &write_fd))
            {
                try_send_all(&*iter);
            }
        }

        for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        {
            if (FD_ISSET(iter->fd, &read_fd))
            {
                read_message(&*iter);

                /*
                  Occasionally we save during normal use, so that we
                  won't lose everything on a system crash
                */
                update_count++;
                if (update_count >= 64)
                {
                    save();
                    update_count = 0;
                }
            }
        }

        for (connection_list_t::iterator iter = connections.begin(); iter != connections.end();)
        {
            if (iter->killme)
            {
                debug(4, L"Close connection %d", iter->fd);

                while (! iter->unsent.empty())
                {
                    message_t *msg = iter->unsent.front();
                    iter->unsent.pop();
                    msg->count--;
                    if (! msg->count)
                        free(msg);
                }

                connection_destroy(&*iter);
                iter = connections.erase(iter);
            }
            else
            {
                ++iter;
            }
        }

        if (connections.empty())
        {
            debug(0, L"No more clients. Quitting");
            save();
            break;
        }

    }
}