Exemple #1
0
/**
 * Handles a watch by reading data, writing data, or disconnecting
 * the transport, as appropriate for the given condition.
 *
 * @param transport the transport.
 * @param watch the watch.
 * @param condition the current state of the watched file descriptor.
 * @returns #FALSE if not enough memory to fully handle the watch
 */
dbus_bool_t
_dbus_transport_handle_watch (DBusTransport           *transport,
                              DBusWatch               *watch,
                              unsigned int             condition)
{
  dbus_bool_t retval;
  
  _dbus_assert (transport->vtable->handle_watch != NULL);

  if (transport->disconnected)
    return TRUE;

  if (dbus_watch_get_socket (watch) < 0)
    {
      _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
      return TRUE;
    }
  
  _dbus_watch_sanitize_condition (watch, &condition);

  _dbus_transport_ref (transport);
  _dbus_watch_ref (watch);
  retval = (* transport->vtable->handle_watch) (transport, watch, condition);
  _dbus_watch_unref (watch);
  _dbus_transport_unref (transport);

  return retval;
}
/**
 * Adds a new watch to the watch list, invoking the
 * application DBusAddWatchFunction if appropriate.
 *
 * @param watch_list the watch list.
 * @param watch the watch to add.
 * @returns #TRUE on success, #FALSE if no memory.
 */
dbus_bool_t
_dbus_watch_list_add_watch (DBusWatchList *watch_list,
                            DBusWatch     *watch)
{
  if (!_dbus_list_append (&watch_list->watches, watch))
    return FALSE;
  
  _dbus_watch_ref (watch);

  if (watch_list->add_watch_function != NULL)
    {
      _dbus_verbose ("Adding watch on fd %d\n",
                     dbus_watch_get_socket (watch));
      
      if (!(* watch_list->add_watch_function) (watch,
                                               watch_list->watch_data))
        {
          _dbus_list_remove_last (&watch_list->watches, watch);
          _dbus_watch_unref (watch);
          return FALSE;
        }
    }
  
  return TRUE;
}
Exemple #3
0
static int ldbus_watch_get_socket(lua_State *L) {
	DBusWatch *watch = check_DBusWatch(L, 1);
	int fd;
	if (watch == NULL || (fd = dbus_watch_get_socket(watch)) == -1) {
		lua_pushnil(L);
	} else {
		lua_pushinteger(L, fd);
	}
	return 1;
}
Exemple #4
0
static dbus_bool_t
handle_watch (DBusWatch       *watch,
              unsigned int     condition,
              void            *data)
{
  DBusBabysitter *sitter = data;
  int revents;
  int fd;
  
  revents = 0;
  if (condition & DBUS_WATCH_READABLE)
    revents |= _DBUS_POLLIN;
  if (condition & DBUS_WATCH_ERROR)
    revents |= _DBUS_POLLERR;
  if (condition & DBUS_WATCH_HANGUP)
    revents |= _DBUS_POLLHUP;

  fd = dbus_watch_get_socket (watch);

  if (fd == sitter->error_pipe_from_child)
    handle_error_pipe (sitter, revents);
  else if (fd == sitter->socket_to_babysitter)
    handle_babysitter_socket (sitter, revents);

  while (LIVE_CHILDREN (sitter) &&
         babysitter_iteration (sitter, FALSE))
    ;

  /* Those might have closed the sockets we're watching. Before returning
   * to the main loop, we must sort that out. */

  if (sitter->error_watch != NULL && sitter->error_pipe_from_child == -1)
    {
      _dbus_watch_invalidate (sitter->error_watch);

      if (sitter->watches != NULL)
        _dbus_watch_list_remove_watch (sitter->watches,  sitter->error_watch);

      _dbus_watch_unref (sitter->error_watch);
      sitter->error_watch = NULL;
    }

  if (sitter->sitter_watch != NULL && sitter->socket_to_babysitter == -1)
    {
      _dbus_watch_invalidate (sitter->sitter_watch);

      if (sitter->watches != NULL)
        _dbus_watch_list_remove_watch (sitter->watches,  sitter->sitter_watch);

      _dbus_watch_unref (sitter->sitter_watch);
      sitter->sitter_watch = NULL;
    }

  return TRUE;
}
/**
 * Returns a UNIX file descriptor to be watched,
 * which may be a pipe, socket, or other type of
 * descriptor. On UNIX this is preferred to
 * dbus_watch_get_socket() since it works with
 * more kinds of #DBusWatch.
 *
 * Always returns -1 on Windows. On Windows you use
 * dbus_watch_get_socket() to get a Winsock socket to watch.
 * 
 * @param watch the DBusWatch object.
 * @returns the file descriptor to watch.
 */
