HomePort
request.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 "value.h"
29 #include "discovery.h"
30 #include "request.h"
31 #include "hpd/common/hpd_common.h"
32 #include <ev.h>
33 #include "daemon.h"
34 #include "log.h"
35 #include "comm.h"
36 #include "model.h"
37 
39  hpd_response_f on_response)
40 {
42  HPD_CALLOC(*request, 1, hpd_request_t);
43  if ((rc = discovery_copy_sid(&(*request)->service, id))) goto alloc_error;
44  (*request)->method = method;
45  (*request)->on_response = on_response;
46  return HPD_E_SUCCESS;
47 
48  alloc_error:
49  request_free_request(*request);
50  switch (rc) {
51  case HPD_E_ALLOC:
53  default:
54  return rc;
55  }
56 }
57 
59 {
60  if (request) {
61  if (request->on_free) request->on_free(request->data);
62  if (request->service) discovery_free_sid(request->service);
63  if (request->value) value_free(request->value);
64  free(request);
65  }
66  return HPD_E_SUCCESS;
67 }
68 
70 {
71  if (value) {
72  HPD_CPY_ALLOC(request->value, value, hpd_value_t);
73  free(value);
74  } else {
75  value_free(request->value);
76  request->value = NULL;
77  }
78  return HPD_E_SUCCESS;
79 
80  alloc_error:
82 }
83 
85 {
86  request->data = data;
87  request->on_free = on_free;
88  return HPD_E_SUCCESS;
89 }
90 
92 {
93  (*id) = req->service;
94  return HPD_E_SUCCESS;
95 }
96 
98 {
99  (*method) = req->method;
100  return HPD_E_SUCCESS;
101 }
102 
104 {
105  (*value) = req->value;
106  return HPD_E_SUCCESS;
107 }
108 
110 {
111  HPD_CALLOC(*response, 1, hpd_response_t);
112  HPD_CPY_ALLOC((*response)->request, request, hpd_request_t);
113  free(request);
114  (*response)->status = status;
115  return HPD_E_SUCCESS;
116 
117  alloc_error:
118  request_free_response(*response);
120 }
121 
123 {
124  if (response) {
125  if (response->request) request_free_request(response->request);
126  if (response->value) value_free(response->value);
127  free(response);
128  }
129  return HPD_E_SUCCESS;
130 }
131 
133 {
134  if (value) {
135  HPD_CPY_ALLOC(response->value, value, hpd_value_t);
136  free(value);
137  } else {
138  value_free(response->value);
139  response->value = NULL;
140  }
141  return HPD_E_SUCCESS;
142 
143  alloc_error:
145 }
146 
148 {
149  (*status) = response->status;
150  return HPD_E_SUCCESS;
151 }
152 
154 {
155  (*value) = response->value;
156  return HPD_E_SUCCESS;
157 }
158 
160 {
161  (*data) = response->request->data;
162  return HPD_E_SUCCESS;
163 }
164 
166 {
167  (*service) = response->request->service;
168  return HPD_E_SUCCESS;
169 }
170 
172 {
173  (*method) = response->request->method;
174  return HPD_E_SUCCESS;
175 }
176 
178 {
179  (*value) = response->request->value;
180  return HPD_E_SUCCESS;
181 }
182 
183 static void request_on_request(hpd_ev_loop_t *loop, ev_async *w, int revents)
184 {
185  hpd_error_t rc;
186  hpd_ev_async_t *async = w->data;
187  hpd_request_t *request = async->request;
188  hpd_service_id_t *service_id = request->service;
189 
190  hpd_t *hpd = service_id->device.adapter.hpd;
191  char *sid = service_id->sid;
192  char *did = service_id->device.did;
193  char *aid = service_id->device.adapter.aid;
194 
195  TAILQ_REMOVE(&hpd->request_watchers, async, HPD_TAILQ_FIELD);
196  ev_async_stop(loop, w);
197  free(async);
198 
199  hpd_service_t *service;
200  hpd_response_t *response;
201 
202  switch (discovery_find_service(service_id, &service)) {
203  case HPD_E_NOT_FOUND: {
204  LOG_DEBUG("Did not find service %s/%s/%s.", aid, did, sid);
205  if ((rc = request_alloc_response(&response, request, HPD_S_404))) goto error_free_request;
206  if ((rc = request_respond(response))) goto error_free_response;
207  return;
208  }
209  }
210 
211  hpd_action_f action = service->actions[request->method].action;
212  if (!action) {
213  if ((rc = request_alloc_response(&response, request, HPD_S_405))) goto error_free_request;
214  if ((rc = request_respond(response))) goto error_free_response;
215  return;
216  }
217 
218  hpd_status_t status;
219  if ((status = action(service->data, request)) != HPD_S_NONE) {
220  if ((rc = request_alloc_response(&response, request, status))) goto error_free_request;
221  if ((rc = request_respond(response))) goto error_free_response;
222  return;
223  }
224 
225  return;
226 
227  error_free_response:
228  request_free_response(response);
229  error_free_request:
230  request_free_request(request);
231  LOG_ERROR("on_request() failed [code: %i].", rc);
232  return;
233 }
234 
235 static void request_on_respond(hpd_ev_loop_t *loop, ev_async *w, int revents)
236 {
237  hpd_error_t rc;
238  hpd_ev_async_t *async = w->data;
239  hpd_response_t *response = async->response;
240  hpd_request_t *request = response->request;
241  hpd_service_id_t *service_id = request->service;
242  hpd_t *hpd = service_id->device.adapter.hpd;
243 
244  TAILQ_REMOVE(&hpd->respond_watchers, async, HPD_TAILQ_FIELD);
245  ev_async_stop(loop, w);
246  free(async);
247 
248  if (request->on_response) request->on_response(request->data, response);
249 
250  if ((rc = request_free_response(response))) {
251  LOG_ERROR("Free function failed [code: %i].", rc);
252  }
253 }
254 
256 {
257  hpd_ev_async_t *async;
258  HPD_CALLOC(async, 1, hpd_ev_async_t);
259  HPD_CPY_ALLOC(async->request, request, hpd_request_t);
260  ev_async_init(&async->watcher, request_on_request);
261  async->watcher.data = async;
262  hpd_t *hpd = request->service->device.adapter.hpd;
263  ev_async_start(hpd->loop, &async->watcher);
264  ev_async_send(hpd->loop, &async->watcher);
265  TAILQ_INSERT_TAIL(&hpd->request_watchers, async, HPD_TAILQ_FIELD);
266  free(request);
267  return HPD_E_SUCCESS;
268 
269  alloc_error:
270  free(async);
272 }
273 
275 {
276  hpd_ev_async_t *async;
277  HPD_CALLOC(async, 1, hpd_ev_async_t);
278  HPD_CPY_ALLOC(async->response, response, hpd_response_t);
279  ev_async_init(&async->watcher, request_on_respond);
280  async->watcher.data = async;
281  hpd_t *hpd = response->request->service->device.adapter.hpd;
282  ev_async_start(hpd->loop, &async->watcher);
283  ev_async_send(hpd->loop, &async->watcher);
284  TAILQ_INSERT_TAIL(&hpd->respond_watchers, async, HPD_TAILQ_FIELD);
285  free(response);
286  return HPD_E_SUCCESS;
287 
288  alloc_error:
289  free(async);
291 }
hpd_error_t request_get_response_request_method(const hpd_response_t *response, hpd_method_t *method)
Definition: request.c:171
enum hpd_status hpd_status_t
Definition: hpd_types.h:168
hpd_device_id_t device
Definition: discovery.h:49
void(* hpd_free_f)(void *data)
[hpd_action_f]
Definition: hpd_types.h:187
static void request_on_respond(hpd_ev_loop_t *loop, ev_async *w, int revents)
Definition: request.c:235
hpd_ev_loop_t * loop
Definition: daemon.h:51
hpd_error_t discovery_find_service(const hpd_service_id_t *id, hpd_service_t **service)
Definition: discovery_id.c:251
static void request_on_request(hpd_ev_loop_t *loop, ev_async *w, int revents)
Definition: request.c:183
hpd_response_f on_response
Definition: comm.h:59
void * data
Definition: model.h:101
hpd_error_t request_get_response_status(const hpd_response_t *response, hpd_status_t *status)
Definition: request.c:147
hpd_error_t request_set_response_value(hpd_response_t *response, hpd_value_t *value)
Definition: request.c:132
hpd_error_t discovery_copy_sid(hpd_service_id_t **dst, const hpd_service_id_t *src)
Definition: discovery_id.c:160
data value
char * sid
Definition: discovery.h:50
#define LOG_RETURN_E_ALLOC()
Definition: log.h:51
hpd_error_t request_respond(hpd_response_t *response)
Definition: request.c:274
hpd_error_t request_request(hpd_request_t *request)
Definition: request.c:255
hpd_free_f on_free
Definition: comm.h:60
free(data.url)
hpd_error_t request_get_response_request_value(const hpd_response_t *response, const hpd_value_t **value)
Definition: request.c:177
hpd_t * hpd
Definition: discovery.h:39
hpd_value_t * value
Definition: comm.h:57
hpd_ev_asyncs_t respond_watchers
Definition: daemon.h:62
hpd_action_f action
Definition: model.h:54
#define HPD_TAILQ_FIELD
Definition: hpd_queue.h:37
hpd_request_t * request
Definition: comm.h:65
void(* hpd_response_f)(void *data, const hpd_response_t *res)
[hpd_free_f]
Definition: hpd_types.h:192
hpd_method_t method
Definition: comm.h:56
char * aid
Definition: discovery.h:40
#define HPD_CALLOC(PTR, NUM, CAST)
Allocates and zeros a structure.
Definition: hpd_common.h:44
hpd_error_t request_get_request_service(const hpd_request_t *req, const hpd_service_id_t **id)
Definition: request.c:91
hpd_value_t * value
Definition: comm.h:67
ev_async watcher
Definition: daemon.h:72
hpd_error_t request_get_response_request_service(const hpd_response_t *response, const hpd_service_id_t **service)
Definition: request.c:165
Definition: comm.h:70
hpd_ev_asyncs_t request_watchers
Definition: daemon.h:61
enum hpd_error hpd_error_t
Definition: hpd_types.h:167
hpd_error_t request_free_response(hpd_response_t *response)
Definition: request.c:122
hpd_error_t request_alloc_request(hpd_request_t **request, const hpd_service_id_t *id, hpd_method_t method, hpd_response_f on_response)
Definition: request.c:38
hpd_error_t request_get_response_value(const hpd_response_t *response, const hpd_value_t **value)
Definition: request.c:153
char * did
Definition: discovery.h:45
#define LOG_DEBUG(FMT,...)
Definition: log.h:46
hpd_service_id_t * service
Definition: comm.h:55
struct data data
hpd_error_t request_alloc_response(hpd_response_t **response, hpd_request_t *request, hpd_status_t status)
Definition: request.c:109
Definition: daemon.h:50
hpd_error_t request_get_response_request_data(const hpd_response_t *response, void **data)
Definition: request.c:159
static struct ev_loop * loop
hpd_status_t(* hpd_action_f)(void *data, hpd_request_t *req)
[hpd_module_def_t functions]
Definition: hpd_types.h:183
hpd_error_t request_set_request_value(hpd_request_t *request, hpd_value_t *value)
Definition: request.c:69
hpd_error_t value_free(hpd_value_t *value)
Definition: value.c:99
void * data
Definition: comm.h:61
#define HPD_CPY_ALLOC(DST, SRC, CAST)
Definition: hpd_common.h:58
hpd_error_t request_get_request_method(const hpd_request_t *req, hpd_method_t *method)
Definition: request.c:97
hpd_error_t request_free_request(hpd_request_t *request)
Definition: request.c:58
hpd_error_t discovery_free_sid(hpd_service_id_t *id)
Definition: discovery_id.c:186
hpd_error_t request_get_request_value(const hpd_request_t *req, const hpd_value_t **value)
Definition: request.c:103
hpd_action_t actions[HPD_M_COUNT]
Definition: model.h:98
struct ev_loop hpd_ev_loop_t
Definition: hpd_types.h:51
hpd_adapter_id_t adapter
Definition: discovery.h:44
#define LOG_ERROR(FMT,...)
Definition: log.h:43
enum hpd_method hpd_method_t
[hpd_log_level_t]
Definition: hpd_types.h:166
hpd_error_t request_set_request_data(hpd_request_t *request, void *data, hpd_free_f on_free)
Definition: request.c:84
hpd_status_t status
Definition: comm.h:66