cis_config
comm_header.h
1 
2 #ifndef CISCOMMHEADER_H_
3 #define CISCOMMHEADER_H_
4 
5 #include <../tools.h>
6 #include <../dataio/AsciiTable.h>
7 
8 #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
9 extern "C" {
10 #endif
11 
12 #define CIS_MSG_HEAD "CIS_MSG_HEAD"
13 #define HEAD_VAL_SEP ":CIS:"
14 #define HEAD_KEY_SEP ",CIS,"
15 #define COMMBUFFSIZ 2000
16 
17 
19 typedef struct comm_head_t {
20  size_t size;
21  char address[COMMBUFFSIZ];
22  int multipart;
23  size_t bodysiz;
24  size_t bodybeg;
25  int valid;
26  char id[COMMBUFFSIZ];
27  char response_address[COMMBUFFSIZ];
28  char request_id[COMMBUFFSIZ];
30  char format_str[COMMBUFFSIZ];
31  char field_names[COMMBUFFSIZ];
32  char field_units[COMMBUFFSIZ];
33  int as_array;
34  char zmq_reply[COMMBUFFSIZ];
35  char zmq_reply_worker[COMMBUFFSIZ];
36 } comm_head_t;
37 
47 static inline
48 comm_head_t init_header(const size_t size, const char *address, const char *id) {
49  comm_head_t out;
50  out.size = size;
51  out.multipart = 0;
52  out.bodysiz = 0;
53  out.bodybeg = 0;
54  out.valid = 1;
55  if (address == NULL)
56  out.address[0] = '\0';
57  else
58  strcpy(out.address, address);
59  if (id == NULL)
60  out.id[0] = '\0';
61  else
62  strcpy(out.id, id);
63  out.response_address[0] = '\0';
64  out.request_id[0] = '\0';
65  out.serializer_type = -1;
66  out.format_str[0] = '\0';
67  out.as_array = 0;
68  out.zmq_reply[0] = '\0';
69  out.zmq_reply_worker[0] = '\0';
70  /* if (response_address == NULL) */
71  /* out.response_address[0] = '\0'; */
72  /* else */
73  /* strcpy(out.response_address, response_address); */
74  return out;
75 };
76 
85 static inline
86 int format_header_entry(char *head, const char *key, const char *value,
87  const size_t headsiz) {
88  int ret = snprintf(head, headsiz, "%s%s%s%s",
89  key, HEAD_VAL_SEP, value, HEAD_KEY_SEP);
90  if (ret > (int)headsiz) {
91  cislog_error("format_header_entry: Formatted header is larger than bufer.\n");
92  return -1;
93  }
94  return ret;
95 };
96 
105 static inline
106 int parse_header_entry(const char *head, const char *key, char *value,
107  const size_t valsiz) {
108  // Compile
109  /*
110  if (strlen(HEAD_KEY_SEP) > 1) {
111  cislog_error("parse_header_entry: HEAD_KEY_SEP is more than one character. Fix regex.");
112  return -1;
113  } */
114  char regex_text[200];
115  regex_text[0] = '\0';
116  strcat(regex_text, HEAD_KEY_SEP);
117  strcat(regex_text, key);
118  strcat(regex_text, HEAD_VAL_SEP);
119  strcat(regex_text, "([^(");
120  strcat(regex_text, HEAD_KEY_SEP);
121  strcat(regex_text, ")]*)");
122  strcat(regex_text, HEAD_KEY_SEP);
123  // Extract substring
124  size_t *sind = NULL;
125  size_t *eind = NULL;
126  int n_sub_matches = find_matches(regex_text, head, &sind, &eind);
127  // Loop until string done
128  if (n_sub_matches < 2) {
129  cislog_debug("parse_header_entry: Could not find match to %s in %s.",
130  regex_text, head);
131  if (sind != NULL) free(sind);
132  if (eind != NULL) free(eind);
133  return -1;
134  }
135  // Extract substring
136  size_t value_size = eind[1] - sind[1];
137  if (value_size > valsiz) {
138  cislog_error("parse_header_entry: Value is larger than buffer.\n");
139  if (sind != NULL) free(sind);
140  if (eind != NULL) free(eind);
141  return -1;
142  }
143  memcpy(value, head + sind[1], value_size);
144  value[value_size] = '\0';
145  if (sind != NULL) free(sind);
146  if (eind != NULL) free(eind);
147  return (int)value_size;
148 };
149 
150 
158 static inline
159 int format_comm_header(const comm_head_t head, char *buf, const size_t bufsiz) {
160  int ret;
161  size_t pos;
162  // Header tag
163  pos = 0;
164  strcpy(buf, CIS_MSG_HEAD);
165  pos += strlen(CIS_MSG_HEAD);
166  if (pos > bufsiz) {
167  cislog_error("First header tag would exceed buffer size\n");
168  return -1;
169  }
170  // Address entry
171  if (strlen(head.address) > 0) {
172  ret = format_header_entry(buf + pos, "address", head.address, bufsiz - pos);
173  if (ret < 0) {
174  cislog_error("Adding address entry would exceed buffer size\n");
175  return ret;
176  } else {
177  pos += ret;
178  }
179  }
180  // Size entry
181  char size_str[100];
182  sprintf(size_str, "%d", (int)(head.size));
183  ret = format_header_entry(buf + pos, "size", size_str, bufsiz - pos);
184  if (ret < 0) {
185  cislog_error("Adding size entry would exceed buffer size\n");
186  return ret;
187  } else {
188  pos += ret;
189  }
190  // ID
191  if (strlen(head.id) > 0) {
192  ret = format_header_entry(buf + pos, "id", head.id, bufsiz - pos);
193  if (ret < 0) {
194  cislog_error("Adding id entry would exceed buffer size\n");
195  return ret;
196  } else {
197  pos += ret;
198  }
199  }
200  // REQUEST_ID
201  if (strlen(head.request_id) > 0) {
202  ret = format_header_entry(buf + pos, "request_id",
203  head.request_id, bufsiz - pos);
204  if (ret < 0) {
205  cislog_error("Adding request_id entry would exceed buffer size\n");
206  return ret;
207  } else {
208  pos += ret;
209  }
210  }
211  // RESPONSE_ADDRESS
212  if (strlen(head.response_address) > 0) {
213  ret = format_header_entry(buf + pos, "response_address",
214  head.response_address, bufsiz - pos);
215  if (ret < 0) {
216  cislog_error("Adding response_address entry would exceed buffer size\n");
217  return ret;
218  } else {
219  pos += ret;
220  }
221  }
222  // Serializer type
223  if (head.serializer_type >= 0) {
224  char stype_str[100];
225  sprintf(stype_str, "%d", head.serializer_type);
226  ret = format_header_entry(buf + pos, "stype", stype_str, bufsiz - pos);
227  if (ret < 0) {
228  cislog_error("Adding stype entry would exceed buffer size\n");
229  return ret;
230  } else {
231  pos += ret;
232  }
233  }
234  // Serializer format_str
235  if (strlen(head.format_str) > 0) {
236  ret = format_header_entry(buf + pos, "format_str",
237  head.format_str, bufsiz - pos);
238  if (ret < 0) {
239  cislog_error("Adding format_str entry would exceed buffer size\n");
240  return ret;
241  } else {
242  pos += ret;
243  }
244  }
245  // Serializer as_array
246  if (head.as_array > 0) {
247  char as_array_str[100];
248  sprintf(as_array_str, "%d", head.as_array);
249  ret = format_header_entry(buf + pos, "as_array", as_array_str, bufsiz - pos);
250  if (ret < 0) {
251  cislog_error("Adding as_array entry would exceed buffer size\n");
252  return ret;
253  } else {
254  pos += ret;
255  }
256  }
257  // ZMQ Reply address
258  if (strlen(head.zmq_reply) > 0) {
259  ret = format_header_entry(buf + pos, "zmq_reply",
260  head.zmq_reply, bufsiz - pos);
261  if (ret < 0) {
262  cislog_error("Adding zmq_reply entry would exceed buffer size\n");
263  return ret;
264  } else {
265  pos += ret;
266  }
267  }
268  // ZMQ Reply address for worker
269  if (strlen(head.zmq_reply_worker) > 0) {
270  ret = format_header_entry(buf + pos, "zmq_reply_worker",
271  head.zmq_reply_worker, bufsiz - pos);
272  if (ret < 0) {
273  cislog_error("Adding zmq_reply_worker entry would exceed buffer size\n");
274  return ret;
275  } else {
276  pos += ret;
277  }
278  }
279  // Closing header tag
280  pos -= strlen(HEAD_KEY_SEP);
281  buf[pos] = '\0';
282  pos += strlen(CIS_MSG_HEAD);
283  if (pos > bufsiz) {
284  cislog_error("Closing header tag would exceed buffer size\n");
285  return -1;
286  }
287  strcat(buf, CIS_MSG_HEAD);
288  /* // Body */
289  /* if (head.body != NULL) { */
290  /* pos += head.bodysiz; */
291  /* if (pos > bufsiz) { */
292  /* cislog_error("Adding body would exceed buffer size\n"); */
293  /* return -1; */
294  /* } */
295  /* memcpy(buf, head.body, head.bodysiz); */
296  /* buf[pos] = '\0'; */
297  /* } */
298  return (int)pos;
299 };
300 
307 static inline
308 comm_head_t parse_comm_header(const char *buf, const size_t bufsiz) {
309  comm_head_t out = init_header(0, NULL, NULL);
310  size_t sind, eind;
311  int ret;
312 #ifdef _WIN32
313  // Windows regex of newline is buggy
314  size_t sind1, eind1, sind2, eind2;
315  char re_head_tag[COMMBUFFSIZ];
316  sprintf(re_head_tag, "(%s)", CIS_MSG_HEAD);
317  ret = find_match(re_head_tag, buf, &sind1, &eind1);
318  if (ret > 0) {
319  sind = sind1;
320  ret = find_match(re_head_tag, buf + eind1, &sind2, &eind2);
321  if (ret > 0)
322  eind = eind1 + eind2;
323  }
324 #else
325  // Extract just header
326  char re_head[COMMBUFFSIZ] = CIS_MSG_HEAD;
327  strcat(re_head, "(.*)");
328  strcat(re_head, CIS_MSG_HEAD);
329  // strcat(re_head, ".*");
330  ret = find_match(re_head, buf, &sind, &eind);
331 #endif
332  if (ret < 0) {
333  cislog_error("parse_comm_header: could not find header in '%.1000s'", buf);
334  out.valid = 0;
335  return out;
336  } else if (ret == 0) {
337  cislog_debug("parse_comm_header: No header in '%.1000s...'", buf);
338  out.multipart = 0;
339  out.size = bufsiz;
340  } else {
341  out.multipart = 1;
342  // Extract just header
343  size_t headsiz = (eind-sind);
344  out.bodysiz = bufsiz - headsiz;
345  out.bodybeg = eind;
346  headsiz -= (2*strlen(CIS_MSG_HEAD));
347  char *head = (char*)malloc(headsiz + 2*strlen(HEAD_KEY_SEP) + 1);
348  strcpy(head, HEAD_KEY_SEP);
349  memcpy(head + strlen(HEAD_KEY_SEP), buf + sind + strlen(CIS_MSG_HEAD), headsiz);
350  head[headsiz + strlen(HEAD_KEY_SEP)] = '\0';
351  strcat(head, HEAD_KEY_SEP);
352  // Extract address
353  ret = parse_header_entry(head, "address", out.address, COMMBUFFSIZ);
354  // Extract size
355  char size_str[COMMBUFFSIZ];
356  ret = parse_header_entry(head, "size", size_str, COMMBUFFSIZ);
357  if (ret < 0) {
358  cislog_error("parse_comm_header: could not find size in header");
359  out.valid = 0;
360  free(head);
361  return out;
362  }
363  out.size = atoi(size_str);
364  // Extract id & response address
365  ret = parse_header_entry(head, "id", out.id, COMMBUFFSIZ);
366  ret = parse_header_entry(head, "response_address", out.response_address, COMMBUFFSIZ);
367  ret = parse_header_entry(head, "request_id", out.request_id, COMMBUFFSIZ);
368  // Extract serializer type
369  char stype_str[COMMBUFFSIZ];
370  ret = parse_header_entry(head, "stype", stype_str, COMMBUFFSIZ);
371  if (ret >= 0)
372  out.serializer_type = atoi(stype_str);
373  // Extract as_array serialization parameter
374  char array_str[COMMBUFFSIZ];
375  ret = parse_header_entry(head, "as_array", array_str, COMMBUFFSIZ);
376  if (ret >= 0)
377  out.as_array = atoi(array_str);
378  // Extract serializer information
379  ret = parse_header_entry(head, "format_str", out.format_str, COMMBUFFSIZ);
380  ret = parse_header_entry(head, "field_names", out.field_names, COMMBUFFSIZ);
381  ret = parse_header_entry(head, "field_units", out.field_units, COMMBUFFSIZ);
382  // ZMQ reply addresses
383  ret = parse_header_entry(head, "zmq_reply", out.zmq_reply, COMMBUFFSIZ);
384  ret = parse_header_entry(head, "zmq_reply_worker", out.zmq_reply_worker, COMMBUFFSIZ);
385  // Free header
386  free(head);
387  }
388  return out;
389 };
390 
391 #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
392 }
393 #endif
394 
395 #endif /*CISCOMMHEADER_H_*/
char field_names[COMMBUFFSIZ]
String containing field names.
Definition: comm_header.h:31
char response_address[COMMBUFFSIZ]
Response address.
Definition: comm_header.h:27
char request_id[COMMBUFFSIZ]
Request id.
Definition: comm_header.h:28
char zmq_reply_worker[COMMBUFFSIZ]
Reply address for worker socket.
Definition: comm_header.h:35
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
char address[COMMBUFFSIZ]
Address that message will comm in on.
Definition: comm_header.h:21
int valid
1 if the header is valid, 0 otherwise.
Definition: comm_header.h:25
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
size_t size
Size of incoming message.
Definition: comm_header.h:20
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
char field_units[COMMBUFFSIZ]
String containing field units.
Definition: comm_header.h:32
char id[COMMBUFFSIZ]
Unique ID associated with this message.
Definition: comm_header.h:26
Header information passed by comms for multipart messages.
Definition: comm_header.h:19