static void client_start_tls(struct client *client) { int fd_ssl; client_ref(client); if (!client_unref(&client) || client->destroyed) return; fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool, client->set, client->ssl_set, &client->ssl_proxy); if (fd_ssl == -1) { client_notify_disconnect(client, CLIENT_DISCONNECT_INTERNAL_ERROR, "TLS initialization failed."); client_destroy(client, "Disconnected: TLS initialization failed."); return; } ssl_proxy_set_client(client->ssl_proxy, client); ssl_proxy_start(client->ssl_proxy); client->starttls = TRUE; client->tls = TRUE; client->secured = TRUE; login_refresh_proctitle(); client->fd = fd_ssl; client->io = io_add(client->fd, IO_READ, client_input, client); i_stream_unref(&client->input); o_stream_unref(&client->output); client_open_streams(client); client->v.starttls(client); }
static int32_t rtp_sinker_consumable(network_sinker *ns, proto_watch *pw, int32_t stm_i, uint32_t size) { int32_t err = -EINVAL; media_sinker *sinker = (media_sinker*)ns; rtp_sinker *rs = (rtp_sinker*)ns; network_client *nc = (network_client*)rs->interleaved; if (rs->trans_mode == RTP_OVER_RTSP && nc) { //@{Interleaved rtp mode} client_ref((client*)nc); RELEASE_LOCK(sinker->lock); err = network_client_consumable(nc, size); client_unref((client*)nc); AQUIRE_LOCK(sinker->lock); return err; } if (pw) { return proto_watch_writeable(pw, size); } return err; }
/* 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); }
static void connection_get_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { Client *client = user_data; client->connection = g_bus_get_finish (res, NULL); if (client->connection == NULL) { call_lost_handler (client); goto out; } /* No need to schedule this in idle as we're already in the thread * that the user called g_bus_own_name() from. This is because * g_bus_get() guarantees that. * * Also, we need to ensure that the handler is invoked *before* * we call RequestName(). Otherwise there is a race. */ if (client->bus_acquired_handler != NULL) { client->bus_acquired_handler (client->connection, client->name, client->user_data); } has_connection (client); out: client_unref (client); }
/** * g_bus_unwatch_name: * @watcher_id: An identifier obtained from g_bus_watch_name() * * Stops watching a name. * * Since: 2.26 */ void g_bus_unwatch_name (guint watcher_id) { Client *client; g_return_if_fail (watcher_id > 0); client = NULL; G_LOCK (lock); if (watcher_id == 0 || map_id_to_client == NULL || (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL) { g_warning ("Invalid id %d passed to g_bus_unwatch_name()", watcher_id); goto out; } client->cancelled = TRUE; g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id))); out: G_UNLOCK (lock); /* do callback without holding lock */ if (client != NULL) { client_unref (client); } }
static void call_handler_data_free (CallHandlerData *data) { if (data->connection != NULL) g_object_unref (data->connection); client_unref (data->client); g_free (data); }
int hi_talk_cli_close(hi_talk_cli_t *hdl) { if (!hdl) { return (-1); } client_unref((talk_client_t *)hdl); return 0; }
/* 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); }
login_proxy_free_full(struct login_proxy **_proxy, const char *reason, bool delayed) { struct login_proxy *proxy = *_proxy; struct client *client = proxy->client; const char *ipstr; unsigned int delay_ms = 0; *_proxy = NULL; if (proxy->destroying) return; proxy->destroying = TRUE; /* we'll disconnect server side in any case. */ login_proxy_disconnect(proxy); if (proxy->client_fd != -1) { /* detached proxy */ DLLIST_REMOVE(&login_proxies, proxy); if (delayed) delay_ms = login_proxy_delay_disconnect(proxy); ipstr = net_ip2addr(&proxy->client->ip); client_log(proxy->client, t_strdup_printf( "proxy(%s): disconnecting %s%s%s", proxy->client->virtual_user, ipstr != NULL ? ipstr : "", reason == NULL ? "" : t_strdup_printf(" (%s)", reason), delay_ms == 0 ? "" : t_strdup_printf(" - disconnecting client in %ums", delay_ms))); if (proxy->client_io != NULL) io_remove(&proxy->client_io); } else { i_assert(proxy->client_io == NULL); i_assert(proxy->client_input == NULL); i_assert(proxy->client_output == NULL); i_assert(proxy->client_fd == -1); DLLIST_REMOVE(&login_proxies_pending, proxy); if (proxy->callback != NULL) proxy->callback(proxy->client); } if (delay_ms == 0) login_proxy_free_final(proxy); else { proxy->client_io = io_add_istream(proxy->client_input, proxy_client_disconnected_input, proxy); } client->login_proxy = NULL; client_unref(&client); }
static void rtp_sinker_fin(network_sinker *ns) { rtp_sinker *rs = (rtp_sinker*)ns; if (rs->interleaved) { client_unref((client*)rs->interleaved); rs->interleaved = NULL; } }
void client_set_del(client_set *cs, client *c) { int32_t err; AQUIRE_LOCK(cs->lock); err = __client_set_del(cs, c); RELEASE_LOCK(cs->lock); if (!err) { client_unref(c); } }
static void start_service_by_name_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { Client *client = user_data; GVariant *result; result = NULL; result = g_dbus_connection_call_finish (client->connection, res, NULL); if (result != NULL) { guint32 start_service_result; g_variant_get (result, "(u)", &start_service_result); if (start_service_result == 1) /* DBUS_START_REPLY_SUCCESS */ { invoke_get_name_owner (client); } else if (start_service_result == 2) /* DBUS_START_REPLY_ALREADY_RUNNING */ { invoke_get_name_owner (client); } else { g_warning ("Unexpected reply %d from StartServiceByName() method", start_service_result); call_vanished_handler (client, FALSE); client->initialized = TRUE; } } else { /* Errors are not unexpected; the bus will reply e.g. * * org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2 * was not provided by any .service files * * This doesn't mean that the name doesn't have an owner, just * that it's not provided by a .service file. So proceed to * invoke GetNameOwner(). */ invoke_get_name_owner (client); } if (result != NULL) g_variant_unref (result); client_unref (client); }
static void connection_get_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { Client *client = user_data; client->connection = g_bus_get_finish (res, NULL); if (client->connection == NULL) { call_vanished_handler (client, FALSE); goto out; } has_connection (client); out: client_unref (client); }
static void get_name_owner_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { Client *client = user_data; GVariant *result; const char *name_owner; name_owner = NULL; result = NULL; result = g_dbus_connection_call_finish (client->connection, res, NULL); if (result != NULL) { g_variant_get (result, "(&s)", &name_owner); } if (name_owner != NULL) { g_warn_if_fail (client->name_owner == NULL); client->name_owner = g_strdup (name_owner); call_appeared_handler (client); } else { call_vanished_handler (client, FALSE); } client->initialized = TRUE; if (result != NULL) g_variant_unref (result); client_unref (client); }
void client_destroy(struct client *client, const char *reason) { if (client->destroyed) return; client->destroyed = TRUE; if (!client->login_success && reason != NULL) { reason = t_strconcat(reason, " ", client_get_extra_disconnect_reason(client), NULL); } if (reason != NULL) client_log(client, reason); if (last_client == client) last_client = client->prev; DLLIST_REMOVE(&clients, client); if (client->input != NULL) i_stream_close(client->input); if (client->output != NULL) o_stream_close(client->output); if (client->master_tag != 0) { i_assert(client->auth_request == NULL); i_assert(client->authenticating); i_assert(client->refcount > 1); client->authenticating = FALSE; master_auth_request_abort(master_auth, client->master_tag); client->refcount--; } else if (client->auth_request != NULL) { i_assert(client->authenticating); sasl_server_auth_abort(client); } else { i_assert(!client->authenticating); } if (client->io != NULL) io_remove(&client->io); if (client->to_disconnect != NULL) timeout_remove(&client->to_disconnect); if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (client->auth_response != NULL) str_free(&client->auth_response); if (client->fd != -1) { net_disconnect(client->fd); client->fd = -1; } if (client->proxy_password != NULL) { safe_memset(client->proxy_password, 0, strlen(client->proxy_password)); i_free_and_null(client->proxy_password); } if (client->proxy_sasl_client != NULL) dsasl_client_free(&client->proxy_sasl_client); if (client->login_proxy != NULL) login_proxy_free(&client->login_proxy); if (client->v.destroy != NULL) client->v.destroy(client); if (client_unref(&client) && initial_service_count == 1) { /* as soon as this connection is done with proxying (or whatever), the process will die. there's no need for authentication anymore, so close the connection. do this only with initial service_count=1, in case there are other clients with pending authentications */ auth_client_disconnect(auth_client, "unnecessary connection"); } login_client_destroyed(); login_refresh_proctitle(); }
static void request_name_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { Client *client = user_data; GVariant *result; guint32 request_name_reply; gboolean subscribe; request_name_reply = 0; result = NULL; result = g_dbus_connection_call_finish (client->connection, res, NULL); if (result != NULL) { g_variant_get (result, "(u)", &request_name_reply); g_variant_unref (result); } subscribe = FALSE; switch (request_name_reply) { case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */ /* We got the name - now listen for NameLost and NameAcquired */ call_acquired_handler (client); subscribe = TRUE; client->needs_release = TRUE; break; case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */ /* Waiting in line - listen for NameLost and NameAcquired */ call_lost_handler (client); subscribe = TRUE; client->needs_release = TRUE; break; default: /* assume we couldn't get the name - explicit fallthrough */ case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */ case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */ /* Some other part of the process is already owning the name */ call_lost_handler (client); break; } if (subscribe) { /* start listening to NameLost and NameAcquired messages */ client->name_lost_subscription_id = g_dbus_connection_signal_subscribe (client->connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameLost", "/org/freedesktop/DBus", client->name, on_name_lost_or_acquired, client, NULL); client->name_acquired_subscription_id = g_dbus_connection_signal_subscribe (client->connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameAcquired", "/org/freedesktop/DBus", client->name, on_name_lost_or_acquired, client, NULL); } client_unref (client); }
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason) { struct login_proxy *proxy = *_proxy; struct client *client = proxy->client; const char *ipstr; *_proxy = NULL; if (proxy->destroying) return; proxy->destroying = TRUE; if (proxy->to != NULL) timeout_remove(&proxy->to); if (proxy->to_notify != NULL) timeout_remove(&proxy->to_notify); if (proxy->state_rec != NULL) proxy->state_rec->num_waiting_connections--; if (proxy->to != NULL) timeout_remove(&proxy->to); if (proxy->server_io != NULL) io_remove(&proxy->server_io); if (proxy->server_input != NULL) i_stream_destroy(&proxy->server_input); if (proxy->server_output != NULL) o_stream_destroy(&proxy->server_output); if (proxy->client_fd != -1) { /* detached proxy */ DLLIST_REMOVE(&login_proxies, proxy); ipstr = net_ip2addr(&proxy->client->ip); client_log(proxy->client, t_strdup_printf( "proxy(%s): disconnecting %s%s", proxy->client->virtual_user, ipstr != NULL ? ipstr : "", reason == NULL ? "" : t_strdup_printf(" (%s)", reason))); if (proxy->client_io != NULL) io_remove(&proxy->client_io); if (proxy->client_output != NULL) o_stream_destroy(&proxy->client_output); net_disconnect(proxy->client_fd); } else { i_assert(proxy->client_io == NULL); i_assert(proxy->client_output == NULL); DLLIST_REMOVE(&login_proxies_pending, proxy); if (proxy->callback != NULL) proxy->callback(proxy->client); } if (proxy->server_fd != -1) net_disconnect(proxy->server_fd); if (proxy->ssl_server_proxy != NULL) ssl_proxy_free(&proxy->ssl_server_proxy); i_free(proxy->host); i_free(proxy); client->login_proxy = NULL; client_unref(&client); }
static void request_name_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { Client *client = user_data; GVariant *result; guint32 request_name_reply; gboolean subscribe; request_name_reply = 0; result = NULL; /* don't use client->connection - it may be NULL already */ result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, NULL); if (result != NULL) { g_variant_get (result, "(u)", &request_name_reply); g_variant_unref (result); } subscribe = FALSE; switch (request_name_reply) { case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */ /* We got the name - now listen for NameLost and NameAcquired */ call_acquired_handler (client); subscribe = TRUE; client->needs_release = TRUE; break; case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */ /* Waiting in line - listen for NameLost and NameAcquired */ call_lost_handler (client); subscribe = TRUE; client->needs_release = TRUE; break; default: /* assume we couldn't get the name - explicit fallthrough */ case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */ case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */ /* Some other part of the process is already owning the name */ call_lost_handler (client); break; } if (subscribe) { GDBusConnection *connection = NULL; /* if cancelled, there is no point in subscribing to signals - if not, make sure * we use a known good Connection object since it may be set to NULL at any point * after being cancelled */ G_LOCK (lock); if (!client->cancelled) connection = g_object_ref (client->connection); G_UNLOCK (lock); /* start listening to NameLost and NameAcquired messages */ if (connection != NULL) { client->name_lost_subscription_id = g_dbus_connection_signal_subscribe (connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameLost", "/org/freedesktop/DBus", client->name, G_DBUS_SIGNAL_FLAGS_NONE, on_name_lost_or_acquired, client, NULL); client->name_acquired_subscription_id = g_dbus_connection_signal_subscribe (connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameAcquired", "/org/freedesktop/DBus", client->name, G_DBUS_SIGNAL_FLAGS_NONE, on_name_lost_or_acquired, client, NULL); g_object_unref (connection); } } client_unref (client); }
/** * g_bus_unown_name: * @owner_id: An identifier obtained from g_bus_own_name() * * Stops owning a name. * * Since: 2.26 */ void g_bus_unown_name (guint owner_id) { Client *client; g_return_if_fail (owner_id > 0); client = NULL; G_LOCK (lock); if (owner_id == 0 || map_id_to_client == NULL || (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (owner_id))) == NULL) { g_warning ("Invalid id %d passed to g_bus_unown_name()", owner_id); goto out; } client->cancelled = TRUE; g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (owner_id))); out: G_UNLOCK (lock); /* do callback without holding lock */ if (client != NULL) { /* Release the name if needed */ if (client->needs_release && client->connection != NULL) { GVariant *result; GError *error; guint32 release_name_reply; /* TODO: it kinda sucks having to do a sync call to release the name - but if * we don't, then a subsequent grab of the name will make the bus daemon return * IN_QUEUE which will trigger name_lost(). * * I believe this is a bug in the bus daemon. */ error = NULL; result = g_dbus_connection_call_sync (client->connection, "org.freedesktop.DBus", /* bus name */ "/org/freedesktop/DBus", /* object path */ "org.freedesktop.DBus", /* interface name */ "ReleaseName", /* method name */ g_variant_new ("(s)", client->name), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (result == NULL) { g_warning ("Error releasing name %s: %s", client->name, error->message); g_error_free (error); } else { g_variant_get (result, "(u)", &release_name_reply); if (release_name_reply != 1 /* DBUS_RELEASE_NAME_REPLY_RELEASED */) { g_warning ("Unexpected reply %d when releasing name %s", release_name_reply, client->name); } g_variant_unref (result); } } if (client->disconnected_signal_handler_id > 0) g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id); if (client->name_acquired_subscription_id > 0) g_dbus_connection_signal_unsubscribe (client->connection, client->name_acquired_subscription_id); if (client->name_lost_subscription_id > 0) g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id); client->disconnected_signal_handler_id = 0; client->name_acquired_subscription_id = 0; client->name_lost_subscription_id = 0; if (client->connection != NULL) { g_object_unref (client->connection); client->connection = NULL; } client_unref (client); } }
static void sasl_callback(struct client *client, enum sasl_server_reply sasl_reply, const char *data, const char *const *args) { struct client_auth_reply reply; i_assert(!client->destroyed || sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED || sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED); switch (sasl_reply) { case SASL_SERVER_REPLY_SUCCESS: if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { client_auth_parse_args(client, args, &reply); if (client_auth_handle_reply(client, &reply, TRUE)) break; } client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS, NULL, NULL); client_destroy_success(client, "Login"); break; case SASL_SERVER_REPLY_AUTH_FAILED: case SASL_SERVER_REPLY_AUTH_ABORTED: if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { client_auth_parse_args(client, args, &reply); reply.nologin = TRUE; if (client_auth_handle_reply(client, &reply, FALSE)) break; } if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) { client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED, NULL, "Authentication aborted by client."); } else if (data == NULL) { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED, NULL, AUTH_FAILED_MSG); } else { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED_REASON, NULL, data); } if (!client->destroyed) client_auth_failed(client); break; case SASL_SERVER_REPLY_MASTER_FAILED: if (data != NULL) { /* authentication itself succeeded, we just hit some internal failure. */ client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL, NULL, data); } /* the fd may still be hanging somewhere in kernel or another process. make sure the client gets disconnected. */ if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN) i_error("shutdown() failed: %m"); if (data == NULL) client_destroy_internal_failure(client); else client_destroy_success(client, data); break; case SASL_SERVER_REPLY_CONTINUE: i_assert(client->v.auth_send_challenge != NULL); client->v.auth_send_challenge(client, data); if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (client->auth_response != NULL) str_truncate(client->auth_response, 0); i_assert(client->io == NULL); client->auth_waiting = TRUE; client->io = io_add(client->fd, IO_READ, client_auth_input, client); client_auth_input(client); return; } client_unref(&client); }
static void client_close(struct context *ctx, struct conn *conn) { rstatus_t status; struct msg *msg, *nmsg; /* current and next message */ ASSERT(conn->type == CONN_CLIENT); client_close_stats(ctx, conn->owner, conn->err, conn->eof); if (conn->sd < 0) { client_unref(conn); return; } msg = conn->rmsg; if (msg != NULL) { conn->rmsg = NULL; ASSERT(msg->peer == NULL); ASSERT(msg->request && !msg->done); log_debug(LOG_INFO, "close c %d discarding pending req %"PRIu64" len " "%"PRIu32" type %d", conn->sd, msg->id, msg->mlen, msg->type); req_put(msg); } ASSERT(conn->smsg == NULL); ASSERT(TAILQ_EMPTY(&conn->imsg_q)); for (msg = TAILQ_FIRST(&conn->omsg_q); msg != NULL; msg = nmsg) { nmsg = TAILQ_NEXT(msg, c_tqe); /* dequeue the message (request) from client outq */ conn_dequeue_outq(ctx, conn, msg); if (msg->done) { log_debug(LOG_INFO, "close c %d discarding %s req %"PRIu64" len " "%"PRIu32" type %d", conn->sd, msg->error ? "error": "completed", msg->id, msg->mlen, msg->type); req_put(msg); } else { msg->swallow = 1; ASSERT(msg->request); ASSERT(msg->peer == NULL); log_debug(LOG_INFO, "close c %d schedule swallow of req %"PRIu64" " "len %"PRIu32" type %d", conn->sd, msg->id, msg->mlen, msg->type); } stats_pool_incr(ctx, client_dropped_requests); } ASSERT(TAILQ_EMPTY(&conn->omsg_q)); status = close(conn->sd); if (status < 0) { log_error("close c %d failed, ignored: %s", conn->sd, strerror(errno)); } conn->sd = -1; client_unref(conn); }