Fawkes API Fawkes Development Version
|
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