+ health_code_update();
+
+ return ret;
+}
+
+/*
+ * Receive registration and populate the given msg structure.
+ *
+ * On success return 0 else a negative value returned by the ustctl call.
+ */
+int ust_app_recv_registration(int sock, struct ust_register_msg *msg)
+{
+ int ret;
+ uint32_t pid, ppid, uid, gid;
+
+ assert(msg);
+
+ ret = ustctl_recv_reg_msg(sock, &msg->type, &msg->major, &msg->minor,
+ &pid, &ppid, &uid, &gid,
+ &msg->bits_per_long,
+ &msg->uint8_t_alignment,
+ &msg->uint16_t_alignment,
+ &msg->uint32_t_alignment,
+ &msg->uint64_t_alignment,
+ &msg->long_alignment,
+ &msg->byte_order,
+ msg->name);
+ if (ret < 0) {
+ switch (-ret) {
+ case EPIPE:
+ case ECONNRESET:
+ case LTTNG_UST_ERR_EXITING:
+ DBG3("UST app recv reg message failed. Application died");
+ break;
+ case LTTNG_UST_ERR_UNSUP_MAJOR:
+ ERR("UST app recv reg unsupported version %d.%d. Supporting %d.%d",
+ msg->major, msg->minor, LTTNG_UST_ABI_MAJOR_VERSION,
+ LTTNG_UST_ABI_MINOR_VERSION);
+ break;
+ default:
+ ERR("UST app recv reg message failed with ret %d", ret);
+ break;
+ }
+ goto error;
+ }
+ msg->pid = (pid_t) pid;
+ msg->ppid = (pid_t) ppid;
+ msg->uid = (uid_t) uid;
+ msg->gid = (gid_t) gid;
+
+error:
+ return ret;
+}
+
+/*
+ * Return a ust app channel object using the application object and the channel
+ * object descriptor has a key. If not found, NULL is returned. A RCU read side
+ * lock MUST be acquired before calling this function.
+ */
+static struct ust_app_channel *find_channel_by_objd(struct ust_app *app,
+ int objd)
+{
+ struct lttng_ht_node_ulong *node;
+ struct lttng_ht_iter iter;
+ struct ust_app_channel *ua_chan = NULL;
+
+ assert(app);
+
+ lttng_ht_lookup(app->ust_objd, (void *)((unsigned long) objd), &iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (node == NULL) {
+ DBG2("UST app channel find by objd %d not found", objd);
+ goto error;
+ }
+
+ ua_chan = caa_container_of(node, struct ust_app_channel, ust_objd_node);
+
+error:
+ return ua_chan;
+}
+
+/*
+ * Reply to a register channel notification from an application on the notify
+ * socket. The channel metadata is also created.
+ *
+ * The session UST registry lock is acquired in this function.
+ *
+ * On success 0 is returned else a negative value.
+ */
+static int reply_ust_register_channel(int sock, int sobjd, int cobjd,
+ size_t nr_fields, struct ustctl_field *fields)
+{
+ int ret, ret_code = 0;
+ uint32_t chan_id, reg_count;
+ uint64_t chan_reg_key;
+ enum ustctl_channel_header type;
+ struct ust_app *app;
+ struct ust_app_channel *ua_chan;
+ struct ust_app_session *ua_sess;
+ struct ust_registry_session *registry;
+ struct ust_registry_channel *chan_reg;
+
+ rcu_read_lock();
+
+ /* Lookup application. If not found, there is a code flow error. */
+ app = find_app_by_notify_sock(sock);
+ if (!app) {
+ DBG("Application socket %d is being teardown. Abort event notify",
+ sock);
+ ret = 0;
+ free(fields);
+ goto error_rcu_unlock;
+ }
+
+ /* Lookup channel by UST object descriptor. */
+ ua_chan = find_channel_by_objd(app, cobjd);
+ if (!ua_chan) {
+ DBG("Application channel is being teardown. Abort event notify");
+ ret = 0;
+ free(fields);
+ goto error_rcu_unlock;
+ }
+
+ assert(ua_chan->session);
+ ua_sess = ua_chan->session;
+
+ /* Get right session registry depending on the session buffer type. */
+ registry = get_session_registry(ua_sess);
+ assert(registry);
+
+ /* Depending on the buffer type, a different channel key is used. */
+ if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+ chan_reg_key = ua_chan->tracing_channel_id;
+ } else {
+ chan_reg_key = ua_chan->key;
+ }
+
+ pthread_mutex_lock(®istry->lock);
+
+ chan_reg = ust_registry_channel_find(registry, chan_reg_key);
+ assert(chan_reg);
+
+ if (!chan_reg->register_done) {
+ reg_count = ust_registry_get_event_count(chan_reg);
+ if (reg_count < 31) {
+ type = USTCTL_CHANNEL_HEADER_COMPACT;
+ } else {
+ type = USTCTL_CHANNEL_HEADER_LARGE;
+ }
+
+ chan_reg->nr_ctx_fields = nr_fields;
+ chan_reg->ctx_fields = fields;
+ chan_reg->header_type = type;
+ } else {
+ /* Get current already assigned values. */
+ type = chan_reg->header_type;
+ free(fields);
+ /* Set to NULL so the error path does not do a double free. */
+ fields = NULL;
+ }
+ /* Channel id is set during the object creation. */
+ chan_id = chan_reg->chan_id;
+
+ /* Append to metadata */
+ if (!chan_reg->metadata_dumped) {
+ ret_code = ust_metadata_channel_statedump(registry, chan_reg);
+ if (ret_code) {
+ ERR("Error appending channel metadata (errno = %d)", ret_code);
+ goto reply;
+ }
+ }
+
+reply:
+ DBG3("UST app replying to register channel key %" PRIu64
+ " with id %u, type: %d, ret: %d", chan_reg_key, chan_id, type,
+ ret_code);
+
+ ret = ustctl_reply_register_channel(sock, chan_id, type, ret_code);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("UST app reply channel failed with ret %d", ret);
+ } else {
+ DBG3("UST app reply channel failed. Application died");
+ }
+ goto error;
+ }
+
+ /* This channel registry registration is completed. */
+ chan_reg->register_done = 1;
+
+error:
+ pthread_mutex_unlock(®istry->lock);
+error_rcu_unlock:
+ rcu_read_unlock();
+ if (ret) {
+ free(fields);
+ }
+ return ret;
+}
+
+/*
+ * Add event to the UST channel registry. When the event is added to the
+ * registry, the metadata is also created. Once done, this replies to the
+ * application with the appropriate error code.
+ *
+ * The session UST registry lock is acquired in the function.
+ *
+ * On success 0 is returned else a negative value.
+ */
+static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
+ char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
+ char *model_emf_uri)
+{
+ int ret, ret_code;
+ uint32_t event_id = 0;
+ uint64_t chan_reg_key;
+ struct ust_app *app;
+ struct ust_app_channel *ua_chan;
+ struct ust_app_session *ua_sess;
+ struct ust_registry_session *registry;
+
+ rcu_read_lock();
+
+ /* Lookup application. If not found, there is a code flow error. */
+ app = find_app_by_notify_sock(sock);
+ if (!app) {
+ DBG("Application socket %d is being teardown. Abort event notify",
+ sock);
+ ret = 0;
+ free(sig);
+ free(fields);
+ free(model_emf_uri);
+ goto error_rcu_unlock;
+ }
+
+ /* Lookup channel by UST object descriptor. */
+ ua_chan = find_channel_by_objd(app, cobjd);
+ if (!ua_chan) {
+ DBG("Application channel is being teardown. Abort event notify");
+ ret = 0;
+ free(sig);
+ free(fields);
+ free(model_emf_uri);
+ goto error_rcu_unlock;
+ }
+
+ assert(ua_chan->session);
+ ua_sess = ua_chan->session;
+
+ registry = get_session_registry(ua_sess);
+ assert(registry);
+
+ if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+ chan_reg_key = ua_chan->tracing_channel_id;
+ } else {
+ chan_reg_key = ua_chan->key;
+ }
+
+ pthread_mutex_lock(®istry->lock);
+
+ /*
+ * From this point on, this call acquires the ownership of the sig, fields
+ * and model_emf_uri meaning any free are done inside it if needed. These
+ * three variables MUST NOT be read/write after this.
+ */
+ ret_code = ust_registry_create_event(registry, chan_reg_key,
+ sobjd, cobjd, name, sig, nr_fields, fields, loglevel,
+ model_emf_uri, ua_sess->buffer_type, &event_id);
+
+ /*
+ * The return value is returned to ustctl so in case of an error, the
+ * application can be notified. In case of an error, it's important not to
+ * return a negative error or else the application will get closed.
+ */
+ ret = ustctl_reply_register_event(sock, event_id, ret_code);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("UST app reply event failed with ret %d", ret);
+ } else {
+ DBG3("UST app reply event failed. Application died");
+ }
+ /*
+ * No need to wipe the create event since the application socket will
+ * get close on error hence cleaning up everything by itself.
+ */
+ goto error;
+ }
+
+ DBG3("UST registry event %s with id %" PRId32 " added successfully",
+ name, event_id);
+
+error:
+ pthread_mutex_unlock(®istry->lock);
+error_rcu_unlock:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Handle application notification through the given notify socket.
+ *
+ * Return 0 on success or else a negative value.
+ */
+int ust_app_recv_notify(int sock)
+{
+ int ret;
+ enum ustctl_notify_cmd cmd;
+
+ DBG3("UST app receiving notify from sock %d", sock);
+
+ ret = ustctl_recv_notify(sock, &cmd);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("UST app recv notify failed with ret %d", ret);
+ } else {
+ DBG3("UST app recv notify failed. Application died");
+ }
+ goto error;
+ }
+
+ switch (cmd) {
+ case USTCTL_NOTIFY_CMD_EVENT:
+ {
+ int sobjd, cobjd, loglevel;
+ char name[LTTNG_UST_SYM_NAME_LEN], *sig, *model_emf_uri;
+ size_t nr_fields;
+ struct ustctl_field *fields;
+
+ DBG2("UST app ustctl register event received");
+
+ ret = ustctl_recv_register_event(sock, &sobjd, &cobjd, name, &loglevel,
+ &sig, &nr_fields, &fields, &model_emf_uri);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("UST app recv event failed with ret %d", ret);
+ } else {
+ DBG3("UST app recv event failed. Application died");
+ }
+ goto error;
+ }
+
+ /*
+ * Add event to the UST registry coming from the notify socket. This
+ * call will free if needed the sig, fields and model_emf_uri. This
+ * code path loses the ownsership of these variables and transfer them
+ * to the this function.
+ */
+ ret = add_event_ust_registry(sock, sobjd, cobjd, name, sig, nr_fields,
+ fields, loglevel, model_emf_uri);
+ if (ret < 0) {
+ goto error;
+ }
+
+ break;
+ }
+ case USTCTL_NOTIFY_CMD_CHANNEL:
+ {
+ int sobjd, cobjd;
+ size_t nr_fields;
+ struct ustctl_field *fields;
+
+ DBG2("UST app ustctl register channel received");
+
+ ret = ustctl_recv_register_channel(sock, &sobjd, &cobjd, &nr_fields,
+ &fields);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("UST app recv channel failed with ret %d", ret);
+ } else {
+ DBG3("UST app recv channel failed. Application died");
+ }
+ goto error;
+ }
+
+ /*
+ * The fields ownership are transfered to this function call meaning
+ * that if needed it will be freed. After this, it's invalid to access
+ * fields or clean it up.
+ */
+ ret = reply_ust_register_channel(sock, sobjd, cobjd, nr_fields,
+ fields);
+ if (ret < 0) {
+ goto error;
+ }
+
+ break;
+ }
+ default:
+ /* Should NEVER happen. */
+ assert(0);
+ }
+
+error: