Fawkes API  Fawkes Development Version
msg.cpp
00001 
00002 /***************************************************************************
00003  *  msg.cpp - IPC message queue
00004  *
00005  *  Generated: Mon Mar 13 17:44:59 2006
00006  *  Copyright  2005-2006  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <utils/ipc/msg.h>
00025 #include <utils/ipc/msg_exceptions.h>
00026 
00027 #include <errno.h>
00028 
00029 #include <sys/types.h>
00030 #include <sys/ipc.h>
00031 #include <sys/msg.h>
00032 
00033 namespace fawkes {
00034 
00035 /// @cond INTERNALS
00036 class IPCMessageQueueData
00037 {
00038  public:
00039   key_t   key;
00040   int     msgqid;
00041   int     msgflg;
00042 
00043 };
00044 /// @endcond
00045 
00046 /** @class IPCMessageQueue utils/ipc/msg.h
00047  * IPC message queue.
00048  * This class gives access to IPC message queues. You can use this to send
00049  * messages between different applications running on the same host.
00050  *
00051  * @see qa_ipc_msg.cpp
00052  * @ingroup IPC
00053  * @author Tim Niemueller
00054  *
00055  *
00056  * @var IPCMessageQueue::destroy_on_delete
00057  * destroy this message queue on delete?
00058  *
00059  */
00060 
00061 
00062 /** Maximum size of a message.
00063  */
00064 const int IPCMessageQueue::MaxMessageSize = 8192; // from linux/msg.h
00065 
00066 
00067 /** Create or open a message queue
00068  * If a message key with the given identification criteria exists it is
00069  * opened for sending and receiving. If no such queue exists a new one is
00070  * create. Use isValid() to check success.
00071  * @param path path given to ftok to create the message queue identifier
00072  * @param id id given to ftok to create the message queue identifier
00073  * @param destroy_on_delete destroy the message queue if the dtor is called?
00074  * @param create Create the queue if it does not exist, do not create the queue
00075  *               otherwise, use isValid() to check if queue was opened
00076  */
00077 IPCMessageQueue::IPCMessageQueue(const char *path, char id,
00078                                  bool create, bool destroy_on_delete)
00079 {
00080   data = new IPCMessageQueueData();
00081 
00082   this->destroy_on_delete = destroy_on_delete;
00083 
00084   data->msgflg = 0666;
00085   if (create) {
00086     data->msgflg |= IPC_CREAT;
00087   }
00088 
00089   data->key = ftok(path, id);
00090   data->msgqid = msgget(data->key, data->msgflg);
00091 }
00092 
00093 
00094 /** Create or open a message queue
00095  * This is a simplified version of the above function. The path is omitted
00096  * and . (dot, the current working directory) is used instead.
00097  * @param id id give to ftok to create the message queue identifier, preferably
00098  *           use an id from msg_registry.h
00099  * @param destroy_on_delete set to true to destroy the message queue if the dtor is called
00100  * @param create if true create the queue if it does not exist, do not create the queue
00101  *               otherwise, use isValid() to check if queue was opened successfully.
00102  */
00103 IPCMessageQueue::IPCMessageQueue(int id, bool create, bool destroy_on_delete)
00104 {
00105   data = new IPCMessageQueueData();
00106 
00107   this->destroy_on_delete = destroy_on_delete;
00108 
00109   data->msgflg = 0666;
00110   if (create) {
00111     data->msgflg |= IPC_CREAT;
00112   }
00113 
00114   data->key = id;
00115   data->msgqid = msgget(data->key, data->msgflg);
00116 }
00117 
00118 
00119 /** Destructor */
00120 IPCMessageQueue::~IPCMessageQueue()
00121 {
00122   if ((data->msgqid != -1) && destroy_on_delete) {
00123     msgctl(data->msgqid, IPC_RMID, 0);
00124   }
00125   delete data;
00126 }
00127 
00128 
00129 /** Check if the message queue is valid
00130  * If the queue could not be opened yet (for example if you gave create=false to the
00131  * constructor) isValid() will try to open the queue.
00132  * @return This method returns false if the message queue could not be opened
00133  *         or if it has been closed, it returns true if messages can be sent or received.
00134  */
00135 bool
00136 IPCMessageQueue::isValid()
00137 {
00138   if (data->msgqid == -1) {
00139     data->msgqid = msgget(data->key, data->msgflg);
00140     if (data->msgqid == -1) {
00141       return false;
00142     } else {
00143       struct msqid_ds m;
00144       if (msgctl(data->msgqid, IPC_STAT, &m) != -1) {
00145         return true;
00146       } else {
00147         data->msgqid = -1;
00148         return false;
00149       }
00150     }
00151   } else {
00152     struct msqid_ds m;
00153     if (msgctl(data->msgqid, IPC_STAT, &m) != -1) {
00154       return true;
00155     } else {
00156       data->msgqid = -1;
00157       return false;
00158     }
00159   }
00160 }
00161 
00162 
00163 /** Receive messages from this queue of the given message type
00164  * @param mtype the message type
00165  * @param msg The place where the received data will be copied on success.
00166  * You _must_ have the mtype long field as described for MessageStruct. On recv the
00167  * struct does not have to be inialized,
00168  * but the memory has to be allocated already. See the note about the data_size!
00169  * @param data_size The size of the _whole_ struct, including the mtype field. NOT
00170  * just the size of the mtext field as for msgrcv!
00171  * @return returns true, if a message of the appropriate type could be read that fitted
00172  *         the given memory size. The received data is stored in data.
00173  * @see MessageStruct
00174  * @exception MessageTooBigException Message was too big and did not fit into buffer.
00175  *                                   Message remains on queue and needs to be fetched
00176  *                                   with a bigger buffer.
00177  */
00178 bool
00179 IPCMessageQueue::recv(long mtype, MessageStruct *msg, unsigned int data_size)
00180 {
00181   if (data->msgqid == -1) return false;
00182 
00183   if ( msgrcv(data->msgqid, (struct msgbuf *)msg, data_size - sizeof(long),
00184               mtype, IPC_NOWAIT) == -1 ) {
00185     if ((errno == EIDRM) || (errno == EINVAL)) {
00186       data->msgqid = -1;
00187     }
00188     if (errno == E2BIG) {
00189       throw MessageTooBigException();
00190     }
00191     return false;
00192   } else {
00193     return true;
00194   }
00195 }
00196 
00197 
00198 /** Receive messages from this queue of any type
00199  * @param msg a pointer to a message struct of the appropriate size. This is
00200  *            most likely your own incarnation. It must point to a chunk of memory
00201  *            which has at least max_data_size bytes.
00202  * @param max_data_size The maximum size the data may have.
00203  * @param data_size after successfuly recv will contain the number of bytes actually
00204  *        copied into data including the size of the mtype field!
00205  * @return true, if a message could be read that fitted
00206  *         the given memory size. The received data is stored in data. False, if
00207  *         no message was in the queue or the queue has been removed.
00208  * @see MessageStruct
00209  */
00210 bool
00211 IPCMessageQueue::recvNext(MessageStruct *msg, unsigned int max_data_size,
00212                        int *data_size)
00213 {
00214   if (data->msgqid == -1) return false;
00215 
00216   if ( (*data_size = msgrcv(data->msgqid, (struct msgbuf *)msg,
00217                             max_data_size - sizeof(long), 0, IPC_NOWAIT)) == -1 ) {
00218     if ((errno == EIDRM) || (errno == EINVAL)) {
00219       data->msgqid = -1;
00220     }
00221     return false;
00222   } else {
00223     return true;
00224   }
00225 }
00226 
00227 
00228 /** Receive messages from this queue of the given message type
00229  * @param msg The data to be sent, see note for recv()
00230  * @param data_size the full data size (sizeof(typeof(data))), NOT just the size of the
00231  * mtext field (see recv()).
00232  * @return true, if the message could be sent, false otherwise.
00233  * @see MessageStruct
00234  */
00235 bool
00236 IPCMessageQueue::send(MessageStruct *msg, unsigned int data_size)
00237 {
00238   if (data->msgqid == -1) return false;
00239 
00240   if (msgsnd(data->msgqid, msg, data_size - sizeof(long), IPC_NOWAIT) == -1) {
00241     if (errno == EIDRM) {
00242       data->msgqid = -1;
00243     }
00244     return false;
00245   } else {
00246     return true;
00247   }
00248 }
00249 
00250 
00251 } // end namespace fawkes