msg.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /** @file crsp_msg.c
  2. * @brief Class represents a single message of CRSP protocol.
  3. *
  4. * CRSP message consist of main header, a block of parameter headers and then
  5. * parameters themselfs. Class stores these data. Additionally class knows
  6. * the structure of message and can send and receive messages via socket. It
  7. * uses external faux_net_t object to do so. The receive function is necessary
  8. * because message has a variable length and message parsing is needed to get
  9. * actual length of message. The send function is usefull because class uses
  10. * struct iovec array to compose outgoing message so it's not necessary to
  11. * assemble message into the single long memory chunk.
  12. */
  13. #include <stdlib.h>
  14. #include <stdint.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <assert.h>
  18. #include <unistd.h>
  19. #include <errno.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <fcntl.h>
  23. #include <sys/socket.h>
  24. #include <sys/un.h>
  25. #include <arpa/inet.h>
  26. #include <faux/faux.h>
  27. #include <faux/str.h>
  28. #include <faux/list.h>
  29. #include <faux/net.h>
  30. #include <faux/msg.h>
  31. // Global variable to switch debug on/off (1/0)
  32. int crsp_debug = 0;
  33. /** @brief Opaque faux_msg_s structure. */
  34. struct faux_msg_s {
  35. faux_hdr_t *hdr; // Message header
  36. faux_list_t *params; // List of parameters
  37. };
  38. /** @brief Allocate memory to store message.
  39. *
  40. * This static function is needed because new message object can be created
  41. * in a different ways. The first way is creating outgoing message manually and
  42. * the second way is receiving CRSP message from network. These ways need
  43. * different initialization but the same memory allocation.
  44. *
  45. * @return Allocated but not fully initialized faux_msg_t object
  46. * or NULL on error
  47. */
  48. static faux_msg_t *faux_msg_allocate(void)
  49. {
  50. faux_msg_t *msg = NULL;
  51. msg = faux_zmalloc(sizeof(*msg));
  52. assert(msg);
  53. if (!msg)
  54. return NULL;
  55. // Init message header
  56. msg->hdr = faux_zmalloc(sizeof(*msg->hdr));
  57. assert(msg->hdr);
  58. if (!msg->hdr) {
  59. faux_msg_free(msg);
  60. return NULL;
  61. }
  62. msg->params = faux_list_new(
  63. FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE, NULL, NULL, faux_free);
  64. return msg;
  65. }
  66. /** @brief Creates new faux_msg_t object. It's usually outgoing message.
  67. *
  68. * Function initializes main message header with default values. Usually
  69. * only outgoing messages need initialized header.
  70. *
  71. * @param [in] magic Protocol's magic number.
  72. * @param [in] major Protocol's version major number.
  73. * @param [in] minor Protocol's version minor number.
  74. * @return Allocated and initilized faux_msg_t object or NULL on error.
  75. */
  76. faux_msg_t *faux_msg_new(uint32_t magic, uint8_t major, uint8_t minor)
  77. {
  78. faux_msg_t *msg = NULL;
  79. msg = faux_msg_allocate();
  80. assert(msg);
  81. if (!msg)
  82. return NULL;
  83. // Init
  84. msg->hdr->magic = htonl(magic);
  85. msg->hdr->major = major;
  86. msg->hdr->minor = minor;
  87. faux_msg_set_cmd(msg, 0);
  88. faux_msg_set_status(msg, 0);
  89. faux_msg_set_req_id(msg, 0l);
  90. faux_msg_set_param_num(msg, 0l);
  91. faux_msg_set_len(msg, sizeof(*msg->hdr));
  92. return msg;
  93. }
  94. /** @brief Frees allocated message.
  95. *
  96. * @param [in] msg Allocated faux_msg_t object.
  97. */
  98. void faux_msg_free(faux_msg_t *msg)
  99. {
  100. if (!msg)
  101. return;
  102. faux_list_free(msg->params);
  103. faux_free(msg->hdr);
  104. faux_free(msg);
  105. }
  106. /** @brief Sets command code to header.
  107. *
  108. * See the protocol and header description for possible values.
  109. *
  110. * @param [in] msg Allocated faux_msg_t object.
  111. * @param [in] cmd Command code (16 bit).
  112. */
  113. void faux_msg_set_cmd(faux_msg_t *msg, uint16_t cmd)
  114. {
  115. assert(msg);
  116. assert(msg->hdr);
  117. if (!msg || !msg->hdr)
  118. return;
  119. msg->hdr->cmd = htons(cmd);
  120. }
  121. /** @brief Gets command code from header.
  122. *
  123. * See the protocol and header description for possible values.
  124. *
  125. * @param [in] msg Allocated faux_msg_t object.
  126. * @param [out] cmd Command code.
  127. * @return 0 - success, < 0 - fail
  128. */
  129. int faux_msg_get_cmd(const faux_msg_t *msg, uint16_t *cmd)
  130. {
  131. assert(msg);
  132. assert(msg->hdr);
  133. if (!msg || !msg->hdr)
  134. return -1;
  135. if (cmd)
  136. *cmd = ntohs(msg->hdr->cmd);
  137. return 0;
  138. }
  139. /** @brief Sets message status to header.
  140. *
  141. * See the protocol and header description for possible values.
  142. *
  143. * @param [in] msg Allocated faux_msg_t object.
  144. * @param [in] status Message status.
  145. */
  146. void faux_msg_set_status(faux_msg_t *msg, uint32_t status)
  147. {
  148. assert(msg);
  149. assert(msg->hdr);
  150. if (!msg || !msg->hdr)
  151. return;
  152. msg->hdr->status = htonl(status);
  153. }
  154. /** @brief Gets message status from header.
  155. *
  156. * See the protocol and header description for possible values.
  157. *
  158. * @param [in] msg Allocated faux_msg_t object.
  159. * @param [out] status Message status.
  160. * @return 0 - success, < 0 -fail
  161. */
  162. int faux_msg_get_status(const faux_msg_t *msg, uint32_t *status)
  163. {
  164. assert(msg);
  165. assert(msg->hdr);
  166. if (!msg || !msg->hdr)
  167. return -1;
  168. if (status)
  169. *status = ntohl(msg->hdr->status);
  170. return 0;
  171. }
  172. /** @brief Sets request ID to header.
  173. *
  174. * @param [in] msg Allocated faux_msg_t object.
  175. * @param [in] req_id Request ID.
  176. */
  177. void faux_msg_set_req_id(faux_msg_t *msg, uint32_t req_id)
  178. {
  179. assert(msg);
  180. assert(msg->hdr);
  181. if (!msg || !msg->hdr)
  182. return;
  183. msg->hdr->req_id = htonl(req_id);
  184. }
  185. /** @brief Gets request ID from header.
  186. *
  187. * @param [in] msg Allocated faux_msg_t object.
  188. * @param [out] req_id Request ID.
  189. * @return 0 - success, < 0 - fail
  190. */
  191. int faux_msg_get_req_id(const faux_msg_t *msg, uint32_t *req_id)
  192. {
  193. assert(msg);
  194. assert(msg->hdr);
  195. if (!msg || !msg->hdr)
  196. return -1;
  197. if (req_id)
  198. *req_id = ntohl(msg->hdr->req_id);
  199. return 0;
  200. }
  201. /** @brief Sets number of parameters to header.
  202. *
  203. * It's a static function because external user can add or remove parameters
  204. * but class calculates total number of parameters internally.
  205. *
  206. * @param [in] msg Allocated faux_msg_t object.
  207. * @param [in] param_num Number of parameters.
  208. */
  209. static void faux_msg_set_param_num(faux_msg_t *msg, uint32_t param_num)
  210. {
  211. assert(msg);
  212. assert(msg->hdr);
  213. if (!msg || !msg->hdr)
  214. return;
  215. msg->hdr->param_num = htonl(param_num);
  216. }
  217. /** @brief Gets number of parameters from header.
  218. *
  219. * @param [in] msg Allocated faux_msg_t object.
  220. * @return Number of parameters.
  221. */
  222. int faux_msg_get_param_num(const faux_msg_t *msg, uint32_t *param_num)
  223. {
  224. assert(msg);
  225. assert(msg->hdr);
  226. if (!msg || !msg->hdr)
  227. return -1;
  228. if (param_num)
  229. *param_num = ntohl(msg->hdr->param_num);
  230. return 0;
  231. }
  232. /** @brief Sets total length of message to header.
  233. *
  234. * It's a static function because external user can add or remove parameters
  235. * but class calculates total length of message internally.
  236. *
  237. * @param [in] msg Allocated faux_msg_t object.
  238. * @param [in] len Total length of message.
  239. */
  240. static void faux_msg_set_len(faux_msg_t *msg, uint32_t len)
  241. {
  242. assert(msg);
  243. assert(msg->hdr);
  244. if (!msg || !msg->hdr)
  245. return;
  246. msg->hdr->len = htonl(len);
  247. }
  248. /** @brief Gets total length of message from header.
  249. *
  250. * @param [in] msg Allocated faux_msg_t object.
  251. * @param [out] len Total length of message.
  252. * @return 0 - success, < 0 - fail
  253. */
  254. int faux_msg_get_len(const faux_msg_t *msg, uint32_t *len)
  255. {
  256. assert(msg);
  257. assert(msg->hdr);
  258. if (!msg || !msg->hdr)
  259. return -1;
  260. if (len)
  261. *len = ntohl(msg->hdr->len);
  262. return 0;
  263. }
  264. /** @brief Gets magic number from header.
  265. *
  266. * @param [in] msg Allocated faux_msg_t object.
  267. * @param [out] magic Magic number.
  268. * @return 0 - success, < 0 - fail
  269. */
  270. int faux_msg_get_magic(const faux_msg_t *msg, uint32_t *magic)
  271. {
  272. assert(msg);
  273. assert(msg->hdr);
  274. if (!msg || !msg->hdr)
  275. return -1;
  276. if (magic)
  277. *magic = ntohl(msg->hdr->magic);
  278. return 0;
  279. }
  280. /** @brief Gets version from header.
  281. *
  282. * @param [in] msg Allocated faux_msg_t object.
  283. * @param [out] major Major version number.
  284. * @param [out] minor Minor version number.
  285. * @return 0 - success, < 0 - fail
  286. */
  287. int faux_msg_get_version(const faux_msg_t *msg, uint8_t *major, uint8_t *minor)
  288. {
  289. assert(msg);
  290. assert(msg->hdr);
  291. if (!msg || !msg->hdr)
  292. return -1;
  293. if (major)
  294. *major = msg->hdr->major;
  295. if (minor)
  296. *minor = msg->hdr->minor;
  297. return 0;
  298. }
  299. /** @brief Internal function to add message parameter
  300. *
  301. * Internal function can update or don't update number of parameters and
  302. * whole length within message header. It can be used while
  303. * message receive to don't break already calculated header
  304. * values. So when user is constructing message the values must be updated.
  305. *
  306. * @param [in] msg Allocated faux_msg_t object.
  307. * @param [in] type Type of parameter.
  308. * @param [in] buf Parameter's data buffer.
  309. * @param [in] len Parameter's data length.
  310. * @param [in] upadte_len Flag that says to update or don't update number of
  311. * parameters and total message length within header. BOOL_TRUE - update,
  312. * BOOL_FALSE - don't update.
  313. * @return Length of parameter's data or < 0 on error.
  314. */
  315. static ssize_t faux_msg_add_param_internal(faux_msg_t *msg,
  316. uint16_t type, const void *buf, size_t len, bool_t update_len)
  317. {
  318. faux_phdr_t *phdr = NULL;
  319. char *param = NULL;
  320. assert(msg);
  321. assert(msg->hdr);
  322. if (!msg || !msg->hdr)
  323. return -1;
  324. // Allocate parameter header and data
  325. param = faux_zmalloc(sizeof(*phdr) + len);
  326. assert(param);
  327. if (!param)
  328. return -1;
  329. // Init param hdr
  330. phdr = (faux_phdr_t *)param;
  331. phdr->param_type = htonl(type);
  332. phdr->param_len = htonl(len);
  333. // Copy data
  334. memcpy(param + sizeof(*phdr), buf, len);
  335. if (update_len) {
  336. uint32_t cur_param_num = 0;
  337. uint32_t cur_len = 0;
  338. // Update number of parameters
  339. faux_msg_get_param_num(msg, &cur_param_num);
  340. faux_msg_set_param_num(msg, cur_param_num + 1);
  341. // Update whole message length
  342. faux_msg_get_len(msg, &cur_len);
  343. crsp_msg_set_len(crsp_msg, cur_len + sizeof(*phdr) + len);
  344. }
  345. // Add to parameter list
  346. faux_list_add(msg->params, param);
  347. return len;
  348. }
  349. /** @brief Adds parameter to message.
  350. *
  351. * @param [in] msg Allocated faux_msg_t object.
  352. * @param [in] type Type of parameter.
  353. * @param [in] buf Parameter's data buffer.
  354. * @param [in] len Parameter's data length.
  355. * @return Length of parameter's data or < 0 on error.
  356. */
  357. ssize_t faux_msg_add_param(faux_msg_t *msg, uint16_t type,
  358. const void *buf, size_t len)
  359. {
  360. return faux_msg_add_param_internal(msg, type, buf, len, BOOL_TRUE);
  361. }
  362. /** @brief Initializes iterator to iterate through the message parameters.
  363. *
  364. * The iterator must be initialized before iteration.
  365. *
  366. * @param [in] crsp_msg Allocated crsp_msg_t object.
  367. * @return Initialized iterator.
  368. */
  369. faux_list_node_t *crsp_msg_init_param_iter(const crsp_msg_t *crsp_msg)
  370. {
  371. assert(crsp_msg);
  372. assert(crsp_msg->params);
  373. if (!crsp_msg || !crsp_msg->params)
  374. return NULL;
  375. return faux_list_head(crsp_msg->params);
  376. }
  377. /** @brief Internal function to get parameter's data by node (faux_list_node_t).
  378. *
  379. * Note function returns the main data by output arguments.
  380. *
  381. * @param [in] node Node from the parameter's list.
  382. * @param [out] param_type Type of parameter. See the crsp_param_e enumeration.
  383. * @param [out] param_buf Parameter's data buffer.
  384. * @param [out] param_len Parameter's data length.
  385. * @return Pointer to parameter's header or NULL on error.
  386. */
  387. static crsp_phdr_t *crsp_msg_get_param_by_node(const faux_list_node_t *node,
  388. crsp_param_e *param_type, void **param_data, uint32_t *param_len)
  389. {
  390. char *param = NULL;
  391. crsp_phdr_t *phdr = NULL;
  392. char *data = NULL;
  393. if (!node)
  394. return NULL;
  395. param = faux_list_data(node);
  396. phdr = (crsp_phdr_t *)param;
  397. data = param + sizeof(*phdr);
  398. if (param_type)
  399. *param_type = phdr->param_type;
  400. if (param_data)
  401. *param_data = data;
  402. if (param_len)
  403. *param_len = ntohl(phdr->param_len);
  404. return phdr;
  405. }
  406. /** @brief Iterate through the message parameters.
  407. *
  408. * First parameter (iterator/node) must be initialized first by
  409. * crsp_msg_init_param_iter().
  410. *
  411. * @param [in] node Initialized iterator of parameter list.
  412. * @param [out] param_type Type of parameter. See the crsp_param_e enumeration.
  413. * @param [out] param_buf Parameter's data buffer.
  414. * @param [out] param_len Parameter's data length.
  415. * @return Pointer to parameter's header or NULL on error.
  416. */
  417. crsp_phdr_t *crsp_msg_get_param_each(faux_list_node_t **node,
  418. crsp_param_e *param_type, void **param_data, uint32_t *param_len)
  419. {
  420. faux_list_node_t *current_node = NULL;
  421. if (!node || !*node)
  422. return NULL;
  423. current_node = *node;
  424. *node = faux_list_next_node(current_node);
  425. return crsp_msg_get_param_by_node(current_node,
  426. param_type, param_data, param_len);
  427. }
  428. /** @brief Gets message parameter by the index.
  429. *
  430. * @param [in] crsp_msg Allocated crsp_msg_t object.
  431. * @param [in] index Parameter's index.
  432. * @param [out] param_type Type of parameter. See the crsp_param_e enumeration.
  433. * @param [out] param_buf Parameter's data buffer.
  434. * @param [out] param_len Parameter's data length.
  435. * @return Pointer to parameter's header or NULL on error.
  436. */
  437. crsp_phdr_t *crsp_msg_get_param_by_index(const crsp_msg_t *crsp_msg, unsigned int index,
  438. crsp_param_e *param_type, void **param_data, uint32_t *param_len)
  439. {
  440. faux_list_node_t *iter = NULL;
  441. unsigned int i = 0;
  442. assert(crsp_msg);
  443. assert(crsp_msg->hdr);
  444. if (!crsp_msg || !crsp_msg->hdr)
  445. return NULL;
  446. if (index >= crsp_msg_get_param_num(crsp_msg)) // Non-existent entry
  447. return NULL;
  448. iter = crsp_msg_init_param_iter(crsp_msg);
  449. while ((i != index) && iter) {
  450. i++;
  451. iter = faux_list_next_node(iter);
  452. }
  453. return crsp_msg_get_param_by_node(iter,
  454. param_type, param_data, param_len);
  455. }
  456. /** @brief Gets message parameter by parameter's type.
  457. *
  458. * @param [in] crsp_msg Allocated crsp_msg_t object.
  459. * @param [in] param_type Type of parameter. See the crsp_param_e enumeration.
  460. * @param [out] param_buf Parameter's data buffer.
  461. * @param [out] param_len Parameter's data length.
  462. * @return Pointer to parameter's header or NULL on error.
  463. */
  464. crsp_phdr_t *crsp_msg_get_param_by_type(const crsp_msg_t *crsp_msg,
  465. crsp_param_e param_type, void **param_data, uint32_t *param_len)
  466. {
  467. faux_list_node_t *iter = NULL;
  468. assert(crsp_msg);
  469. assert(crsp_msg->hdr);
  470. if (!crsp_msg || !crsp_msg->hdr)
  471. return NULL;
  472. for (iter = crsp_msg_init_param_iter(crsp_msg);
  473. iter; iter = faux_list_next_node(iter)) {
  474. crsp_phdr_t *phdr = NULL;
  475. phdr = (crsp_phdr_t *)faux_list_data(iter);
  476. if (phdr->param_type == param_type)
  477. return crsp_msg_get_param_by_node(iter,
  478. NULL, param_data, param_len);
  479. }
  480. // Not found
  481. return NULL;
  482. }
  483. /** @brief Sends CRSP message to network.
  484. *
  485. * Function sends message to network using preinitialized faux_net_t object.
  486. * User can specify timeout, signal mask, etc while faux_net_t object creation.
  487. *
  488. * Function can return length less than whole message length in the following
  489. * cases:
  490. * - An error has occured like broken file descriptor.
  491. * - Interrupted by allowed signal (see signal mask).
  492. * - Timeout.
  493. *
  494. * @param [in] crsp_msg Allocated crsp_msg_t object.
  495. * @param [in] faux_net Preinitialized faux_net_t object.
  496. * @return Length of sent data or < 0 on error.
  497. */
  498. ssize_t crsp_msg_send(crsp_msg_t *crsp_msg, faux_net_t *faux_net)
  499. {
  500. unsigned int vec_entries_num = 0;
  501. struct iovec *iov = NULL;
  502. unsigned int i = 0;
  503. faux_list_node_t *iter = NULL;
  504. size_t ret = 0;
  505. assert(crsp_msg);
  506. assert(crsp_msg->hdr);
  507. if (!crsp_msg || !crsp_msg->hdr)
  508. return -1;
  509. // Calculate number if struct iovec entries.
  510. // n = (msg header) + ((param hdr) + (param data)) * (param_num)
  511. vec_entries_num = 1 + (2 * crsp_msg_get_param_num(crsp_msg));
  512. iov = faux_zmalloc(vec_entries_num * sizeof(*iov));
  513. // Message header
  514. iov[i].iov_base = crsp_msg->hdr;
  515. iov[i].iov_len = sizeof(*crsp_msg->hdr);
  516. i++;
  517. // Parameter headers
  518. for (iter = crsp_msg_init_param_iter(crsp_msg);
  519. iter; iter = faux_list_next_node(iter)) {
  520. crsp_phdr_t *phdr = NULL;
  521. phdr = (crsp_phdr_t *)faux_list_data(iter);
  522. iov[i].iov_base = phdr;
  523. iov[i].iov_len = sizeof(*phdr);
  524. i++;
  525. }
  526. // Parameter data
  527. for (iter = crsp_msg_init_param_iter(crsp_msg);
  528. iter; iter = faux_list_next_node(iter)) {
  529. crsp_phdr_t *phdr = NULL;
  530. void *data = NULL;
  531. phdr = (crsp_phdr_t *)faux_list_data(iter);
  532. data = (char *)phdr + sizeof(*phdr);
  533. iov[i].iov_base = data;
  534. iov[i].iov_len = ntohl(phdr->param_len);
  535. i++;
  536. }
  537. ret = faux_net_sendv(faux_net, iov, vec_entries_num);
  538. faux_free(iov);
  539. // Debug
  540. if (crsp_msg && ret > 0 && crsp_debug) {
  541. printf("(o) ");
  542. crsp_msg_debug(crsp_msg);
  543. }
  544. return ret;
  545. }
  546. /** @brief Receives full CRSP message and allocates crsp_msg_t object for it.
  547. *
  548. * Function receives message from network using preinitialized faux_net_t object.
  549. * User can specify timeout, signal mask, etc while faux_net_t object creation.
  550. *
  551. * Function can return length less than whole message length in the following
  552. * cases:
  553. * - An error has occured like broken file descriptor.
  554. * - Interrupted by allowed signal (see signal mask).
  555. * - Timeout.
  556. *
  557. * It can be an logical errors while message receiving like wrong protocol
  558. * version. So function has additional parameter named 'status'. It will
  559. * be CRSP_STATUS_OK in a case when all is ok but function can return NULL and
  560. * set appropriate status to this parameter. It can be
  561. * CRSP_STATUS_WRONG_VERSION for example. The function will return NULL
  562. * and CRSP_STATUS_OK on some system errors like illegal parameters or
  563. * insufficient of memory.
  564. *
  565. * @param [in] faux_net Preinitialized faux_net_t object.
  566. * @param [out] status Status while message receiving. Can be NULL.
  567. * @return Allocated crsp_msg_t object. Object contains received message.
  568. */
  569. crsp_msg_t *crsp_msg_recv(faux_net_t *faux_net, crsp_recv_e *status)
  570. {
  571. crsp_msg_t *crsp_msg = NULL;
  572. size_t received = 0;
  573. crsp_phdr_t *phdr = NULL;
  574. unsigned int param_num = 0;
  575. size_t phdr_whole_len = 0;
  576. size_t max_data_len = 0;
  577. size_t cur_data_len = 0;
  578. unsigned int i = 0;
  579. char *data = NULL;
  580. if (status)
  581. *status = CRSP_RECV_OK;
  582. crsp_msg = crsp_msg_allocate();
  583. assert(crsp_msg);
  584. if (!crsp_msg)
  585. return NULL;
  586. // Receive message header
  587. received = faux_net_recv(faux_net,
  588. crsp_msg->hdr, sizeof(*crsp_msg->hdr));
  589. if (received != sizeof(*crsp_msg->hdr)) {
  590. crsp_msg_free(crsp_msg);
  591. return NULL;
  592. }
  593. if (!crsp_msg_check_hdr(crsp_msg, status)) {
  594. crsp_msg_free(crsp_msg);
  595. return NULL;
  596. }
  597. // Receive parameter headers
  598. param_num = crsp_msg_get_param_num(crsp_msg);
  599. if (param_num != 0) {
  600. phdr_whole_len = param_num * sizeof(*phdr);
  601. phdr = faux_zmalloc(phdr_whole_len);
  602. received = faux_net_recv(faux_net, phdr, phdr_whole_len);
  603. if (received != phdr_whole_len) {
  604. faux_free(phdr);
  605. crsp_msg_free(crsp_msg);
  606. if (status)
  607. *status = CRSP_RECV_BROKEN_PARAM;
  608. return NULL;
  609. }
  610. // Find out maximum data length
  611. for (i = 0; i < param_num; i++) {
  612. cur_data_len = ntohl(phdr[i].param_len);
  613. if (cur_data_len > max_data_len)
  614. max_data_len = cur_data_len;
  615. }
  616. // Receive parameter data
  617. data = faux_zmalloc(max_data_len);
  618. for (i = 0; i < param_num; i++) {
  619. cur_data_len = ntohl(phdr[i].param_len);
  620. if (0 == cur_data_len)
  621. continue;
  622. received = faux_net_recv(faux_net,
  623. data, cur_data_len);
  624. if (received != cur_data_len) {
  625. faux_free(data);
  626. faux_free(phdr);
  627. crsp_msg_free(crsp_msg);
  628. if (status)
  629. *status = CRSP_RECV_BROKEN_PARAM;
  630. return NULL;
  631. }
  632. crsp_msg_add_param_internal(crsp_msg, phdr[i].param_type,
  633. data, cur_data_len, BOOL_FALSE);
  634. }
  635. faux_free(data);
  636. faux_free(phdr);
  637. }
  638. // Debug
  639. if (crsp_msg && crsp_debug) {
  640. printf("(i) ");
  641. crsp_msg_debug(crsp_msg);
  642. }
  643. return crsp_msg;
  644. }
  645. /** @brief Gets CRSP_PARAM_CDP_URI parameter from message.
  646. *
  647. * Protocol helper.
  648. *
  649. * @param [in] crsp_msg Allocated crsp_msg_t object.
  650. * @return Allocated C-string or NULL on error. Must be freed by faux_str_free().
  651. */
  652. char *crsp_msg_get_param_cdp_uri(const crsp_msg_t *crsp_msg)
  653. {
  654. char *req_uri = NULL;
  655. uint32_t req_uri_len = 0;
  656. if (!crsp_msg_get_param_by_type(crsp_msg, CRSP_PARAM_CDP_URI,
  657. (void **)&req_uri, &req_uri_len))
  658. return NULL;
  659. if (0 == req_uri_len)
  660. return NULL;
  661. return faux_str_dupn(req_uri, req_uri_len);
  662. }
  663. /** @brief Print CRSP message debug info.
  664. *
  665. * Function prints header values and parameters.
  666. *
  667. * @param [in] crsp_msg Allocated crsp_msg_t object.
  668. */
  669. void crsp_msg_debug(crsp_msg_t *crsp_msg)
  670. #ifdef DEBUG
  671. {
  672. faux_list_node_t *iter = 0;
  673. crsp_param_e param_type = CRSP_PARAM_NULL;
  674. void *param_data = NULL;
  675. uint32_t param_len = 0;
  676. assert(crsp_msg);
  677. if (!crsp_msg)
  678. return;
  679. // Header
  680. printf("%c%c%c%c(%u.%u): %c%c %u %u %u |%lub\n",
  681. ((char *)crsp_msg->hdr)[0],
  682. ((char *)crsp_msg->hdr)[1],
  683. ((char *)crsp_msg->hdr)[2],
  684. ((char *)crsp_msg->hdr)[3],
  685. crsp_msg->hdr->major,
  686. crsp_msg->hdr->minor,
  687. crsp_msg_get_cmd(crsp_msg) != CRSP_CMD_NULL ? crsp_msg_get_cmd(crsp_msg) : '_',
  688. crsp_msg_get_status(crsp_msg) != CRSP_STATUS_NULL ? crsp_msg_get_status(crsp_msg) : '_',
  689. crsp_msg_get_req_id(crsp_msg),
  690. crsp_msg_get_param_num(crsp_msg),
  691. crsp_msg_get_len(crsp_msg),
  692. sizeof(*crsp_msg->hdr)
  693. );
  694. // Parameters
  695. iter = crsp_msg_init_param_iter(crsp_msg);
  696. while (crsp_msg_get_param_each(&iter, &param_type, &param_data, &param_len)) {
  697. printf(" %c %u [", param_type, param_len);
  698. if ((CRSP_PARAM_CDP_URI == param_type) ||
  699. (CRSP_PARAM_CRL_FILENAME == param_type)) {
  700. fwrite(param_data, param_len, 1, stdout);
  701. } else {
  702. printf("...");
  703. }
  704. printf("] |%lub\n", sizeof(crsp_phdr_t) + param_len);
  705. }
  706. }
  707. #else
  708. {
  709. crsp_msg = crsp_msg; // Happy compiler
  710. }
  711. #endif