2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <ipc/services.h>
35 #include <fibril_synch.h>
41 static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex
);
42 static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex
);
44 static FIBRIL_MUTEX_INITIALIZE(loc_supplier_mutex
);
45 static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex
);
47 static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex
);
48 static bool loc_callback_created
= false;
49 static loc_cat_change_cb_t cat_change_cb
= NULL
;
51 static async_sess_t
*loc_supp_block_sess
= NULL
;
52 static async_sess_t
*loc_cons_block_sess
= NULL
;
54 static async_sess_t
*loc_supplier_sess
= NULL
;
55 static async_sess_t
*loc_consumer_sess
= NULL
;
57 static void loc_cb_conn(ipc_callid_t iid
, ipc_call_t
*icall
, void *arg
)
61 ipc_callid_t callid
= async_get_call(&call
);
63 if (!IPC_GET_IMETHOD(call
)) {
64 /* TODO: Handle hangup */
68 switch (IPC_GET_IMETHOD(call
)) {
69 case LOC_EVENT_CAT_CHANGE
:
70 fibril_mutex_lock(&loc_callback_mutex
);
71 loc_cat_change_cb_t cb_fun
= cat_change_cb
;
72 fibril_mutex_unlock(&loc_callback_mutex
);
74 async_answer_0(callid
, EOK
);
81 async_answer_0(callid
, ENOTSUP
);
87 static void clone_session(fibril_mutex_t
*mtx
, async_sess_t
*src
,
90 fibril_mutex_lock(mtx
);
92 if ((*dst
== NULL
) && (src
!= NULL
))
95 fibril_mutex_unlock(mtx
);
100 * Must be called with loc_callback_mutex locked.
102 * @return EOK on success.
105 static int loc_callback_create(void)
107 if (!loc_callback_created
) {
109 loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
112 aid_t req
= async_send_0(exch
, LOC_CALLBACK_CREATE
, &answer
);
115 int rc
= async_create_callback_port(exch
, INTERFACE_LOC_CB
, 0, 0,
116 loc_cb_conn
, NULL
, &port
);
118 loc_exchange_end(exch
);
124 async_wait_for(req
, &retval
);
128 loc_callback_created
= true;
134 /** Start an async exchange on the loc session (blocking).
136 * @param iface Location service interface to choose
138 * @return New exchange.
141 async_exch_t
*loc_exchange_begin_blocking(iface_t iface
)
144 case INTERFACE_LOC_SUPPLIER
:
145 fibril_mutex_lock(&loc_supp_block_mutex
);
147 while (loc_supp_block_sess
== NULL
) {
148 clone_session(&loc_supplier_mutex
, loc_supplier_sess
,
149 &loc_supp_block_sess
);
151 if (loc_supp_block_sess
== NULL
)
152 loc_supp_block_sess
=
153 service_connect_blocking(SERVICE_LOC
,
154 INTERFACE_LOC_SUPPLIER
, 0);
157 fibril_mutex_unlock(&loc_supp_block_mutex
);
159 clone_session(&loc_supplier_mutex
, loc_supp_block_sess
,
162 return async_exchange_begin(loc_supp_block_sess
);
163 case INTERFACE_LOC_CONSUMER
:
164 fibril_mutex_lock(&loc_cons_block_mutex
);
166 while (loc_cons_block_sess
== NULL
) {
167 clone_session(&loc_consumer_mutex
, loc_consumer_sess
,
168 &loc_cons_block_sess
);
170 if (loc_cons_block_sess
== NULL
)
171 loc_cons_block_sess
=
172 service_connect_blocking(SERVICE_LOC
,
173 INTERFACE_LOC_CONSUMER
, 0);
176 fibril_mutex_unlock(&loc_cons_block_mutex
);
178 clone_session(&loc_consumer_mutex
, loc_cons_block_sess
,
181 return async_exchange_begin(loc_cons_block_sess
);
187 /** Start an async exchange on the loc session.
189 * @param iface Location service interface to choose
191 * @return New exchange.
194 async_exch_t
*loc_exchange_begin(iface_t iface
)
197 case INTERFACE_LOC_SUPPLIER
:
198 fibril_mutex_lock(&loc_supplier_mutex
);
200 if (loc_supplier_sess
== NULL
)
202 service_connect(SERVICE_LOC
,
203 INTERFACE_LOC_SUPPLIER
, 0);
205 fibril_mutex_unlock(&loc_supplier_mutex
);
207 if (loc_supplier_sess
== NULL
)
210 return async_exchange_begin(loc_supplier_sess
);
211 case INTERFACE_LOC_CONSUMER
:
212 fibril_mutex_lock(&loc_consumer_mutex
);
214 if (loc_consumer_sess
== NULL
)
216 service_connect(SERVICE_LOC
,
217 INTERFACE_LOC_CONSUMER
, 0);
219 fibril_mutex_unlock(&loc_consumer_mutex
);
221 if (loc_consumer_sess
== NULL
)
224 return async_exchange_begin(loc_consumer_sess
);
230 /** Finish an async exchange on the loc session.
232 * @param exch Exchange to be finished.
235 void loc_exchange_end(async_exch_t
*exch
)
237 async_exchange_end(exch
);
240 /** Register new driver with loc. */
241 int loc_server_register(const char *name
)
243 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER
);
246 aid_t req
= async_send_2(exch
, LOC_SERVER_REGISTER
, 0, 0, &answer
);
247 sysarg_t retval
= async_data_write_start(exch
, name
, str_size(name
));
251 loc_exchange_end(exch
);
255 async_connect_to_me(exch
, 0, 0, 0);
258 * First wait for the answer and then end the exchange. The opposite
259 * order is generally wrong because it may lead to a deadlock under
260 * certain circumstances.
262 async_wait_for(req
, &retval
);
263 loc_exchange_end(exch
);
268 /** Register new service.
270 * @param fqsn Fully qualified service name
271 * @param[out] sid Service ID of new service
274 int loc_service_register(const char *fqsn
, service_id_t
*sid
)
276 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER
);
279 aid_t req
= async_send_0(exch
, LOC_SERVICE_REGISTER
, &answer
);
280 sysarg_t retval
= async_data_write_start(exch
, fqsn
, str_size(fqsn
));
284 loc_exchange_end(exch
);
289 * First wait for the answer and then end the exchange. The opposite
290 * order is generally wrong because it may lead to a deadlock under
291 * certain circumstances.
293 async_wait_for(req
, &retval
);
294 loc_exchange_end(exch
);
304 *sid
= (service_id_t
) IPC_GET_ARG1(answer
);
309 /** Unregister service.
311 * @param sid Service ID
313 int loc_service_unregister(service_id_t sid
)
318 exch
= loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER
);
319 retval
= async_req_1_0(exch
, LOC_SERVICE_UNREGISTER
, sid
);
320 loc_exchange_end(exch
);
325 int loc_service_get_id(const char *fqdn
, service_id_t
*handle
,
330 if (flags
& IPC_FLAG_BLOCKING
)
331 exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
333 exch
= loc_exchange_begin(INTERFACE_LOC_CONSUMER
);
339 aid_t req
= async_send_2(exch
, LOC_SERVICE_GET_ID
, flags
, 0,
341 sysarg_t retval
= async_data_write_start(exch
, fqdn
, str_size(fqdn
));
343 loc_exchange_end(exch
);
350 async_wait_for(req
, &retval
);
354 *handle
= (service_id_t
) -1;
360 *handle
= (service_id_t
) IPC_GET_ARG1(answer
);
367 * Provided ID of an object, return its name.
369 * @param method IPC method
370 * @param id Object ID
371 * @param name Place to store pointer to new string. Caller should
372 * free it using free().
373 * @return EOK on success or negative error code
375 static int loc_get_name_internal(sysarg_t method
, sysarg_t id
, char **name
)
378 char name_buf
[LOC_NAME_MAXLEN
+ 1];
384 exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
387 aid_t req
= async_send_1(exch
, method
, id
, &answer
);
388 aid_t dreq
= async_data_read(exch
, name_buf
, LOC_NAME_MAXLEN
,
390 async_wait_for(dreq
, &dretval
);
392 loc_exchange_end(exch
);
394 if (dretval
!= EOK
) {
400 async_wait_for(req
, &retval
);
405 act_size
= IPC_GET_ARG2(dreply
);
406 assert(act_size
<= LOC_NAME_MAXLEN
);
407 name_buf
[act_size
] = '\0';
409 *name
= str_dup(name_buf
);
416 /** Get category name.
418 * Provided ID of a service, return its name.
420 * @param cat_id Category ID
421 * @param name Place to store pointer to new string. Caller should
422 * free it using free().
423 * @return EOK on success or negative error code
425 int loc_category_get_name(category_id_t cat_id
, char **name
)
427 return loc_get_name_internal(LOC_CATEGORY_GET_NAME
, cat_id
, name
);
430 /** Get service name.
432 * Provided ID of a service, return its name.
434 * @param svc_id Service ID
435 * @param name Place to store pointer to new string. Caller should
436 * free it using free().
437 * @return EOK on success or negative error code
439 int loc_service_get_name(service_id_t svc_id
, char **name
)
441 return loc_get_name_internal(LOC_SERVICE_GET_NAME
, svc_id
, name
);
444 /** Get service server name.
446 * Provided ID of a service, return the name of its server.
448 * @param svc_id Service ID
449 * @param name Place to store pointer to new string. Caller should
450 * free it using free().
451 * @return EOK on success or negative error code
453 int loc_service_get_server_name(service_id_t svc_id
, char **name
)
455 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME
, svc_id
, name
);
458 int loc_namespace_get_id(const char *name
, service_id_t
*handle
,
463 if (flags
& IPC_FLAG_BLOCKING
)
464 exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
466 exch
= loc_exchange_begin(INTERFACE_LOC_CONSUMER
);
472 aid_t req
= async_send_2(exch
, LOC_NAMESPACE_GET_ID
, flags
, 0,
474 sysarg_t retval
= async_data_write_start(exch
, name
, str_size(name
));
476 loc_exchange_end(exch
);
483 async_wait_for(req
, &retval
);
487 *handle
= (service_id_t
) -1;
493 *handle
= (service_id_t
) IPC_GET_ARG1(answer
);
500 * Provided name of a category, return its ID.
502 * @param name Category name
503 * @param cat_id Place to store ID
504 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
505 * @return EOK on success or negative error code
507 int loc_category_get_id(const char *name
, category_id_t
*cat_id
,
512 if (flags
& IPC_FLAG_BLOCKING
)
513 exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
515 exch
= loc_exchange_begin(INTERFACE_LOC_CONSUMER
);
521 aid_t req
= async_send_0(exch
, LOC_CATEGORY_GET_ID
,
523 sysarg_t retval
= async_data_write_start(exch
, name
, str_size(name
));
525 loc_exchange_end(exch
);
532 async_wait_for(req
, &retval
);
536 *cat_id
= (category_id_t
) -1;
542 *cat_id
= (category_id_t
) IPC_GET_ARG1(answer
);
548 loc_object_type_t
loc_id_probe(service_id_t handle
)
550 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
553 int retval
= async_req_1_1(exch
, LOC_ID_PROBE
, handle
, &type
);
555 loc_exchange_end(exch
);
558 return LOC_OBJECT_NONE
;
560 return (loc_object_type_t
) type
;
563 async_sess_t
*loc_service_connect(service_id_t handle
, iface_t iface
,
568 if (flags
& IPC_FLAG_BLOCKING
)
569 sess
= service_connect_blocking(SERVICE_LOC
, iface
, handle
);
571 sess
= service_connect(SERVICE_LOC
, iface
, handle
);
576 int loc_null_create(void)
578 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
581 int retval
= async_req_0_1(exch
, LOC_NULL_CREATE
, &null_id
);
583 loc_exchange_end(exch
);
588 return (int) null_id
;
591 void loc_null_destroy(int null_id
)
593 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
594 async_req_1_0(exch
, LOC_NULL_DESTROY
, (sysarg_t
) null_id
);
595 loc_exchange_end(exch
);
598 static size_t loc_count_namespaces_internal(async_exch_t
*exch
)
601 int retval
= async_req_0_1(exch
, LOC_GET_NAMESPACE_COUNT
, &count
);
608 /** Add service to category.
610 * @param svc_id Service ID
611 * @param cat_id Category ID
612 * @return EOK on success or negative error code
614 int loc_service_add_to_cat(service_id_t svc_id
, service_id_t cat_id
)
619 exch
= loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER
);
620 retval
= async_req_2_0(exch
, LOC_SERVICE_ADD_TO_CAT
, svc_id
, cat_id
);
621 loc_exchange_end(exch
);
626 static size_t loc_count_services_internal(async_exch_t
*exch
,
627 service_id_t ns_handle
)
630 int retval
= async_req_1_1(exch
, LOC_GET_SERVICE_COUNT
, ns_handle
,
638 size_t loc_count_namespaces(void)
640 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
641 size_t size
= loc_count_namespaces_internal(exch
);
642 loc_exchange_end(exch
);
647 size_t loc_count_services(service_id_t ns_handle
)
649 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
650 size_t size
= loc_count_services_internal(exch
, ns_handle
);
651 loc_exchange_end(exch
);
656 size_t loc_get_namespaces(loc_sdesc_t
**data
)
658 /* Loop until read is succesful */
660 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
661 size_t count
= loc_count_namespaces_internal(exch
);
662 loc_exchange_end(exch
);
667 loc_sdesc_t
*devs
= (loc_sdesc_t
*) calloc(count
, sizeof(loc_sdesc_t
));
671 exch
= loc_exchange_begin(INTERFACE_LOC_CONSUMER
);
674 aid_t req
= async_send_0(exch
, LOC_GET_NAMESPACES
, &answer
);
675 int rc
= async_data_read_start(exch
, devs
, count
* sizeof(loc_sdesc_t
));
677 loc_exchange_end(exch
);
679 if (rc
== EOVERFLOW
) {
681 * Number of namespaces has changed since
682 * the last call of LOC_GET_NAMESPACE_COUNT
695 async_wait_for(req
, &retval
);
705 size_t loc_get_services(service_id_t ns_handle
, loc_sdesc_t
**data
)
707 /* Loop until read is succesful */
709 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
710 size_t count
= loc_count_services_internal(exch
, ns_handle
);
711 loc_exchange_end(exch
);
716 loc_sdesc_t
*devs
= (loc_sdesc_t
*) calloc(count
, sizeof(loc_sdesc_t
));
720 exch
= loc_exchange_begin(INTERFACE_LOC_CONSUMER
);
723 aid_t req
= async_send_1(exch
, LOC_GET_SERVICES
, ns_handle
, &answer
);
724 int rc
= async_data_read_start(exch
, devs
, count
* sizeof(loc_sdesc_t
));
726 loc_exchange_end(exch
);
728 if (rc
== EOVERFLOW
) {
730 * Number of services has changed since
731 * the last call of LOC_GET_SERVICE_COUNT
744 async_wait_for(req
, &retval
);
754 static int loc_category_get_ids_once(sysarg_t method
, sysarg_t arg1
,
755 sysarg_t
*id_buf
, size_t buf_size
, size_t *act_size
)
757 async_exch_t
*exch
= loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER
);
760 aid_t req
= async_send_1(exch
, method
, arg1
, &answer
);
761 int rc
= async_data_read_start(exch
, id_buf
, buf_size
);
763 loc_exchange_end(exch
);
771 async_wait_for(req
, &retval
);
777 *act_size
= IPC_GET_ARG1(answer
);
783 * Returns an allocated array of service IDs.
785 * @param method IPC method
786 * @param arg1 IPC argument 1
787 * @param data Place to store pointer to array of IDs
788 * @param count Place to store number of IDs
789 * @return EOK on success or negative error code
791 static int loc_get_ids_internal(sysarg_t method
, sysarg_t arg1
,
792 sysarg_t
**data
, size_t *count
)
798 int rc
= loc_category_get_ids_once(method
, arg1
, NULL
, 0,
803 size_t alloc_size
= act_size
;
804 service_id_t
*ids
= malloc(alloc_size
);
809 rc
= loc_category_get_ids_once(method
, arg1
, ids
, alloc_size
,
814 if (act_size
<= alloc_size
)
817 alloc_size
= act_size
;
818 ids
= realloc(ids
, alloc_size
);
823 *count
= act_size
/ sizeof(category_id_t
);
828 /** Get list of services in category.
830 * Returns an allocated array of service IDs.
832 * @param cat_id Category ID
833 * @param data Place to store pointer to array of IDs
834 * @param count Place to store number of IDs
835 * @return EOK on success or negative error code
837 int loc_category_get_svcs(category_id_t cat_id
, service_id_t
**data
,
840 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS
, cat_id
,
844 /** Get list of categories.
846 * Returns an allocated array of category IDs.
848 * @param data Place to store pointer to array of IDs
849 * @param count Place to store number of IDs
850 * @return EOK on success or negative error code
852 int loc_get_categories(category_id_t
**data
, size_t *count
)
854 return loc_get_ids_internal(LOC_GET_CATEGORIES
, 0,
858 int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun
)
860 fibril_mutex_lock(&loc_callback_mutex
);
861 if (loc_callback_create() != EOK
) {
862 fibril_mutex_unlock(&loc_callback_mutex
);
866 cat_change_cb
= cb_fun
;
867 fibril_mutex_unlock(&loc_callback_mutex
);