int
dbus_watch_get_unix_fd (DBusWatch *watch)
{
  /* FIXME remove #ifdef and do this on a lower level
   * (watch should have set_socket and set_unix_fd and track
   * which it has, and the transport should provide the
   * appropriate watch type)
   */
#ifdef DBUS_UNIX
  return watch->fd;
#else
  return dbus_watch_get_socket( watch );
#endif
}
/**
 * Sets data which can be retrieved with dbus_watch_get_data().
 * Intended for use by the DBusAddWatchFunction and
 * DBusRemoveWatchFunction to store their own data.  For example with
 * Qt you might store the QSocketNotifier for this watch and with GLib
 * you might store a GSource.
 *
 * @param watch the DBusWatch object.
 * @param data the data.
 * @param free_data_function function to be called to free the data.
 */
void
dbus_watch_set_data (DBusWatch        *watch,
                     void             *data,
                     DBusFreeFunction  free_data_function)
{
  _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
                 dbus_watch_get_socket (watch),
                 data, free_data_function, watch->data, watch->free_data_function);
  
  if (watch->free_data_function != NULL)
    (* watch->free_data_function) (watch->data);
  
  watch->data = data;
  watch->free_data_function = free_data_function;
}
/**
 * Removes a watch from the watch list, invoking the
 * application's DBusRemoveWatchFunction if appropriate.
 *
 * @param watch_list the watch list.
 * @param watch the watch to remove.
 */
void
_dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
                                DBusWatch     *watch)
{
  if (!_dbus_list_remove (&watch_list->watches, watch))
    _dbus_assert_not_reached ("Nonexistent watch was removed");
  
  if (watch_list->remove_watch_function != NULL)
    {
      _dbus_verbose ("Removing watch on fd %d\n",
                     dbus_watch_get_socket (watch));
      
      (* watch_list->remove_watch_function) (watch,
                                             watch_list->watch_data);
    }
  
  _dbus_watch_unref (watch);
}
Exemple #8
0
static dbus_bool_t
handle_watch (DBusWatch       *watch,
              unsigned int     condition,
              void            *data)
{
  DBusBabysitter *sitter = _dbus_babysitter_ref (data);
  int revents;
  int fd;
  
  revents = 0;
  if (condition & DBUS_WATCH_READABLE)
    revents |= _DBUS_POLLIN;
  if (condition & DBUS_WATCH_ERROR)
    revents |= _DBUS_POLLERR;
  if (condition & DBUS_WATCH_HANGUP)
    revents |= _DBUS_POLLHUP;

  fd = dbus_watch_get_socket (watch);

  if (fd == sitter->error_pipe_from_child)
    handle_error_pipe (sitter, revents);
  else if (fd == sitter->socket_to_babysitter.fd)
    handle_babysitter_socket (sitter, revents);

  while (LIVE_CHILDREN (sitter) &&
         babysitter_iteration (sitter, FALSE))
    ;

  /* fd.o #32992: if the handle_* methods closed their sockets, they previously
   * didn't always remove the watches. Check that we don't regress. */
  _dbus_assert (sitter->socket_to_babysitter.fd != -1 || sitter->sitter_watch == NULL);
  _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);

  if (_dbus_babysitter_get_child_exited (sitter) &&
      sitter->finished_cb != NULL)
    {
      sitter->finished_cb (sitter, sitter->finished_data);
      sitter->finished_cb = NULL;
    }

  _dbus_babysitter_unref (sitter);
  return TRUE;
}
/**
 * Sets a watch to the given enabled state, invoking the
 * application's DBusWatchToggledFunction if appropriate.
 *
 * @param watch_list the watch list.
 * @param watch the watch to toggle.
 * @param enabled #TRUE to enable
 */
void
_dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
                               DBusWatch               *watch,
                               dbus_bool_t              enabled)
{
  enabled = !!enabled;
  
  if (enabled == watch->enabled)
    return;

  watch->enabled = enabled;
  
  if (watch_list->watch_toggled_function != NULL)
    {
      _dbus_verbose ("Toggling watch %p on fd %d to %d\n",
                     watch, dbus_watch_get_socket (watch), watch->enabled);
      
      (* watch_list->watch_toggled_function) (watch,
                                              watch_list->watch_data);
    }
}
static dbus_bool_t
socket_handle_watch (DBusTransport *transport,
                   DBusWatch     *watch,
                   unsigned int   flags)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;

  _dbus_assert (watch == socket_transport->read_watch ||
                watch == socket_transport->write_watch);
  _dbus_assert (watch != NULL);
  
  /* If we hit an error here on a write watch, don't disconnect the transport yet because data can
   * still be in the buffer and do_reading may need several iteration to read
   * it all (because of its max_bytes_read_per_iteration limit). 
   */
  if (!(flags & DBUS_WATCH_READABLE) && unix_error_with_read_to_come (transport, watch, flags))
    {
      _dbus_verbose ("Hang up or error on watch\n");
      _dbus_transport_disconnect (transport);
      return TRUE;
    }
  
  if (watch == socket_transport->read_watch &&
      (flags & DBUS_WATCH_READABLE))
    {
      dbus_bool_t auth_finished;
#if 1
      _dbus_verbose ("handling read watch %p flags = %x\n",
                     watch, flags);
#endif
      if (!do_authentication (transport, TRUE, FALSE, &auth_finished))
        return FALSE;

      /* We don't want to do a read immediately following
       * a successful authentication.  This is so we
       * have a chance to propagate the authentication
       * state further up.  Specifically, we need to
       * process any pending data from the auth object.
       */
      if (!auth_finished)
	{
	  if (!do_reading (transport))
	    {
	      _dbus_verbose ("no memory to read\n");
	      return FALSE;
	    }
	}
      else
        {
          _dbus_verbose ("Not reading anything since we just completed the authentication\n");
        }
    }
  else if (watch == socket_transport->write_watch &&
           (flags & DBUS_WATCH_WRITABLE))
    {
#if 1
      _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n",
                     _dbus_connection_has_messages_to_send_unlocked (transport->connection));
#endif
      if (!do_authentication (transport, FALSE, TRUE, NULL))
        return FALSE;
      
      if (!do_writing (transport))
        {
          _dbus_verbose ("no memory to write\n");
          return FALSE;
        }

      /* See if we still need the write watch */
      check_write_watch (transport);
    }
#ifdef DBUS_ENABLE_VERBOSE_MODE
  else
    {
      if (watch == socket_transport->read_watch)
        _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n",
                       flags);
      else if (watch == socket_transport->write_watch)
        _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n",
                       flags);
      else
        _dbus_verbose ("asked to handle watch %p on fd %" DBUS_SOCKET_FORMAT " that we don't recognize\n",
                       watch, dbus_watch_get_socket (watch));
    }
#endif /* DBUS_ENABLE_VERBOSE_MODE */

  return TRUE;
}
/**
 * Sets the watch functions. This function is the "backend"
 * for dbus_connection_set_watch_functions() and
 * dbus_server_set_watch_functions().
 *
 * @param watch_list the watch list.
 * @param add_function the add watch function.
 * @param remove_function the remove watch function.
 * @param toggled_function function on toggling enabled flag, or #NULL
 * @param data the data for those functions.
 * @param free_data_function the function to free the data.
 * @returns #FALSE if not enough memory
 *
 */
