1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** POSIX wrapper for THREADX                                             */
16 /**                                                                       */
17 /**                                                                       */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 /* Include necessary system files.  */
23 
24 #include "tx_api.h"     /* Threadx API */
25 #include "pthread.h"    /* Posix API */
26 #include "px_int.h"     /* Posix helper functions */
27 
28 
29 /**************************************************************************/
30 /*                                                                        */
31 /*  FUNCTION                                               RELEASE        */
32 /*                                                                        */
33 /*    mq_open                                             PORTABLE C      */
34 /*                                                           6.2.0        */
35 /*  AUTHOR                                                                */
36 /*                                                                        */
37 /*    William E. Lamie, Microsoft Corporation                             */
38 /*                                                                        */
39 /*  DESCRIPTION                                                           */
40 /*                                                                        */
41 /*    This routine establishes connection between a named message queue   */
42 /*    and the calling a thread                                            */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    mqName                      name of the queue to open.              */
47 /*    oflags                      O_RDONLY, O_WRONLY, O_RDWR, or O_CREAT, */
48 /*                                O_EXCEL,O_NONBLOCK.                     */
49 /*                                extra optional parameters.              */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*     queue_des                  If successful                           */
54 /*     ERROR                      If fails                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    posix_find_queue            find queue of given name                */
59 /*    posix_mq_create             create a queue                          */
60 /*    posix_get_queue_des         gets a queue-descriptor for Queue       */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    Application Code                                                    */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  06-02-2021      William E. Lamie        Initial Version 6.1.7         */
71 /*  10-31-2022      Scott Larson            Update comparison with NULL,  */
72 /*                                            resulting in version 6.2.0  */
73 /*                                                                        */
74 /**************************************************************************/
mq_open(const CHAR * mqName,ULONG oflags,...)75 mqd_t  mq_open(const CHAR * mqName, ULONG oflags,...)
76 {
77 
78 POSIX_MSG_QUEUE     *posix_queue;
79 struct mq_des       *queue_des;
80 struct mq_attr      *q_attr;
81 mode_t               mode;
82 va_list              create_queue;
83 ULONG                len;
84 ULONG                temp1;
85 
86     len = strlen(mqName);
87     if(len > PATH_MAX)
88     {
89         /* Return error.  */
90         posix_errno = ENAMETOOLONG;
91         posix_set_pthread_errno(ENAMETOOLONG);
92 
93         /*. Return error.  */
94         return((struct mq_des *)ERROR);
95     }
96     switch(oflags & 0xFF00)
97     {
98         case O_CREAT:
99 
100         case (O_EXCL | O_CREAT):
101 
102              va_start(create_queue, oflags);
103              mode   = va_arg(create_queue, mode_t);
104              mode = mode;  /* just to keep the complier happy */
105              q_attr = va_arg(create_queue, struct mq_attr *);
106              va_end(create_queue);
107 
108              /* Check for valid messages and its size.  */
109              if(!q_attr || q_attr->mq_maxmsg > MQ_MAXMSG || q_attr->mq_msgsize > MQ_MSGSIZE)
110              {
111                  /* return POSIX error.for invalid oflag.  */
112                  posix_errno = EINVAL;
113                  posix_set_pthread_errno(EINVAL);
114                  /* return error.  */
115                  return ((struct mq_des *)ERROR);
116              }
117 
118              /* Check if name is exist. NULL if successful.  */
119              if((posix_queue = posix_find_queue(mqName)) != NULL)
120              {
121                  if(posix_queue->unlink_flag == TX_TRUE)
122                  {
123                      /* return POSIX error.  */
124                      posix_errno = ENOENT;
125                  posix_set_pthread_errno(ENOENT);
126                     /* return error.  */
127                     return ((struct mq_des *)ERROR);
128                  }
129 
130                  /* Set Posix error if name exist.  */
131                  posix_errno = EEXIST;
132                  posix_set_pthread_errno(EEXIST);
133                  /* return error */
134                  return((struct mq_des *)ERROR);
135              }
136 
137              /* If q_attr is NULL then the default attributes of the struct
138                 mq_attr are used */
139              if(q_attr == NULL)
140              {
141                  q_attr = &(posix_qattr_default);
142                  temp1 = q_attr->mq_maxmsg;
143                  temp1= temp1 ;         /* Just to keep complier happy */
144              }
145 
146              /* Create a queue which returns posix queue if successful and
147                 NULL if fails.  */
148              if(!(posix_queue = posix_mq_create(mqName, q_attr)))
149              {
150 
151                 /* posix_errno is filled up in mq_create.  */
152                 return((struct mq_des *)ERROR);
153              }
154              /* open count incremented by one.  */
155              posix_queue->open_count += 1;
156              break;
157 
158         case O_EXCL:
159             /* Check if name is exist. NULL if successful.  */
160             if(!(posix_queue = posix_find_queue(mqName)))
161             {
162                 /* return POSIX error.  */
163                 posix_errno = EBADF;
164                 posix_set_pthread_errno(EBADF);
165                 /* return error.  */
166                 return ((struct mq_des *)ERROR);
167             }
168 
169             return(OK);
170 
171         case O_RDONLY:
172         case O_WRONLY:
173         case O_RDWR:
174         case O_NONBLOCK:
175             /* Check if name is exist. NULL if successful.  */
176             if((posix_queue = posix_find_queue(mqName)) != NULL)
177             {
178                 if(posix_queue->unlink_flag == TX_TRUE)
179                 {
180                     /* return POSIX error.  */
181                     posix_errno = ENOENT;
182                     posix_set_pthread_errno(ENOENT);
183                     /* return error.  */
184                     return ((struct mq_des *)ERROR);
185                 }
186                 /* open count incremented by one.  */
187                 posix_queue->open_count += 1;
188             }
189             break;
190 
191     default:
192             /* return POSIX error.for invalid oflag.  */
193             posix_errno = EINVAL;
194             posix_set_pthread_errno(EINVAL);
195             /* return error.  */
196             return ((struct mq_des *)ERROR);
197     }
198 
199     queue_des = posix_get_queue_des(posix_queue);
200     /* Store the flags.  */
201     queue_des->f_flag = oflags;
202     return(queue_des);
203 }
204