+ pthread_rwlock_unlock(&listeners_rwlock);
+}
+
+/*
+ * Jobs callback for broadcasting string asynchronously
+ */
+static void broadcast_job(int signum, void *closure)
+{
+ struct job_broadcast *jb = closure;
+
+ if (signum == 0)
+ broadcast(jb);
+ destroy_job_broadcast(jb);
+}
+
+/*
+ * Broadcasts the string 'event' with its 'object'
+ */
+static int unhooked_broadcast(const char *event, struct json_object *object, const uuid_binary_t uuid, uint8_t hop)
+{
+ uuid_binary_t local_uuid;
+ struct job_broadcast *jb;
+ int rc;
+#if EVENT_BROADCAST_MEMORY_COUNT
+ int iter, count;
+#endif
+
+ /* check if lately sent */
+ if (!uuid) {
+ uuid_new_binary(local_uuid);
+ uuid = local_uuid;
+ hop = EVENT_BROADCAST_HOP_MAX;
+#if EVENT_BROADCAST_MEMORY_COUNT
+ pthread_mutex_lock(&uniqueness.mutex);
+ } else {
+ pthread_mutex_lock(&uniqueness.mutex);
+ iter = (int)uniqueness.base;
+ count = (int)uniqueness.count;
+ while (count) {
+ if (0 == memcmp(uuid, uniqueness.uuids[iter], sizeof(uuid_binary_t))) {
+ pthread_mutex_unlock(&uniqueness.mutex);
+ return 0;
+ }
+ if (++iter == EVENT_BROADCAST_MEMORY_COUNT)
+ iter = 0;
+ count--;
+ }
+ }
+ iter = (int)uniqueness.base;
+ if (uniqueness.count < EVENT_BROADCAST_MEMORY_COUNT)
+ iter += (int)(uniqueness.count++);
+ else if (++uniqueness.base == EVENT_BROADCAST_MEMORY_COUNT)
+ uniqueness.base = 0;
+ memcpy(uniqueness.uuids[iter], uuid, sizeof(uuid_binary_t));
+ pthread_mutex_unlock(&uniqueness.mutex);
+#else
+ }
+#endif
+
+ /* create the structure for the job */
+ jb = make_job_broadcast(event, object, uuid, hop);
+ if (jb == NULL) {
+ ERROR("Cant't create broadcast string job item for %s(%s)",
+ event, json_object_to_json_string(object));
+ json_object_put(object);
+ return -1;
+ }
+
+ /* queue the job */
+ rc = jobs_queue(BROADCAST_JOB_GROUP, 0, broadcast_job, jb);
+ if (rc) {
+ ERROR("cant't queue broadcast string job item for %s(%s)",
+ event, json_object_to_json_string(object));
+ destroy_job_broadcast(jb);
+ }
+ return rc;
+}
+
+/*
+ * Broadcasts the event 'evtid' with its 'object'
+ * 'object' is released (like json_object_put)
+ * Returns the count of listener that received the event.
+ */
+int afb_evt_evtid_broadcast(struct afb_evtid *evtid, struct json_object *object)
+{
+ return unhooked_broadcast(evtid->fullname, object, NULL, 0);
+}
+
+#if WITH_AFB_HOOK
+/*
+ * Broadcasts the event 'evtid' with its 'object'
+ * 'object' is released (like json_object_put)
+ * Returns the count of listener that received the event.
+ */
+int afb_evt_evtid_hooked_broadcast(struct afb_evtid *evtid, struct json_object *object)
+{
+ int result;
+
+ json_object_get(object);
+
+ if (evtid->hookflags & afb_hook_flag_evt_broadcast_before)
+ afb_hook_evt_broadcast_before(evtid->fullname, evtid->id, object);
+
+ result = afb_evt_evtid_broadcast(evtid, object);
+
+ if (evtid->hookflags & afb_hook_flag_evt_broadcast_after)
+ afb_hook_evt_broadcast_after(evtid->fullname, evtid->id, object, result);
+