dbus_bool_t
_dbus_watch_list_set_functions (DBusWatchList           *watch_list,
                                DBusAddWatchFunction     add_function,
                                DBusRemoveWatchFunction  remove_function,
                                DBusWatchToggledFunction toggled_function,
                                void                    *data,
                                DBusFreeFunction         free_data_function)
{
  /* Add watches with the new watch function, failing on OOM */
  if (add_function != NULL)
    {
      DBusList *link;
      
      link = _dbus_list_get_first_link (&watch_list->watches);
      while (link != NULL)
        {
          DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
                                                     link);

#ifdef DBUS_ENABLE_VERBOSE_MODE
          {
            const char *watch_type;
            int flags;

            flags = dbus_watch_get_flags (link->data);
            if ((flags & DBUS_WATCH_READABLE) &&
                (flags & DBUS_WATCH_WRITABLE))
              watch_type = "readwrite";
            else if (flags & DBUS_WATCH_READABLE)
              watch_type = "read";
            else if (flags & DBUS_WATCH_WRITABLE)
              watch_type = "write";
            else
              watch_type = "not read or write";
            
            _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n",
                           watch_type,
                           dbus_watch_get_socket (link->data));
          }
#endif /* DBUS_ENABLE_VERBOSE_MODE */
          
          if (!(* add_function) (link->data, data))
            {
              /* remove it all again and return FALSE */
              DBusList *link2;
              
              link2 = _dbus_list_get_first_link (&watch_list->watches);
              while (link2 != link)
                {
                  DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
                                                             link2);
                  
                  _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
                                 dbus_watch_get_socket (link2->data));
                  
                  (* remove_function) (link2->data, data);
                  
                  link2 = next;
                }

              return FALSE;
            }
      
          link = next;
        }
    }
  
  /* Remove all current watches from previous watch handlers */

  if (watch_list->remove_watch_function != NULL)
    {
      _dbus_verbose ("Removing all pre-existing watches\n");
      
      _dbus_list_foreach (&watch_list->watches,
                          (DBusForeachFunction) watch_list->remove_watch_function,
                          watch_list->watch_data);
    }

  if (watch_list->watch_free_data_function != NULL)
    (* watch_list->watch_free_data_function) (watch_list->watch_data);
  
  watch_list->add_watch_function = add_function;
  watch_list->remove_watch_function = remove_function;
  watch_list->watch_toggled_function = toggled_function;
  watch_list->watch_data = data;
  watch_list->watch_free_data_function = free_data_function;

  return TRUE;
}
static dbus_bool_t
socket_handle_watch (DBusWatch    *watch,
                   unsigned int  flags,
                   void         *data)
{
  DBusServer *server = data;
  DBusServerSocket *socket_server = data;

#ifndef DBUS_DISABLE_ASSERT
  int i;
  dbus_bool_t found = FALSE;
#endif

  SERVER_LOCK (server);

#ifndef DBUS_DISABLE_ASSERT
  for (i = 0 ; i < socket_server->n_fds ; i++)
    {
      if (socket_server->watch[i] == watch)
        found = TRUE;
    }
  _dbus_assert (found);
#endif

  _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);

  if (flags & DBUS_WATCH_READABLE)
    {
      int client_fd;
      int listen_fd;

      listen_fd = dbus_watch_get_socket (watch);

      if (socket_server->noncefile)
          client_fd = _dbus_accept_with_noncefile (listen_fd, socket_server->noncefile);
      else 
          client_fd = _dbus_accept (listen_fd);

      if (client_fd < 0)
        {
          /* EINTR handled for us */

          if (_dbus_get_is_errno_eagain_or_ewouldblock ())
            _dbus_verbose ("No client available to accept after all\n");
          else
            _dbus_verbose ("Failed to accept a client connection: %s\n",
                           _dbus_strerror_from_errno ());

          SERVER_UNLOCK (server);
        }
      else
        {
          if (!handle_new_client_fd_and_unlock (server, client_fd))
            _dbus_verbose ("Rejected client connection due to lack of memory\n");
        }
    }

  if (flags & DBUS_WATCH_ERROR)
    _dbus_verbose ("Error on server listening socket\n");

  if (flags & DBUS_WATCH_HANGUP)
    _dbus_verbose ("Hangup on server listening socket\n");

  return TRUE;
}