• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
274     mqueueCB = privateMqPersonal->mq_posixdes;
275     if (mqueueCB == NULL || mqueueCB->mq_personal == NULL) {
276         errno = EBADF;
277         return LOS_NOK;
278     }
279 
280     /* find the personal and remove */
281     if (mqueueCB->mq_personal == privateMqPersonal) {
282         mqueueCB->mq_personal = privateMqPersonal->mq_next;
283     } else {
284         for (tmp = mqueueCB->mq_personal; tmp->mq_next != NULL; tmp = tmp->mq_next) {
285             if (tmp->mq_next == privateMqPersonal) {
286                 break;
287             }
288         }
289         if (tmp->mq_next == NULL) {
290             errno = EBADF;
291             return LOS_NOK;
292         }
293         tmp->mq_next = privateMqPersonal->mq_next;
294     }
295     /* flag no use */
296     privateMqPersonal->mq_status = 0;
297 
298     /* free the personal */
299     (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, privateMqPersonal);
300 
301     if ((mqueueCB->unlinkflag == TRUE) && (mqueueCB->mq_personal == NULL)) {
302         return DoMqueueDelete(mqueueCB);
303     }
304     return LOS_OK;
305 }
306 
307 /* Translate a sysFd into privateMqPersonal */
MqGetPrivDataBuff(mqd_t personal)308 STATIC struct mqpersonal *MqGetPrivDataBuff(mqd_t personal)
309 {
310     INT32 sysFd = (INT32)personal;
311     INT32 id = sysFd - MQUEUE_FD_OFFSET;
312 
313     /* Filter illegal id */
314     if ((id < 0) || (id >= MAX_MQ_FD)) {
315         errno = EBADF;
316         return NULL;
317     }
318     return IPC_QUEUE_MQ_PRIV_BUF[id];
319 }
320 
321 /**
322  * Alloc sysFd, storage mq private data, set using bit.
323  *
324  * @param maxfdp: Maximum allowed application of mqueue sysFd.
325  * @param fdset: Mqueue sysFd bit map.
326  * @param privateMqPersonal: Private data.
327  * @return the index of the new fd; -1 on error
328  */
MqAllocSysFd(int maxfdp,struct mqpersonal * privateMqPersonal)329 STATIC INT32 MqAllocSysFd(int maxfdp, struct mqpersonal *privateMqPersonal)
330 {
331     INT32 i;
332     fd_set *fdset = &IPC_QUEUE_FD_SET;
333     for (i = 0; i < maxfdp; i++) {
334         /* sysFd: used bit setting, and get the index of swtmrID buffer */
335         if (fdset && !(FD_ISSET(i + MQUEUE_FD_OFFSET, fdset))) {
336             FD_SET(i + MQUEUE_FD_OFFSET, fdset);
337             if (!IPC_QUEUE_MQ_PRIV_BUF[i]) {
338                 IPC_QUEUE_MQ_PRIV_BUF[i] = privateMqPersonal;
339                 return i + MQUEUE_FD_OFFSET;
340             }
341         }
342     }
343     return -1;
344 }
345 
MqFreeSysFd(mqd_t personal)346 STATIC VOID MqFreeSysFd(mqd_t personal)
347 {
348     INT32 sysFd = (INT32)personal;
349     fd_set *fdset = &IPC_QUEUE_FD_SET;
350     if (fdset && FD_ISSET(sysFd, fdset)) {
351         FD_CLR(sysFd, fdset);
352         IPC_QUEUE_MQ_PRIV_BUF[sysFd - MQUEUE_FD_OFFSET] = NULL;
353     }
354 }
355 
356 /* Mqueue fd reference count */
MqueueRefer(int sysFd)357 void MqueueRefer(int sysFd)
358 {
359     struct mqarray *mqueueCB = NULL;
360     struct mqpersonal *privateMqPersonal = NULL;
361 
362     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
363     /* Get the personal sysFd and reset personal fd -1 */
364     privateMqPersonal = MqGetPrivDataBuff((mqd_t)sysFd);
365     if (privateMqPersonal == NULL) {
366         goto OUT_UNLOCK;
367     }
368     mqueueCB = privateMqPersonal->mq_posixdes;
369     if (mqueueCB == NULL) {
370         goto OUT_UNLOCK;
371     }
372 
373     privateMqPersonal->mq_refcount++;
374 OUT_UNLOCK:
375     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
376     return;
377 }
378 
MqTryClose(struct mqpersonal * privateMqPersonal)379 STATIC INT32 MqTryClose(struct mqpersonal *privateMqPersonal)
380 {
381     struct mqarray *mqueueCB = NULL;
382     mqueueCB = privateMqPersonal->mq_posixdes;
383     if (mqueueCB == NULL) {
384         errno = ENFILE;
385         return false;
386     }
387 
388     if (privateMqPersonal->mq_refcount == 0) {
389         return TRUE;
390     }
391     privateMqPersonal->mq_refcount--;
392     return FALSE;
393 }
394 
395 /* Set the mode data bit,for consumer's mode comparing. */
MqueueModeAnalysisSet(struct mqpersonal * privateMqPersonal)396 STATIC INT32 MqueueModeAnalysisSet(struct mqpersonal *privateMqPersonal)
397 {
398     UINT32 mode;
399     UINT32 intSave;
400     User *user = NULL;
401     struct mqarray *mqueueCB = NULL;
402 
403     if ((INT32)(UINTPTR)privateMqPersonal < 0) {
404         return -1;
405     }
406     /* Get mqueueCB of first time creating mqueue */
407     mqueueCB = privateMqPersonal->mq_posixdes;
408     if (mqueueCB == NULL) {
409         errno = ENFILE;
410         return -1;
411     }
412 
413     mode = mqueueCB->mq_personal->mq_mode;
414     /* Set mqueue gid uid */
415     SCHEDULER_LOCK(intSave);
416     user = OsCurrUserGet();
417     mqueueCB->euid = user->effUserID;
418     mqueueCB->egid = user->effGid;
419     SCHEDULER_UNLOCK(intSave);
420 
421     /* Set mode data bit */
422     if (mode & S_IRUSR) {
423         mqueueCB->mode_data.usr |= S_IRUSR;
424     }
425     if (mode & S_IWUSR) {
426         mqueueCB->mode_data.usr |= S_IWUSR;
427     }
428     if (mode & S_IRGRP) {
429         mqueueCB->mode_data.grp |= S_IRGRP;
430     }
431     if (mode & S_IWGRP) {
432         mqueueCB->mode_data.grp |= S_IWGRP;
433     }
434     if (mode & S_IROTH) {
435         mqueueCB->mode_data.oth |= S_IROTH;
436     }
437     if (mode & S_IWOTH) {
438         mqueueCB->mode_data.oth |= S_IWOTH;
439     }
440     return 0;
441 }
442 
GetPermissionOfVisitor(struct mqarray * mqueueCB)443 STATIC INT32 GetPermissionOfVisitor(struct mqarray *mqueueCB)
444 {
445     uid_t euid;
446     gid_t egid;
447     UINT32 intSave;
448     User *user = NULL;
449 
450     if (mqueueCB == NULL) {
451         errno = ENOENT;
452         return -EPERM;
453     }
454 
455     /* Get the visitor process euid and egid */
456     SCHEDULER_LOCK(intSave);
457     user = OsCurrUserGet();
458     euid = user->effUserID;
459     egid = user->effGid;
460     SCHEDULER_UNLOCK(intSave);
461 
462     /* root */
463     if (euid == 0) {
464         return ENOERR;
465     }
466     if (euid == mqueueCB->euid) { /* usr */
467         if (!((mqueueCB->mode_data.usr & S_IRUSR) || (mqueueCB->mode_data.usr & S_IWUSR))) {
468             errno = EACCES;
469             goto ERR_OUT;
470         }
471     } else if (egid == mqueueCB->egid) { /* grp */
472         if (!((mqueueCB->mode_data.grp & S_IRGRP) || (mqueueCB->mode_data.grp & S_IWGRP))) {
473             errno = EACCES;
474             goto ERR_OUT;
475         }
476     } else { /* oth */
477         if (!((mqueueCB->mode_data.oth & S_IROTH) || (mqueueCB->mode_data.oth & S_IWOTH))) {
478             errno = EACCES;
479             goto ERR_OUT;
480         }
481     }
482     return ENOERR;
483 
484 ERR_OUT:
485     return -EPERM;
486 }
487 
GetMqueueAttr(struct mq_attr * defaultAttr,struct mq_attr * attr)488 STATIC INT32 GetMqueueAttr(struct mq_attr *defaultAttr, struct mq_attr *attr)
489 {
490     if (attr != NULL) {
491         if (LOS_ArchCopyFromUser(defaultAttr, attr, sizeof(struct mq_attr))) {
492             errno = EFAULT;
493             return -1;
494         }
495         if ((defaultAttr->mq_maxmsg < 0) || (defaultAttr->mq_maxmsg > (long int)USHRT_MAX) ||
496             (defaultAttr->mq_msgsize < 0) || (defaultAttr->mq_msgsize > (long int)(USHRT_MAX - sizeof(UINT32)))) {
497             errno = EINVAL;
498             return -1;
499         }
500     }
501     return 0;
502 }
503 
mq_open(const char * mqName,int openFlag,...)504 mqd_t mq_open(const char *mqName, int openFlag, ...)
505 {
506     struct mqarray *mqueueCB = NULL;
507     struct mqpersonal *privateMqPersonal = (struct mqpersonal *)-1;
508     struct mq_attr *attr = NULL;
509     struct mq_attr defaultAttr = { 0, MQ_MAX_MSG_NUM, MQ_MAX_MSG_LEN, 0 };
510     va_list ap;
511     int sysFd;
512     mqd_t mqFd = -1;
513     unsigned int mode = 0;
514 
515     if (MqNameCheck(mqName) == -1) {
516         return (mqd_t)-1;
517     }
518 
519     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
520     mqueueCB = GetMqueueCBByName(mqName);
521     if ((UINT32)openFlag & (UINT32)O_CREAT) {
522         if (mqueueCB != NULL) {
523             if (((UINT32)openFlag & (UINT32)O_EXCL)) {
524                 errno = EEXIST;
525                 goto OUT;
526             }
527             privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);
528         } else {
529             va_start(ap, openFlag);
530             mode = va_arg(ap, unsigned int);
531             attr = va_arg(ap, struct mq_attr *);
532             va_end(ap);
533 
534             if (GetMqueueAttr(&defaultAttr, attr)) {
535                 goto OUT;
536             }
537             privateMqPersonal = DoMqueueCreate(&defaultAttr, mqName, openFlag, mode);
538         }
539         /* Set mode data bit ,just for the first node */
540         if (MqueueModeAnalysisSet(privateMqPersonal)) {
541             if ((INT32)(UINTPTR)privateMqPersonal > 0) {
542                 (VOID)DoMqueueClose(privateMqPersonal);
543             }
544             goto OUT;
545         }
546     } else {
547         if (GetPermissionOfVisitor(mqueueCB)) {
548             goto OUT;
549         }
550         privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);
551     }
552 
553     if ((INT32)(UINTPTR)privateMqPersonal > 0) {
554         /* alloc sysFd */
555         sysFd = MqAllocSysFd(MAX_MQ_FD, privateMqPersonal);
556         if (sysFd == -1) {
557             /* there are no more mq sysFd to use, close the personal */
558             (VOID)DoMqueueClose(privateMqPersonal);
559             errno = ENFILE;
560         }
561         mqFd = (mqd_t)sysFd;
562     }
563 OUT:
564     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
565     return mqFd;
566 }
567 
mq_close(mqd_t personal)568 int mq_close(mqd_t personal)
569 {
570     INT32 ret = -1;
571     struct mqpersonal *privateMqPersonal = NULL;
572 
573     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
574 
575     /* Get the personal sysFd and reset personal fd -1 */
576     privateMqPersonal = MqGetPrivDataBuff(personal);
577     if (privateMqPersonal == NULL) {
578         goto OUT_UNLOCK;
579     }
580 
581     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
582         errno = EBADF;
583         goto OUT_UNLOCK;
584     }
585 
586     if (!MqTryClose(privateMqPersonal)) {
587         ret = 0;
588         goto OUT_UNLOCK;
589     }
590 
591     ret = DoMqueueClose(privateMqPersonal);
592     if (ret < 0) {
593         goto OUT_UNLOCK;
594     }
595     MqFreeSysFd(personal);
596 
597 OUT_UNLOCK:
598     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
599     return ret;
600 }
601 
OsMqGetAttr(mqd_t personal,struct mq_attr * mqAttr)602 int OsMqGetAttr(mqd_t personal, struct mq_attr *mqAttr)
603 {
604     struct mqarray *mqueueCB = NULL;
605     struct mqpersonal *privateMqPersonal = NULL;
606 
607     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
608     privateMqPersonal = MqGetPrivDataBuff(personal);
609     if (privateMqPersonal == NULL) {
610         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
611         return -1;
612     }
613 
614     if (mqAttr == NULL) {
615         errno = EINVAL;
616         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
617         return -1;
618     }
619 
620     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
621         errno = EBADF;
622         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
623         return -1;
624     }
625 
626     mqueueCB = privateMqPersonal->mq_posixdes;
627     mqAttr->mq_maxmsg = mqueueCB->mqcb->queueLen;
628     mqAttr->mq_msgsize = mqueueCB->mqcb->queueSize - sizeof(UINT32);
629     mqAttr->mq_curmsgs = mqueueCB->mqcb->readWriteableCnt[OS_QUEUE_READ];
630     mqAttr->mq_flags = privateMqPersonal->mq_flags;
631     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
632     return 0;
633 }
634 
OsMqSetAttr(mqd_t personal,const struct mq_attr * mqSetAttr,struct mq_attr * mqOldAttr)635 int OsMqSetAttr(mqd_t personal, const struct mq_attr *mqSetAttr, struct mq_attr *mqOldAttr)
636 {
637     struct mqpersonal *privateMqPersonal = NULL;
638 
639     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
640     privateMqPersonal = MqGetPrivDataBuff(personal);
641     if (privateMqPersonal == NULL) {
642         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
643         return -1;
644     }
645 
646     if (mqSetAttr == NULL) {
647         errno = EINVAL;
648         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
649         return -1;
650     }
651 
652     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
653         errno = EBADF;
654         (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
655         return -1;
656     }
657 
658     if (mqOldAttr != NULL) {
659         (VOID)OsMqGetAttr(personal, mqOldAttr);
660     }
661 
662     privateMqPersonal->mq_flags = (INT32)((UINT32)privateMqPersonal->mq_flags & (UINT32)(~FNONBLOCK)); /* clear */
663     if (((UINT32)mqSetAttr->mq_flags & (UINT32)FNONBLOCK) == (UINT32)FNONBLOCK) {
664         privateMqPersonal->mq_flags = (INT32)((UINT32)privateMqPersonal->mq_flags | (UINT32)FNONBLOCK);
665     }
666     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
667     return 0;
668 }
669 
mq_getsetattr(mqd_t mqd,const struct mq_attr * new,struct mq_attr * old)670 int mq_getsetattr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
671 {
672     if (new == NULL) {
673         return OsMqGetAttr(mqd, old);
674     }
675     return OsMqSetAttr(mqd, new, old);
676 }
677 
mq_unlink(const char * mqName)678 int mq_unlink(const char *mqName)
679 {
680     INT32 ret = 0;
681     struct mqarray *mqueueCB = NULL;
682 
683     if (MqNameCheck(mqName) == -1) {
684         return -1;
685     }
686 
687     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
688     mqueueCB = GetMqueueCBByName(mqName);
689     if (mqueueCB == NULL) {
690         errno = ENOENT;
691         goto ERROUT_UNLOCK;
692     }
693 
694     if (mqueueCB->mq_personal != NULL) {
695         mqueueCB->unlinkflag = TRUE;
696     } else if (mqueueCB->unlink_ref == 0) {
697         ret = DoMqueueDelete(mqueueCB);
698     }
699 
700     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
701     return ret;
702 
703 ERROUT_UNLOCK:
704     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
705     return -1;
706 }
707 
ConvertTimeout(long flags,const struct timespec * absTimeout,UINT64 * ticks)708 STATIC INT32 ConvertTimeout(long flags, const struct timespec *absTimeout, UINT64 *ticks)
709 {
710     if ((UINT32)flags & (UINT32)FNONBLOCK) {
711         *ticks = LOS_NO_WAIT;
712         return 0;
713     }
714 
715     if (absTimeout == NULL) {
716         *ticks = LOS_WAIT_FOREVER;
717         return 0;
718     }
719 
720     if (!ValidTimeSpec(absTimeout)) {
721         errno = EINVAL;
722         return -1;
723     }
724 
725     *ticks = OsTimeSpec2Tick(absTimeout);
726     return 0;
727 }
728 
MqParamCheck(mqd_t personal,const char * msg,size_t msgLen)729 STATIC INLINE BOOL MqParamCheck(mqd_t personal, const char *msg, size_t msgLen)
730 {
731     if (personal < 0) {
732         return FALSE;
733     }
734 
735     if ((msg == NULL) || (msgLen == 0)) {
736         errno = EINVAL;
737         return FALSE;
738     }
739     return TRUE;
740 }
741 
742 /*
743  * Send realtime a signal to process which registered itself
744  * successfully by mq_notify.
745  */
MqSendNotify(struct mqarray * mqueueCB)746 static void MqSendNotify(struct mqarray *mqueueCB)
747 {
748     struct mqnotify *mqnotify = &mqueueCB->mq_notify;
749 
750     if ((mqnotify->pid) && (mqueueCB->mqcb->readWriteableCnt[OS_QUEUE_READ] == 0)) {
751         siginfo_t info;
752 
753         switch (mqnotify->notify.sigev_notify) {
754             case SIGEV_SIGNAL:
755                 /* sends signal */
756                 /* Create the siginfo structure */
757                 info.si_signo = mqnotify->notify.sigev_signo;
758                 info.si_code = SI_MESGQ;
759                 info.si_value = mqnotify->notify.sigev_value;
760                 OsDispatch(mqnotify->pid, &info, OS_USER_KILL_PERMISSION);
761                 break;
762             case SIGEV_NONE:
763             default:
764                 break;
765         }
766         /* after notification unregisters process */
767         mqnotify->pid = 0;
768     }
769 }
770 
771 #define OS_MQ_GOTO_ERROUT_UNLOCK_IF(expr, errcode) \
772     if (expr) {                        \
773         errno = errcode;                 \
774         goto ERROUT_UNLOCK;                     \
775     }
776 #define OS_MQ_GOTO_ERROUT_IF(expr, errcode) \
777     if (expr) {                        \
778         errno = errcode;                 \
779         goto ERROUT;                     \
780     }
mq_timedsend(mqd_t personal,const char * msg,size_t msgLen,unsigned int msgPrio,const struct timespec * absTimeout)781 int mq_timedsend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio,
782                  const struct timespec *absTimeout)
783 {
784     UINT32 mqueueID, err;
785     UINT64 absTicks;
786     struct mqarray *mqueueCB = NULL;
787     struct mqpersonal *privateMqPersonal = NULL;
788 
789     OS_MQ_GOTO_ERROUT_IF(!MqParamCheck(personal, msg, msgLen), errno);
790     OS_MQ_GOTO_ERROUT_IF(msgPrio > (MQ_PRIO_MAX - 1), EINVAL);
791 
792     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
793     privateMqPersonal = MqGetPrivDataBuff(personal);
794 
795     OS_MQ_GOTO_ERROUT_UNLOCK_IF(privateMqPersonal == NULL || privateMqPersonal->mq_status != MQ_USE_MAGIC, EBADF);
796 
797     mqueueCB = privateMqPersonal->mq_posixdes;
798     OS_MQ_GOTO_ERROUT_UNLOCK_IF(msgLen > (size_t)(mqueueCB->mqcb->queueSize - sizeof(UINT32)), EMSGSIZE);
799 
800     OS_MQ_GOTO_ERROUT_UNLOCK_IF((((UINT32)privateMqPersonal->mq_flags & (UINT32)O_WRONLY) != (UINT32)O_WRONLY) &&
801                                 (((UINT32)privateMqPersonal->mq_flags & (UINT32)O_RDWR) != (UINT32)O_RDWR),
802                                 EBADF);
803 
804     OS_MQ_GOTO_ERROUT_UNLOCK_IF(ConvertTimeout(privateMqPersonal->mq_flags, absTimeout, &absTicks) == -1, errno);
805     mqueueID = mqueueCB->mq_id;
806     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
807 
808     if (LOS_ListEmpty(&mqueueCB->mqcb->readWriteList[OS_QUEUE_READ])) {
809         MqSendNotify(mqueueCB);
810     }
811 
812     err = LOS_QueueWriteCopy(mqueueID, (VOID *)msg, (UINT32)msgLen, (UINT32)absTicks);
813     if (map_errno(err) != ENOERR) {
814         goto ERROUT;
815     }
816     return 0;
817 ERROUT_UNLOCK:
818     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
819 ERROUT:
820     return -1;
821 }
822 
mq_timedreceive(mqd_t personal,char * msg,size_t msgLen,unsigned int * msgPrio,const struct timespec * absTimeout)823 ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio,
824                         const struct timespec *absTimeout)
825 {
826     UINT32 mqueueID, err;
827     UINT32 receiveLen;
828     UINT64 absTicks;
829     struct mqarray *mqueueCB = NULL;
830     struct mqpersonal *privateMqPersonal = NULL;
831 
832     if (!MqParamCheck(personal, msg, msgLen)) {
833         goto ERROUT;
834     }
835 
836     if (msgPrio != NULL) {
837         *msgPrio = 0;
838     }
839 
840     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
841     privateMqPersonal = MqGetPrivDataBuff(personal);
842     if (privateMqPersonal == NULL || privateMqPersonal->mq_status != MQ_USE_MAGIC) {
843         errno = EBADF;
844         goto ERROUT_UNLOCK;
845     }
846 
847     mqueueCB = privateMqPersonal->mq_posixdes;
848     if (msgLen < (size_t)(mqueueCB->mqcb->queueSize - sizeof(UINT32))) {
849         errno = EMSGSIZE;
850         goto ERROUT_UNLOCK;
851     }
852 
853     if (((UINT32)privateMqPersonal->mq_flags & (UINT32)O_WRONLY) == (UINT32)O_WRONLY) {
854         errno = EBADF;
855         goto ERROUT_UNLOCK;
856     }
857 
858     if (ConvertTimeout(privateMqPersonal->mq_flags, absTimeout, &absTicks) == -1) {
859         goto ERROUT_UNLOCK;
860     }
861 
862     receiveLen = msgLen;
863     mqueueID = mqueueCB->mq_id;
864     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
865 
866     err = LOS_QueueReadCopy(mqueueID, (VOID *)msg, &receiveLen, (UINT32)absTicks);
867     if (map_errno(err) == ENOERR) {
868         return (ssize_t)receiveLen;
869     } else {
870         goto ERROUT;
871     }
872 
873 ERROUT_UNLOCK:
874     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
875 ERROUT:
876     return -1;
877 }
878 
879 /* not support the prio */
mq_send(mqd_t personal,const char * msg_ptr,size_t msg_len,unsigned int msg_prio)880 int mq_send(mqd_t personal, const char *msg_ptr, size_t msg_len, unsigned int msg_prio)
881 {
882     return mq_timedsend(personal, msg_ptr, msg_len, msg_prio, NULL);
883 }
884 
mq_receive(mqd_t personal,char * msg_ptr,size_t msg_len,unsigned int * msg_prio)885 ssize_t mq_receive(mqd_t personal, char *msg_ptr, size_t msg_len, unsigned int *msg_prio)
886 {
887     return mq_timedreceive(personal, msg_ptr, msg_len, msg_prio, NULL);
888 }
889 
MqNotifyParamCheck(mqd_t personal,const struct sigevent * sigev)890 STATIC INLINE BOOL MqNotifyParamCheck(mqd_t personal, const struct sigevent *sigev)
891 {
892     if (personal < 0) {
893         errno = EBADF;
894         goto ERROUT;
895     }
896 
897     if (sigev != NULL) {
898         if (sigev->sigev_notify != SIGEV_NONE && sigev->sigev_notify != SIGEV_SIGNAL) {
899             errno = EINVAL;
900             goto ERROUT;
901         }
902         if (sigev->sigev_notify == SIGEV_SIGNAL && !GOOD_SIGNO(sigev->sigev_signo)) {
903             errno = EINVAL;
904             goto ERROUT;
905         }
906     }
907 
908     return TRUE;
909 ERROUT:
910     return FALSE;
911 }
912 
OsMqNotify(mqd_t personal,const struct sigevent * sigev)913 int OsMqNotify(mqd_t personal, const struct sigevent *sigev)
914 {
915     struct mqarray *mqueueCB = NULL;
916     struct mqnotify *mqnotify = NULL;
917     struct mqpersonal *privateMqPersonal = NULL;
918 
919     if (!MqNotifyParamCheck(personal, sigev)) {
920         goto ERROUT;
921     }
922 
923     (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
924     privateMqPersonal = MqGetPrivDataBuff(personal);
925     if (privateMqPersonal == NULL) {
926         goto OUT_UNLOCK;
927     }
928 
929     if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
930         errno = EBADF;
931         goto OUT_UNLOCK;
932     }
933 
934     mqueueCB = privateMqPersonal->mq_posixdes;
935     mqnotify = &mqueueCB->mq_notify;
936 
937     if (sigev == NULL) {
938         if (mqnotify->pid == LOS_GetCurrProcessID()) {
939             mqnotify->pid = 0;
940         }
941     } else if (mqnotify->pid != 0) {
942         errno = EBUSY;
943         goto OUT_UNLOCK;
944     } else {
945         switch (sigev->sigev_notify) {
946             case SIGEV_NONE:
947                 mqnotify->notify.sigev_notify = SIGEV_NONE;
948                 break;
949             case SIGEV_SIGNAL:
950                 mqnotify->notify.sigev_signo = sigev->sigev_signo;
951                 mqnotify->notify.sigev_value = sigev->sigev_value;
952                 mqnotify->notify.sigev_notify = SIGEV_SIGNAL;
953                 break;
954             default:
955                 break;
956         }
957 
958         mqnotify->pid = LOS_GetCurrProcessID();
959     }
960 
961     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
962     return 0;
963 OUT_UNLOCK:
964     (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
965 ERROUT:
966     return -1;
967 }
968 
OsMqueueCBDestroy(struct mqarray * queueTable)969 VOID OsMqueueCBDestroy(struct mqarray *queueTable)
970 {
971     if (queueTable == NULL) {
972         return;
973     }
974 
975     for (UINT32 index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
976         struct mqarray *mqueueCB = &(queueTable[index]);
977         if (mqueueCB->mq_name == NULL) {
978             continue;
979         }
980         (VOID)DoMqueueClose(mqueueCB->mq_personal);
981     }
982 }
983 #endif
984