/* Could be called from any thread, so it could be called after client_unref() * has started finalising the #Client. Avoid that by looking up the #Client * atomically. */ static void on_connection_disconnected (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data) { guint watcher_id = GPOINTER_TO_UINT (user_data); Client *client = NULL; client = dup_client (watcher_id); if (client == NULL) return; if (client->name_owner_changed_subscription_id > 0) g_dbus_connection_signal_unsubscribe (client->connection, client->name_owner_changed_subscription_id); if (client->disconnected_signal_handler_id > 0) g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id); g_object_unref (client->connection); client->disconnected_signal_handler_id = 0; client->name_owner_changed_subscription_id = 0; client->connection = NULL; call_vanished_handler (client, FALSE); client_unref (client); }
/* Will always be called from the thread which acquired client->main_context. */ static void on_name_owner_changed (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { guint watcher_id = GPOINTER_TO_UINT (user_data); Client *client = NULL; const gchar *name; const gchar *old_owner; const gchar *new_owner; client = dup_client (watcher_id); if (client == NULL) return; if (!client->initialized) goto out; if (g_strcmp0 (object_path, "/org/freedesktop/DBus") != 0 || g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0 || g_strcmp0 (sender_name, "org.freedesktop.DBus") != 0) goto out; g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner); /* we only care about a specific name */ if (g_strcmp0 (name, client->name) != 0) goto out; if ((old_owner != NULL && strlen (old_owner) > 0) && client->name_owner != NULL) { g_free (client->name_owner); client->name_owner = NULL; call_vanished_handler (client, FALSE); } if (new_owner != NULL && strlen (new_owner) > 0) { g_warn_if_fail (client->name_owner == NULL); g_free (client->name_owner); client->name_owner = g_strdup (new_owner); call_appeared_handler (client); } out: client_unref (client); }
/* * par_main() * Endless loop to receive and serve requests */ static void par_main() { struct msg msg; int x; struct file *f; loop: /* * Receive a message, log an error and then keep going */ x = msg_receive(lp_port, &msg); if (x < 0) { syslog(LOG_ERR, "msg_receive"); goto loop; } /* * All incoming data should fit in one buffer */ if (msg.m_nseg > 1) { msg_err(msg.m_sender, EINVAL); goto loop; } /* * Categorize by basic message operation */ f = hash_lookup(filehash, msg.m_sender); switch (msg.m_op & MSG_MASK) { case M_CONNECT: /* New client */ new_client(&msg); break; case M_DISCONNECT: /* Client done */ dead_client(&msg, f); break; case M_DUP: /* File handle dup during exec() */ dup_client(&msg, f); break; case M_ABORT: /* Aborted operation */ /* * We are synchronous. At the time we handle this * message, any I/O is completed. Just answer * with an abort message. */ msg_reply(msg.m_sender, &msg); break; case FS_WRITE: /* Write */ if (check_gen(&msg, f)) { break; } par_write(&msg, f); break; case FS_STAT: /* Get stat of file */ if (check_gen(&msg, f)) { break; } par_stat(&msg, f); break; case FS_WSTAT: /* Writes stats */ if (check_gen(&msg, f)) { break; } par_wstat(&msg, f); break; default: /* Unknown */ msg_err(msg.m_sender, EINVAL); break; } goto loop; }
/* * namer_main() * Endless loop to receive and serve requests */ static void namer_main() { struct msg msg; int x; struct file *f; loop: /* * Receive a message, log an error and then keep going */ x = msg_receive(namerport, &msg); if (x < 0) { perror("namer: msg_receive"); goto loop; } /* * All requests should fit in one buffer */ if (msg.m_nseg > 1) { msg_err(msg.m_sender, EINVAL); goto loop; } /* * Categorize by basic message operation */ f = hash_lookup(filehash, msg.m_sender); switch (msg.m_op & MSG_MASK) { case M_CONNECT: /* New client */ new_client(&msg); break; case M_DISCONNECT: /* Client done */ dead_client(&msg, f); break; case M_DUP: /* File handle dup during exec() */ dup_client(&msg, f); break; case M_ABORT: /* Aborted operation */ /* * We're synchronous, so presumably the operation * is all done and this abort is old news. */ msg_reply(msg.m_sender, &msg); break; case FS_OPEN: /* Look up file from directory */ if (!valid_fname(msg.m_buf, x)) { msg_err(msg.m_sender, ESRCH); break; } namer_open(&msg, f); break; case FS_READ: /* Read file */ namer_read(&msg, f); break; case FS_WRITE: /* Write file */ namer_write(&msg, f); break; case FS_SEEK: /* Set new file position */ namer_seek(&msg, f); break; case FS_REMOVE: /* Get rid of a file */ namer_remove(&msg, f); break; case FS_STAT: /* Stat node */ namer_stat(&msg, f); break; case FS_WSTAT: /* Write stat info */ namer_wstat(&msg, f); break; default: /* Unknown */ msg_err(msg.m_sender, EINVAL); break; } goto loop; }
/* * tmpfs_main() * Endless loop to receive and serve requests */ static void tmpfs_main() { struct msg msg; int x; struct file *f; extern int valid_fname(char *, int); loop: /* * Receive a message, log an error and then keep going */ x = msg_receive(rootport, &msg); if (x < 0) { syslog(LOG_ERR, "msg_receive"); goto loop; } /* * Categorize by basic message operation */ f = hash_lookup(filehash, msg.m_sender); switch (msg.m_op & MSG_MASK) { case M_CONNECT: /* New client */ new_client(&msg); break; case M_DISCONNECT: /* Client done */ dead_client(&msg, f); break; case M_DUP: /* File handle dup during exec() */ dup_client(&msg, f); break; case M_ABORT: /* Aborted operation */ /* * We're synchronous, so presumably the operation * is all done and this abort is old news. */ msg_reply(msg.m_sender, &msg); break; case FS_OPEN: /* Look up file from directory */ if ((msg.m_nseg != 1) || !valid_fname(msg.m_buf, msg.m_buflen)) { msg_err(msg.m_sender, EINVAL); break; } tmpfs_open(&msg, f); break; case FS_ABSREAD: /* Set position, then read */ if (msg.m_arg1 < 0) { msg_err(msg.m_sender, EINVAL); break; } f->f_pos = msg.m_arg1; /* VVV fall into VVV */ case FS_READ: /* Read file */ tmpfs_read(&msg, f); break; case FS_ABSWRITE: /* Set position, then write */ if (msg.m_arg1 < 0) { msg_err(msg.m_sender, EINVAL); break; } f->f_pos = msg.m_arg1; /* VVV fall into VVV */ case FS_WRITE: /* Write file */ tmpfs_write(&msg, f); break; case FS_SEEK: /* Set new file position */ tmpfs_seek(&msg, f); break; case FS_REMOVE: /* Get rid of a file */ if ((msg.m_nseg != 1) || !valid_fname(msg.m_buf, msg.m_buflen)) { msg_err(msg.m_sender, EINVAL); break; } tmpfs_remove(&msg, f); break; case FS_STAT: /* Tell about file */ tmpfs_stat(&msg, f); break; case FS_WSTAT: /* Set stuff on file */ tmpfs_wstat(&msg, f); break; case FS_FID: /* Return file ID for caching */ tmpfs_fid(&msg, f); break; default: /* Unknown */ msg_err(msg.m_sender, EINVAL); break; } goto loop; }