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