1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #include <chcore/container/hashtable.h>
13 #include <string.h>
14 #include <assert.h>
15 #include <chcore/syscall.h>
16
17 #include <ipclib.h>
18
19 #include <chanmgr.h>
20
21 #define CHANMGR_DEFAULT_HTABLE_SIZE 1024
22 #define HASH_BASE 998244353
23
24 #define info(fmt, ...) \
25 printf("<%s:%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
26
27 /* check name empty at ipc entry */
__chan_name_empty(char * name)28 static inline bool __chan_name_empty(char *name)
29 {
30 /* to avoid overflow */
31 name[CHAN_REQ_NAME_LEN - 1] = 0;
32 return strlen(name) == 0;
33 }
34
__hash_name(const char * name)35 static uint32_t __hash_name(const char *name)
36 {
37 size_t i, len;
38 uint32_t hashsum = 0;
39
40 len = strlen(name);
41 for (i = 0; i < len; i++) {
42 hashsum = hashsum * HASH_BASE + (uint32_t)name[i];
43 }
44
45 return hashsum;
46 }
47
__hash_taskid(uint32_t taskid,int ch_num)48 static inline uint32_t __hash_taskid(uint32_t taskid, int ch_num)
49 {
50 return taskid * HASH_BASE + ch_num;
51 }
52
__ch_num_valid(int ch_num)53 static inline bool __ch_num_valid(int ch_num)
54 {
55 return ch_num == 0 || ch_num == 1;
56 }
57
58 struct channel_entry {
59 struct hlist_node name2chan_node;
60 struct hlist_node cid2chan_node;
61 struct hlist_node badge2chan_node;
62 badge_t badge;
63 char *name;
64 int cap;
65 uint32_t taskid;
66 int ch_num;
67 struct reg_items_st reg_items;
68 };
69
70 struct tamgr_entry {
71 struct hlist_node name2taskid_node;
72 struct hlist_node badge2tamgr_node;
73 badge_t badge;
74 char *name;
75 uint32_t taskid;
76 };
77
78 static struct chanmgr chanmgr;
79
channel_entry_init(struct channel_entry * entry)80 void channel_entry_init(struct channel_entry *entry)
81 {
82 init_hlist_node(&entry->name2chan_node);
83 init_hlist_node(&entry->cid2chan_node);
84 init_hlist_node(&entry->badge2chan_node);
85 entry->name = NULL;
86 entry->ch_num = -1;
87 entry->cap = -1;
88 entry->taskid = 0;
89 entry->badge = 0;
90 }
91
channel_entry_deinit(struct channel_entry * entry)92 void channel_entry_deinit(struct channel_entry *entry)
93 {
94 if (entry->name) {
95 free(entry->name);
96 }
97 }
98
chanmgr_init(void)99 int chanmgr_init(void)
100 {
101 int ret;
102
103 init_htable(&chanmgr.name2chan, CHANMGR_DEFAULT_HTABLE_SIZE);
104 init_htable(&chanmgr.cid2chan, CHANMGR_DEFAULT_HTABLE_SIZE);
105 init_htable(&chanmgr.badge2chan, CHANMGR_DEFAULT_HTABLE_SIZE);
106 init_htable(&chanmgr.name2taskid, CHANMGR_DEFAULT_HTABLE_SIZE);
107 init_htable(&chanmgr.badge2tamgr, CHANMGR_DEFAULT_HTABLE_SIZE);
108 ret = pthread_mutex_init(&chanmgr.lock, NULL);
109
110 return ret;
111 }
112
chanmgr_deinit(void)113 void chanmgr_deinit(void)
114 {
115 }
116
__get_entry_by_name(const char * name)117 static struct channel_entry *__get_entry_by_name(const char *name)
118 {
119 struct hlist_head *bucket;
120 struct channel_entry *entry;
121 uint32_t hashsum;
122
123 hashsum = __hash_name(name);
124 bucket = htable_get_bucket(&chanmgr.name2chan, hashsum);
125 for_each_in_hlist (entry, name2chan_node, bucket) {
126 if (entry->name != NULL && strcmp(name, entry->name) == 0) {
127 return entry;
128 }
129 }
130
131 return NULL;
132 }
133
__get_entry_by_cid(uint32_t taskid,int ch_num)134 static struct channel_entry *__get_entry_by_cid(uint32_t taskid, int ch_num)
135 {
136 struct hlist_head *bucket;
137 struct channel_entry *entry;
138 uint32_t hashsum;
139
140 if (!__ch_num_valid(ch_num)) {
141 return NULL;
142 }
143
144 hashsum = __hash_taskid(taskid, ch_num);
145 bucket = htable_get_bucket(&chanmgr.cid2chan, hashsum);
146 for_each_in_hlist (entry, cid2chan_node, bucket) {
147 if (entry->taskid == taskid && entry->ch_num == ch_num) {
148 return entry;
149 }
150 }
151
152 return NULL;
153 }
154
__get_tamgr_entry_by_name(const char * name)155 static struct tamgr_entry *__get_tamgr_entry_by_name(const char *name)
156 {
157 struct hlist_head *bucket;
158 struct tamgr_entry *entry;
159 uint32_t hashsum;
160
161 hashsum = __hash_name(name);
162 bucket = htable_get_bucket(&chanmgr.name2taskid, hashsum);
163 for_each_in_hlist (entry, name2taskid_node, bucket) {
164 if (strcmp(name, entry->name) == 0) {
165 return entry;
166 }
167 }
168
169 return NULL;
170 }
171
chanmgr_handle_create_channel(ipc_msg_t * ipc_msg,badge_t badge,int pid,int tid)172 void chanmgr_handle_create_channel(ipc_msg_t *ipc_msg, badge_t badge, int pid,
173 int tid)
174 {
175 struct channel_entry *entry;
176 int ret, cap;
177 size_t len;
178 uint32_t hashsum;
179 struct reg_items_st reg_items;
180 struct chan_request *req = (struct chan_request *)ipc_get_msg_data(ipc_msg);
181 uint32_t taskid = pid_to_taskid(tid, pid);
182
183 pthread_mutex_lock(&chanmgr.lock);
184
185 memcpy(®_items,
186 &req->create_channel.reg_items,
187 sizeof(struct reg_items_st));
188 if (__chan_name_empty(req->create_channel.name)) {
189 reg_items.reg_name = false;
190 }
191 if (!__ch_num_valid(req->create_channel.ch_num)) {
192 reg_items.reg_pid = false;
193 }
194 if (!reg_items.reg_name && !reg_items.reg_pid) {
195 ret = -EINVAL;
196 goto out_fail;
197 }
198
199 if (reg_items.reg_name) {
200 entry = __get_entry_by_name(req->create_channel.name);
201 if (entry != NULL) {
202 ret = -EEXIST;
203 goto out_fail;
204 }
205 }
206 if (reg_items.reg_pid) {
207 entry = __get_entry_by_cid(taskid, req->create_channel.ch_num);
208 if (entry != NULL) {
209 ret = -EEXIST;
210 goto out_fail;
211 }
212 }
213
214 entry = malloc(sizeof(*entry));
215 if (entry == NULL) {
216 ret = -ENOMEM;
217 goto out_fail;
218 }
219 channel_entry_init(entry);
220
221 cap = (int)ipc_get_msg_cap(ipc_msg, 0);
222 if (cap < 0) {
223 ret = -EINVAL;
224 goto out_free_entry;
225 }
226 entry->cap = cap;
227 entry->taskid = taskid;
228 entry->badge = badge;
229
230 if (reg_items.reg_name) {
231 len = strlen(req->create_channel.name);
232 entry->name = malloc(len + 1);
233 if (entry->name == NULL) {
234 ret = -ENOMEM;
235 goto out_free_entry;
236 }
237 memcpy(entry->name, req->create_channel.name, len);
238 entry->name[len] = 0;
239 }
240 if (reg_items.reg_pid) {
241 entry->ch_num = req->create_channel.ch_num;
242 }
243
244 memcpy(&entry->reg_items, ®_items, sizeof(struct reg_items_st));
245
246 htable_add(&chanmgr.badge2chan, badge, &entry->badge2chan_node);
247 if (reg_items.reg_name) {
248 hashsum = __hash_name(entry->name);
249 htable_add(&chanmgr.name2chan, hashsum, &entry->name2chan_node);
250 }
251 if (reg_items.reg_pid) {
252 hashsum = __hash_taskid(entry->taskid, entry->ch_num);
253 htable_add(&chanmgr.cid2chan, hashsum, &entry->cid2chan_node);
254 }
255
256 pthread_mutex_unlock(&chanmgr.lock);
257 ret = 0;
258 ipc_return(ipc_msg, ret);
259
260 out_free_entry:
261 free(entry);
262
263 out_fail:
264 pthread_mutex_unlock(&chanmgr.lock);
265 ipc_return(ipc_msg, ret);
266 }
267
chanmgr_handle_remove_channel(ipc_msg_t * ipc_msg,badge_t badge,int pid,int tid)268 void chanmgr_handle_remove_channel(ipc_msg_t *ipc_msg, badge_t badge, int pid,
269 int tid)
270 {
271 int ret;
272 struct channel_entry *entry = NULL;
273 struct chan_request *req = (struct chan_request *)ipc_get_msg_data(ipc_msg);
274
275 pthread_mutex_lock(&chanmgr.lock);
276
277 if (!__chan_name_empty(req->remove_channel.name)) {
278 entry = __get_entry_by_name(req->remove_channel.name);
279 }
280 if (entry == NULL && __ch_num_valid(req->remove_channel.ch_num)) {
281 entry = __get_entry_by_cid(req->remove_channel.taskid,
282 req->remove_channel.ch_num);
283 }
284 if (entry == NULL) {
285 ret = -ENOENT;
286 goto out;
287 }
288 if (badge != entry->badge) {
289 ret = -EINVAL;
290 goto out;
291 }
292
293 ret = usys_revoke_cap(entry->cap, false);
294
295 hlist_del(&entry->badge2chan_node);
296 if (entry->reg_items.reg_name || entry->reg_items.reg_tamgr) {
297 hlist_del(&entry->name2chan_node);
298 }
299 if (entry->reg_items.reg_pid) {
300 hlist_del(&entry->cid2chan_node);
301 }
302 channel_entry_deinit(entry);
303 free(entry);
304
305 out:
306 pthread_mutex_unlock(&chanmgr.lock);
307 ipc_return(ipc_msg, ret);
308 }
309
chanmgr_handle_register_tamgr(ipc_msg_t * ipc_msg,badge_t badge,int pid,int tid)310 void chanmgr_handle_register_tamgr(ipc_msg_t *ipc_msg, badge_t badge, int pid,
311 int tid)
312 {
313 int ret;
314 struct tamgr_entry *entry;
315 struct chan_request *req = (struct chan_request *)ipc_get_msg_data(ipc_msg);
316 char name[CHAN_REQ_NAME_LEN];
317 size_t len;
318
319 pthread_mutex_lock(&chanmgr.lock);
320
321 memcpy(name, req->register_tamgr.name, sizeof(name));
322 name[CHAN_REQ_NAME_LEN - 1] = '\0';
323 if (__chan_name_empty(name)) {
324 ret = -EINVAL;
325 goto out;
326 }
327
328 entry = __get_tamgr_entry_by_name(name);
329 if (entry) {
330 ret = -EEXIST;
331 goto out;
332 }
333
334 entry = malloc(sizeof(*entry));
335 if (entry == NULL) {
336 ret = -ENOMEM;
337 goto out;
338 }
339
340 len = strlen(name);
341 entry->name = malloc(len + 1);
342 if (entry->name == NULL) {
343 ret = -ENOMEM;
344 goto out_free_entry;
345 }
346 memcpy(entry->name, name, len + 1);
347 init_hlist_node(&entry->badge2tamgr_node);
348 init_hlist_node(&entry->name2taskid_node);
349 entry->badge = badge;
350 entry->taskid = pid_to_taskid(tid, pid);
351
352 htable_add(&chanmgr.badge2tamgr, badge, &entry->badge2tamgr_node);
353 htable_add(&chanmgr.name2taskid, __hash_name(entry->name), &entry->name2taskid_node);
354
355 pthread_mutex_unlock(&chanmgr.lock);
356 ipc_return(ipc_msg, 0);
357
358 out_free_entry:
359 free(entry);
360 out:
361 pthread_mutex_unlock(&chanmgr.lock);
362 ipc_return(ipc_msg, ret);
363 }
364
chanmgr_handle_hunt_by_name(ipc_msg_t * ipc_msg,int pid,int tid)365 void chanmgr_handle_hunt_by_name(ipc_msg_t *ipc_msg, int pid, int tid)
366 {
367 int ret;
368 struct tamgr_entry *entry = NULL;
369 struct chan_request *req = (struct chan_request *)ipc_get_msg_data(ipc_msg);
370
371 pthread_mutex_lock(&chanmgr.lock);
372
373 if (__chan_name_empty(req->hunt_by_name.name)) {
374 ret = -EINVAL;
375 goto out;
376 }
377
378 entry = __get_tamgr_entry_by_name(req->hunt_by_name.name);
379 if (entry == NULL) {
380 ret = -ENOENT;
381 goto out;
382 }
383
384 req->hunt_by_name.taskid = entry->taskid;
385 /* TODO: gtask's taskid is 0 */
386 if (req->hunt_by_name.taskid == GTASK_TASKID) {
387 req->hunt_by_name.taskid = 0;
388 }
389 ret = 0;
390
391 out:
392 pthread_mutex_unlock(&chanmgr.lock);
393 ipc_return(ipc_msg, ret);
394 }
395
chanmgr_handle_get_ch_from_path(ipc_msg_t * ipc_msg,int pid,int tid)396 void chanmgr_handle_get_ch_from_path(ipc_msg_t *ipc_msg, int pid, int tid)
397 {
398 int ret;
399 struct channel_entry *entry = NULL;
400 struct chan_request *req = (struct chan_request *)ipc_get_msg_data(ipc_msg);
401
402 pthread_mutex_lock(&chanmgr.lock);
403
404 if (__chan_name_empty(req->get_ch_from_path.name)) {
405 ret = -EINVAL;
406 goto out;
407 }
408
409 entry = __get_entry_by_name(req->get_ch_from_path.name);
410 if (entry == NULL) {
411 ret = -ENOENT;
412 goto out;
413 }
414
415 ipc_msg->cap_slot_number = 1;
416 ret = ipc_set_msg_cap(ipc_msg, 0, entry->cap);
417 if (ret < 0) {
418 ret = -EINVAL;
419 } else {
420 ret = 0;
421 }
422
423 out:
424 pthread_mutex_unlock(&chanmgr.lock);
425 if (ret == 0) {
426 ipc_return_with_cap(ipc_msg, ret);
427 } else {
428 ipc_return(ipc_msg, ret);
429 }
430 }
431
chanmgr_handle_get_ch_from_taskid(ipc_msg_t * ipc_msg,int pid,int tid)432 void chanmgr_handle_get_ch_from_taskid(ipc_msg_t *ipc_msg, int pid, int tid)
433 {
434 int ret;
435 struct channel_entry *entry = NULL;
436 struct chan_request *req = (struct chan_request *)ipc_get_msg_data(ipc_msg);
437
438 pthread_mutex_lock(&chanmgr.lock);
439
440 if (!__ch_num_valid(req->get_ch_from_taskid.ch_num)) {
441 ret = -EINVAL;
442 goto out;
443 }
444 /* TODO: gtask's taskid is 0 */
445 if (req->get_ch_from_taskid.taskid == 0) {
446 req->get_ch_from_taskid.taskid = GTASK_TASKID;
447 }
448 entry = __get_entry_by_cid(req->get_ch_from_taskid.taskid,
449 req->get_ch_from_taskid.ch_num);
450 if (entry == NULL) {
451 ret = -ENOENT;
452 goto out;
453 }
454
455 ipc_msg->cap_slot_number = 1;
456 ret = ipc_set_msg_cap(ipc_msg, 0, entry->cap);
457 if (ret < 0) {
458 ret = -EINVAL;
459 } else {
460 ret = 0;
461 }
462
463 out:
464 pthread_mutex_unlock(&chanmgr.lock);
465 if (ret == 0) {
466 ipc_return_with_cap(ipc_msg, ret);
467 } else {
468 ipc_return(ipc_msg, ret);
469 }
470 }
471
chanmgr_destructor(badge_t client_badge)472 void chanmgr_destructor(badge_t client_badge)
473 {
474 struct hlist_head *bucket;
475 struct channel_entry *entry, *tmp;
476 struct tamgr_entry *tamgr_entry, *tamgr_tmp;
477
478 pthread_mutex_lock(&chanmgr.lock);
479
480 bucket = htable_get_bucket(&chanmgr.badge2chan, client_badge);
481 for_each_in_hlist_safe (entry, tmp, badge2chan_node, bucket) {
482 if (entry->badge == client_badge) {
483 usys_revoke_cap(entry->cap, false);
484
485 hlist_del(&entry->badge2chan_node);
486 if (entry->reg_items.reg_name || entry->reg_items.reg_tamgr) {
487 hlist_del(&entry->name2chan_node);
488 }
489 if (entry->reg_items.reg_pid) {
490 hlist_del(&entry->cid2chan_node);
491 }
492 channel_entry_deinit(entry);
493 free(entry);
494 }
495 }
496
497 bucket = htable_get_bucket(&chanmgr.badge2tamgr, client_badge);
498 for_each_in_hlist_safe (tamgr_entry, tamgr_tmp, badge2tamgr_node, bucket) {
499 if (tamgr_entry->badge == client_badge) {
500 htable_del(&tamgr_entry->badge2tamgr_node);
501 htable_del(&tamgr_entry->name2taskid_node);
502 free(tamgr_entry->name);
503 free(tamgr_entry);
504 }
505 }
506
507 pthread_mutex_unlock(&chanmgr.lock);
508 }
509