HomePort
event.c
Go to the documentation of this file.
1 /*
2  * Copyright 2011 Aalborg University. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  * conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  * of conditions and the following disclaimer in the documentation and/or other materials
12  * provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY Aalborg University ''AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Aalborg University OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  */
27 
28 #include "daemon.h"
29 #include "event.h"
30 #include "discovery.h"
31 #include "value.h"
32 #include "log.h"
33 #include "comm.h"
34 #include "model.h"
35 
37 {
38  HPD_CALLOC(*listener, 1, hpd_listener_t);
39  (*listener)->hpd = hpd;
40  return HPD_E_SUCCESS;
41 
42  alloc_error:
44 }
45 
47 {
48  if (listener->on_free) listener->on_free(listener->data);
49  free(listener);
50  return HPD_E_SUCCESS;
51 }
52 
54 {
55  if (listener->on_free) listener->on_free(listener->data);
56  listener->data = data;
57  listener->on_free = on_free;
58  return HPD_E_SUCCESS;
59 }
60 
62 {
63  listener->on_change = on_change;
64  return HPD_E_SUCCESS;
65 }
66 
68 {
69  listener->on_attach = on_attach;
70  listener->on_detach = on_detach;
71  return HPD_E_SUCCESS;
72 }
73 
75 {
76  TAILQ_INSERT_TAIL(&listener->hpd->configuration->listeners, listener, HPD_TAILQ_FIELD);
77  return HPD_E_SUCCESS;
78 }
79 
81 {
82  if (listener) {
83  if (listener->on_free) listener->on_free(listener->data);
84  TAILQ_REMOVE(&listener->hpd->configuration->listeners, listener, HPD_TAILQ_FIELD);
85  free(listener);
86  }
87  return HPD_E_SUCCESS;
88 }
89 
91 {
92  (*data) = listener->data;
93  return HPD_E_SUCCESS;
94 }
95 
97 {
98  hpd_error_t rc;
99  hpd_configuration_t *configuration = listener->hpd->configuration;
100  hpd_adapter_t *adapter;
101  hpd_device_t *device;
102  TAILQ_FOREACH(adapter, &configuration->adapters, HPD_TAILQ_FIELD) {
103  TAILQ_FOREACH(device, adapter->devices, HPD_TAILQ_FIELD) {
104  hpd_device_id_t *did;
105  if ((rc = discovery_alloc_did(&did, configuration->hpd, adapter->id, device->id))) return rc;
106  listener->on_attach(listener->data, did);
107  if ((rc = discovery_free_did(did))) return rc;
108  }
109  }
110  return HPD_E_SUCCESS;
111 }
112 
113 static void event_on_changed(hpd_ev_loop_t *loop, ev_async *w, int revents)
114 {
115  hpd_error_t rc;
116  hpd_ev_async_t *async = w->data;
117  hpd_t *hpd = async->hpd;
118  hpd_service_id_t *id = async->service;
119  hpd_value_t *value = async->value;
120 
121  TAILQ_REMOVE(&hpd->changed_watchers, async, HPD_TAILQ_FIELD);
122  ev_async_stop(loop, w);
123  free(async);
124 
125  hpd_listener_t *listener;
126  TAILQ_FOREACH(listener, &hpd->configuration->listeners, HPD_TAILQ_FIELD) {
127  if (listener->on_change) listener->on_change(listener->data, id, value);
128  }
129 
130  if ((rc = discovery_free_sid(id))) {
131  LOG_ERROR("free function failed [code: %i].", rc);
132  }
133 
134  if ((rc = value_free(value))) {
135  LOG_ERROR("free function failed [code: %i].", rc);
136  }
137 }
138 
139 static void event_on_attached(hpd_ev_loop_t *loop, ev_async *w, int revents)
140 {
141  hpd_error_t rc;
142  hpd_ev_async_t *async = w->data;
143  hpd_t *hpd = async->hpd;
144  hpd_device_id_t *id = async->device;
145 
146  TAILQ_REMOVE(&hpd->attached_watchers, async, HPD_TAILQ_FIELD);
147  ev_async_stop(loop, w);
148  free(async);
149 
150  hpd_listener_t *listener;
151  // TODO With this loop delayed, hpd_foreach_attached() is likely to provide duplicated calls for the same devices
152  TAILQ_FOREACH(listener, &hpd->configuration->listeners, HPD_TAILQ_FIELD) {
153  if (listener->on_attach) listener->on_attach(listener->data, id);
154  }
155 
156  if ((rc = discovery_free_did(id))) {
157  LOG_ERROR("free function failed [code: %i].", rc);
158  }
159 }
160 
161 static void event_on_detached(hpd_ev_loop_t *loop, ev_async *w, int revents)
162 {
163  hpd_error_t rc;
164  hpd_ev_async_t *async = w->data;
165  hpd_t *hpd = async->hpd;
166  hpd_device_id_t *id = async->device;
167 
168  TAILQ_REMOVE(&hpd->detached_watchers, async, HPD_TAILQ_FIELD);
169  ev_async_stop(loop, w);
170  free(async);
171 
172  hpd_listener_t *listener;
173  TAILQ_FOREACH(listener, &hpd->configuration->listeners, HPD_TAILQ_FIELD) {
174  if (listener->on_detach) listener->on_detach(listener->data, id);
175  }
176 
177  if ((rc = discovery_free_did(id))) {
178  LOG_ERROR("free function failed [code: %i].", rc);
179  }
180 }
181 
183 {
185  hpd_ev_async_t *async;
186  HPD_CALLOC(async, 1, hpd_ev_async_t);
187  HPD_CPY_ALLOC(async->value, val, hpd_value_t);
188  if ((rc = discovery_copy_sid(&async->service, id))) goto copy_sid_error;
189  hpd_t *hpd = id->device.adapter.hpd;
190  async->hpd = hpd;
191  ev_async_init(&async->watcher, event_on_changed);
192  async->watcher.data = async;
193  ev_async_start(hpd->loop, &async->watcher);
194  ev_async_send(hpd->loop, &async->watcher);
195  TAILQ_INSERT_TAIL(&hpd->changed_watchers, async, HPD_TAILQ_FIELD);
196  free(val);
197  return HPD_E_SUCCESS;
198 
199  copy_sid_error:
200  free(async->value);
201  alloc_error:
202  free(async);
203  switch (rc) {
204  case HPD_E_ALLOC:
206  default:
207  return rc;
208  }
209 }
210 
212 {
213  hpd_error_t rc;
214  hpd_device_t *device;
215  TAILQ_FOREACH(device, adapter->devices, HPD_TAILQ_FIELD) {
216  // TODO Could alternatively remove the attached watchers and return an error
217  if ((rc = event_inform_device_attached(device)))
218  LOG_ERROR("event_inform_device_attached() [code: %i].", rc);
219  }
220  return HPD_E_SUCCESS;
221 }
222 
224 {
225  hpd_error_t rc;
226  hpd_device_t *device;
227  TAILQ_FOREACH(device, adapter->devices, HPD_TAILQ_FIELD) {
228  // TODO Could alternatively remove the attached watchers and return an error
229  if ((rc = event_inform_device_detached(device)))
230  LOG_ERROR("event_inform_device_detached() [code: %i].", rc);
231  }
232  return HPD_E_SUCCESS;
233 }
234 
236 {
238  hpd_ev_async_t *async;
239  HPD_CALLOC(async, 1, hpd_ev_async_t);
240  hpd_adapter_t *adapter = device->adapter;
241  hpd_t *hpd = adapter->configuration->hpd;
242  if ((rc = discovery_alloc_did(&async->device, hpd, adapter->id, device->id))) goto did_error;
243  async->hpd = hpd;
244  ev_async_init(&async->watcher, event_on_attached);
245  async->watcher.data = async;
246  ev_async_start(hpd->loop, &async->watcher);
247  ev_async_send(hpd->loop, &async->watcher);
248  TAILQ_INSERT_TAIL(&hpd->attached_watchers, async, HPD_TAILQ_FIELD);
249  return HPD_E_SUCCESS;
250 
251  did_error:
252  free(async);
253  alloc_error:
254  switch (rc) {
255  case HPD_E_ALLOC:
257  default:
258  return rc;
259  }
260 }
261 
263 {
265  hpd_ev_async_t *async;
266  HPD_CALLOC(async, 1, hpd_ev_async_t);
267  hpd_adapter_t *adapter = device->adapter;
268  hpd_t *hpd = adapter->configuration->hpd;
269  if ((rc = discovery_alloc_did(&async->device, hpd, adapter->id, device->id))) goto did_error;
270  async->hpd = hpd;
271  ev_async_init(&async->watcher, event_on_detached);
272  async->watcher.data = async;
273  ev_async_start(hpd->loop, &async->watcher);
274  ev_async_send(hpd->loop, &async->watcher);
275  TAILQ_INSERT_TAIL(&hpd->detached_watchers, async, HPD_TAILQ_FIELD);
276  return HPD_E_SUCCESS;
277 
278  did_error:
279  free(async);
280  alloc_error:
281  switch (rc) {
282  case HPD_E_ALLOC:
284  default:
285  return rc;
286  }
287 }
hpd_error_t event_set_device_callback(hpd_listener_t *listener, hpd_device_f on_attach, hpd_device_f on_detach)
Definition: event.c:67
void(* hpd_free_f)(void *data)
[hpd_action_f]
Definition: hpd_types.h:187
char * id
Definition: model.h:70
hpd_ev_loop_t * loop
Definition: daemon.h:51
static void event_on_changed(hpd_ev_loop_t *loop, ev_async *w, int revents)
Definition: event.c:113
hpd_device_f on_attach
Definition: comm.h:47
hpd_error_t discovery_copy_sid(hpd_service_id_t **dst, const hpd_service_id_t *src)
Definition: discovery_id.c:160
data value
#define LOG_RETURN_E_ALLOC()
Definition: log.h:51
hpd_error_t event_inform_adapter_attached(hpd_adapter_t *adapter)
Definition: event.c:211
free(data.url)
hpd_error_t discovery_free_did(hpd_device_id_t *id)
Definition: discovery_id.c:178
hpd_free_f on_free
Definition: comm.h:51
#define HPD_TAILQ_FIELD
Definition: hpd_queue.h:37
hpd_listeners_t listeners
Definition: model.h:60
hpd_t * hpd
Definition: comm.h:44
#define HPD_CALLOC(PTR, NUM, CAST)
Allocates and zeros a structure.
Definition: hpd_common.h:44
hpd_error_t event_foreach_attached(const hpd_listener_t *listener)
Definition: event.c:96
hpd_error_t event_subscribe(hpd_listener_t *listener)
Definition: event.c:74
ev_async watcher
Definition: daemon.h:72
hpd_error_t event_inform_adapter_detached(hpd_adapter_t *adapter)
Definition: event.c:223
hpd_error_t event_free_listener(hpd_listener_t *listener)
Definition: event.c:46
hpd_error_t discovery_alloc_did(hpd_device_id_t **id, hpd_t *hpd, const char *aid, const char *did)
Definition: discovery_id.c:104
hpd_configuration_t * configuration
Definition: daemon.h:52
hpd_adapters_t adapters
Definition: model.h:59
Definition: comm.h:70
void(* hpd_device_f)(void *data, const hpd_device_id_t *device)
Device callback for listeners.
Definition: hpd_types.h:196
enum hpd_error hpd_error_t
Definition: hpd_types.h:167
hpd_value_f on_change
Definition: comm.h:46
struct data data
Definition: daemon.h:50
hpd_error_t event_unsubscribe(hpd_listener_t *listener)
Definition: event.c:80
static struct ev_loop * loop
static void event_on_detached(hpd_ev_loop_t *loop, ev_async *w, int revents)
Definition: event.c:161
hpd_ev_asyncs_t changed_watchers
Definition: daemon.h:63
hpd_error_t value_free(hpd_value_t *value)
Definition: value.c:99
#define HPD_CPY_ALLOC(DST, SRC, CAST)
Definition: hpd_common.h:58
hpd_error_t event_inform_device_attached(hpd_device_t *device)
Definition: event.c:235
char * id
Definition: model.h:83
hpd_error_t event_get_listener_data(const hpd_listener_t *listener, void **data)
Definition: event.c:90
hpd_t * hpd
Definition: model.h:61
hpd_configuration_t * configuration
Definition: model.h:66
void(* hpd_value_f)(void *data, const hpd_service_id_t *service, const hpd_value_t *val)
Value callback for listeners.
Definition: hpd_types.h:194
hpd_error_t discovery_free_sid(hpd_service_id_t *id)
Definition: discovery_id.c:186
hpd_ev_asyncs_t detached_watchers
Definition: daemon.h:65
static void event_on_attached(hpd_ev_loop_t *loop, ev_async *w, int revents)
Definition: event.c:139
hpd_error_t event_inform_device_detached(hpd_device_t *device)
Definition: event.c:262
hpd_device_f on_detach
Definition: comm.h:48
hpd_error_t event_set_listener_data(hpd_listener_t *listener, void *data, hpd_free_f on_free)
Definition: event.c:53
hpd_ev_asyncs_t attached_watchers
Definition: daemon.h:64
struct ev_loop hpd_ev_loop_t
Definition: hpd_types.h:51
#define LOG_ERROR(FMT,...)
Definition: log.h:43
hpd_error_t event_set_value_callback(hpd_listener_t *listener, hpd_value_f on_change)
Definition: event.c:61
void * data
Definition: comm.h:50
hpd_error_t event_changed(const hpd_service_id_t *id, hpd_value_t *val)
Definition: event.c:182
hpd_adapter_t * adapter
Definition: model.h:79
hpd_devices_t * devices
Definition: model.h:68
hpd_error_t event_alloc_listener(hpd_listener_t **listener, hpd_t *hpd)
Definition: event.c:36