1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "mqueue.h"
33 #ifdef LOSCFG_FS_VFS
34 #include "fcntl.h"
35 #include "pthread.h"
36 #include "map_error.h"
37 #include "time_posix.h"
38 #include "los_memory.h"
39 #include "los_vm_map.h"
40 #include "los_process_pri.h"
41 #include "fs/file.h"
42 #include "user_copy.h"
43 
44 
45 #define FNONBLOCK   O_NONBLOCK
46 
47 #ifndef LOSCFG_IPC_CONTAINER
48 /* GLOBALS */
49 STATIC fd_set g_queueFdSet;
50 STATIC struct mqarray g_queueTable[LOSCFG_BASE_IPC_QUEUE_LIMIT];
51 STATIC pthread_mutex_t g_mqueueMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
52 STATIC struct mqpersonal *g_mqPrivBuf[MAX_MQ_FD];
53 
54 #define IPC_QUEUE_FD_SET g_queueFdSet
55 #define IPC_QUEUE_TABLE  g_queueTable
56 #define IPC_QUEUE_MUTEX  g_mqueueMutex
57 #define IPC_QUEUE_MQ_PRIV_BUF g_mqPrivBuf
58 #endif
59 
60 /* LOCAL FUNCTIONS */
MqNameCheck(const CHAR *mqName)61 STATIC INLINE INT32 MqNameCheck(const CHAR *mqName)
62 {
63     if (mqName == NULL) {
64         errno = EINVAL;
65         return -1;
66     }
67 
68     if (strlen(mqName) == 0) {
69         errno = EINVAL;
70         return -1;
71     }
72 
73     if (strlen(mqName) > (PATH_MAX - 1)) {
74         errno = ENAMETOOLONG;
75         return -1;
76     }
77     return 0;
78 }
79 
GetMqueueCBByID(UINT32 queueID, LosQueueCB **queueCB)80 STATIC INLINE UINT32 GetMqueueCBByID(UINT32 queueID, LosQueueCB **queueCB)
81 {
82     LosQueueCB *tmpQueueCB = NULL;
83     if (queueCB == NULL) {
84         errno = EINVAL;
85         return LOS_ERRNO_QUEUE_READ_PTR_NULL;
86     }
87     tmpQueueCB = GET_QUEUE_HANDLE(queueID);
88     if ((GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) || (tmpQueueCB->queueID != queueID)) {
89         return LOS_ERRNO_QUEUE_INVALID;
90     }
91     *queueCB = tmpQueueCB;
92 
93     return LOS_OK;
94 }
95 
GetMqueueCBByName(const CHAR *name)96 STATIC INLINE struct mqarray *GetMqueueCBByName(const CHAR *name)
97 {
98     UINT32 index;
99     UINT32 mylen = strlen(name);
100 
101     for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
102         if ((IPC_QUEUE_TABLE[index].mq_name == NULL) || (strlen(IPC_QUEUE_TABLE[index].mq_name) != mylen)) {
103             continue;
104         }
105 
106         if (strncmp(name, (const CHAR *)(IPC_QUEUE_TABLE[index].mq_name), mylen) == 0) {
107             return &(IPC_QUEUE_TABLE[index]);
108         }
109     }
110     return NULL;
111 }
112 
DoMqueueDelete(struct mqarray *mqueueCB)113 STATIC INT32 DoMqueueDelete(struct mqarray *mqueueCB)
114 {
115     UINT32 ret;
116 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
117     OsIPCLimitMqFree();
118 #endif
119     if (mqueueCB->mq_name != NULL) {
120         LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name);
121         mqueueCB->mq_name = NULL;
122     }
123 
124     mqueueCB->mqcb = NULL;
125     /* When mqueue-list head node needed free ,reset the mode_data */
126     mqueueCB->mode_data.data = 0;
127     mqueueCB->euid = -1;
128     mqueueCB->egid = -1;
129     mqueueCB->mq_notify.pid = 0;
130 
131     ret = LOS_QueueDelete(mqueueCB->mq_id);
132     switch (ret) {
133         case LOS_OK:
134             return 0;
135         case LOS_ERRNO_QUEUE_NOT_FOUND:
136         case LOS_ERRNO_QUEUE_NOT_CREATE:
137         case LOS_ERRNO_QUEUE_IN_TSKUSE:
138         case LOS_ERRNO_QUEUE_IN_TSKWRITE:
139             errno = EAGAIN;
140             return -1;
141         default:
142             errno = EINVAL;
143             return -1;
144     }
145 }
146 
SaveMqueueName(const CHAR *mqName, struct mqarray *mqueueCB)147 STATIC int SaveMqueueName(const CHAR *mqName, struct mqarray *mqueueCB)
148 {
149     size_t nameLen;
150 
151     nameLen = strlen(mqName); /* sys_mq_open has checked name and name length */
152     mqueueCB->mq_name = (char *)LOS_MemAlloc(OS_SYS_MEM_ADDR, nameLen + 1);
153     if (mqueueCB->mq_name == NULL) {
154         errno = ENOMEM;
155         return LOS_NOK;
156     }
157 
158     if (strncpy_s(mqueueCB->mq_name, (nameLen + 1), mqName, nameLen) != EOK) {
159         LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name);
160         mqueueCB->mq_name = NULL;
161         errno = EINVAL;
162         return LOS_NOK;
163     }
164     mqueueCB->mq_name[nameLen] = '\0';
165     return LOS_OK;
166 }
167 
MqueueCBInit(struct mqarray *mqueueCB, const struct mq_attr *attr, INT32 openFlag, UINT32 mode)168 STATIC VOID MqueueCBInit(struct mqarray *mqueueCB, const struct mq_attr *attr, INT32 openFlag, UINT32 mode)
169 {
170     mqueueCB->unlinkflag = FALSE;
171     mqueueCB->unlink_ref = 0;
172     mqueueCB->mq_personal->mq_status = MQ_USE_MAGIC;
173     mqueueCB->mq_personal->mq_next = NULL;
174     mqueueCB->mq_personal->mq_posixdes = mqueueCB;
175     mqueueCB->mq_personal->mq_flags = (INT32)((UINT32)openFlag | ((UINT32)attr->mq_flags & (UINT32)FNONBLOCK));
176     mqueueCB->mq_personal->mq_mode = mode;
177     mqueueCB->mq_personal->mq_refcount = 0;
178     mqueueCB->mq_notify.pid = 0;
179 }
180 
DoMqueueCreate(const struct mq_attr *attr, const CHAR *mqName, INT32 openFlag, UINT32 mode)181 STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR *mqName, INT32 openFlag, UINT32 mode)
182 {
183     struct mqarray *mqueueCB = NULL;
184     UINT32 mqueueID;
185 
186 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
187     if (OsIPCLimitMqAlloc() != LOS_OK) {
188         return (struct mqpersonal *)-1;
189     }
190 #endif
191     UINT32 err = LOS_QueueCreate(NULL, attr->mq_maxmsg, &mqueueID, 0, attr->mq_msgsize);
192     if (map_errno(err) != ENOERR) {
193         goto ERROUT;
194     }
195 
196     if (IPC_QUEUE_TABLE[GET_QUEUE_INDEX(mqueueID)].mqcb == NULL) {
197         mqueueCB = &(IPC_QUEUE_TABLE[GET_QUEUE_INDEX(mqueueID)]);
198         mqueueCB->mq_id = mqueueID;
199     }
200 
201     if (mqueueCB == NULL) {
202         errno = EINVAL;
203         goto ERROUT;
204     }
205 
206     if (SaveMqueueName(mqName, mqueueCB) != LOS_OK) {
207         goto ERROUT;
208     }
209 
210     if (GetMqueueCBByID(mqueueCB->mq_id, &(mqueueCB->mqcb)) != LOS_OK) {
211         errno = ENOSPC;
212         goto ERROUT;
213     }
214 
215     mqueueCB->mq_personal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));
216     if (mqueueCB->mq_personal == NULL) {
217         (VOID)LOS_QueueDelete(mqueueCB->mq_id);
218         mqueueCB->mqcb->queueHandle = NULL;
219         mqueueCB->mqcb = NULL;
220         errno = ENOSPC;
221         goto ERROUT;
222     }
223 
224     MqueueCBInit(mqueueCB, attr, openFlag, mode);
225 
226     return mqueueCB->mq_personal;
227 ERROUT:
228 
229     if ((mqueueCB != NULL) && (mqueueCB->mq_name != NULL)) {
230         LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name);
231         mqueueCB->mq_name = NULL;
232     }
233 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
234     OsIPCLimitMqFree();
235 #endif
236     return (struct mqpersonal *)-1;
237 }
238 
DoMqueueOpen(struct mqarray *mqueueCB, INT32 openFlag)239 STATIC struct mqpersonal *DoMqueueOpen(struct mqarray *mqueueCB, INT32 openFlag)
240 {
241     struct mqpersonal *privateMqPersonal = NULL;
242 
243     /* already have the same name of g_squeuetable */
244     if (mqueueCB->unlinkflag == TRUE) {
245         errno = EINVAL;
246         goto ERROUT;
247     }
248     /* alloc mqprivate and add to mqarray */
249     privateMqPersonal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));
250     if (privateMqPersonal == NULL) {
251         errno = ENOSPC;
252         goto ERROUT;
253     }
254 
255     privateMqPersonal->mq_next = mqueueCB->mq_personal;
256     mqueueCB->mq_personal = privateMqPersonal;
257 
258     privateMqPersonal->mq_posixdes = mqueueCB;
259     privateMqPersonal->mq_flags = openFlag;
260     privateMqPersonal->mq_status = MQ_USE_MAGIC;
261     privateMqPersonal->mq_refcount = 0;
262 
263     return privateMqPersonal;
264 
265 ERROUT:
266     return (struct mqpersonal *)-1;
267 }
268 
DoMqueueClose(struct mqpersonal *privateMqPersonal)269 STATIC INT32 DoMqueueClose(struct mqpersonal *privateMqPersonal)
270 {
271     struct mqarray *mqueueCB = NULL;
272     struct mqpersonal *tmp = NULL;
273     INT32 ret;
274 
275     mqueueCB = privateMqPersonal->mq_posixdes;
276     if (mqueueCB == NULL || mqueueCB->mq_personal == NULL) {
277         errno = EBADF;
278         return LOS_NOK;
279     }
280 
281     if ((mqueueCB->unlinkflag == TRUE) && (privateMqPersonal->mq_next == NULL)) {
282         ret = DoMqueueDelete(mqueueCB);
283         if (ret < 0) {
284             return ret;
285         }
286     }
287     /* find the personal and remove */
288     if (mqueueCB->mq_personal == privateMqPersonal) {
289         mqueueCB->mq_personal = privateMqPersonal->mq_next;
290     } else {
291         for (tmp = mqueueCB->mq_personal; tmp->mq_next != NULL; tmp = tmp->mq_next) {
292             if (tmp->mq_next == privateMqPersonal) {
293                 break;
294             }
295         }
296         if (tmp->mq_next == NULL) {
297             errno = EBADF;
298             return LOS_NOK;
299         }
300         tmp->mq_next = privateMqPersonal->mq_next;
301     }
302     /* flag no use */
303     privateMqPersonal->mq_status = 0;
304 
305     /* free the personal */
306     (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, privateMqPersonal);
307 
308     return LOS_OK;
309 }
310 
311 /* Translate a sysFd into privateMqPersonal */
MqGetPrivDataBuff(mqd_t personal)312 STATIC struct mqpersonal *MqGetPrivDataBuff(mqd_t personal)
313 {
314     INT32 sysFd = (INT32)personal;
315     INT32 id = sysFd - MQUEUE_FD_OFFSET;
316 
317     /* Filter illegal id */
318     if ((id < 0) || (id >= MAX_MQ_FD)) {
319         errno = EBADF;
320         return NULL;
321     }
322     return IPC_QUEUE_MQ_PRIV_BUF[id];
323 }
324 
325 /**
326  * Alloc sysFd, storage mq private data, set using bit.
327  *
328  * @param maxfdp: Maximum allowed application of mqueue sysFd.
329  * @param fdset: Mqueue sysFd bit map.
330  * @param privateMqPersonal: Private data.
331  * @return the index of the new fd; -1 on error
332  */
MqAllocSysFd(int maxfdp, struct mqpersonal *privateMqPersonal)333 STATIC INT32 MqAllocSysFd(int maxfdp, struct mqpersonal *privateMqPersonal)
334 {
335     INT32 i;
336     fd_set *fdset = &IPC_QUEUE_FD_SET;
337     for (i = 0; i < maxfdp; i++) {
338         /* sysFd: used bit setting, and get the index of swtmrID buffer */
339         if (fdset && !(FD_ISSET(i + MQUEUE_FD_OFFSET, fdset))) {
340             FD_SET(i + MQUEUE_FD_OFFSET, fdset);
341             if (!IPC_QUEUE_MQ_PRIV_BUF[i]) {
342                 IPC_QUEUE_MQ_PRIV_BUF[i] = privateMqPersonal;
343                 return i + MQUEUE_FD_OFFSET;
344             }
345         }
346     }
347     return -1;
348 }
349 
MqFreeSysFd(mqd_t personal)350 STATIC VOID MqFreeSysFd(mqd_t personal)
351 {
352     INT32 sysFd = (INT32)personal;
353     fd_set *fdset = &IPC_QUEUE_FD_SET;
354     if (fdset && FD_ISSET(sysFd, fdset)) {
355         FD_CLR(sysFd, fdset);
356         IPC_QUEUE_MQ_PRIV_BUF[sysFd - MQUEUE_FD_OFFSET] = NULL;
357     }
358 }
359 
360 /* Mqueue fd reference count */
MqueueRefer(int sysFd)361 void MqueueRefer(int sysFd)
362 {
363     struct mqarray *mqueueCB = NULL;
364     struct mqpersonal *privateMqPersonal = NULL;
365 
366     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
367     /* Get the personal sysFd and reset personal fd -1 */
368     privateMqPersonal = MqGetPrivDataBuff((mqd_t)sysFd);
369     if (privateMqPersonal == NULL) {
370         goto OUT_UNLOCK;
371     }
372     mqueueCB = privateMqPersonal->mq_posixdes;
373     if (mqueueCB == NULL) {
374         goto OUT_UNLOCK;
375     }
376 
377     privateMqPersonal->mq_refcount++;
378 OUT_UNLOCK:
379     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
380     return;
381 }
382 
MqTryClose(struct mqpersonal *privateMqPersonal)383 STATIC INT32 MqTryClose(struct mqpersonal *privateMqPersonal)
384 {
385     struct mqarray *mqueueCB = NULL;
386     mqueueCB = privateMqPersonal->mq_posixdes;
387     if (mqueueCB == NULL) {
388         errno = ENFILE;
389         return false;
390     }
391 
392     if (privateMqPersonal->mq_refcount == 0) {
393         return TRUE;
394     }
395     privateMqPersonal->mq_refcount--;
396     return FALSE;
397 }
398 
399 /* Set the mode data bit,for consumer's mode comparing. */
MqueueModeAnalysisSet(struct mqpersonal *privateMqPersonal)400 STATIC INT32 MqueueModeAnalysisSet(struct mqpersonal *privateMqPersonal)
401 {
402     UINT32 mode;
403     UINT32 intSave;
404     User *user = NULL;
405     struct mqarray *mqueueCB = NULL;
406 
407     if ((INT32)(UINTPTR)privateMqPersonal < 0) {
408         return -1;
409     }
410     /* Get mqueueCB of first time creating mqueue */
411     mqueueCB = privateMqPersonal->mq_posixdes;
412     if (mqueueCB == NULL) {
413         errno = ENFILE;
414         return -1;
415     }
416 
417     mode = mqueueCB->mq_personal->mq_mode;
418     /* Set mqueue gid uid */
419     SCHEDULER_LOCK(intSave);
420     user = OsCurrUserGet();
421     mqueueCB->euid = user->effUserID;
422     mqueueCB->egid = user->effGid;
423     SCHEDULER_UNLOCK(intSave);
424 
425     /* Set mode data bit */
426     if (mode & S_IRUSR) {
427         mqueueCB->mode_data.usr |= S_IRUSR;
428     }
429     if (mode & S_IWUSR) {
430         mqueueCB->mode_data.usr |= S_IWUSR;
431     }
432     if (mode & S_IRGRP) {
433         mqueueCB->mode_data.grp |= S_IRGRP;
434     }
435     if (mode & S_IWGRP) {
436         mqueueCB->mode_data.grp |= S_IWGRP;
437     }
438     if (mode & S_IROTH) {
439         mqueueCB->mode_data.oth |= S_IROTH;
440     }
441     if (mode & S_IWOTH) {
442         mqueueCB->mode_data.oth |= S_IWOTH;
443     }
444     return 0;
445 }
446 
GetPermissionOfVisitor(struct mqarray *mqueueCB)447 STATIC INT32 GetPermissionOfVisitor(struct mqarray *mqueueCB)
448 {
449     uid_t euid;
450     gid_t egid;
451     UINT32 intSave;
452     User *user = NULL;
453 
454     if (mqueueCB == NULL) {
455         errno = ENOENT;
456         return -EPERM;
457     }
458 
459     /* Get the visitor process euid and egid */
460     SCHEDULER_LOCK(intSave);
461     user = OsCurrUserGet();
462     euid = user->effUserID;
463     egid = user->effGid;
464     SCHEDULER_UNLOCK(intSave);
465 
466     /* root */
467     if (euid == 0) {
468         return ENOERR;
469     }
470     if (euid == mqueueCB->euid) { /* usr */
471         if (!((mqueueCB->mode_data.usr & S_IRUSR) || (mqueueCB->mode_data.usr & S_IWUSR))) {
472             errno = EACCES;
473             goto ERR_OUT;
474         }
475     } else if (egid == mqueueCB->egid) { /* grp */
476         if (!((mqueueCB->mode_data.grp & S_IRGRP) || (mqueueCB->mode_data.grp & S_IWGRP))) {
477             errno = EACCES;
478             goto ERR_OUT;
479         }
480     } else { /* oth */
481         if (!((mqueueCB->mode_data.oth & S_IROTH) || (mqueueCB->mode_data.oth & S_IWOTH))) {
482             errno = EACCES;
483             goto ERR_OUT;
484         }
485     }
486     return ENOERR;
487 
488 ERR_OUT:
489     return -EPERM;
490 }
491 
GetMqueueAttr(struct mq_attr *defaultAttr, struct mq_attr *attr)492 STATIC INT32 GetMqueueAttr(struct mq_attr *defaultAttr, struct mq_attr *attr)
493 {
494     if (attr != NULL) {
495         if (LOS_ArchCopyFromUser(defaultAttr, attr, sizeof(struct mq_attr))) {
496             errno = EFAULT;
497             return -1;
498         }
499         if ((defaultAttr->mq_maxmsg < 0) || (defaultAttr->mq_maxmsg > (long int)USHRT_MAX) ||
500             (defaultAttr->mq_msgsize < 0) || (defaultAttr->mq_msgsize > (long int)(USHRT_MAX - sizeof(UINT32)))) {
501             errno = EINVAL;
502             return -1;
503         }
504     }
505     return 0;
506 }
507 
mq_open(const char *mqName, int openFlag, ...)508 mqd_t mq_open(const char *mqName, int openFlag, ...)
509 {
510     struct mqarray *mqueueCB = NULL;
511     struct mqpersonal *privateMqPersonal = (struct mqpersonal *)-1;
512     struct mq_attr *attr = NULL;
513     struct mq_attr defaultAttr = { 0, MQ_MAX_MSG_NUM, MQ_MAX_MSG_LEN, 0 };
514     va_list ap;
515     int sysFd;
516     mqd_t mqFd = -1;
517     unsigned int mode = 0;
518 
519     if (MqNameCheck(mqName) == -1) {
520         return (mqd_t)-1;
521     }
522 
523     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
524     mqueueCB = GetMqueueCBByName(mqName);
525     if ((UINT32)openFlag & (UINT32)O_CREAT) {
526         if (mqueueCB != NULL) {
527             if (((UINT32)openFlag & (UINT32)O_EXCL)) {
528                 errno = EEXIST;
529                 goto OUT;
530             }
531             privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);
532         } else {
533             va_start(ap, openFlag);
534             mode = va_arg(ap, unsigned int);
535             attr = va_arg(ap, struct mq_attr *);
536             va_end(ap);
537 
538             if (GetMqueueAttr(&defaultAttr, attr)) {
539                 goto OUT;
540             }
541             privateMqPersonal = DoMqueueCreate(&defaultAttr, mqName, openFlag, mode);
542         }
543         /* Set mode data bit ,just for the first node */
544         if (MqueueModeAnalysisSet(privateMqPersonal)) {
545             if ((INT32)(UINTPTR)privateMqPersonal > 0) {
546                 (VOID)DoMqueueClose(privateMqPersonal);
547             }
548             goto OUT;
549         }
550     } else {
551         if (GetPermissionOfVisitor(mqueueCB)) {
552             goto OUT;
553         }
554         privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);
555     }
556 
557     if ((INT32)(UINTPTR)privateMqPersonal > 0) {
558         /* alloc sysFd */
559         sysFd = MqAllocSysFd(MAX_MQ_FD, privateMqPersonal);
560         if (sysFd == -1) {
561             /* there are no more mq sysFd to use, close the personal */
562             (VOID)DoMqueueClose(privateMqPersonal);
563             errno = ENFILE;
564         }
565         mqFd = (mqd_t)sysFd;
566     }
567 OUT:
568     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
569     return mqFd;
570 }
571 
mq_close(mqd_t personal)572 int mq_close(mqd_t personal)
573 {
574     INT32 ret = -1;
575     struct mqpersonal *privateMqPersonal = NULL;
576 
577     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
578 
579     /* Get the personal sysFd and reset personal fd -1 */
580     privateMqPersonal = MqGetPrivDataBuff(personal);
581     if (privateMqPersonal == NULL) {
582         goto OUT_UNLOCK;
583     }
584 
585     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
586         errno = EBADF;
587         goto OUT_UNLOCK;
588     }
589 
590     if (!MqTryClose(privateMqPersonal)) {
591         ret = 0;
592         goto OUT_UNLOCK;
593     }
594 
595     ret = DoMqueueClose(privateMqPersonal);
596     if (ret < 0) {
597         goto OUT_UNLOCK;
598     }
599     MqFreeSysFd(personal);
600 
601 OUT_UNLOCK:
602     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
603     return ret;
604 }
605 
OsMqGetAttr(mqd_t personal, struct mq_attr *mqAttr)606 int OsMqGetAttr(mqd_t personal, struct mq_attr *mqAttr)
607 {
608     struct mqarray *mqueueCB = NULL;
609     struct mqpersonal *privateMqPersonal = NULL;
610 
611     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
612     privateMqPersonal = MqGetPrivDataBuff(personal);
613     if (privateMqPersonal == NULL) {
614         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
615         return -1;
616     }
617 
618     if (mqAttr == NULL) {
619         errno = EINVAL;
620         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
621         return -1;
622     }
623 
624     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
625         errno = EBADF;
626         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
627         return -1;
628     }
629 
630     mqueueCB = privateMqPersonal->mq_posixdes;
631     mqAttr->mq_maxmsg = mqueueCB->mqcb->queueLen;
632     mqAttr->mq_msgsize = mqueueCB->mqcb->queueSize - sizeof(UINT32);
633     mqAttr->mq_curmsgs = mqueueCB->mqcb->readWriteableCnt[OS_QUEUE_READ];
634     mqAttr->mq_flags = privateMqPersonal->mq_flags;
635     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
636     return 0;
637 }
638 
OsMqSetAttr(mqd_t personal, const struct mq_attr *mqSetAttr, struct mq_attr *mqOldAttr)639 int OsMqSetAttr(mqd_t personal, const struct mq_attr *mqSetAttr, struct mq_attr *mqOldAttr)
640 {
641     struct mqpersonal *privateMqPersonal = NULL;
642 
643     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
644     privateMqPersonal = MqGetPrivDataBuff(personal);
645     if (privateMqPersonal == NULL) {
646         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
647         return -1;
648     }
649 
650     if (mqSetAttr == NULL) {
651         errno = EINVAL;
652         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
653         return -1;
654     }
655 
656     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
657         errno = EBADF;
658         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
659         return -1;
660     }
661 
662     if (mqOldAttr != NULL) {
663         (VOID)OsMqGetAttr(personal, mqOldAttr);
664     }
665 
666     privateMqPersonal->mq_flags = (INT32)((UINT32)privateMqPersonal->mq_flags & (UINT32)(~FNONBLOCK)); /* clear */
667     if (((UINT32)mqSetAttr->mq_flags & (UINT32)FNONBLOCK) == (UINT32)FNONBLOCK) {
668         privateMqPersonal->mq_flags = (INT32)((UINT32)privateMqPersonal->mq_flags | (UINT32)FNONBLOCK);
669     }
670     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
671     return 0;
672 }
673 
mq_getsetattr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)674 int mq_getsetattr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
675 {
676     if (new == NULL) {
677         return OsMqGetAttr(mqd, old);
678     }
679     return OsMqSetAttr(mqd, new, old);
680 }
681 
mq_unlink(const char *mqName)682 int mq_unlink(const char *mqName)
683 {
684     INT32 ret = 0;
685     struct mqarray *mqueueCB = NULL;
686 
687     if (MqNameCheck(mqName) == -1) {
688         return -1;
689     }
690 
691     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
692     mqueueCB = GetMqueueCBByName(mqName);
693     if (mqueueCB == NULL) {
694         errno = ENOENT;
695         goto ERROUT_UNLOCK;
696     }
697 
698     if (mqueueCB->mq_personal != NULL) {
699         mqueueCB->unlinkflag = TRUE;
700     } else if (mqueueCB->unlink_ref == 0) {
701         ret = DoMqueueDelete(mqueueCB);
702     }
703 
704     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
705     return ret;
706 
707 ERROUT_UNLOCK:
708     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
709     return -1;
710 }
711 
ConvertTimeout(long flags, const struct timespec *absTimeout, UINT64 *ticks)712 STATIC INT32 ConvertTimeout(long flags, const struct timespec *absTimeout, UINT64 *ticks)
713 {
714     if ((UINT32)flags & (UINT32)FNONBLOCK) {
715         *ticks = LOS_NO_WAIT;
716         return 0;
717     }
718 
719     if (absTimeout == NULL) {
720         *ticks = LOS_WAIT_FOREVER;
721         return 0;
722     }
723 
724     if (!ValidTimeSpec(absTimeout)) {
725         errno = EINVAL;
726         return -1;
727     }
728 
729     *ticks = OsTimeSpec2Tick(absTimeout);
730     return 0;
731 }
732 
MqParamCheck(mqd_t personal, const char *msg, size_t msgLen)733 STATIC INLINE BOOL MqParamCheck(mqd_t personal, const char *msg, size_t msgLen)
734 {
735     if (personal < 0) {
736         return FALSE;
737     }
738 
739     if ((msg == NULL) || (msgLen == 0)) {
740         errno = EINVAL;
741         return FALSE;
742     }
743     return TRUE;
744 }
745 
746 /*
747  * Send realtime a signal to process which registered itself
748  * successfully by mq_notify.
749  */
MqSendNotify(struct mqarray *mqueueCB)750 static void MqSendNotify(struct mqarray *mqueueCB)
751 {
752     struct mqnotify *mqnotify = &mqueueCB->mq_notify;
753 
754     if ((mqnotify->pid) && (mqueueCB->mqcb->readWriteableCnt[OS_QUEUE_READ] == 0)) {
755         siginfo_t info;
756 
757         switch (mqnotify->notify.sigev_notify) {
758             case SIGEV_SIGNAL:
759                 /* sends signal */
760                 /* Create the siginfo structure */
761                 info.si_signo = mqnotify->notify.sigev_signo;
762                 info.si_code = SI_MESGQ;
763                 info.si_value = mqnotify->notify.sigev_value;
764                 OsDispatch(mqnotify->pid, &info, OS_USER_KILL_PERMISSION);
765                 break;
766             case SIGEV_NONE:
767             default:
768                 break;
769         }
770         /* after notification unregisters process */
771         mqnotify->pid = 0;
772     }
773 }
774 
775 #define OS_MQ_GOTO_ERROUT_UNLOCK_IF(expr, errcode) \
776     if (expr) {                        \
777         errno = errcode;                 \
778         goto ERROUT_UNLOCK;                     \
779     }
780 #define OS_MQ_GOTO_ERROUT_IF(expr, errcode) \
781     if (expr) {                        \
782         errno = errcode;                 \
783         goto ERROUT;                     \
784     }
mq_timedsend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio, const struct timespec *absTimeout)785 int mq_timedsend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio,
786                  const struct timespec *absTimeout)
787 {
788     UINT32 mqueueID, err;
789     UINT64 absTicks;
790     struct mqarray *mqueueCB = NULL;
791     struct mqpersonal *privateMqPersonal = NULL;
792 
793     OS_MQ_GOTO_ERROUT_IF(!MqParamCheck(personal, msg, msgLen), errno);
794     OS_MQ_GOTO_ERROUT_IF(msgPrio > (MQ_PRIO_MAX - 1), EINVAL);
795 
796     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
797     privateMqPersonal = MqGetPrivDataBuff(personal);
798 
799     OS_MQ_GOTO_ERROUT_UNLOCK_IF(privateMqPersonal == NULL || privateMqPersonal->mq_status != MQ_USE_MAGIC, EBADF);
800 
801     mqueueCB = privateMqPersonal->mq_posixdes;
802     OS_MQ_GOTO_ERROUT_UNLOCK_IF(msgLen > (size_t)(mqueueCB->mqcb->queueSize - sizeof(UINT32)), EMSGSIZE);
803 
804     OS_MQ_GOTO_ERROUT_UNLOCK_IF((((UINT32)privateMqPersonal->mq_flags & (UINT32)O_WRONLY) != (UINT32)O_WRONLY) &&
805                                 (((UINT32)privateMqPersonal->mq_flags & (UINT32)O_RDWR) != (UINT32)O_RDWR),
806                                 EBADF);
807 
808     OS_MQ_GOTO_ERROUT_UNLOCK_IF(ConvertTimeout(privateMqPersonal->mq_flags, absTimeout, &absTicks) == -1, errno);
809     mqueueID = mqueueCB->mq_id;
810     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
811 
812     if (LOS_ListEmpty(&mqueueCB->mqcb->readWriteList[OS_QUEUE_READ])) {
813         MqSendNotify(mqueueCB);
814     }
815 
816     err = LOS_QueueWriteCopy(mqueueID, (VOID *)msg, (UINT32)msgLen, (UINT32)absTicks);
817     if (map_errno(err) != ENOERR) {
818         goto ERROUT;
819     }
820     return 0;
821 ERROUT_UNLOCK:
822     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
823 ERROUT:
824     return -1;
825 }
826 
mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio, const struct timespec *absTimeout)827 ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio,
828                         const struct timespec *absTimeout)
829 {
830     UINT32 mqueueID, err;
831     UINT32 receiveLen;
832     UINT64 absTicks;
833     struct mqarray *mqueueCB = NULL;
834     struct mqpersonal *privateMqPersonal = NULL;
835 
836     if (!MqParamCheck(personal, msg, msgLen)) {
837         goto ERROUT;
838     }
839 
840     if (msgPrio != NULL) {
841         *msgPrio = 0;
842     }
843 
844     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
845     privateMqPersonal = MqGetPrivDataBuff(personal);
846     if (privateMqPersonal == NULL || privateMqPersonal->mq_status != MQ_USE_MAGIC) {
847         errno = EBADF;
848         goto ERROUT_UNLOCK;
849     }
850 
851     mqueueCB = privateMqPersonal->mq_posixdes;
852     if (msgLen < (size_t)(mqueueCB->mqcb->queueSize - sizeof(UINT32))) {
853         errno = EMSGSIZE;
854         goto ERROUT_UNLOCK;
855     }
856 
857     if (((UINT32)privateMqPersonal->mq_flags & (UINT32)O_WRONLY) == (UINT32)O_WRONLY) {
858         errno = EBADF;
859         goto ERROUT_UNLOCK;
860     }
861 
862     if (ConvertTimeout(privateMqPersonal->mq_flags, absTimeout, &absTicks) == -1) {
863         goto ERROUT_UNLOCK;
864     }
865 
866     receiveLen = msgLen;
867     mqueueID = mqueueCB->mq_id;
868     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
869 
870     err = LOS_QueueReadCopy(mqueueID, (VOID *)msg, &receiveLen, (UINT32)absTicks);
871     if (map_errno(err) == ENOERR) {
872         return (ssize_t)receiveLen;
873     } else {
874         goto ERROUT;
875     }
876 
877 ERROUT_UNLOCK:
878     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
879 ERROUT:
880     return -1;
881 }
882 
883 /* not support the prio */
mq_send(mqd_t personal, const char *msg_ptr, size_t msg_len, unsigned int msg_prio)884 int mq_send(mqd_t personal, const char *msg_ptr, size_t msg_len, unsigned int msg_prio)
885 {
886     return mq_timedsend(personal, msg_ptr, msg_len, msg_prio, NULL);
887 }
888 
mq_receive(mqd_t personal, char *msg_ptr, size_t msg_len, unsigned int *msg_prio)889 ssize_t mq_receive(mqd_t personal, char *msg_ptr, size_t msg_len, unsigned int *msg_prio)
890 {
891     return mq_timedreceive(personal, msg_ptr, msg_len, msg_prio, NULL);
892 }
893 
MqNotifyParamCheck(mqd_t personal, const struct sigevent *sigev)894 STATIC INLINE BOOL MqNotifyParamCheck(mqd_t personal, const struct sigevent *sigev)
895 {
896     if (personal < 0) {
897         errno = EBADF;
898         goto ERROUT;
899     }
900 
901     if (sigev != NULL) {
902         if (sigev->sigev_notify != SIGEV_NONE && sigev->sigev_notify != SIGEV_SIGNAL) {
903             errno = EINVAL;
904             goto ERROUT;
905         }
906         if (sigev->sigev_notify == SIGEV_SIGNAL && !GOOD_SIGNO(sigev->sigev_signo)) {
907             errno = EINVAL;
908             goto ERROUT;
909         }
910     }
911 
912     return TRUE;
913 ERROUT:
914     return FALSE;
915 }
916 
OsMqNotify(mqd_t personal, const struct sigevent *sigev)917 int OsMqNotify(mqd_t personal, const struct sigevent *sigev)
918 {
919     struct mqarray *mqueueCB = NULL;
920     struct mqnotify *mqnotify = NULL;
921     struct mqpersonal *privateMqPersonal = NULL;
922 
923     if (!MqNotifyParamCheck(personal, sigev)) {
924         goto ERROUT;
925     }
926 
927     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
928     privateMqPersonal = MqGetPrivDataBuff(personal);
929     if (privateMqPersonal == NULL) {
930         goto OUT_UNLOCK;
931     }
932 
933     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
934         errno = EBADF;
935         goto OUT_UNLOCK;
936     }
937 
938     mqueueCB = privateMqPersonal->mq_posixdes;
939     mqnotify = &mqueueCB->mq_notify;
940 
941     if (sigev == NULL) {
942         if (mqnotify->pid == LOS_GetCurrProcessID()) {
943             mqnotify->pid = 0;
944         }
945     } else if (mqnotify->pid != 0) {
946         errno = EBUSY;
947         goto OUT_UNLOCK;
948     } else {
949         switch (sigev->sigev_notify) {
950             case SIGEV_NONE:
951                 mqnotify->notify.sigev_notify = SIGEV_NONE;
952                 break;
953             case SIGEV_SIGNAL:
954                 mqnotify->notify.sigev_signo = sigev->sigev_signo;
955                 mqnotify->notify.sigev_value = sigev->sigev_value;
956                 mqnotify->notify.sigev_notify = SIGEV_SIGNAL;
957                 break;
958             default:
959                 break;
960         }
961 
962         mqnotify->pid = LOS_GetCurrProcessID();
963     }
964 
965     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
966     return 0;
967 OUT_UNLOCK:
968     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
969 ERROUT:
970     return -1;
971 }
972 
OsMqueueCBDestroy(struct mqarray *queueTable)973 VOID OsMqueueCBDestroy(struct mqarray *queueTable)
974 {
975     if (queueTable == NULL) {
976         return;
977     }
978 
979     for (UINT32 index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
980         struct mqarray *mqueueCB = &(queueTable[index]);
981         if (mqueueCB->mq_name == NULL) {
982             continue;
983         }
984         (VOID)DoMqueueClose(mqueueCB->mq_personal);
985     }
986 }
987 #endif
988