Fawkes API  Fawkes Development Version
msg.cpp
1 
2 /***************************************************************************
3  * msg.cpp - IPC message queue
4  *
5  * Generated: Mon Mar 13 17:44:59 2006
6  * Copyright 2005-2006 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <sys/ipc.h>
25 #include <sys/msg.h>
26 #include <sys/types.h>
27 #include <utils/ipc/msg.h>
28 #include <utils/ipc/msg_exceptions.h>
29 
30 #include <errno.h>
31 
32 namespace fawkes {
33 
34 /// @cond INTERNALS
35 class IPCMessageQueueData
36 {
37 public:
38  key_t key;
39  int msgqid;
40  int msgflg;
41 };
42 /// @endcond
43 
44 /** @class IPCMessageQueue utils/ipc/msg.h
45  * IPC message queue.
46  * This class gives access to IPC message queues. You can use this to send
47  * messages between different applications running on the same host.
48  *
49  * @see qa_ipc_msg.cpp
50  * @ingroup IPC
51  * @author Tim Niemueller
52  *
53  *
54  * @var IPCMessageQueue::destroy_on_delete
55  * destroy this message queue on delete?
56  *
57  */
58 
59 /** Maximum size of a message.
60  */
61 const int IPCMessageQueue::MaxMessageSize = 8192; // from linux/msg.h
62 
63 /** Create or open a message queue
64  * If a message key with the given identification criteria exists it is
65  * opened for sending and receiving. If no such queue exists a new one is
66  * create. Use isValid() to check success.
67  * @param path path given to ftok to create the message queue identifier
68  * @param id id given to ftok to create the message queue identifier
69  * @param destroy_on_delete destroy the message queue if the dtor is called?
70  * @param create Create the queue if it does not exist, do not create the queue
71  * otherwise, use isValid() to check if queue was opened
72  */
73 IPCMessageQueue::IPCMessageQueue(const char *path, char id, bool create, bool destroy_on_delete)
74 {
75  data = new IPCMessageQueueData();
76 
77  this->destroy_on_delete = destroy_on_delete;
78 
79  data->msgflg = 0666;
80  if (create) {
81  data->msgflg |= IPC_CREAT;
82  }
83 
84  data->key = ftok(path, id);
85  data->msgqid = msgget(data->key, data->msgflg);
86 }
87 
88 /** Create or open a message queue
89  * This is a simplified version of the above function. The path is omitted
90  * and . (dot, the current working directory) is used instead.
91  * @param id id give to ftok to create the message queue identifier, preferably
92  * use an id from msg_registry.h
93  * @param destroy_on_delete set to true to destroy the message queue if the dtor is called
94  * @param create if true create the queue if it does not exist, do not create the queue
95  * otherwise, use isValid() to check if queue was opened successfully.
96  */
97 IPCMessageQueue::IPCMessageQueue(int id, bool create, bool destroy_on_delete)
98 {
99  data = new IPCMessageQueueData();
100 
101  this->destroy_on_delete = destroy_on_delete;
102 
103  data->msgflg = 0666;
104  if (create) {
105  data->msgflg |= IPC_CREAT;
106  }
107 
108  data->key = id;
109  data->msgqid = msgget(data->key, data->msgflg);
110 }
111 
112 /** Destructor */
114 {
115  if ((data->msgqid != -1) && destroy_on_delete) {
116  msgctl(data->msgqid, IPC_RMID, 0);
117  }
118  delete data;
119 }
120 
121 /** Check if the message queue is valid
122  * If the queue could not be opened yet (for example if you gave create=false to the
123  * constructor) isValid() will try to open the queue.
124  * @return This method returns false if the message queue could not be opened
125  * or if it has been closed, it returns true if messages can be sent or received.
126  */
127 bool
129 {
130  if (data->msgqid == -1) {
131  data->msgqid = msgget(data->key, data->msgflg);
132  if (data->msgqid == -1) {
133  return false;
134  } else {
135  struct msqid_ds m;
136  if (msgctl(data->msgqid, IPC_STAT, &m) != -1) {
137  return true;
138  } else {
139  data->msgqid = -1;
140  return false;
141  }
142  }
143  } else {
144  struct msqid_ds m;
145  if (msgctl(data->msgqid, IPC_STAT, &m) != -1) {
146  return true;
147  } else {
148  data->msgqid = -1;
149  return false;
150  }
151  }
152 }
153 
154 /** Receive messages from this queue of the given message type
155  * @param mtype the message type
156  * @param msg The place where the received data will be copied on success.
157  * You _must_ have the mtype long field as described for MessageStruct. On recv the
158  * struct does not have to be inialized,
159  * but the memory has to be allocated already. See the note about the data_size!
160  * @param data_size The size of the _whole_ struct, including the mtype field. NOT
161  * just the size of the mtext field as for msgrcv!
162  * @return returns true, if a message of the appropriate type could be read that fitted
163  * the given memory size. The received data is stored in data.
164  * @see MessageStruct
165  * @exception MessageTooBigException Message was too big and did not fit into buffer.
166  * Message remains on queue and needs to be fetched
167  * with a bigger buffer.
168  */
169 bool
170 IPCMessageQueue::recv(long mtype, MessageStruct *msg, unsigned int data_size)
171 {
172  if (data->msgqid == -1)
173  return false;
174 
175  if (msgrcv(data->msgqid, (struct msgbuf *)msg, data_size - sizeof(long), mtype, IPC_NOWAIT)
176  == -1) {
177  if ((errno == EIDRM) || (errno == EINVAL)) {
178  data->msgqid = -1;
179  }
180  if (errno == E2BIG) {
181  throw MessageTooBigException();
182  }
183  return false;
184  } else {
185  return true;
186  }
187 }
188 
189 /** Receive messages from this queue of any type
190  * @param msg a pointer to a message struct of the appropriate size. This is
191  * most likely your own incarnation. It must point to a chunk of memory
192  * which has at least max_data_size bytes.
193  * @param max_data_size The maximum size the data may have.
194  * @param data_size after successfuly recv will contain the number of bytes actually
195  * copied into data including the size of the mtype field!
196  * @return true, if a message could be read that fitted
197  * the given memory size. The received data is stored in data. False, if
198  * no message was in the queue or the queue has been removed.
199  * @see MessageStruct
200  */
201 bool
202 IPCMessageQueue::recvNext(MessageStruct *msg, unsigned int max_data_size, int *data_size)
203 {
204  if (data->msgqid == -1)
205  return false;
206 
207  if ((*data_size =
208  msgrcv(data->msgqid, (struct msgbuf *)msg, max_data_size - sizeof(long), 0, IPC_NOWAIT))
209  == -1) {
210  if ((errno == EIDRM) || (errno == EINVAL)) {
211  data->msgqid = -1;
212  }
213  return false;
214  } else {
215  return true;
216  }
217 }
218 
219 /** Receive messages from this queue of the given message type
220  * @param msg The data to be sent, see note for recv()
221  * @param data_size the full data size (sizeof(typeof(data))), NOT just the size of the
222  * mtext field (see recv()).
223  * @return true, if the message could be sent, false otherwise.
224  * @see MessageStruct
225  */
226 bool
227 IPCMessageQueue::send(MessageStruct *msg, unsigned int data_size)
228 {
229  if (data->msgqid == -1)
230  return false;
231 
232  if (msgsnd(data->msgqid, msg, data_size - sizeof(long), IPC_NOWAIT) == -1) {
233  if (errno == EIDRM) {
234  data->msgqid = -1;
235  }
236  return false;
237  } else {
238  return true;
239  }
240 }
241 
242 } // end namespace fawkes
bool send(MessageStruct *msg, unsigned int data_size)
Receive messages from this queue of the given message type.
Definition: msg.cpp:227
bool recvNext(MessageStruct *msg, unsigned int max_data_size, int *data_size)
Receive messages from this queue of any type.
Definition: msg.cpp:202
Fawkes library namespace.
bool isValid()
Check if the message queue is valid If the queue could not be opened yet (for example if you gave cre...
Definition: msg.cpp:128
~IPCMessageQueue()
Destructor.
Definition: msg.cpp:113
bool destroy_on_delete
destroy this message queue on delete?
Definition: msg.h:69
IPCMessageQueue(const char *path, char id, bool create=false, bool destroy_on_delete=false)
Create or open a message queue If a message key with the given identification criteria exists it is o...
Definition: msg.cpp:73
static const int MaxMessageSize
Maximum size of a message.
Definition: msg.h:34
This is the struct of the messages that has to be fed to send and receive methods.
Definition: msg.h:39
bool recv(long mtype, MessageStruct *msg, unsigned int data_size)
Receive messages from this queue of the given message type.
Definition: msg.cpp:170
Message did not fit into buffer.
static long mtype(char *buffer)
Get the message type.
Definition: msg.h:63