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