cis_config
IPCComm.h
1 #ifdef IPCINSTALLED
2 #include <fcntl.h> /* For O_* constants */
3 #include <sys/stat.h> /* For mode constants */
4 #include <sys/msg.h>
5 #include <sys/types.h>
6 #include <sys/sem.h>
7 #include <sys/shm.h>
8 #endif /*IPCINSTALLED*/
9 #include <CommBase.h>
10 
12 #ifndef CISIPCCOMM_H_
13 #define CISIPCCOMM_H_
14 
15 #ifdef IPCINSTALLED
16 
18 static unsigned _cisChannelsCreated = 0;
20 #define _cisTrackChannels 256
21 
22 static int _cisChannelNames[_cisTrackChannels];
23 //static char * _cisChannelNames[_cisTrackChannels];
25 static unsigned _cisChannelsUsed = 0;
26 static unsigned _ipc_rand_seeded = 0;
27 
31 typedef struct msgbuf_t {
32  long mtype;
33  char data[CIS_MSG_MAX];
34 } msgbuf_t;
35 
41 static inline
42 int check_channels(comm_t comm) {
43  // Fail if name is empty
44  if (strlen(comm.name) == 0) {
45  cislog_error("Cannot create channel with empty name.");
46  return -1;
47  }
48  // Fail if trying to re-use the same channel twice
49  unsigned i;
50  char *key = comm.address;
51  for (i = 0; i < _cisChannelsUsed; i++ ) {
52  if (_cisChannelNames[i] == atoi(comm.address)) {
53  /* if (0 == strcmp(_cisChannelNames[i], key)) { */
54  cislog_error("Attempt to re-use channel: name=%s, key=%s, i=%d",
55  comm.name, key, i);
56  return -1;
57  }
58  }
59  // Fail if > _cisTrackChannels channels used
60  if (_cisChannelsUsed >= _cisTrackChannels) {
61  cislog_error("Too many channels in use, max: %d", _cisTrackChannels);
62  return -1;
63  }
64  return 0;
65 };
66 
71 static inline
72 void add_channel(const comm_t comm) {
73  // printf("add_channel(%s): %d, %s\n", comm.name, _cisChannelsUsed, comm.address);
74  _cisChannelNames[_cisChannelsUsed++] = atoi(comm.address);
75 };
76 
85 static inline
86 int remove_comm(const comm_t comm, const int close_comm) {
87  int ret;
88  if (close_comm) {
89  ret = msgctl(((int*)comm.handle)[0], IPC_RMID, NULL);
90  /* if (ret < 0) { */
91  /* cislog_error("remove_comm(%s): Could not close comm.", comm.name); */
92  /* return ret; */
93  /* } */
94  }
95  ret = -1;
96  unsigned i;
97  int ich = atoi(comm.address);
98  for (i = 0; i < _cisChannelsUsed; i++) {
99  if (ich == _cisChannelNames[i]) {
100  memmove(_cisChannelNames + i, _cisChannelNames + i + 1,
101  (_cisTrackChannels - (i + 1))*sizeof(int));
102  _cisChannelsUsed--;
103  ret = 0;
104  break;
105  }
106  }
107  if (ret < 0) {
108  cislog_error("remove_comm(%s): Could not locate comm in register.", comm.name);
109  }
110  /* if ((ret != -1) && (ich == (int)(_cisChannelsUsed - 1))) { */
111  /* /\* memmove(_cisChannelNames + ich, _cisChannelNames + ich + 1, *\/ */
112  /* /\* (_cisTrackChannels - (ich + 1))*sizeof(char*)); *\/ */
113  /* _cisChannelsUsed--; */
114  /* } */
115  return ret;
116 };
117 
123 static inline
124 int new_ipc_address(comm_t *comm) {
125  int ret;
126  // TODO: small chance of reusing same number
127  int key = 0;
128  if (!(_ipc_rand_seeded)) {
129  srand(ptr2seed(comm));
130  _ipc_rand_seeded = 1;
131  }
132  while (key == 0) {
133  key = rand();
134  } // _cisChannelsUsed + 1;
135  if (strlen(comm->name) == 0) {
136  sprintf(comm->name, "tempnewIPC.%d", key);
137  } else {
138  ret = check_channels(*comm);
139  if (ret < 0)
140  return ret;
141  }
142  sprintf(comm->address, "%d", key);
143  int *fid = (int*)malloc(sizeof(int));
144  if (fid == NULL) {
145  cislog_error("new_ipc_address: Could not malloc queue fid.");
146  return -1;
147  }
148  fid[0] = msgget(key, (IPC_CREAT | 0777));
149  if (fid[0] < 0) {
150  cislog_error("new_ipc_address: msgget(%d, %d | 0777) ret(%d), errno(%d): %s",
151  key, IPC_CREAT, fid[0], errno, strerror(errno));
152  return -1;
153  }
154  comm->handle = (void*)fid;
155  add_channel(*comm);
156  _cisChannelsCreated++;
157  return 0;
158 };
159 
165 static inline
166 int init_ipc_comm(comm_t *comm) {
167  if (comm->valid == 0)
168  return -1;
169  if (strlen(comm->name) == 0) {
170  sprintf(comm->name, "tempinitIPC.%s", comm->address);
171  } else {
172  int ret = check_channels(*comm);
173  if (ret < 0)
174  return ret;
175  }
176  add_channel(*comm);
177  int qkey = atoi(comm->address);
178  int *fid = (int *)malloc(sizeof(int));
179  if (fid == NULL) {
180  cislog_error("init_ipc_comm: Could not malloc queue fid.");
181  return -1;
182  }
183  fid[0] = msgget(qkey, 0600);
184  if (fid[0] < 0) {
185  cislog_error("init_ipc_address: msgget(%d, 0600) ret(%d), errno(%d): %s",
186  qkey, fid[0], errno, strerror(errno));
187  return -1;
188  }
189  comm->handle = (void*)fid;
190  return 0;
191 };
192 
198 static inline
199 int free_ipc_comm(comm_t *x) {
200  if (x->handle != NULL) {
201  if (strcmp(x->direction, "recv") == 0) {
202  remove_comm(*x, 1);
203  } else {
204  remove_comm(*x, 0);
205  }
206  free(x->handle);
207  x->handle = NULL;
208  }
209  return 0;
210 };
211 
217 static inline
218 int ipc_comm_nmsg(const comm_t x) {
219  struct msqid_ds buf;
220  if (x.handle == NULL) {
221  cislog_error("ipc_comm_nmsg: Queue handle is NULL.");
222  return -1;
223  }
224  int rc = msgctl(((int*)x.handle)[0], IPC_STAT, &buf);
225  if (rc != 0) {
226  /* cislog_error("ipc_comm_nmsg: Could not access queue."); */
227  return 0;
228  }
229  int ret = buf.msg_qnum;
230  return ret;
231 };
232 
242 static inline
243 int ipc_comm_send(const comm_t x, const char *data, const size_t len) {
244  cislog_debug("ipc_comm_send(%s): %d bytes", x.name, len);
245  if (comm_base_send(x, data, len) == -1)
246  return -1;
247  msgbuf_t t;
248  t.mtype = 1;
249  memcpy(t.data, data, len);
250  int ret = -1;
251  int handle = ((int*)(x.handle))[0];
252  while (1) {
253  ret = msgsnd(handle, &t, len, IPC_NOWAIT);
254  cislog_debug("ipc_comm_send(%s): msgsnd returned %d", x.name, ret);
255  if (ret == 0) break;
256  if ((ret == -1) && (errno == EAGAIN)) {
257  cislog_debug("ipc_comm_send(%s): msgsnd, sleep", x.name);
258  usleep(CIS_SLEEP_TIME);
259  } else {
260  cislog_error("ipc_comm_send: msgsend(%d, %p, %d, IPC_NOWAIT) ret(%d), errno(%d): %s",
261  (int*)x.handle, &t, len, ret, errno, strerror(errno));
262  ret = -1;
263  break;
264  }
265  }
266  cislog_debug("ipc_comm_send(%s): returning %d", x.name, ret);
267  return ret;
268 };
269 
282 static inline
283 int ipc_comm_recv(const comm_t x, char **data, const size_t len,
284  const int allow_realloc) {
285  cislog_debug("ipc_comm_recv(%s)", x.name);
286  msgbuf_t t;
287  t.mtype = 1;
288  int ret = -1;
289  int len_recv = -1;
290  while (1) {
291  ret = msgrcv(((int*)x.handle)[0], &t, CIS_MSG_MAX, 0, IPC_NOWAIT);
292  if (ret == -1 && errno == ENOMSG) {
293  cislog_debug("ipc_comm_recv(%s): no input, sleep", x.name);
294  usleep(CIS_SLEEP_TIME);
295  } else {
296  cislog_debug("ipc_comm_recv(%s): received input: %d bytes, ret=%d",
297  x.name, strlen(t.data), ret);
298  break;
299  }
300  }
301  if (ret <= 0) {
302  cislog_debug("ipc_comm_recv: msgrecv(%d, %p, %d, 0, IPC_NOWAIT): %s",
303  (int*)x.handle, &t, (int)CIS_MSG_MAX, strerror(errno));
304  return -1;
305  }
306  len_recv = ret + 1;
307  if (len_recv > (int)len) {
308  if (allow_realloc) {
309  cislog_debug("ipc_comm_recv(%s): reallocating buffer from %d to %d bytes.",
310  x.name, (int)len, len_recv);
311  (*data) = (char*)realloc(*data, len_recv);
312  if (*data == NULL) {
313  cislog_error("ipc_comm_recv(%s): failed to realloc buffer.", x.name);
314  return -1;
315  }
316  } else {
317  cislog_error("ipc_comm_recv(%s): buffer (%d bytes) is not large enough for message (%d bytes)",
318  x.name, len, len_recv);
319  return -(len_recv - 1);
320  }
321  }
322  memcpy(*data, t.data, len_recv);
323  (*data)[len_recv - 1] = '\0';
324  ret = len_recv - 1;
325  cislog_debug("ipc_comm_recv(%s): returns %d bytes", x.name, ret);
326  return ret;
327 };
328 
340 static inline
341 int ipc_comm_send_nolimit(const comm_t x, const char *data, const size_t len){
342  cislog_debug("ipc_comm_send_nolimit(%s): %d bytes", x.name, len);
343  int ret = -1;
344  size_t msgsiz = 0;
345  char msg[CIS_MSG_MAX];
346  sprintf(msg, "%ld", (long)(len));
347  ret = ipc_comm_send(x, msg, strlen(msg));
348  if (ret != 0) {
349  cislog_debug("ipc_comm_send_nolimit(%s): sending size of payload failed.", x.name);
350  return ret;
351  }
352  size_t prev = 0;
353  while (prev < len) {
354  if ((len - prev) > CIS_MSG_MAX)
355  msgsiz = CIS_MSG_MAX;
356  else
357  msgsiz = len - prev;
358  ret = ipc_comm_send(x, data + prev, msgsiz);
359  if (ret != 0) {
360  cislog_debug("ipc_comm_send_nolimit(%s): send interupted at %d of %d bytes.",
361  x.name, (int)prev, (int)len);
362  break;
363  }
364  prev += msgsiz;
365  cislog_debug("ipc_comm_send_nolimit(%s): %d of %d bytes sent",
366  x.name, prev, len);
367  }
368  if (ret == 0)
369  cislog_debug("ipc_comm_send_nolimit(%s): %d bytes completed", x.name, len);
370  return ret;
371 };
372 
373 
374 // Definitions in the case where IPC libraries not installed
375 #else /*IPCINSTALLED*/
376 
380 static inline
381 void ipc_install_error() {
382  cislog_error("Compiler flag 'IPCINSTALLED' not defined so IPC bindings are disabled.");
383 };
384 
390 static inline
391 int free_ipc_comm(comm_t *x) {
392  // Prevent C4100 warning on windows by referencing param
393 #ifdef _WIN32
394  x;
395 #endif
396  ipc_install_error();
397  return 1;
398 };
399 
405 static inline
406 int new_ipc_address(comm_t *comm) {
407  // Prevent C4100 warning on windows by referencing param
408 #ifdef _WIN32
409  comm;
410 #endif
411  ipc_install_error();
412  return -1;
413 };
414 
420 static inline
421 int init_ipc_comm(comm_t *comm) {
422  // Prevent C4100 warning on windows by referencing param
423 #ifdef _WIN32
424  comm;
425 #endif
426  ipc_install_error();
427  return -1;
428 };
429 
435 static inline
436 int ipc_comm_nmsg(const comm_t x) {
437  // Prevent C4100 warning on windows by referencing param
438 #ifdef _WIN32
439  x;
440 #endif
441  ipc_install_error();
442  return -1;
443 };
444 
454 static inline
455 int ipc_comm_send(const comm_t x, const char *data, const size_t len) {
456  // Prevent C4100 warning on windows by referencing param
457 #ifdef _WIN32
458  x;
459  data;
460  len;
461 #endif
462  ipc_install_error();
463  return -1;
464 };
465 
478 static inline
479 int ipc_comm_recv(const comm_t x, char **data, const size_t len,
480  const int allow_realloc) {
481  // Prevent C4100 warning on windows by referencing param
482 #ifdef _WIN32
483  x;
484  data;
485  len;
486  allow_realloc;
487 #endif
488  ipc_install_error();
489  return -1;
490 };
491 
492 #endif /*IPCINSTALLED*/
493 #endif /*CISIPCCOMM_H_*/
void * handle
Pointer to handle for comm.
Definition: CommBase.h:25
Communication structure.
Definition: CommBase.h:19
char address[COMM_ADDRESS_SIZE]
Comm address.
Definition: CommBase.h:22
char direction[COMM_DIR_SIZE]
send or recv for direction messages will go.
Definition: CommBase.h:23
char name[COMM_NAME_SIZE]
Comm name.
Definition: CommBase.h:21
int valid
1 if communicator initialized, 0 otherwise.
Definition: CommBase.h:24