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