cis_config
ZMQComm.h
1 
2 #ifndef CISZMQCOMM_H_
3 #define CISZMQCOMM_H_
4 
5 #include <CommBase.h>
6 
7 #ifdef ZMQINSTALLED
8 
9 #include <czmq.h>
10 
11 static unsigned _zmq_rand_seeded = 0;
12 static unsigned _last_port_set = 0;
13 static unsigned _cisSocketsCreated = 0;
14 static int _last_port = 49152;
15 /* static double _wait_send_t = 0; // 0.0001; */
16 static char _reply_msg[100] = "CIS_REPLY";
17 static char _purge_msg[100] = "CIS_PURGE";
18 static int _zmq_sleeptime = 10000;
19 
23 typedef struct zmq_reply_t {
24  int nsockets;
25  zsock_t **sockets;
26  char **addresses;
27  int n_msg;
28  int n_rep;
29 } zmq_reply_t;
30 
31 
32 // Forward declarations
33 static inline
34 int zmq_comm_nmsg(const comm_t x);
35 static inline
36 int zmq_comm_recv(const comm_t x, char **data, const size_t len,
37  const int allow_realloc);
38 
39 
45 static inline
46 int free_zmq_reply(zmq_reply_t *x) {
47  int i = 0;
48  if (x != NULL) {
49  if (x->sockets != NULL) {
50  for (i = 0; i < x->nsockets; i++) {
51  if (x->sockets[i] != NULL) {
52  zsock_destroy(&(x->sockets[i]));
53  x->sockets[i] = NULL;
54  }
55  }
56  free(x->sockets);
57  }
58  if (x->addresses != NULL) {
59  for (i = 0; i < x->nsockets; i++) {
60  if (x->addresses[i] != NULL) {
61  free(x->addresses[i]);
62  x->addresses[i] = NULL;
63  }
64  }
65  free(x->addresses);
66  }
67  x->nsockets = 0;
68  }
69  return 0;
70 }
71 
77 static inline
78 int init_zmq_reply(comm_t *comm) {
79  zmq_reply_t *zrep = (zmq_reply_t*)malloc(sizeof(zmq_reply_t));
80  if (zrep == NULL) {
81  cislog_error("init_zmq_reply(%s): Failed to malloc reply.", comm->name);
82  return -1;
83  }
84  zrep->nsockets = 0;
85  zrep->sockets = NULL;
86  zrep->addresses = NULL;
87  zrep->n_msg = 0;
88  zrep->n_rep = 0;
89  comm->reply = (void*)zrep;
90  return 0;
91 };
92 
99 static inline
100 int find_reply_socket(const comm_t *comm, const char *address) {
101  int ret = -1;
102  // Get reply
103  zmq_reply_t *zrep = (zmq_reply_t*)(comm->reply);
104  if (zrep == NULL) {
105  cislog_error("find_reply_socket(%s): Reply structure not initialized.", comm->name);
106  return -2;
107  }
108  int i = 0;
109  for (i = 0; i < zrep->nsockets; i++) {
110  if (strcmp(zrep->addresses[i], address) == 0) {
111  ret = i;
112  break;
113  }
114  }
115  return ret;
116 };
117 
123 static inline
124 int do_reply_send(const comm_t *comm) {
125  // Get reply
126  zmq_reply_t *zrep = (zmq_reply_t*)(comm->reply);
127  if (zrep == NULL) {
128  cislog_error("do_reply_send(%s): Reply structure not initialized.", comm->name);
129  return -1;
130  }
131  zrep->n_msg++;
132  zsock_t *s = (zsock_t*)(zrep->sockets[0]);
133  if (s == NULL) {
134  cislog_error("do_reply_send(%s): Socket is NULL.", comm->name);
135  return -1;
136  }
137  // Poll
138  cislog_debug("do_reply_send(%s): address=%s, begin", comm->name,
139  zrep->addresses[0]);
140  zpoller_t *poller = zpoller_new(s, NULL);
141  if (poller == NULL) {
142  cislog_error("do_reply_send(%s): Could not create poller", comm->name);
143  return -1;
144  }
145  void *p = zpoller_wait(poller, -1);
146  zpoller_destroy(&poller);
147  if (p == NULL) {
148  if (zpoller_terminated(poller)) {
149  cislog_error("do_reply_send(%s): Poller interrupted", comm->name);
150  } else if (zpoller_expired(poller)) {
151  cislog_error("do_reply_send(%s): Poller expired", comm->name);
152  } else {
153  cislog_error("do_reply_send(%s): Poller failed", comm->name);
154  }
155  return -1;
156  }
157  // Receive
158  zframe_t *msg = zframe_recv(s);
159  if (msg == NULL) {
160  cislog_error("do_reply_send(%s): did not receive", comm->name);
161  return -1;
162  }
163  char *msg_data = (char*)zframe_data(msg);
164  // Check for EOF
165  int is_purge = 0;
166  if (strcmp(msg_data, CIS_MSG_EOF) == 0) {
167  cislog_debug("do_reply_send(%s): EOF received", comm->name);
168  zrep->n_msg = 0;
169  zrep->n_rep = 0;
170  return -2;
171  } else if (strcmp(msg_data, _purge_msg) == 0) {
172  is_purge = 1;
173  }
174  // Send
175  // zsock_set_linger(s, _zmq_sleeptime);
176  int ret = zframe_send(&msg, s, 0);
177  // Check for purge or EOF
178  if (ret < 0) {
179  cislog_error("do_reply_send(%s): Error sending reply frame.", comm->name);
180  zframe_destroy(&msg);
181  } else {
182  if (is_purge == 1) {
183  cislog_debug("do_reply_send(%s): PURGE received", comm->name);
184  zrep->n_msg = 0;
185  zrep->n_rep = 0;
186  ret = do_reply_send(comm);
187  } else {
188  zrep->n_rep++;
189  }
190  }
191  cislog_debug("do_reply_send(%s): address=%s, end", comm->name,
192  zrep->addresses[0]);
193  return ret;
194 };
195 
203 static inline
204 int do_reply_recv(const comm_t *comm, const int isock, const char *msg) {
205  // Get reply
206  zmq_reply_t *zrep = (zmq_reply_t*)(comm->reply);
207  if (zrep == NULL) {
208  cislog_error("do_reply_recv(%s): Reply structure not initialized.", comm->name);
209  return -1;
210  }
211  zsock_t *s = (zsock_t*)(zrep->sockets[isock]);
212  if (s == NULL) {
213  cislog_error("do_reply_recv(%s): Socket is NULL.", comm->name);
214  return -1;
215  }
216  cislog_debug("do_reply_recv(%s): address=%s, begin", comm->name,
217  zrep->addresses[isock]);
218  zframe_t *msg_send = zframe_new(msg, strlen(msg));
219  if (msg_send == NULL) {
220  cislog_error("do_reply_recv(%s): Error creating frame.", comm->name);
221  return -1;
222  }
223  // Send
224  int ret = zframe_send(&msg_send, s, 0);
225  if (ret < 0) {
226  cislog_error("do_reply_recv(%s): Error sending confirmation.", comm->name);
227  zframe_destroy(&msg_send);
228  return -1;
229  }
230  if (strcmp(msg, CIS_MSG_EOF) == 0) {
231  zrep->n_msg = 0;
232  zrep->n_rep = 0;
233  zsock_set_linger(s, _zmq_sleeptime);
234  return -2;
235  }
236  // Receive
237  zframe_t *msg_recv = zframe_recv(s);
238  if (msg_recv == NULL) {
239  cislog_error("do_reply_recv(%s): did not receive", comm->name);
240  return -1;
241  }
242  zframe_destroy(&msg_recv);
243  zrep->n_rep++;
244  cislog_debug("do_reply_recv(%s): address=%s, end", comm->name,
245  zrep->addresses[isock]);
246  return 0;
247 };
248 
256 static inline
257 char* check_reply_send(const comm_t *comm, const char *data, const int len,
258  int *new_len) {
259  char *out = NULL;
260  new_len[0] = len;
261  // Get reply
262  zmq_reply_t *zrep = (zmq_reply_t*)(comm->reply);
263  if (zrep == NULL) {
264  cislog_error("check_reply_send(%s): Reply structure not initialized.", comm->name);
265  return out;
266  }
267  // Create socket
268  if (zrep->nsockets == 0) {
269  zrep->sockets = (zsock_t**)malloc(sizeof(zsock_t*));
270  if (zrep->sockets == NULL) {
271  cislog_error("check_reply_send(%s): Error mallocing sockets.", comm->name);
272  return out;
273  }
274  zrep->nsockets = 1;
275  zrep->sockets[0] = zsock_new(ZMQ_REP);
276  zsock_set_linger(zrep->sockets[0], 0);
277  if (zrep->sockets[0] == NULL) {
278  cislog_error("check_reply_send(%s): Could not initialize empty socket.",
279  comm->name);
280  return out;
281  }
282  char protocol[50] = "tcp";
283  char host[50] = "localhost";
284  if (strcmp(host, "localhost") == 0)
285  strcpy(host, "127.0.0.1");
286  char address[100];
287  if (_last_port_set == 0) {
288  cislog_debug("model_index = %s", getenv("CIS_MODEL_INDEX"));
289  _last_port = 49152 + 1000 * atoi(getenv("CIS_MODEL_INDEX"));
290  _last_port_set = 1;
291  cislog_debug("_last_port = %d", _last_port);
292  }
293  sprintf(address, "%s://%s:*[%d-]", protocol, host, _last_port + 1);
294  int port = zsock_bind(zrep->sockets[0], "%s", address);
295  if (port == -1) {
296  cislog_error("check_reply_send(%s): Could not bind socket to address = %s",
297  comm->name, address);
298  return out;
299  }
300  _last_port = port;
301  sprintf(address, "%s://%s:%d", protocol, host, port);
302  zrep->addresses = (char**)malloc(sizeof(char*));
303  zrep->addresses[0] = (char*)malloc((strlen(address) + 1)*sizeof(char));
304  strcpy(zrep->addresses[0], address);
305  }
306  // Add address to new message
307  out = (char*)malloc(2*(strlen(_reply_msg) + 2) +
308  strlen(zrep->addresses[0]) + len + 1);
309  sprintf(out, ":%s:%s:%s:", _reply_msg, zrep->addresses[0], _reply_msg);
310  new_len[0] = len + (int)strlen(out);
311  memcpy(out + strlen(out), data, len);
312  out[new_len[0]] = '\0';
313  return out;
314 };
315 
316 
325 static inline
326 int check_reply_recv(const comm_t *comm, char *data, const size_t len) {
327  int new_len = (int)len;
328  int ret = 0;
329  // Get reply
330  zmq_reply_t *zrep = (zmq_reply_t*)(comm->reply);
331  if (zrep == NULL) {
332  cislog_error("check_reply_recv(%s): Reply structure not initialized.", comm->name);
333  return -1;
334  }
335  zrep->n_msg++;
336  // Extract address
337  char re_reply[500];
338  sprintf(re_reply, ":%s:(.*):%s:", _reply_msg, _reply_msg);
339  size_t sind, eind;
340  ret = find_match(re_reply, data, &sind, &eind);
341  if (ret <= 0) {
342  cislog_error("check_reply_recv(%s): Error parsing reply header in '%s'",
343  comm->name, data);
344  return -1;
345  }
346  size_t headsiz = (eind-sind);
347  new_len = (int)(len - headsiz);
348  char address[100];
349  headsiz -= (2*(strlen(_reply_msg) + 2));
350  memcpy(address, data + sind + strlen(_reply_msg) + 2, headsiz);
351  address[headsiz] = '\0';
352  memmove(data, data + eind, new_len);
353  data[new_len] = '\0';
354  // Match address and create if it dosn't exist
355  int isock = find_reply_socket(comm, address);
356  if (isock < 0) {
357  if (isock == -2) {
358  cislog_error("check_reply_recv(%s): Error locating socket.", comm->name);
359  return -1;
360  }
361  // Realloc arrays
362  zrep->sockets = (zsock_t**)realloc(zrep->sockets,
363  sizeof(zsock_t*)*(zrep->nsockets + 1));
364  if (zrep->sockets == NULL) {
365  cislog_error("check_reply_recv(%s): Error reallocing sockets.", comm->name);
366  return -1;
367  }
368  zrep->addresses = (char**)realloc(zrep->addresses,
369  sizeof(char*)*(zrep->nsockets + 1));
370  if (zrep->addresses == NULL) {
371  cislog_error("check_reply_recv(%s): Error reallocing addresses.", comm->name);
372  return -1;
373  }
374  // Create new socket
375  isock = zrep->nsockets;
376  zrep->nsockets++;
377  zrep->sockets[isock] = zsock_new(ZMQ_REQ);
378  zsock_set_linger(zrep->sockets[isock], 0);
379  if (zrep->sockets[isock] == NULL) {
380  cislog_error("check_reply_recv(%s): Could not initialize empty socket.",
381  comm->name);
382  return -1;
383  }
384  zrep->addresses[isock] = (char*)malloc(sizeof(char)*(strlen(address) + 1));
385  if (zrep->addresses[isock] == NULL) {
386  cislog_error("check_reply_recv(%s): Could not realloc new address.",
387  comm->name);
388  return -1;
389  }
390  strcpy(zrep->addresses[isock], address);
391  ret = zsock_connect(zrep->sockets[isock], "%s", address);
392  if (ret < 0) {
393  cislog_error("check_reply_recv(%s): Could not connect to socket.",
394  comm->name);
395  return -1;
396  }
397  }
398  // Confirm message receipt
399  ret = do_reply_recv(comm, isock, _reply_msg);
400  if (ret < 0) {
401  cislog_error("check_reply_recv(%s): Error during reply.", comm->name);
402  return -1;
403  }
404  return new_len;
405 };
406 
412 static inline
413 int new_zmq_address(comm_t *comm) {
414  // TODO: Get protocol/host from input
415  char protocol[50] = "tcp";
416  char host[50] = "localhost";
417  char address[100];
418  if (strcmp(host, "localhost") == 0)
419  strcpy(host, "127.0.0.1");
420  if ((strcmp(protocol, "inproc") == 0) ||
421  (strcmp(protocol, "ipc") == 0)) {
422  // TODO: small chance of reusing same number
423  int key = 0;
424  if (!(_zmq_rand_seeded)) {
425  srand(ptr2seed(comm));
426  _zmq_rand_seeded = 1;
427  }
428  while (key == 0) key = rand();
429  if (strlen(comm->name) == 0)
430  sprintf(comm->name, "tempnewZMQ-%d", key);
431  sprintf(address, "%s://%s", protocol, comm->name);
432  } else {
433  if (_last_port_set == 0) {
434  cislog_debug("model_index = %s", getenv("CIS_MODEL_INDEX"));
435  _last_port = 49152 + 1000 * atoi(getenv("CIS_MODEL_INDEX"));
436  _last_port_set = 1;
437  cislog_debug("_last_port = %d", _last_port);
438  }
439  sprintf(address, "%s://%s:*[%d-]", protocol, host, _last_port + 1);
440  /* strcat(address, ":!"); // For random port */
441  }
442  // Bind
443  zsock_t *s = zsock_new(ZMQ_PAIR);
444  if (s == NULL) {
445  cislog_error("new_zmq_address: Could not initialize empty socket.");
446  return -1;
447  }
448  zsock_set_linger(s, 0);
449  int port = zsock_bind(s, "%s", address);
450  if (port == -1) {
451  cislog_error("new_zmq_address: Could not bind socket to address = %s",
452  address);
453  return -1;
454  }
455  // Add port to address
456  if ((strcmp(protocol, "inproc") != 0) &&
457  (strcmp(protocol, "ipc") != 0)) {
458  _last_port = port;
459  sprintf(address, "%s://%s:%d", protocol, host, port);
460  }
461  strcpy(comm->address, address);
462  cislog_debug("new_zmq_address: Bound socket to %s", comm->address);
463  if (strlen(comm->name) == 0)
464  sprintf(comm->name, "tempnewZMQ-%d", port);
465  comm->handle = (void*)s;
466  _cisSocketsCreated++;
467  // Init reply
468  int ret = init_zmq_reply(comm);
469  return ret;
470 };
471 
477 static inline
478 int init_zmq_comm(comm_t *comm) {
479  int ret = -1;
480  if (comm->valid == 0)
481  return ret;
482  zsock_t *s = zsock_new(ZMQ_PAIR);
483  if (s == NULL) {
484  cislog_error("init_zmq_address: Could not initialize empty socket.");
485  return -1;
486  }
487  zsock_set_linger(s, 0);
488  ret = zsock_connect(s, "%s", comm->address);
489  if (ret == -1) {
490  cislog_error("init_zmq_address: Could not connect socket to address = %s",
491  comm->address);
492  zsock_destroy(&s);
493  return ret;
494  }
495  cislog_debug("init_zmq_address: Connected socket to %s", comm->address);
496  if (strlen(comm->name) == 0)
497  sprintf(comm->name, "tempinitZMQ-%s", comm->address);
498  // Asign to void pointer
499  comm->handle = (void*)s;
500  ret = init_zmq_reply(comm);
501  return ret;
502 };
503 
509 static inline
510 int free_zmq_comm(comm_t *x) {
511  int ret = 0;
512  if (x == NULL)
513  return ret;
514  // Drain input
515  if ((is_recv(x->direction)) && (x->valid == 1)) {
516  if (_cis_error_flag == 0) {
517  size_t data_len = 100;
518  char *data = (char*)malloc(data_len);
519  while (zmq_comm_nmsg(*x) > 0) {
520  ret = zmq_comm_recv(*x, &data, data_len, 1);
521  if (ret < 0) {
522  if (ret == -2) {
523  x->recv_eof[0] = 1;
524  break;
525  }
526  }
527  }
528  free(data);
529  }
530  }
531  // Free reply
532  if (x->reply != NULL) {
533  zmq_reply_t *zrep = (zmq_reply_t*)(x->reply);
534  // Free reply
535  ret = free_zmq_reply(zrep);
536  free(x->reply);
537  x->reply = NULL;
538  }
539  if (x->handle != NULL) {
540  zsock_t *s = (zsock_t*)(x->handle);
541  if (s != NULL) {
542  cislog_debug("Destroying socket: %s", x->address);
543  zsock_destroy(&s);
544  }
545  x->handle = NULL;
546  }
547  return ret;
548 };
549 
555 static inline
556 int zmq_comm_nmsg(const comm_t x) {
557  int out = 0;
558  if (is_recv(x.direction)) {
559  if (x.handle != NULL) {
560  zsock_t *s = (zsock_t*)(x.handle);
561  zpoller_t *poller = zpoller_new(s, NULL);
562  if (poller == NULL) {
563  cislog_error("zmq_comm_nmsg: Could not create poller");
564  return -1;
565  }
566  void *p = zpoller_wait(poller, 1);
567  if (p == NULL) {
568  if (zpoller_terminated(poller)) {
569  cislog_error("zmq_comm_nmsg: Poller interrupted");
570  out = -1;
571  } else {
572  out = 0;
573  }
574  } else {
575  out = 1;
576  }
577  zpoller_destroy(&poller);
578  }
579  } else {
580  /* if (x.last_send[0] != 0) { */
581  /* time_t now; */
582  /* time(&now); */
583  /* double elapsed = difftime(now, x.last_send[0]); */
584  /* if (elapsed > _wait_send_t) */
585  /* out = 0; */
586  /* else */
587  /* out = 1; */
588  /* } */
589  zmq_reply_t *zrep = (zmq_reply_t*)(x.reply);
590  if (zrep != NULL) {
591  cislog_debug("zmq_comm_nmsg(%s): nmsg = %d, nrep = %d",
592  x.name, zrep->n_msg, zrep->n_rep);
593  out = zrep->n_msg - zrep->n_rep;
594  }
595  }
596  return out;
597 };
598 
608 static inline
609 int zmq_comm_send(const comm_t x, const char *data, const size_t len) {
610  cislog_debug("zmq_comm_send(%s): %d bytes", x.name, len);
611  if (comm_base_send(x, data, len) == -1)
612  return -1;
613  zsock_t *s = (zsock_t*)(x.handle);
614  if (s == NULL) {
615  cislog_error("zmq_comm_send(%s): socket handle is NULL", x.name);
616  return -1;
617  }
618  int new_len = 0;
619  char *new_data = check_reply_send(&x, data, (int)len, &new_len);
620  if (new_data == NULL) {
621  cislog_error("zmq_comm_send(%s): Adding reply address failed.", x.name);
622  return -1;
623  }
624  zframe_t *f = zframe_new(new_data, new_len);
625  int ret = -1;
626  if (f == NULL) {
627  cislog_error("zmq_comm_send(%s): frame handle is NULL", x.name);
628  } else {
629  ret = zframe_send(&f, s, 0);
630  if (ret < 0) {
631  cislog_error("zmq_comm_send(%s): Error in zframe_send", x.name);
632  zframe_destroy(&f);
633  }
634  }
635  // Get reply
636  if (ret >= 0) {
637  ret = do_reply_send(&x);
638  if (ret < 0) {
639  if (ret == -2) {
640  cislog_error("zmq_comm_send(%s): EOF received", x.name);
641  } else {
642  cislog_error("zmq_comm_send(%s): Error in do_reply_send", x.name);
643  }
644  }
645  }
646  cislog_debug("zmq_comm_send(%s): returning %d", x.name, ret);
647  free(new_data);
648  return ret;
649 };
650 
663 static inline
664 int zmq_comm_recv(const comm_t x, char **data, const size_t len,
665  const int allow_realloc) {
666  cislog_debug("zmq_comm_recv(%s)", x.name);
667  zsock_t *s = (zsock_t*)(x.handle);
668  if (s == NULL) {
669  cislog_error("zmq_comm_recv(%s): socket handle is NULL", x.name);
670  return -1;
671  }
672  while (1) {
673  int nmsg = zmq_comm_nmsg(x);
674  if (nmsg < 0) return -1;
675  else if (nmsg > 0) break;
676  else {
677  cislog_debug("zmq_comm_recv(%s): no messages, sleep", x.name);
678  usleep(CIS_SLEEP_TIME);
679  }
680  }
681  zframe_t *out = zframe_recv(s);
682  if (out == NULL) {
683  cislog_debug("zmq_comm_recv(%s): did not receive", x.name);
684  return -1;
685  }
686  size_t len_recv = zframe_size(out) + 1;
687  if (len_recv > len) {
688  if (allow_realloc) {
689  cislog_debug("zmq_comm_recv(%s): reallocating buffer from %d to %d bytes.",
690  x.name, len, len_recv);
691  (*data) = (char*)realloc(*data, len_recv);
692  if (*data == NULL) {
693  cislog_error("zmq_comm_recv(%s): failed to realloc buffer.", x.name);
694  zframe_destroy(&out);
695  return -1;
696  }
697  } else {
698  cislog_error("zmq_comm_recv(%s): buffer (%d bytes) is not large enough for message (%d bytes)",
699  x.name, len, len_recv);
700  zframe_destroy(&out);
701  return -((int)(len_recv - 1));
702  }
703  }
704  memcpy(*data, zframe_data(out), len_recv);
705  (*data)[len_recv-1] = '\0';
706  zframe_destroy(&out);
707  int ret = (int)len_recv - 1;
708  ret = check_reply_recv(&x, *data, (size_t)ret);
709  cislog_debug("zmq_comm_recv(%s): returning %d", x.name, ret);
710  return ret;
711 };
712 
713 
714 // Definitions in the case where ZMQ libraries not installed
715 #else /*ZMQINSTALLED*/
716 
720 static inline
721 void zmq_install_error() {
722  cislog_error("Compiler flag 'ZMQINSTALLED' not defined so ZMQ bindings are disabled.");
723 };
724 
730 static inline
731 int free_zmq_comm(comm_t *x) {
732  zmq_install_error();
733  return 1;
734 };
735 
741 static inline
742 int new_zmq_address(comm_t *comm) {
743  zmq_install_error();
744  return -1;
745 };
746 
752 static inline
753 int init_zmq_comm(comm_t *comm) {
754  zmq_install_error();
755  return -1;
756 };
757 
763 static inline
764 int zmq_comm_nmsg(const comm_t x) {
765  zmq_install_error();
766  return -1;
767 };
768 
778 static inline
779 int zmq_comm_send(const comm_t x, const char *data, const size_t len) {
780  zmq_install_error();
781  return -1;
782 };
783 
796 static inline
797 int zmq_comm_recv(const comm_t x, char **data, const size_t len,
798  const int allow_realloc) {
799  zmq_install_error();
800  return -1;
801 };
802 
803 #endif /*ZMQINSTALLED*/
804 #endif /*CISZMQCOMM_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
int * recv_eof
Flag specifying if EOF has been received.
Definition: CommBase.h:33
void * reply
Reply information.
Definition: CommBase.h:35