• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&reg_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, &reg_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