Rev 4345 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4345 | Rev 4348 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2006 Ondrej Palkovsky |
2 | * Copyright (c) 2006 Ondrej Palkovsky |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
13 | * documentation and/or other materials provided with the distribution. |
14 | * - The name of the author may not be used to endorse or promote products |
14 | * - The name of the author may not be used to endorse or promote products |
15 | * derived from this software without specific prior written permission. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup ns |
29 | /** @addtogroup ns |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | 32 | ||
33 | /** |
33 | /** |
34 | * @file ns.c |
34 | * @file ns.c |
35 | * @brief Naming service for HelenOS IPC. |
35 | * @brief Naming service for HelenOS IPC. |
36 | */ |
36 | */ |
37 | 37 | ||
38 | 38 | ||
39 | #include <ipc/ipc.h> |
39 | #include <ipc/ipc.h> |
40 | #include <ipc/ns.h> |
40 | #include <ipc/ns.h> |
41 | #include <ipc/services.h> |
41 | #include <ipc/services.h> |
42 | #include <stdio.h> |
42 | #include <stdio.h> |
43 | #include <bool.h> |
43 | #include <bool.h> |
44 | #include <unistd.h> |
44 | #include <unistd.h> |
45 | #include <stdlib.h> |
45 | #include <stdlib.h> |
46 | #include <errno.h> |
46 | #include <errno.h> |
47 | #include <assert.h> |
47 | #include <assert.h> |
48 | #include <libadt/list.h> |
48 | #include <libadt/list.h> |
49 | #include <libadt/hash_table.h> |
49 | #include <libadt/hash_table.h> |
50 | #include <sysinfo.h> |
50 | #include <sysinfo.h> |
51 | #include <loader/loader.h> |
51 | #include <loader/loader.h> |
52 | #include <ddi.h> |
52 | #include <ddi.h> |
53 | #include <as.h> |
53 | #include <as.h> |
54 | 54 | ||
55 | #define NAME "ns" |
55 | #define NAME "ns" |
56 | 56 | ||
57 | #define NS_HASH_TABLE_CHAINS 20 |
57 | #define NS_HASH_TABLE_CHAINS 20 |
58 | 58 | ||
59 | static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call); |
59 | static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call); |
60 | static void connect_to_service(ipcarg_t service, ipc_call_t *call, |
60 | static void connect_to_service(ipcarg_t service, ipc_call_t *call, |
61 | ipc_callid_t callid); |
61 | ipc_callid_t callid); |
62 | 62 | ||
63 | void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
63 | void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
64 | ipc_callid_t callid); |
64 | ipc_callid_t callid); |
65 | void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
65 | void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
66 | ipc_callid_t callid); |
66 | ipc_callid_t callid); |
67 | 67 | ||
68 | 68 | ||
69 | /* Static functions implementing NS hash table operations. */ |
69 | /* Static functions implementing NS hash table operations. */ |
70 | static hash_index_t ns_hash(unsigned long *key); |
70 | static hash_index_t ns_hash(unsigned long *key); |
71 | static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item); |
71 | static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item); |
72 | static void ns_remove(link_t *item); |
72 | static void ns_remove(link_t *item); |
73 | 73 | ||
74 | /** Operations for NS hash table. */ |
74 | /** Operations for NS hash table. */ |
75 | static hash_table_operations_t ns_hash_table_ops = { |
75 | static hash_table_operations_t ns_hash_table_ops = { |
76 | .hash = ns_hash, |
76 | .hash = ns_hash, |
77 | .compare = ns_compare, |
77 | .compare = ns_compare, |
78 | .remove_callback = ns_remove |
78 | .remove_callback = ns_remove |
79 | }; |
79 | }; |
80 | 80 | ||
81 | /** NS hash table structure. */ |
81 | /** NS hash table structure. */ |
82 | static hash_table_t ns_hash_table; |
82 | static hash_table_t ns_hash_table; |
83 | 83 | ||
84 | /** NS hash table item. */ |
84 | /** NS hash table item. */ |
85 | typedef struct { |
85 | typedef struct { |
86 | link_t link; |
86 | link_t link; |
87 | ipcarg_t service; /**< Number of the service. */ |
87 | ipcarg_t service; /**< Number of the service. */ |
88 | ipcarg_t phone; /**< Phone registered with the service. */ |
88 | ipcarg_t phone; /**< Phone registered with the service. */ |
89 | ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
89 | ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
90 | } hashed_service_t; |
90 | } hashed_service_t; |
91 | 91 | ||
92 | /** Pending connection structure. */ |
92 | /** Pending connection structure. */ |
93 | typedef struct { |
93 | typedef struct { |
94 | link_t link; |
94 | link_t link; |
95 | ipcarg_t service; /**< Number of the service. */ |
95 | ipcarg_t service; /**< Number of the service. */ |
96 | ipc_callid_t callid; /**< Call ID waiting for the connection */ |
96 | ipc_callid_t callid; /**< Call ID waiting for the connection */ |
97 | ipcarg_t arg2; /**< Second argument */ |
97 | ipcarg_t arg2; /**< Second argument */ |
98 | ipcarg_t arg3; /**< Third argument */ |
98 | ipcarg_t arg3; /**< Third argument */ |
99 | } pending_req_t; |
99 | } pending_req_t; |
100 | 100 | ||
101 | static link_t pending_req; |
101 | static link_t pending_req; |
102 | 102 | ||
103 | /** Request for connection to a clonable service. */ |
103 | /** Request for connection to a clonable service. */ |
104 | typedef struct { |
104 | typedef struct { |
105 | link_t link; |
105 | link_t link; |
106 | ipcarg_t service; |
106 | ipcarg_t service; |
107 | ipc_call_t call; |
107 | ipc_call_t call; |
108 | ipc_callid_t callid; |
108 | ipc_callid_t callid; |
109 | } cs_req_t; |
109 | } cs_req_t; |
110 | 110 | ||
111 | /** List of clonable-service connection requests. */ |
111 | /** List of clonable-service connection requests. */ |
112 | static link_t cs_req; |
112 | static link_t cs_req; |
113 | 113 | ||
114 | static void *clockaddr = NULL; |
114 | static void *clockaddr = NULL; |
115 | static void *klogaddr = NULL; |
115 | static void *klogaddr = NULL; |
116 | 116 | ||
117 | /** Return true if @a service is clonable. */ |
117 | /** Return true if @a service is clonable. */ |
118 | static bool service_clonable(int service) |
118 | static bool service_clonable(int service) |
119 | { |
119 | { |
120 | return (service == SERVICE_LOAD); |
120 | return (service == SERVICE_LOAD); |
121 | } |
121 | } |
122 | 122 | ||
123 | static void get_as_area(ipc_callid_t callid, ipc_call_t *call, char *name, void **addr) |
123 | static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, count_t pages, void **addr) |
124 | { |
124 | { |
125 | void *ph_addr; |
125 | if (ph_addr == NULL) { |
- | 126 | ipc_answer_0(callid, ENOENT); |
|
- | 127 | return; |
|
- | 128 | } |
|
126 | 129 | ||
127 | if (!*addr) { |
130 | if (*addr == NULL) { |
128 | ph_addr = (void *) sysinfo_value(name); |
131 | *addr = as_get_mappable_page(pages * PAGE_SIZE); |
- | 132 | ||
129 | if (!ph_addr) { |
133 | if (*addr == NULL) { |
130 | ipc_answer_0(callid, ENOENT); |
134 | ipc_answer_0(callid, ENOENT); |
131 | return; |
135 | return; |
132 | } |
136 | } |
133 | *addr = as_get_mappable_page(PAGE_SIZE); |
- | |
- | 137 | ||
134 | if (physmem_map(ph_addr, *addr, 1, |
138 | if (physmem_map(ph_addr, *addr, pages, |
135 | AS_AREA_READ | AS_AREA_CACHEABLE) != 0) { |
139 | AS_AREA_READ | AS_AREA_CACHEABLE) != 0) { |
136 | ipc_answer_0(callid, ENOENT); |
140 | ipc_answer_0(callid, ENOENT); |
137 | return; |
141 | return; |
138 | } |
142 | } |
139 | } |
143 | } |
- | 144 | ||
140 | ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ); |
145 | ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ); |
141 | } |
146 | } |
142 | 147 | ||
143 | /** Process pending connection requests */ |
148 | /** Process pending connection requests */ |
144 | static void process_pending_req() |
149 | static void process_pending_req() |
145 | { |
150 | { |
146 | link_t *cur; |
151 | link_t *cur; |
147 | 152 | ||
148 | loop: |
153 | loop: |
149 | for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
154 | for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
150 | pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
155 | pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
151 | 156 | ||
152 | unsigned long keys[3] = { |
157 | unsigned long keys[3] = { |
153 | pr->service, |
158 | pr->service, |
154 | 0, |
159 | 0, |
155 | 0 |
160 | 0 |
156 | }; |
161 | }; |
157 | 162 | ||
158 | link_t *link = hash_table_find(&ns_hash_table, keys); |
163 | link_t *link = hash_table_find(&ns_hash_table, keys); |
159 | if (!link) |
164 | if (!link) |
160 | continue; |
165 | continue; |
161 | 166 | ||
162 | hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
167 | hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
163 | ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone, |
168 | ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone, |
164 | pr->arg2, pr->arg3, 0, IPC_FF_NONE); |
169 | pr->arg2, pr->arg3, 0, IPC_FF_NONE); |
165 | 170 | ||
166 | if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
171 | if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
167 | ipc_answer_0(pr->callid, retval); |
172 | ipc_answer_0(pr->callid, retval); |
168 | 173 | ||
169 | list_remove(cur); |
174 | list_remove(cur); |
170 | free(pr); |
175 | free(pr); |
171 | goto loop; |
176 | goto loop; |
172 | } |
177 | } |
173 | } |
178 | } |
174 | 179 | ||
175 | int main(int argc, char **argv) |
180 | int main(int argc, char **argv) |
176 | { |
181 | { |
177 | printf(NAME ": HelenOS IPC Naming Service\n"); |
182 | printf(NAME ": HelenOS IPC Naming Service\n"); |
178 | 183 | ||
179 | if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3, |
184 | if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3, |
180 | &ns_hash_table_ops)) { |
185 | &ns_hash_table_ops)) { |
181 | printf(NAME ": No memory available for services\n"); |
186 | printf(NAME ": No memory available for services\n"); |
182 | return ENOMEM; |
187 | return ENOMEM; |
183 | } |
188 | } |
184 | 189 | ||
185 | list_initialize(&pending_req); |
190 | list_initialize(&pending_req); |
186 | list_initialize(&cs_req); |
191 | list_initialize(&cs_req); |
187 | 192 | ||
188 | printf(NAME ": Accepting connections\n"); |
193 | printf(NAME ": Accepting connections\n"); |
189 | while (true) { |
194 | while (true) { |
190 | process_pending_req(); |
195 | process_pending_req(); |
191 | 196 | ||
192 | ipc_call_t call; |
197 | ipc_call_t call; |
193 | ipc_callid_t callid = ipc_wait_for_call(&call); |
198 | ipc_callid_t callid = ipc_wait_for_call(&call); |
194 | ipcarg_t retval; |
199 | ipcarg_t retval; |
195 | 200 | ||
196 | switch (IPC_GET_METHOD(call)) { |
201 | switch (IPC_GET_METHOD(call)) { |
197 | case IPC_M_SHARE_IN: |
202 | case IPC_M_SHARE_IN: |
198 | switch (IPC_GET_ARG3(call)) { |
203 | switch (IPC_GET_ARG3(call)) { |
199 | case SERVICE_MEM_REALTIME: |
204 | case SERVICE_MEM_REALTIME: |
200 | get_as_area(callid, &call, "clock.faddr", &clockaddr); |
205 | get_as_area(callid, &call, sysinfo_value("clock.faddr"), 1, &clockaddr); |
201 | break; |
206 | break; |
202 | case SERVICE_MEM_KLOG: |
207 | case SERVICE_MEM_KLOG: |
203 | get_as_area(callid, &call, "klog.faddr", &klogaddr); |
208 | get_as_area(callid, &call, sysinfo_value("klog.faddr"), sysinfo_value("klog.pages"), &klogaddr); |
204 | break; |
209 | break; |
205 | default: |
210 | default: |
206 | ipc_answer_0(callid, ENOENT); |
211 | ipc_answer_0(callid, ENOENT); |
207 | } |
212 | } |
208 | continue; |
213 | continue; |
209 | case IPC_M_PHONE_HUNGUP: |
214 | case IPC_M_PHONE_HUNGUP: |
210 | retval = EOK; |
215 | retval = EOK; |
211 | break; |
216 | break; |
212 | case IPC_M_CONNECT_TO_ME: |
217 | case IPC_M_CONNECT_TO_ME: |
213 | /* |
218 | /* |
214 | * Server requests service registration. |
219 | * Server requests service registration. |
215 | */ |
220 | */ |
216 | if (service_clonable(IPC_GET_ARG1(call))) { |
221 | if (service_clonable(IPC_GET_ARG1(call))) { |
217 | register_clonable(IPC_GET_ARG1(call), |
222 | register_clonable(IPC_GET_ARG1(call), |
218 | IPC_GET_ARG5(call), &call, callid); |
223 | IPC_GET_ARG5(call), &call, callid); |
219 | continue; |
224 | continue; |
220 | } else { |
225 | } else { |
221 | retval = register_service(IPC_GET_ARG1(call), |
226 | retval = register_service(IPC_GET_ARG1(call), |
222 | IPC_GET_ARG5(call), &call); |
227 | IPC_GET_ARG5(call), &call); |
223 | } |
228 | } |
224 | break; |
229 | break; |
225 | case IPC_M_CONNECT_ME_TO: |
230 | case IPC_M_CONNECT_ME_TO: |
226 | /* |
231 | /* |
227 | * Client requests to be connected to a service. |
232 | * Client requests to be connected to a service. |
228 | */ |
233 | */ |
229 | if (service_clonable(IPC_GET_ARG1(call))) { |
234 | if (service_clonable(IPC_GET_ARG1(call))) { |
230 | connect_to_clonable(IPC_GET_ARG1(call), |
235 | connect_to_clonable(IPC_GET_ARG1(call), |
231 | &call, callid); |
236 | &call, callid); |
232 | continue; |
237 | continue; |
233 | } else { |
238 | } else { |
234 | connect_to_service(IPC_GET_ARG1(call), &call, |
239 | connect_to_service(IPC_GET_ARG1(call), &call, |
235 | callid); |
240 | callid); |
236 | continue; |
241 | continue; |
237 | } |
242 | } |
238 | break; |
243 | break; |
239 | default: |
244 | default: |
240 | retval = ENOENT; |
245 | retval = ENOENT; |
241 | break; |
246 | break; |
242 | } |
247 | } |
243 | 248 | ||
244 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
249 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
245 | ipc_answer_0(callid, retval); |
250 | ipc_answer_0(callid, retval); |
246 | } |
251 | } |
247 | 252 | ||
248 | /* Not reached */ |
253 | /* Not reached */ |
249 | return 0; |
254 | return 0; |
250 | } |
255 | } |
251 | 256 | ||
252 | /** Register service. |
257 | /** Register service. |
253 | * |
258 | * |
254 | * @param service Service to be registered. |
259 | * @param service Service to be registered. |
255 | * @param phone Phone to be used for connections to the service. |
260 | * @param phone Phone to be used for connections to the service. |
256 | * @param call Pointer to call structure. |
261 | * @param call Pointer to call structure. |
257 | * |
262 | * |
258 | * @return Zero on success or a value from @ref errno.h. |
263 | * @return Zero on success or a value from @ref errno.h. |
259 | * |
264 | * |
260 | */ |
265 | */ |
261 | int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call) |
266 | int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call) |
262 | { |
267 | { |
263 | unsigned long keys[3] = { |
268 | unsigned long keys[3] = { |
264 | service, |
269 | service, |
265 | call->in_phone_hash, |
270 | call->in_phone_hash, |
266 | 0 |
271 | 0 |
267 | }; |
272 | }; |
268 | 273 | ||
269 | if (hash_table_find(&ns_hash_table, keys)) |
274 | if (hash_table_find(&ns_hash_table, keys)) |
270 | return EEXISTS; |
275 | return EEXISTS; |
271 | 276 | ||
272 | hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t)); |
277 | hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t)); |
273 | if (!hs) |
278 | if (!hs) |
274 | return ENOMEM; |
279 | return ENOMEM; |
275 | 280 | ||
276 | link_initialize(&hs->link); |
281 | link_initialize(&hs->link); |
277 | hs->service = service; |
282 | hs->service = service; |
278 | hs->phone = phone; |
283 | hs->phone = phone; |
279 | hs->in_phone_hash = call->in_phone_hash; |
284 | hs->in_phone_hash = call->in_phone_hash; |
280 | hash_table_insert(&ns_hash_table, keys, &hs->link); |
285 | hash_table_insert(&ns_hash_table, keys, &hs->link); |
281 | 286 | ||
282 | return 0; |
287 | return 0; |
283 | } |
288 | } |
284 | 289 | ||
285 | /** Connect client to service. |
290 | /** Connect client to service. |
286 | * |
291 | * |
287 | * @param service Service to be connected to. |
292 | * @param service Service to be connected to. |
288 | * @param call Pointer to call structure. |
293 | * @param call Pointer to call structure. |
289 | * @param callid Call ID of the request. |
294 | * @param callid Call ID of the request. |
290 | * |
295 | * |
291 | * @return Zero on success or a value from @ref errno.h. |
296 | * @return Zero on success or a value from @ref errno.h. |
292 | * |
297 | * |
293 | */ |
298 | */ |
294 | void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid) |
299 | void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid) |
295 | { |
300 | { |
296 | ipcarg_t retval; |
301 | ipcarg_t retval; |
297 | unsigned long keys[3] = { |
302 | unsigned long keys[3] = { |
298 | service, |
303 | service, |
299 | 0, |
304 | 0, |
300 | 0 |
305 | 0 |
301 | }; |
306 | }; |
302 | 307 | ||
303 | link_t *link = hash_table_find(&ns_hash_table, keys); |
308 | link_t *link = hash_table_find(&ns_hash_table, keys); |
304 | if (!link) { |
309 | if (!link) { |
305 | if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) { |
310 | if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) { |
306 | /* Blocking connection, add to pending list */ |
311 | /* Blocking connection, add to pending list */ |
307 | pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t)); |
312 | pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t)); |
308 | if (!pr) { |
313 | if (!pr) { |
309 | retval = ENOMEM; |
314 | retval = ENOMEM; |
310 | goto out; |
315 | goto out; |
311 | } |
316 | } |
312 | 317 | ||
313 | pr->service = service; |
318 | pr->service = service; |
314 | pr->callid = callid; |
319 | pr->callid = callid; |
315 | pr->arg2 = IPC_GET_ARG2(*call); |
320 | pr->arg2 = IPC_GET_ARG2(*call); |
316 | pr->arg3 = IPC_GET_ARG3(*call); |
321 | pr->arg3 = IPC_GET_ARG3(*call); |
317 | list_append(&pr->link, &pending_req); |
322 | list_append(&pr->link, &pending_req); |
318 | return; |
323 | return; |
319 | } |
324 | } |
320 | retval = ENOENT; |
325 | retval = ENOENT; |
321 | goto out; |
326 | goto out; |
322 | } |
327 | } |
323 | 328 | ||
324 | hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
329 | hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
325 | retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call), |
330 | retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call), |
326 | IPC_GET_ARG3(*call), 0, IPC_FF_NONE); |
331 | IPC_GET_ARG3(*call), 0, IPC_FF_NONE); |
327 | - | ||
328 | out: |
332 | out: |
329 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
333 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
330 | ipc_answer_0(callid, retval); |
334 | ipc_answer_0(callid, retval); |
331 | } |
335 | } |
332 | 336 | ||
333 | /** Register clonable service. |
337 | /** Register clonable service. |
334 | * |
338 | * |
335 | * @param service Service to be registered. |
339 | * @param service Service to be registered. |
336 | * @param phone Phone to be used for connections to the service. |
340 | * @param phone Phone to be used for connections to the service. |
337 | * @param call Pointer to call structure. |
341 | * @param call Pointer to call structure. |
338 | * |
342 | * |
339 | */ |
343 | */ |
340 | void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
344 | void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
341 | ipc_callid_t callid) |
345 | ipc_callid_t callid) |
342 | { |
346 | { |
343 | if (list_empty(&cs_req)) { |
347 | if (list_empty(&cs_req)) { |
344 | /* There was no pending connection request. */ |
348 | /* There was no pending connection request. */ |
345 | printf(NAME ": Unexpected clonable server.\n"); |
349 | printf(NAME ": Unexpected clonable server.\n"); |
346 | ipc_answer_0(callid, EBUSY); |
350 | ipc_answer_0(callid, EBUSY); |
347 | return; |
351 | return; |
348 | } |
352 | } |
349 | 353 | ||
350 | cs_req_t *csr = list_get_instance(cs_req.next, cs_req_t, link); |
354 | cs_req_t *csr = list_get_instance(cs_req.next, cs_req_t, link); |
351 | list_remove(&csr->link); |
355 | list_remove(&csr->link); |
352 | 356 | ||
353 | /* Currently we can only handle a single type of clonable service. */ |
357 | /* Currently we can only handle a single type of clonable service. */ |
354 | assert(csr->service == SERVICE_LOAD); |
358 | assert(csr->service == SERVICE_LOAD); |
355 | 359 | ||
356 | ipc_answer_0(callid, EOK); |
360 | ipc_answer_0(callid, EOK); |
357 | 361 | ||
358 | int rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call), |
362 | int rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call), |
359 | IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE); |
363 | IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE); |
360 | 364 | ||
361 | free(csr); |
365 | free(csr); |
- | 366 | ipc_hangup(phone); |
|
362 | } |
367 | } |
363 | 368 | ||
364 | /** Connect client to clonable service. |
369 | /** Connect client to clonable service. |
365 | * |
370 | * |
366 | * @param service Service to be connected to. |
371 | * @param service Service to be connected to. |
367 | * @param call Pointer to call structure. |
372 | * @param call Pointer to call structure. |
368 | * @param callid Call ID of the request. |
373 | * @param callid Call ID of the request. |
369 | * |
374 | * |
370 | * @return Zero on success or a value from @ref errno.h. |
375 | * @return Zero on success or a value from @ref errno.h. |
371 | * |
376 | * |
372 | */ |
377 | */ |
373 | void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
378 | void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
374 | ipc_callid_t callid) |
379 | ipc_callid_t callid) |
375 | { |
380 | { |
376 | assert(service == SERVICE_LOAD); |
381 | assert(service == SERVICE_LOAD); |
377 | 382 | ||
378 | cs_req_t *csr = malloc(sizeof(cs_req_t)); |
383 | cs_req_t *csr = malloc(sizeof(cs_req_t)); |
379 | if (csr == NULL) { |
384 | if (csr == NULL) { |
380 | ipc_answer_0(callid, ENOMEM); |
385 | ipc_answer_0(callid, ENOMEM); |
381 | return; |
386 | return; |
382 | } |
387 | } |
383 | 388 | ||
384 | /* Spawn a loader. */ |
389 | /* Spawn a loader. */ |
385 | int rc = loader_spawn("loader"); |
390 | int rc = loader_spawn("loader"); |
386 | 391 | ||
387 | if (rc < 0) { |
392 | if (rc < 0) { |
388 | free(csr); |
393 | free(csr); |
389 | ipc_answer_0(callid, rc); |
394 | ipc_answer_0(callid, rc); |
390 | return; |
395 | return; |
391 | } |
396 | } |
392 | 397 | ||
393 | csr->service = service; |
398 | csr->service = service; |
394 | csr->call = *call; |
399 | csr->call = *call; |
395 | csr->callid = callid; |
400 | csr->callid = callid; |
396 | 401 | ||
397 | /* |
402 | /* |
398 | * We can forward the call only after the server we spawned connects |
403 | * We can forward the call only after the server we spawned connects |
399 | * to us. Meanwhile we might need to service more connection requests. |
404 | * to us. Meanwhile we might need to service more connection requests. |
400 | * Thus we store the call in a queue. |
405 | * Thus we store the call in a queue. |
401 | */ |
406 | */ |
402 | list_append(&csr->link, &cs_req); |
407 | list_append(&csr->link, &cs_req); |
403 | } |
408 | } |
404 | 409 | ||
405 | /** Compute hash index into NS hash table. |
410 | /** Compute hash index into NS hash table. |
406 | * |
411 | * |
407 | * @param key Pointer keys. However, only the first key (i.e. service number) |
412 | * @param key Pointer keys. However, only the first key (i.e. service number) |
408 | * is used to compute the hash index. |
413 | * is used to compute the hash index. |
409 | * |
414 | * |
410 | * @return Hash index corresponding to key[0]. |
415 | * @return Hash index corresponding to key[0]. |
411 | * |
416 | * |
412 | */ |
417 | */ |
413 | hash_index_t ns_hash(unsigned long *key) |
418 | hash_index_t ns_hash(unsigned long *key) |
414 | { |
419 | { |
415 | assert(key); |
420 | assert(key); |
416 | return (*key % NS_HASH_TABLE_CHAINS); |
421 | return (*key % NS_HASH_TABLE_CHAINS); |
417 | } |
422 | } |
418 | 423 | ||
419 | /** Compare a key with hashed item. |
424 | /** Compare a key with hashed item. |
420 | * |
425 | * |
421 | * This compare function always ignores the third key. |
426 | * This compare function always ignores the third key. |
422 | * It exists only to make it possible to remove records |
427 | * It exists only to make it possible to remove records |
423 | * originating from connection with key[1] in_phone_hash |
428 | * originating from connection with key[1] in_phone_hash |
424 | * value. Note that this is close to being classified |
429 | * value. Note that this is close to being classified |
425 | * as a nasty hack. |
430 | * as a nasty hack. |
426 | * |
431 | * |
427 | * @param key Array of keys. |
432 | * @param key Array of keys. |
428 | * @param keys Must be lesser or equal to 3. |
433 | * @param keys Must be lesser or equal to 3. |
429 | * @param item Pointer to a hash table item. |
434 | * @param item Pointer to a hash table item. |
430 | * |
435 | * |
431 | * @return Non-zero if the key matches the item, zero otherwise. |
436 | * @return Non-zero if the key matches the item, zero otherwise. |
432 | * |
437 | * |
433 | */ |
438 | */ |
434 | int ns_compare(unsigned long key[], hash_count_t keys, link_t *item) |
439 | int ns_compare(unsigned long key[], hash_count_t keys, link_t *item) |
435 | { |
440 | { |
436 | assert(key); |
441 | assert(key); |
437 | assert(keys <= 3); |
442 | assert(keys <= 3); |
438 | assert(item); |
443 | assert(item); |
439 | 444 | ||
440 | hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link); |
445 | hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link); |
441 | 446 | ||
442 | if (keys == 2) |
447 | if (keys == 2) |
443 | return key[1] == hs->in_phone_hash; |
448 | return key[1] == hs->in_phone_hash; |
444 | else |
449 | else |
445 | return key[0] == hs->service; |
450 | return key[0] == hs->service; |
446 | } |
451 | } |
447 | 452 | ||
448 | /** Perform actions after removal of item from the hash table. |
453 | /** Perform actions after removal of item from the hash table. |
449 | * |
454 | * |
450 | * @param item Item that was removed from the hash table. |
455 | * @param item Item that was removed from the hash table. |
451 | * |
456 | * |
452 | */ |
457 | */ |
453 | void ns_remove(link_t *item) |
458 | void ns_remove(link_t *item) |
454 | { |
459 | { |
455 | assert(item); |
460 | assert(item); |
456 | free(hash_table_get_instance(item, hashed_service_t, link)); |
461 | free(hash_table_get_instance(item, hashed_service_t, link)); |
457 | } |
462 | } |
458 | 463 | ||
459 | /** |
464 | /** |
460 | * @} |
465 | * @} |
461 | */ |
466 | */ |
462 | 467 |