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_*/
void * handle
Pointer to handle for comm.
Definition: CommBase.h:29
Communication structure.
Definition: CommBase.h:23
char address[COMM_ADDRESS_SIZE]
Comm address.
Definition: CommBase.h:26
char direction[COMM_DIR_SIZE]
send or recv for direction messages will go.
Definition: CommBase.h:27
char name[COMM_NAME_SIZE]
Comm name.
Definition: CommBase.h:25
int valid
1 if communicator initialized, 0 otherwise.
Definition: CommBase.h:28