cis_config
communication.h
1 
2 #ifndef CISCOMMUNICATION_H_
3 #define CISCOMMUNICATION_H_
4 
5 #include <../tools.h>
6 #include <../serialize/serialize.h>
7 #include <comm_header.h>
8 #include <CommBase.h>
9 #include <IPCComm.h>
10 #include <ZMQComm.h>
11 #include <RPCComm.h>
12 #include <ServerComm.h>
13 #include <ClientComm.h>
14 #include <AsciiFileComm.h>
15 #include <AsciiTableComm.h>
16 #include <DefaultComm.h>
17 
18 #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
19 extern "C" {
20 #endif
21 
23 static void **vcomms2clean = NULL;
24 static size_t ncomms2clean = 0;
25 static size_t clean_registered = 0;
26 
27 // Forward declaration of eof
28 static
29 int comm_send_eof(const comm_t x);
30 static
31 int comm_nmsg(const comm_t x);
32 
33 
39 static
40 int free_comm_type(comm_t *x) {
41  comm_type t = x->type;
42  int ret = 1;
43  if (t == IPC_COMM)
44  ret = free_ipc_comm(x);
45  else if (t == ZMQ_COMM)
46  ret = free_zmq_comm(x);
47  else if (t == RPC_COMM)
48  ret = free_rpc_comm(x);
49  else if (t == SERVER_COMM)
50  ret = free_server_comm(x);
51  else if (t == CLIENT_COMM)
52  ret = free_client_comm(x);
53  else if (t == ASCII_FILE_COMM)
54  ret = free_ascii_file_comm(x);
55  else if ((t == ASCII_TABLE_COMM) || (t == ASCII_TABLE_ARRAY_COMM))
56  ret = free_ascii_table_comm(x);
57  else {
58  cislog_error("free_comm_type: Unsupported comm_type %d", t);
59  }
60  return ret;
61 };
62 
68 static
69 int free_comm(comm_t *x) {
70  int ret = 0;
71  if (x == NULL)
72  return ret;
73  cislog_debug("free_comm(%s)", x->name);
74  // Send EOF for output comms and then wait for messages to be recv'd
75  if ((is_send(x->direction)) && (x->valid)) {
76  if (_cis_error_flag == 0) {
77  cislog_debug("free_comm(%s): Sending EOF", x->name);
78  comm_send_eof(*x);
79  while (comm_nmsg(*x) > 0) {
80  cislog_debug("free_comm(%s): draining %d messages",
81  x->name, comm_nmsg(*x));
82  usleep(CIS_SLEEP_TIME);
83  }
84  } else {
85  cislog_error("free_comm(%s): Error registered", x->name);
86  }
87  }
88  ret = free_comm_type(x);
89  int idx = x->index_in_register;
90  free_comm_base(x);
91  if (idx >= 0) {
92  if (vcomms2clean[idx] != NULL) {
93  free(vcomms2clean[idx]);
94  vcomms2clean[idx] = NULL;
95  }
96  }
97  return ret;
98 };
99 
103 static
104 void clean_comms(void) {
105  size_t i;
106  cislog_debug("atexit begin");
107  for (i = 0; i < ncomms2clean; i++) {
108  if (vcomms2clean[i] != NULL) {
109  free_comm((comm_t*)(vcomms2clean[i]));
110  }
111  }
112  if (vcomms2clean != NULL) {
113  free(vcomms2clean);
114  vcomms2clean = NULL;
115  }
116  ncomms2clean = 0;
117 #if defined(ZMQINSTALLED)
118  // #if defined(_WIN32) && defined(ZMQINSTALLED)
119  zsys_shutdown();
120 #endif
121  cislog_debug("atexit done");
122  /* printf(""); */
123 };
124 
131 static
132 int register_comm(comm_t *x) {
133  if (clean_registered == 0) {
134  atexit(clean_comms);
135  clean_registered = 1;
136  }
137  if (x == NULL) {
138  return 0;
139  }
140  void **t_vcomms2clean = (void**)realloc(vcomms2clean, sizeof(void*)*(ncomms2clean + 1));
141  if (t_vcomms2clean == NULL) {
142  cislog_error("register_comm(%s): Failed to realloc the comm list.", x->name);
143  return -1;
144  }
145  vcomms2clean = t_vcomms2clean;
146  x->index_in_register = (int)ncomms2clean;
147  vcomms2clean[ncomms2clean++] = (void*)x;
148  return 0;
149 };
150 
157 static
158 int new_comm_type(comm_t *x) {
159  comm_type t = x->type;
160  int flag;
161  if (t == IPC_COMM)
162  flag = new_ipc_address(x);
163  else if (t == ZMQ_COMM)
164  flag = new_zmq_address(x);
165  else if (t == RPC_COMM)
166  flag = new_rpc_address(x);
167  else if (t == SERVER_COMM)
168  flag = new_server_address(x);
169  else if (t == CLIENT_COMM)
170  flag = new_client_address(x);
171  else if (t == ASCII_FILE_COMM)
172  flag = new_ascii_file_address(x);
173  else if (t == ASCII_TABLE_COMM)
174  flag = new_ascii_table_address(x);
175  else if (t == ASCII_TABLE_ARRAY_COMM)
176  flag = new_ascii_table_array_address(x);
177  else {
178  cislog_error("new_comm_type: Unsupported comm_type %d", t);
179  flag = -1;
180  }
181  return flag;
182 };
183 
190 static
191 int init_comm_type(comm_t *x) {
192  comm_type t = x->type;
193  int flag;
194  if (t == IPC_COMM)
195  flag = init_ipc_comm(x);
196  else if (t == ZMQ_COMM)
197  flag = init_zmq_comm(x);
198  else if (t == RPC_COMM)
199  flag = init_rpc_comm(x);
200  else if (t == SERVER_COMM)
201  flag = init_server_comm(x);
202  else if (t == CLIENT_COMM)
203  flag = init_client_comm(x);
204  else if (t == ASCII_FILE_COMM)
205  flag = init_ascii_file_comm(x);
206  else if (t == ASCII_TABLE_COMM)
207  flag = init_ascii_table_comm(x);
208  else if (t == ASCII_TABLE_ARRAY_COMM)
209  flag = init_ascii_table_array_comm(x);
210  else {
211  cislog_error("init_comm_type: Unsupported comm_type %d", t);
212  flag = -1;
213  }
214  cislog_debug("init_comm_type(%s): Done, flag = %d", x->name, flag);
215  return flag;
216 };
217 
228 static
229 comm_t new_comm(char *address, const char *direction, const comm_type t,
230  void *seri_info) {
231  comm_t *ret = new_comm_base(address, direction, t, seri_info);
232  if (ret == NULL) {
233  cislog_error("new_comm: Could not initialize base.");
234  return empty_comm_base();
235  }
236  int flag;
237  if (address == NULL) {
238  flag = new_comm_type(ret);
239  } else {
240  flag = init_comm_type(ret);
241  }
242  if (flag < 0) {
243  cislog_error("new_comm: Failed to initialize new comm address.");
244  ret->valid = 0;
245  } else {
246  if (strlen(ret->name) == 0) {
247  sprintf(ret->name, "temp.%s", ret->address);
248  }
249  flag = register_comm(ret);
250  if (flag < 0) {
251  cislog_error("new_comm: Failed to register new comm.");
252  ret->valid = 0;
253  }
254  }
255  return ret[0];
256 };
257 
270 static
271 comm_t init_comm(const char *name, const char *direction, const comm_type t,
272  const void *seri_info) {
273  cislog_debug("init_comm: Initializing comm.");
274 #ifdef _WIN32
275  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
276  _set_abort_behavior(0,_WRITE_ABORT_MSG);
277 #endif
278  comm_t *ret = init_comm_base(name, direction, t, seri_info);
279  if (ret == NULL) {
280  cislog_error("init_comm(%s): Could not initialize base.", name);
281  return empty_comm_base();
282  }
283  int flag = init_comm_type(ret);
284  if (flag < 0) {
285  cislog_error("init_comm(%s): Could not initialize comm.", name);
286  ret->valid = 0;
287  } else {
288  flag = register_comm(ret);
289  if (flag < 0) {
290  cislog_error("init_comm(%s): Failed to register new comm.", name);
291  ret->valid = 0;
292  }
293  }
294  cislog_debug("init_comm(%s): Initialized comm.", name);
295  return ret[0];
296 };
297 
303 static
304 int comm_nmsg(const comm_t x) {
305  int ret = -1;
306  if (x.valid == 0) {
307  cislog_error("comm_nmsg: Invalid comm");
308  return ret;
309  }
310  comm_type t = x.type;
311  if (t == IPC_COMM)
312  ret = ipc_comm_nmsg(x);
313  else if (t == ZMQ_COMM)
314  ret = zmq_comm_nmsg(x);
315  else if (t == RPC_COMM)
316  ret = rpc_comm_nmsg(x);
317  else if (t == SERVER_COMM)
318  ret = server_comm_nmsg(x);
319  else if (t == CLIENT_COMM)
320  ret = client_comm_nmsg(x);
321  else if (t == ASCII_FILE_COMM)
322  ret = ascii_file_comm_nmsg(x);
323  else if ((t == ASCII_TABLE_COMM) || (t == ASCII_TABLE_ARRAY_COMM))
324  ret = ascii_table_comm_nmsg(x);
325  else {
326  cislog_error("comm_nmsg: Unsupported comm_type %d", t);
327  }
328  return ret;
329 };
330 
340 static
341 int comm_send_single(const comm_t x, const char *data, const size_t len) {
342  int ret = -1;
343  if (x.valid == 0) {
344  cislog_error("comm_send_single: Invalid comm");
345  return ret;
346  }
347  comm_type t = x.type;
348  if (t == IPC_COMM)
349  ret = ipc_comm_send(x, data, len);
350  else if (t == ZMQ_COMM)
351  ret = zmq_comm_send(x, data, len);
352  else if (t == RPC_COMM)
353  ret = rpc_comm_send(x, data, len);
354  else if (t == SERVER_COMM)
355  ret = server_comm_send(x, data, len);
356  else if (t == CLIENT_COMM)
357  ret = client_comm_send(x, data, len);
358  else if (t == ASCII_FILE_COMM)
359  ret = ascii_file_comm_send(x, data, len);
360  else if ((t == ASCII_TABLE_COMM) || (t == ASCII_TABLE_ARRAY_COMM))
361  ret = ascii_table_comm_send(x, data, len);
362  else {
363  cislog_error("comm_send_single: Unsupported comm_type %d", t);
364  }
365  if (ret >= 0) {
366  time(x.last_send);
367  /* time_t now; */
368  /* time(&now); */
369  /* x.last_send[0] = now; */
370  }
371  return ret;
372 };
373 
374 
383 static
384 comm_head_t comm_send_multipart_header(const comm_t x, const char * data,
385  const size_t len) {
386  comm_head_t head = init_header(len, NULL, NULL);
387  sprintf(head.id, "%d", rand());
388  head.multipart = 1;
389  head.valid = 1;
390  // Add serializer information to header on first send
391  if ((x.used[0] == 0) && (x.is_file == 0)) {
392  seri_t *serializer;
393  if (x.type == CLIENT_COMM) {
394  comm_t *req_comm = (comm_t*)(x.handle);
395  serializer = req_comm->serializer;
396  } else {
397  serializer = x.serializer;
398  }
399  if (serializer->type == DIRECT_SERI) {
400  head.serializer_type = 0;
401  } else if (serializer->type == FORMAT_SERI) {
402  head.serializer_type = 1;
403  strcpy(head.format_str, (char*)(serializer->info));
404  } else if (serializer->type == ARRAY_SERI) {
405  head.serializer_type = 2;
406  strcpy(head.format_str, (char*)(serializer->info));
407  head.as_array = 1;
408  } else if (serializer->type == ASCII_TABLE_SERI) {
409  head.serializer_type = 1;
410  asciiTable_t *table = (asciiTable_t*)(serializer->info);
411  strcpy(head.format_str, table->format_str);
412  } else if (serializer->type == ASCII_TABLE_ARRAY_SERI) {
413  head.serializer_type = 2;
414  asciiTable_t *table = (asciiTable_t*)(serializer->info);
415  strcpy(head.format_str, table->format_str);
416  head.as_array = 1;
417  } else if (serializer->type == PLY_SERI) {
418  head.serializer_type = 8;
419  } else if (serializer->type == OBJ_SERI) {
420  head.serializer_type = 9;
421  }
422  }
423  const comm_t *x0;
424  if (x.type == SERVER_COMM) {
425  comm_t **res_comm = (comm_t**)(x.info);
426  if (res_comm[0] == NULL) {
427  cislog_error("comm_send_multipart_header(%s): no response comm registered",
428  x.name);
429  head.valid = 0;
430  return head;
431  }
432  x0 = &((*res_comm)[0]);
433  // Why was this necessary?
434  strcpy(head.id, x.address);
435  } else if (x.type == CLIENT_COMM) {
436  if (!(is_eof(data))) {
437  head = client_response_header(x, head);
438  }
439  x0 = (comm_t*)(x.handle);
440  } else {
441  x0 = &x;
442  }
443  // Get ZMQ header info
444  if (x0->type == ZMQ_COMM) {
445  char *reply_address = set_reply_send(x0);
446  if (reply_address == NULL) {
447  cislog_error("comm_send_multipart_header: Could not set reply address.");
448  head.valid = 0;
449  return head;
450  }
451  strcpy(head.zmq_reply, reply_address);
452  }
453  return head;
454 };
455 
463 static
464 int comm_send_multipart(const comm_t x, const char *data, const size_t len) {
465  //char headbuf[CIS_MSG_BUF];
466  int headbuf_len = CIS_MSG_BUF;
467  int headlen = 0, ret = -1;
468  if (x.valid == 0) {
469  cislog_error("comm_send_multipart: Invalid comm");
470  return ret;
471  }
472  comm_t xmulti = empty_comm_base();
473  // Get header
474  comm_head_t head = comm_send_multipart_header(x, data, len);
475  if (head.valid == 0) {
476  cislog_error("comm_send_multipart: Invalid header generated.");
477  return -1;
478  }
479  char *headbuf = (char*)malloc(headbuf_len);
480  if (headbuf == NULL) {
481  cislog_error("comm_send_multipart: Failed to malloc headbuf.");
482  return -1;
483  }
484  // Try to send body in header
485  if (len < x.maxMsgSize) {
486  headlen = format_comm_header(head, headbuf, headbuf_len);
487  if (headlen < 0) {
488  cislog_error("comm_send_multipart: Failed to format header.");
489  free(headbuf);
490  return -1;
491  }
492  if (((size_t)headlen + len) < x.maxMsgSize) {
493  if (((size_t)headlen + len + 1) > (size_t)headbuf_len) {
494  char *t_headbuf = (char*)realloc(headbuf, (size_t)headlen + len + 1);
495  if (t_headbuf == NULL) {
496  cislog_error("comm_send_multipart: Failed to realloc headbuf.");
497  free(headbuf);
498  return -1;
499  }
500  headbuf = t_headbuf;
501  headbuf_len = headlen + (int)len + 1;
502  }
503  head.multipart = 0;
504  memcpy(headbuf + headlen, data, len);
505  headlen += (int)len;
506  headbuf[headlen] = '\0';
507  }
508  }
509  // Get head string
510  if (head.multipart == 1) {
511  // Get address for new comm and add to header
512  xmulti = new_comm(NULL, "send", x.type, NULL);
513  if (!(xmulti.valid)) {
514  cislog_error("comm_send_multipart: Failed to initialize a new comm.");
515  free(headbuf);
516  return -1;
517  }
518  xmulti.sent_eof[0] = 1;
519  xmulti.recv_eof[0] = 1;
520  xmulti.is_work_comm = 1;
521  strcpy(head.address, xmulti.address);
522  if (xmulti.type == ZMQ_COMM) {
523  char *reply_address = set_reply_send(&xmulti);
524  if (reply_address == NULL) {
525  cislog_error("comm_send_multipart: Could not set worker reply address.");
526  return -1;
527  }
528  strcpy(head.zmq_reply_worker, reply_address);
529  }
530  headlen = format_comm_header(head, headbuf, headbuf_len);
531  if (headlen < 0) {
532  cislog_error("comm_send_multipart: Failed to format header.");
533  free(headbuf);
534  free_comm(&xmulti);
535  return -1;
536  }
537  }
538  // Send header
539  ret = comm_send_single(x, headbuf, headlen);
540  if (ret < 0) {
541  cislog_error("comm_send_multipart: Failed to send header.");
542  if (head.multipart == 1)
543  free_comm(&xmulti);
544  free(headbuf);
545  return -1;
546  }
547  if (head.multipart == 0) {
548  cislog_debug("comm_send_multipart(%s): %d bytes completed", x.name, head.size);
549  free(headbuf);
550  return ret;
551  }
552  // Send multipart
553  size_t msgsiz;
554  size_t prev = 0;
555  while (prev < head.size) {
556  if ((head.size - prev) > xmulti.maxMsgSize)
557  msgsiz = xmulti.maxMsgSize;
558  else
559  msgsiz = head.size - prev;
560  ret = comm_send_single(xmulti, data + prev, msgsiz);
561  if (ret < 0) {
562  cislog_debug("comm_send_multipart(%s): send interupted at %d of %d bytes.",
563  x.name, prev, head.size);
564  break;
565  }
566  prev += msgsiz;
567  cislog_debug("comm_send_multipart(%s): %d of %d bytes sent",
568  x.name, prev, head.size);
569  }
570  if (ret == 0)
571  cislog_debug("comm_send_multipart(%s): %d bytes completed", x.name, head.size);
572  // Free multipart
573  free_comm(&xmulti);
574  free(headbuf);
575  if (ret >= 0)
576  x.used[0] = 1;
577  return ret;
578 };
579 
580 
590 static
591 int comm_send(const comm_t x, const char *data, const size_t len) {
592  int ret = -1;
593  if (x.valid == 0) {
594  cislog_error("comm_send: Invalid comm");
595  return ret;
596  }
597  if (x.sent_eof == NULL) {
598  cislog_error("comm_send(%s): sent_eof not initialized.", x.name);
599  return ret;
600  }
601  int sending_eof = 0;
602  if (is_eof(data)) {
603  if (x.sent_eof[0] == 0) {
604  x.sent_eof[0] = 1;
605  if (x.type == CLIENT_COMM) {
606  comm_t *req_comm = (comm_t*)(x.handle);
607  req_comm->sent_eof[0] = 1;
608  }
609  sending_eof = 1;
610  cislog_debug("comm_send(%s): Sending EOF", x.name);
611  } else {
612  cislog_error("comm_send(%s): EOF already sent", x.name);
613  return ret;
614  }
615  }
616  if (((len > x.maxMsgSize) && (x.maxMsgSize > 0)) ||
617  (((x.always_send_header) || (x.used[0] == 0)))) { // && (!(is_eof(data))))) {
618  ret = comm_send_multipart(x, data, len);
619  } else {
620  cislog_debug("comm_send(%s): Sending as single message without a header.",
621  x.name);
622  ret = comm_send_single(x, data, len);
623  }
624  if (sending_eof) {
625  cislog_debug("comm_send(%s): sent EOF, ret = %d", x.name, ret);
626  }
627  if (ret >= 0)
628  x.used[0] = 1;
629  return ret;
630 };
631 
637 static
638 int comm_send_eof(const comm_t x) {
639  int ret = -1;
640  char buf[100] = CIS_MSG_EOF;
641  ret = comm_send(x, buf, strlen(buf));
642  return ret;
643 };
644 
657 static
658 int comm_recv_single(const comm_t x, char **data, const size_t len,
659  const int allow_realloc) {
660  int ret = -1;
661  if (x.valid == 0) {
662  cislog_error("comm_recv_single: Invalid comm");
663  return ret;
664  }
665  comm_type t = x.type;
666  if (t == IPC_COMM)
667  ret = ipc_comm_recv(x, data, len, allow_realloc);
668  else if (t == ZMQ_COMM)
669  ret = zmq_comm_recv(x, data, len, allow_realloc);
670  else if (t == RPC_COMM)
671  ret = rpc_comm_recv(x, data, len, allow_realloc);
672  else if (t == SERVER_COMM)
673  ret = server_comm_recv(x, data, len, allow_realloc);
674  else if (t == CLIENT_COMM)
675  ret = client_comm_recv(x, data, len, allow_realloc);
676  else if (t == ASCII_FILE_COMM)
677  ret = ascii_file_comm_recv(x, data, len, allow_realloc);
678  else if ((t == ASCII_TABLE_COMM) || (t == ASCII_TABLE_ARRAY_COMM))
679  ret = ascii_table_comm_recv(x, data, len, allow_realloc);
680  else {
681  cislog_error("comm_recv: Unsupported comm_type %d", t);
682  }
683  return ret;
684 };
685 
696 static
697 int comm_recv_multipart(const comm_t x, char **data, const size_t len,
698  const size_t headlen, const int allow_realloc) {
699  int ret = -1;
700  if (x.valid == 0) {
701  cislog_error("comm_recv_multipart: Invalid comm");
702  return ret;
703  }
704  usleep(100);
705  comm_head_t head = parse_comm_header(*data, headlen);
706  if (!(head.valid)) {
707  cislog_error("comm_recv_multipart(%s): Error parsing header.", x.name);
708  ret = -1;
709  } else {
710  // Get serializer information from header on first recv
711  if ((x.used[0] == 0) && (x.is_file == 0) && (x.serializer->type == 0)) {
712  int new_type = -1;
713  void *new_info = (void*)(head.format_str);
714  cislog_debug("comm_recv_multipart(%s): Updating serializer type to %d",
715  x.name, head.serializer_type);
716  if (head.serializer_type == 0) {
717  new_type = DIRECT_SERI;
718  } else if (head.serializer_type == 1) {
719  new_type = FORMAT_SERI;
720  } else if (head.serializer_type == 2) {
721  new_type = ASCII_TABLE_ARRAY_SERI;
722  // TODO: Treat this as a separate class
723  // new_type = ARRAY_SERI;
724  } else if (head.serializer_type == 3) {
725  if (head.as_array == 0) {
726  new_type = ASCII_TABLE_SERI;
727  } else {
728  new_type = ASCII_TABLE_ARRAY_SERI;
729  }
730  } else if (head.serializer_type == 8) {
731  new_type = PLY_SERI;
732  } else if (head.serializer_type == 9) {
733  new_type = OBJ_SERI;
734  }
735  if (new_type >= 0) {
736  ret = update_serializer(x.serializer, new_type, new_info);
737  if (ret != 0) {
738  cislog_error("comm_recv_multipart(%s): Error updating serializer.", x.name);
739  return -1;
740  }
741  }
742  // Set name for debug info & simplify formats
743  if ((new_type == ASCII_TABLE_SERI) || (new_type == ASCII_TABLE_ARRAY_SERI)) {
744  asciiTable_t *table = (asciiTable_t*)(x.serializer->info);
745  ret = at_update(table, x.name, "0");
746  if (ret != 0) {
747  cislog_error("comm_recv_multipart(%s): Failed to update asciiTable address.",
748  x.name);
749  return -1;
750  }
751  ret = simplify_formats(table->format_str, CIS_MSG_MAX);
752  if (ret < 0) {
753  cislog_error("comm_recv_multipart(%s): Failed to simplify recvd table format.", x.name);
754  return -1;
755  }
756  } else if (new_type == FORMAT_SERI) {
757  char * format_str = (char*)(x.serializer->info);
758  ret = simplify_formats(format_str, x.serializer->size_info);
759  if (ret < 0) {
760  cislog_error("comm_recv_multipart(%s): Failed to simplify recvd format.", x.name);
761  return -1;
762  }
763  }
764  }
765  if (head.multipart) {
766  // Move part of message after header to front of data
767  memmove(*data, *data + head.bodybeg, head.bodysiz);
768  (*data)[head.bodysiz] = '\0';
769  if (is_eof(*data)) {
770  cislog_debug("comm_recv_multipart(%s): EOF received.", x.name);
771  x.recv_eof[0] = 1;
772  return -2;
773  }
774  // Return early if header contained entire message
775  if (head.size == head.bodysiz) {
776  x.used[0] = 1;
777  return (int)(head.bodysiz);
778  }
779  // Get address for new comm
780  comm_t xmulti = new_comm(head.address, "recv", x.type, NULL);
781  if (!(xmulti.valid)) {
782  cislog_error("comm_recv_multipart: Failed to initialize a new comm.");
783  return -1;
784  }
785  xmulti.sent_eof[0] = 1;
786  xmulti.recv_eof[0] = 1;
787  xmulti.is_work_comm = 1;
788  if (xmulti.type == ZMQ_COMM) {
789  int reply_socket = set_reply_recv(&xmulti, head.zmq_reply_worker);
790  if (reply_socket < 0) {
791  cislog_error("comm_recv_multipart: Failed to set worker reply address.");
792  return -1;
793  }
794  }
795  // Receive parts of message
796  size_t prev = head.bodysiz;
797  size_t msgsiz = 0;
798  // Reallocate data if necessary
799  if ((head.size + 1) > len) {
800  if (allow_realloc) {
801  char *t_data = (char*)realloc(*data, head.size + 1);
802  if (t_data == NULL) {
803  cislog_error("comm_recv_multipart(%s): Failed to realloc buffer",
804  x.name);
805  free(*data);
806  free_comm(&xmulti);
807  return -1;
808  }
809  *data = t_data;
810  } else {
811  cislog_error("comm_recv_multipart(%s): buffer is not large enough",
812  x.name);
813  free_comm(&xmulti);
814  return -1;
815  }
816  }
817  ret = -1;
818  char *pos = (*data) + prev;
819  while (prev < head.size) {
820  msgsiz = head.size - prev + 1;
821  ret = comm_recv_single(xmulti, &pos, msgsiz, 0);
822  if (ret < 0) {
823  cislog_debug("comm_recv_multipart(%s): recv interupted at %d of %d bytes.",
824  x.name, prev, head.size);
825  break;
826  }
827  prev += ret;
828  pos += ret;
829  cislog_debug("comm_recv_multipart(%s): %d of %d bytes received",
830  x.name, prev, head.size);
831  }
832  if (ret > 0) {
833  cislog_debug("comm_recv_multipart(%s): %d bytes completed", x.name, prev);
834  ret = (int)prev;
835  }
836  free_comm(&xmulti);
837  } else {
838  ret = (int)headlen;
839  }
840  }
841  if (ret >= 0)
842  x.used[0] = 1;
843  return ret;
844 };
845 
856 static
857 int comm_recv(const comm_t x, char *data, const size_t len) {
858  int ret = comm_recv_single(x, &data, len, 0);
859  if (ret > 0) {
860  if (is_eof(data)) {
861  cislog_debug("comm_recv(%s): EOF received.", x.name);
862  x.recv_eof[0] = 1;
863  ret = -2;
864  } else {
865  ret = comm_recv_multipart(x, &data, len, ret, 0);
866  }
867  } else {
868  cislog_error("comm_recv_realloc(%s): Failed to receive header or message.",
869  x.name);
870  }
871  return ret;
872 };
873 
883 static
884 int comm_recv_realloc(const comm_t x, char **data, const size_t len) {
885  int ret = comm_recv_single(x, data, len, 1);
886  if (ret > 0) {
887  if (is_eof(*data)) {
888  cislog_debug("comm_recv_realloc(%s): EOF received.", x.name);
889  x.recv_eof[0] = 1;
890  ret = -2;
891  } else {
892  ret = comm_recv_multipart(x, data, len, ret, 1);
893  }
894  } else {
895  cislog_error("comm_recv_realloc(%s): Failed to receive header or message.",
896  x.name);
897  }
898  return ret;
899 };
900 
901 
903 static
904 int comm_send_nolimit(const comm_t x, const char *data, const size_t len) {
905  return comm_send(x, data, len);
906 };
907 
913 static
914 int comm_send_nolimit_eof(const comm_t x) {
915  int ret = -1;
916  if (x.valid == 0) {
917  cislog_error("comm_send_nolimit_eof: Invalid comm");
918  return ret;
919  }
920  if (x.sent_eof == NULL) {
921  cislog_error("comm_send_nolimit_eof(%s): sent_eof not initialized.", x.name);
922  return ret;
923  }
924  if (x.sent_eof[0] == 0) {
925  char buf[2048] = CIS_MSG_EOF;
926  ret = comm_send_nolimit(x, buf, strlen(buf));
927  x.sent_eof[0] = 1;
928  } else {
929  cislog_error("comm_send_nolimit_eof(%s): EOF already sent", x.name);
930  }
931  return ret;
932 };
933 
947 static
948 int comm_recv_nolimit(const comm_t x, char **data, const size_t len) {
949  return comm_recv_realloc(x, data, len);
950 };
951 
962 static
963 int vcommSend(const comm_t x, va_list ap) {
964  int ret = -1;
965  if (x.valid == 0) {
966  cislog_error("vcommSend: Invalid comm");
967  return ret;
968  }
969  size_t buf_siz = CIS_MSG_BUF;
970  // char *buf = NULL;
971  char *buf = (char*)malloc(buf_siz);
972  if (buf == NULL) {
973  cislog_error("vcommSend(%s): Failed to alloc buffer", x.name);
974  return -1;
975  }
976  seri_t *serializer = x.serializer;
977  if (x.type == CLIENT_COMM) {
978  comm_t *handle = (comm_t*)(x.handle);
979  serializer = handle->serializer;
980  }
981  int args_used = 0;
982  ret = serialize(*serializer, &buf, buf_siz, 1, &args_used, ap);
983  if (ret < 0) {
984  cislog_error("vcommSend(%s): serialization error", x.name);
985  free(buf);
986  return -1;
987  }
988  ret = comm_send(x, buf, ret);
989  cislog_debug("vcommSend(%s): comm_send returns %d", x.name, ret);
990  free(buf);
991  if (ret < 0) {
992  return ret;
993  } else {
994  return args_used;
995  }
996 };
997 
1010 static
1011 int vcommRecv(const comm_t x, va_list ap) {
1012  int ret = -1;
1013  if (x.valid == 0) {
1014  cislog_error("vcommRecv: Invalid comm");
1015  return ret;
1016  }
1017  // Receive message
1018  size_t buf_siz = CIS_MSG_BUF;
1019  /* char *buf = NULL; */
1020  char *buf = (char*)malloc(buf_siz);
1021  if (buf == NULL) {
1022  cislog_error("vcommSend(%s): Failed to alloc buffer", x.name);
1023  return -1;
1024  }
1025  ret = comm_recv_nolimit(x, &buf, buf_siz);
1026  if (ret < 0) {
1027  // cislog_error("vcommRecv(%s): Error receiving.", x.name);
1028  free(buf);
1029  return ret;
1030  }
1031  cislog_debug("vcommRecv(%s): comm_recv returns %d: %.10s...", x.name, ret, buf);
1032  // Deserialize message
1033  seri_t *serializer = x.serializer;
1034  if (x.type == SERVER_COMM) {
1035  comm_t *handle = (comm_t*)(x.handle);
1036  serializer = handle->serializer;
1037  }
1038  ret = deserialize(*serializer, buf, ret, ap);
1039  if (ret < 0) {
1040  cislog_error("vcommRecv(%s): error deserializing message (ret=%d)",
1041  x.name, ret);
1042  free(buf);
1043  return -1;
1044  }
1045  cislog_debug("vcommRecv(%s): deserialize_format returns %d", x.name, ret);
1046  free(buf);
1047  return ret;
1048 };
1049 
1050 #define vcommSend_nolimit vcommSend
1051 #define vcommRecv_nolimit vcommRecv
1052 
1053 #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
1054 }
1055 #endif
1056 
1057 #endif /*CISCOMMUNICATION_H_*/
void * handle
Pointer to handle for comm.
Definition: CommBase.h:29
char format_str[LINE_SIZE_MAX]
Format string for rows.
Definition: AsciiTable.h:82
void * info
Pointer to any extra info comm requires.
Definition: CommBase.h:30
Communication structure.
Definition: CommBase.h:23
char address[COMM_ADDRESS_SIZE]
Comm address.
Definition: CommBase.h:26
char zmq_reply_worker[COMMBUFFSIZ]
Reply address for worker socket.
Definition: comm_header.h:35
int is_work_comm
Flag specifying if comm is a temporary work comm.
Definition: CommBase.h:41
Serializer structure.
Definition: SerializeBase.h:19
time_t * last_send
Clock output at time of last send.
Definition: CommBase.h:35
void * info
Pointer to any extra info serializer requires.
Definition: SerializeBase.h:21
int multipart
1 if message is multipart, 0 if it is not.
Definition: comm_header.h:22
size_t bodybeg
Start of body in header.
Definition: comm_header.h:24
size_t maxMsgSize
The maximum message size.
Definition: CommBase.h:32
size_t size_info
Size of allocate space for info.
Definition: SerializeBase.h:22
int * used
Flag specifying if the comm has been used.
Definition: CommBase.h:38
char address[COMMBUFFSIZ]
Address that message will comm in on.
Definition: comm_header.h:21
comm_type type
Comm type.
Definition: CommBase.h:24
int valid
1 if the header is valid, 0 otherwise.
Definition: comm_header.h:25
int is_file
Flag specifying if the comm connects directly to a file.
Definition: CommBase.h:40
int always_send_header
1 if comm should always send a header.
Definition: CommBase.h:33
seri_t * serializer
Serializer for comm messages.
Definition: CommBase.h:31
char zmq_reply[COMMBUFFSIZ]
Reply address for ZMQ sockets.
Definition: comm_header.h:34
char format_str[COMMBUFFSIZ]
Format string for serializer.
Definition: comm_header.h:30
size_t bodysiz
Size of body.
Definition: comm_header.h:23
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 * sent_eof
Flag specifying if EOF has been sent.
Definition: CommBase.h:36
size_t size
Size of incoming message.
Definition: comm_header.h:20
int valid
1 if communicator initialized, 0 otherwise.
Definition: CommBase.h:28
int * recv_eof
Flag specifying if EOF has been received.
Definition: CommBase.h:37
int as_array
1 if messages will be serialized arrays.
Definition: comm_header.h:33
int serializer_type
Code indicating the type of serializer.
Definition: comm_header.h:29
Structure containing information about an ASCII table.
Definition: AsciiTable.h:80
char id[COMMBUFFSIZ]
Unique ID associated with this message.
Definition: comm_header.h:26
int index_in_register
Index of the comm in the comm register.
Definition: CommBase.h:34
seri_type type
Serializer type.
Definition: SerializeBase.h:20
Header information passed by comms for multipart messages.
Definition: comm_header.h:19