cis_config: /root/cis_interface/cis_interface/cis_interface/communication/IPCComm.h Source File

cis_config

IPCComm.h
1
2 #ifndef CISIPCCOMM_H_
3 #define CISIPCCOMM_H_
4
5 #ifdef IPCINSTALLED
6 #include <fcntl.h> /* For O_* constants */
7 #include <sys/stat.h> /* For mode constants */
8 #include <sys/msg.h>
9 #include <sys/types.h>
10 #include <sys/sem.h>
11 #include <sys/shm.h>
12 #endif /*IPCINSTALLED*/
13 #include <CommBase.h>
14
15 #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
16 extern "C" {
17 #endif
18
19 #ifdef IPCINSTALLED
20
22 static unsigned _cisChannelsCreated = 0;
24 #define _cisTrackChannels 256
25
26 static int _cisChannelNames[_cisTrackChannels];
27 //static char * _cisChannelNames[_cisTrackChannels];
29 static unsigned _cisChannelsUsed = 0;
30 static unsigned _ipc_rand_seeded = 0;
31
35 typedef struct msgbuf_t {
36 long mtype;
37 char data[CIS_MSG_MAX];
38 } msgbuf_t;
39
45 static inline
46 int check_channels(comm_t comm) {
47 // Fail if name is empty
48 if (strlen(comm.name) == 0) {
49 cislog_error("Cannot create channel with empty name.");
50 return -1;
51 }
52 // Fail if trying to re-use the same channel twice
53 unsigned i;
54 char *key = comm.address;
55 for (i = 0; i < _cisChannelsUsed; i++ ) {
56 if (_cisChannelNames[i] == atoi(comm.address)) {
57 /* if (0 == strcmp(_cisChannelNames[i], key)) { */
58 cislog_error("Attempt to re-use channel: name=%s, key=%s, i=%d",
59 comm.name, key, i);
60 return -1;
61 }
62 }
63 // Fail if > _cisTrackChannels channels used
64 if (_cisChannelsUsed >= _cisTrackChannels) {
65 cislog_error("Too many channels in use, max: %d", _cisTrackChannels);
66 return -1;
67 }
68 return 0;
69 };
70
75 static inline
76 void add_channel(const comm_t comm) {
77 // printf("add_channel(%s): %d, %s\n", comm.name, _cisChannelsUsed, comm.address);
78 _cisChannelNames[_cisChannelsUsed++] = atoi(comm.address);
79 };
80
89 static inline
90 int remove_comm(const comm_t comm, const int close_comm) {
91 int ret;
92 if (close_comm) {
93 ret = msgctl(((int*)comm.handle)[0], IPC_RMID, NULL);
94 /* if (ret < 0) { */
95 /* cislog_error("remove_comm(%s): Could not close comm.", comm.name); */
96 /* return ret; */
97 /* } */
98 }
99 ret = -1;
100 unsigned i;
101 int ich = atoi(comm.address);
102 for (i = 0; i < _cisChannelsUsed; i++) {
103 if (ich == _cisChannelNames[i]) {
104 memmove(_cisChannelNames + i, _cisChannelNames + i + 1,
105 (_cisTrackChannels - (i + 1))*sizeof(int));
106 _cisChannelsUsed--;
107 ret = 0;
108 break;
109 }
110 }
111 if (ret < 0) {
112 cislog_error("remove_comm(%s): Could not locate comm in register.", comm.name);
113 }
114 /* if ((ret != -1) && (ich == (int)(_cisChannelsUsed - 1))) { */
115 /* /\* memmove(_cisChannelNames + ich, _cisChannelNames + ich + 1, *\/ */
116 /* /\* (_cisTrackChannels - (ich + 1))*sizeof(char*)); *\/ */
117 /* _cisChannelsUsed--; */
118 /* } */
119 return ret;
120 };
121
127 static inline
128 int new_ipc_address(comm_t *comm) {
129 int ret;
130 // TODO: small chance of reusing same number
131 int key = 0;
132 if (!(_ipc_rand_seeded)) {
133 srand(ptr2seed(comm));
134 _ipc_rand_seeded = 1;
135 }
136 while (key == 0) {
137 key = rand();
138 } // _cisChannelsUsed + 1;
139 if (strlen(comm->name) == 0) {
140 sprintf(comm->name, "tempnewIPC.%d", key);
141 } else {
142 ret = check_channels(*comm);
143 if (ret < 0)
144 return ret;
145 }
146 sprintf(comm->address, "%d", key);
147 int *fid = (int*)malloc(sizeof(int));
148 if (fid == NULL) {
149 cislog_error("new_ipc_address: Could not malloc queue fid.");
150 return -1;
151 }
152 fid[0] = msgget(key, (IPC_CREAT | 0777));
153 if (fid[0] < 0) {
154 cislog_error("new_ipc_address: msgget(%d, %d | 0777) ret(%d), errno(%d): %s",
155 key, IPC_CREAT, fid[0], errno, strerror(errno));
156 return -1;
157 }
158 comm->handle = (void*)fid;
159 add_channel(*comm);
160 _cisChannelsCreated++;
161 return 0;
162 };
163
169 static inline
170 int init_ipc_comm(comm_t *comm) {
171 if (comm->valid == 0)
172 return -1;
173 if (strlen(comm->name) == 0) {
174 sprintf(comm->name, "tempinitIPC.%s", comm->address);
175 } else {
176 int ret = check_channels(*comm);
177 if (ret < 0)
178 return ret;
179 }
180 add_channel(*comm);
181 int qkey = atoi(comm->address);
182 int *fid = (int *)malloc(sizeof(int));
183 if (fid == NULL) {
184 cislog_error("init_ipc_comm: Could not malloc queue fid.");
185 return -1;
186 }
187 fid[0] = msgget(qkey, 0600);
188 if (fid[0] < 0) {
189 cislog_error("init_ipc_address: msgget(%d, 0600) ret(%d), errno(%d): %s",
190 qkey, fid[0], errno, strerror(errno));
191 return -1;
192 }
193 comm->handle = (void*)fid;
194 return 0;
195 };
196
202 static inline
203 int free_ipc_comm(comm_t *x) {
204 if (x->handle != NULL) {
205 if (strcmp(x->direction, "recv") == 0) {
206 remove_comm(*x, 1);
207 } else {
208 remove_comm(*x, 0);
209 }
210 free(x->handle);
211 x->handle = NULL;
212 }
213 return 0;
214 };
215
221 static inline
222 int ipc_comm_nmsg(const comm_t x) {
223 struct msqid_ds buf;
224 if (x.handle == NULL) {
225 cislog_error("ipc_comm_nmsg: Queue handle is NULL.");
226 return -1;
227 }
228 int rc = msgctl(((int*)x.handle)[0], IPC_STAT, &buf);
229 if (rc != 0) {
230 /* cislog_error("ipc_comm_nmsg: Could not access queue."); */
231 return 0;
232 }
233 int ret = buf.msg_qnum;
234 return ret;
235 };
236
246 static inline
247 int ipc_comm_send(const comm_t x, const char *data, const size_t len) {
248 cislog_debug("ipc_comm_send(%s): %d bytes", x.name, len);
249 if (comm_base_send(x, data, len) == -1)
250 return -1;
251 msgbuf_t t;
252 t.mtype = 1;
253 memcpy(t.data, data, len);
254 int ret = -1;
255 int handle = ((int*)(x.handle))[0];
256 while (1) {
257 ret = msgsnd(handle, &t, len, IPC_NOWAIT);
258 cislog_debug("ipc_comm_send(%s): msgsnd returned %d", x.name, ret);
259 if (ret == 0) break;
260 if ((ret == -1) && (errno == EAGAIN)) {
261 cislog_debug("ipc_comm_send(%s): msgsnd, sleep", x.name);
262 usleep(CIS_SLEEP_TIME);
263 } else {
264 cislog_error("ipc_comm_send: msgsend(%d, %p, %d, IPC_NOWAIT) ret(%d), errno(%d): %s",
265 (int*)x.handle, &t, len, ret, errno, strerror(errno));
266 ret = -1;
267 break;
268 }
269 }
270 cislog_debug("ipc_comm_send(%s): returning %d", x.name, ret);
271 return ret;
272 };
273
286 static inline
287 int ipc_comm_recv(const comm_t x, char **data, const size_t len,
288 const int allow_realloc) {
289 cislog_debug("ipc_comm_recv(%s)", x.name);
290 msgbuf_t t;
291 t.mtype = 1;
292 int ret = -1;
293 int len_recv = -1;
294 while (1) {
295 ret = msgrcv(((int*)x.handle)[0], &t, CIS_MSG_MAX, 0, IPC_NOWAIT);
296 if (ret == -1 && errno == ENOMSG) {
297 cislog_debug("ipc_comm_recv(%s): no input, sleep", x.name);
298 usleep(CIS_SLEEP_TIME);
299 } else {
300 cislog_debug("ipc_comm_recv(%s): received input: %d bytes, ret=%d",
301 x.name, strlen(t.data), ret);
302 break;
303 }
304 }
305 if (ret <= 0) {
306 cislog_debug("ipc_comm_recv: msgrecv(%d, %p, %d, 0, IPC_NOWAIT): %s",
307 (int*)x.handle, &t, (int)CIS_MSG_MAX, strerror(errno));
308 return -1;
309 }
310 len_recv = ret + 1;
311 if (len_recv > (int)len) {
312 if (allow_realloc) {
313 cislog_debug("ipc_comm_recv(%s): reallocating buffer from %d to %d bytes.",
314 x.name, (int)len, len_recv);
315 (*data) = (char*)realloc(*data, len_recv);
316 if (*data == NULL) {
317 cislog_error("ipc_comm_recv(%s): failed to realloc buffer.", x.name);
318 return -1;
319 }
320 } else {
321 cislog_error("ipc_comm_recv(%s): buffer (%d bytes) is not large enough for message (%d bytes)",
322 x.name, len, len_recv);
323 return -(len_recv - 1);
324 }
325 }
326 memcpy(*data, t.data, len_recv);
327 (*data)[len_recv - 1] = '\0';
328 ret = len_recv - 1;
329 cislog_debug("ipc_comm_recv(%s): returns %d bytes", x.name, ret);
330 return ret;
331 };
332
344 static inline
345 int ipc_comm_send_nolimit(const comm_t x, const char *data, const size_t len){
346 cislog_debug("ipc_comm_send_nolimit(%s): %d bytes", x.name, len);
347 int ret = -1;
348 size_t msgsiz = 0;
349 char msg[CIS_MSG_MAX];
350 sprintf(msg, "%ld", (long)(len));
351 ret = ipc_comm_send(x, msg, strlen(msg));
352 if (ret != 0) {
353 cislog_debug("ipc_comm_send_nolimit(%s): sending size of payload failed.", x.name);
354 return ret;
355 }
356 size_t prev = 0;
357 while (prev < len) {
358 if ((len - prev) > CIS_MSG_MAX)
359 msgsiz = CIS_MSG_MAX;
360 else
361 msgsiz = len - prev;
362 ret = ipc_comm_send(x, data + prev, msgsiz);
363 if (ret != 0) {
364 cislog_debug("ipc_comm_send_nolimit(%s): send interupted at %d of %d bytes.",
365 x.name, (int)prev, (int)len);
366 break;
367 }
368 prev += msgsiz;
369 cislog_debug("ipc_comm_send_nolimit(%s): %d of %d bytes sent",
370 x.name, prev, len);
371 }
372 if (ret == 0)
373 cislog_debug("ipc_comm_send_nolimit(%s): %d bytes completed", x.name, len);
374 return ret;
375 };
376
377
378 // Definitions in the case where IPC libraries not installed
379 #else /*IPCINSTALLED*/
380
384 static inline
385 void ipc_install_error() {
386 cislog_error("Compiler flag 'IPCINSTALLED' not defined so IPC bindings are disabled.");
387 };
388
394 static inline
395 int free_ipc_comm(comm_t *x) {
396 // Prevent C4100 warning on windows by referencing param
397 #ifdef _WIN32
398 x;
399 #endif
400 ipc_install_error();
401 return 1;
402 };
403
409 static inline
410 int new_ipc_address(comm_t *comm) {
411 // Prevent C4100 warning on windows by referencing param
412 #ifdef _WIN32
413 comm;
414 #endif
415 ipc_install_error();
416 return -1;
417 };
418
424 static inline
425 int init_ipc_comm(comm_t *comm) {
426 // Prevent C4100 warning on windows by referencing param
427 #ifdef _WIN32
428 comm;
429 #endif
430 ipc_install_error();
431 return -1;
432 };
433
439 static inline
440 int ipc_comm_nmsg(const comm_t x) {
441 // Prevent C4100 warning on windows by referencing param
442 #ifdef _WIN32
443 x;
444 #endif
445 ipc_install_error();
446 return -1;
447 };
448
458 static inline
459 int ipc_comm_send(const comm_t x, const char *data, const size_t len) {
460 // Prevent C4100 warning on windows by referencing param
461 #ifdef _WIN32
462 x;
463 data;
464 len;
465 #endif
466 ipc_install_error();
467 return -1;
468 };
469
482 static inline
483 int ipc_comm_recv(const comm_t x, char **data, const size_t len,
484 const int allow_realloc) {
485 // Prevent C4100 warning on windows by referencing param
486 #ifdef _WIN32
487 x;
488 data;
489 len;
490 allow_realloc;
491 #endif
492 ipc_install_error();
493 return -1;
494 };
495
496 #endif /*IPCINSTALLED*/
497
498 #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
499 }
500 #endif
501
502 #endif /*CISIPCCOMM_H_*/
comm_t::handle
void * handle
Pointer to handle for comm.
Definition: CommBase.h:29
comm_t
Communication structure.
Definition: CommBase.h:23
comm_t::address
char address[COMM_ADDRESS_SIZE]
Comm address.
Definition: CommBase.h:26
comm_t::direction
char direction[COMM_DIR_SIZE]
send or recv for direction messages will go.
Definition: CommBase.h:27
comm_t::name
char name[COMM_NAME_SIZE]
Comm name.
Definition: CommBase.h:25
comm_t::valid
int valid
1 if communicator initialized, 0 otherwise.
Definition: CommBase.h:28