You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1356 lines
37 KiB

  1. /*
  2. * This file is part of GNUnet
  3. * Copyright (C) 2013 GNUnet e.V.
  4. *
  5. * GNUnet is free software: you can redistribute it and/or modify it
  6. * under the terms of the GNU Affero General Public License as published
  7. * by the Free Software Foundation, either version 3 of the License,
  8. * or (at your option) any later version.
  9. *
  10. * GNUnet is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. SPDX-License-Identifier: AGPL3.0-or-later
  18. */
  19. /**
  20. * @file psycutil/psyc_message.c
  21. * @brief PSYC utilities; receiving/transmitting/logging PSYC messages.
  22. * @author Gabor X Toth
  23. */
  24. #include <inttypes.h>
  25. #include "platform.h"
  26. #include "gnunet_util_lib.h"
  27. #include "gnunet_psyc_util_lib.h"
  28. #include "gnunet_psyc_service.h"
  29. #define LOG(kind,...) GNUNET_log_from (kind, "psyc-util",__VA_ARGS__)
  30. struct GNUNET_PSYC_TransmitHandle
  31. {
  32. /**
  33. * Client connection to service.
  34. */
  35. struct GNUNET_MQ_Handle *mq;
  36. /**
  37. * Message currently being received from the client.
  38. */
  39. struct GNUNET_MessageHeader *msg;
  40. /**
  41. * Envelope for @a msg
  42. */
  43. struct GNUNET_MQ_Envelope *env;
  44. /**
  45. * Callback to request next modifier from client.
  46. */
  47. GNUNET_PSYC_TransmitNotifyModifier notify_mod;
  48. /**
  49. * Closure for the notify callbacks.
  50. */
  51. void *notify_mod_cls;
  52. /**
  53. * Callback to request next data fragment from client.
  54. */
  55. GNUNET_PSYC_TransmitNotifyData notify_data;
  56. /**
  57. * Closure for the notify callbacks.
  58. */
  59. void *notify_data_cls;
  60. /**
  61. * Modifier of the environment that is currently being transmitted.
  62. */
  63. struct GNUNET_PSYC_Modifier *mod;
  64. /**
  65. *
  66. */
  67. const char *mod_value;
  68. /**
  69. * Number of bytes remaining to be transmitted from the current modifier value.
  70. */
  71. uint32_t mod_value_remaining;
  72. /**
  73. * State of the current message being received from client.
  74. */
  75. enum GNUNET_PSYC_MessageState state;
  76. /**
  77. * Number of PSYC_TRANSMIT_ACK messages we are still waiting for.
  78. */
  79. uint8_t acks_pending;
  80. /**
  81. * Is transmission paused?
  82. */
  83. uint8_t paused;
  84. /**
  85. * Are we currently transmitting a message?
  86. */
  87. uint8_t in_transmit;
  88. /**
  89. * Notify callback is currently being called.
  90. */
  91. uint8_t in_notify;
  92. };
  93. struct GNUNET_PSYC_ReceiveHandle
  94. {
  95. /**
  96. * Message callback.
  97. */
  98. GNUNET_PSYC_MessageCallback message_cb;
  99. /**
  100. * Message part callback.
  101. */
  102. GNUNET_PSYC_MessagePartCallback message_part_cb;
  103. /**
  104. * Closure for the callbacks.
  105. */
  106. void *cb_cls;
  107. /**
  108. * ID of the message being received from the PSYC service.
  109. */
  110. uint64_t message_id;
  111. /**
  112. * Public key of the slave from which a message is being received.
  113. */
  114. struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
  115. /**
  116. * State of the currently being received message from the PSYC service.
  117. */
  118. enum GNUNET_PSYC_MessageState state;
  119. /**
  120. * Flags for the currently being received message from the PSYC service.
  121. */
  122. enum GNUNET_PSYC_MessageFlags flags;
  123. /**
  124. * Expected value size for the modifier being received from the PSYC service.
  125. */
  126. uint32_t mod_value_size_expected;
  127. /**
  128. * Actual value size for the modifier being received from the PSYC service.
  129. */
  130. uint32_t mod_value_size;
  131. };
  132. /**** Messages ****/
  133. /**
  134. * Create a PSYC message.
  135. *
  136. * @param method_name
  137. * PSYC method for the message.
  138. * @param env
  139. * Environment for the message.
  140. * @param data
  141. * Data payload for the message.
  142. * @param data_size
  143. * Size of @a data.
  144. *
  145. * @return Message header with size information,
  146. * followed by the message parts.
  147. */
  148. struct GNUNET_PSYC_Message *
  149. GNUNET_PSYC_message_create (const char *method_name,
  150. const struct GNUNET_PSYC_Environment *env,
  151. const void *data,
  152. size_t data_size)
  153. {
  154. struct GNUNET_PSYC_Modifier *mod = NULL;
  155. struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
  156. struct GNUNET_PSYC_MessageModifier *pmod = NULL;
  157. struct GNUNET_MessageHeader *pmsg = NULL;
  158. uint16_t env_size = 0;
  159. if (NULL != env)
  160. {
  161. mod = GNUNET_PSYC_env_head (env);
  162. while (NULL != mod)
  163. {
  164. env_size += sizeof (*pmod) + strlen (mod->name) + 1 + mod->value_size;
  165. mod = mod->next;
  166. }
  167. }
  168. struct GNUNET_PSYC_Message *msg;
  169. uint16_t method_name_size = strlen (method_name) + 1;
  170. if (method_name_size == 1)
  171. return NULL;
  172. uint16_t msg_size = sizeof (*msg) /* header */
  173. + sizeof (*pmeth) + method_name_size /* method */
  174. + env_size /* modifiers */
  175. + ((0 < data_size) ? sizeof (*pmsg) + data_size : 0) /* data */
  176. + sizeof (*pmsg); /* end of message */
  177. msg = GNUNET_malloc (msg_size);
  178. msg->header.size = htons (msg_size);
  179. msg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); /* FIXME */
  180. pmeth = (struct GNUNET_PSYC_MessageMethod *) &msg[1];
  181. pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
  182. pmeth->header.size = htons (sizeof (*pmeth) + method_name_size);
  183. GNUNET_memcpy (&pmeth[1], method_name, method_name_size);
  184. uint16_t p = sizeof (*msg) + sizeof (*pmeth) + method_name_size;
  185. if (NULL != env)
  186. {
  187. mod = GNUNET_PSYC_env_head (env);
  188. while (NULL != mod)
  189. {
  190. uint16_t mod_name_size = strlen (mod->name) + 1;
  191. pmod = (struct GNUNET_PSYC_MessageModifier *) ((char *) msg + p);
  192. pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
  193. pmod->header.size = sizeof (*pmod) + mod_name_size + mod->value_size;
  194. p += pmod->header.size;
  195. pmod->header.size = htons (pmod->header.size);
  196. pmod->oper = mod->oper;
  197. pmod->name_size = htons (mod_name_size);
  198. pmod->value_size = htonl (mod->value_size);
  199. GNUNET_memcpy (&pmod[1], mod->name, mod_name_size);
  200. if (0 < mod->value_size)
  201. GNUNET_memcpy ((char *) &pmod[1] + mod_name_size, mod->value, mod->value_size);
  202. mod = mod->next;
  203. }
  204. }
  205. if (0 < data_size)
  206. {
  207. pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p);
  208. pmsg->size = sizeof (*pmsg) + data_size;
  209. p += pmsg->size;
  210. pmsg->size = htons (pmsg->size);
  211. pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
  212. GNUNET_memcpy (&pmsg[1], data, data_size);
  213. }
  214. pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p);
  215. pmsg->size = htons (sizeof (*pmsg));
  216. pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
  217. GNUNET_assert (p + sizeof (*pmsg) == msg_size);
  218. return msg;
  219. }
  220. void
  221. GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
  222. const struct GNUNET_MessageHeader *msg)
  223. {
  224. uint16_t size = ntohs (msg->size);
  225. uint16_t type = ntohs (msg->type);
  226. GNUNET_log (kind,
  227. "Message of type %d and size %u:\n",
  228. type,
  229. size);
  230. switch (type)
  231. {
  232. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE:
  233. {
  234. const struct GNUNET_PSYC_MessageHeader *pmsg
  235. = (const struct GNUNET_PSYC_MessageHeader *) msg;
  236. GNUNET_log (kind,
  237. "\tID: %" PRIu64 "\tflags: %x" PRIu32 "\n",
  238. GNUNET_ntohll (pmsg->message_id),
  239. ntohl (pmsg->flags));
  240. break;
  241. }
  242. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
  243. {
  244. const struct GNUNET_PSYC_MessageMethod *meth
  245. = (const struct GNUNET_PSYC_MessageMethod *) msg;
  246. GNUNET_log (kind,
  247. "\t%.*s\n",
  248. (int) (size - sizeof (*meth)),
  249. (const char *) &meth[1]);
  250. break;
  251. }
  252. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
  253. {
  254. const struct GNUNET_PSYC_MessageModifier *mod
  255. = (const struct GNUNET_PSYC_MessageModifier *) msg;
  256. uint16_t name_size = ntohs (mod->name_size);
  257. char oper = ' ' < mod->oper ? mod->oper : ' ';
  258. GNUNET_log (kind,
  259. "\t%c%.*s\t%.*s\n",
  260. oper,
  261. (int) name_size,
  262. (const char *) &mod[1],
  263. (int) (size - sizeof (*mod) - name_size),
  264. ((const char *) &mod[1]) + name_size);
  265. break;
  266. }
  267. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
  268. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
  269. GNUNET_log (kind,
  270. "\t%.*s\n",
  271. (int) (size - sizeof (*msg)),
  272. (const char *) &msg[1]);
  273. break;
  274. }
  275. }
  276. /**** Transmitting messages ****/
  277. /**
  278. * Create a transmission handle.
  279. */
  280. struct GNUNET_PSYC_TransmitHandle *
  281. GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq)
  282. {
  283. struct GNUNET_PSYC_TransmitHandle *tmit = GNUNET_new (struct GNUNET_PSYC_TransmitHandle);
  284. tmit->mq = mq;
  285. return tmit;
  286. }
  287. /**
  288. * Destroy a transmission handle.
  289. */
  290. void
  291. GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit)
  292. {
  293. GNUNET_free (tmit);
  294. }
  295. /**
  296. * Queue a message part for transmission.
  297. *
  298. * The message part is added to the current message buffer.
  299. * When this buffer is full, it is added to the transmission queue.
  300. *
  301. * @param tmit
  302. * Transmission handle.
  303. * @param msg
  304. * Message part, or NULL.
  305. * @param tmit_now
  306. * Transmit message now, or wait for buffer to fill up?
  307. * #GNUNET_YES or #GNUNET_NO.
  308. */
  309. static void
  310. transmit_queue_insert (struct GNUNET_PSYC_TransmitHandle *tmit,
  311. const struct GNUNET_MessageHeader *msg,
  312. uint8_t tmit_now)
  313. {
  314. uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0;
  315. LOG (GNUNET_ERROR_TYPE_DEBUG,
  316. "Queueing message part of type %u and size %u (tmit_now: %u)).\n",
  317. NULL != msg ? ntohs (msg->type) : 0, size, tmit_now);
  318. if (NULL != tmit->msg)
  319. {
  320. if (NULL == msg
  321. || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < tmit->msg->size + size)
  322. {
  323. /* End of message or buffer is full, add it to transmission queue
  324. * and start with empty buffer */
  325. tmit->msg->size = htons (tmit->msg->size);
  326. GNUNET_MQ_send (tmit->mq, tmit->env);
  327. tmit->env = NULL;
  328. tmit->msg = NULL;
  329. tmit->acks_pending++;
  330. }
  331. else
  332. {
  333. /* Message fits in current buffer, append */
  334. GNUNET_memcpy ((char *) tmit->msg + tmit->msg->size, msg, size);
  335. tmit->msg->size += size;
  336. }
  337. }
  338. if (NULL == tmit->msg && NULL != msg)
  339. {
  340. /* Empty buffer, copy over message. */
  341. tmit->env = GNUNET_MQ_msg_extra (tmit->msg,
  342. GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD,
  343. GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
  344. /* store current message size in host byte order
  345. * then later switch it to network byte order before sending */
  346. tmit->msg->size = sizeof (*tmit->msg) + size;
  347. GNUNET_memcpy (&tmit->msg[1], msg, size);
  348. }
  349. if (NULL != tmit->msg
  350. && (GNUNET_YES == tmit_now
  351. || (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD
  352. < tmit->msg->size + sizeof (struct GNUNET_MessageHeader))))
  353. {
  354. /* End of message or buffer is full, add it to transmission queue. */
  355. tmit->msg->size = htons (tmit->msg->size);
  356. GNUNET_MQ_send (tmit->mq, tmit->env);
  357. tmit->env = NULL;
  358. tmit->msg = NULL;
  359. tmit->acks_pending++;
  360. }
  361. }
  362. /**
  363. * Request data from client to transmit.
  364. *
  365. * @param tmit Transmission handle.
  366. */
  367. static void
  368. transmit_data (struct GNUNET_PSYC_TransmitHandle *tmit)
  369. {
  370. int notify_ret = GNUNET_YES;
  371. uint16_t data_size = 0;
  372. char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = "";
  373. struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data;
  374. msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
  375. if (NULL != tmit->notify_data)
  376. {
  377. data_size = GNUNET_PSYC_DATA_MAX_PAYLOAD;
  378. tmit->in_notify = GNUNET_YES;
  379. notify_ret = tmit->notify_data (tmit->notify_data_cls, &data_size, &msg[1]);
  380. tmit->in_notify = GNUNET_NO;
  381. }
  382. LOG (GNUNET_ERROR_TYPE_DEBUG,
  383. "transmit_data (ret: %d, size: %u): %.*s\n",
  384. notify_ret, data_size, data_size, &msg[1]);
  385. switch (notify_ret)
  386. {
  387. case GNUNET_NO:
  388. if (0 == data_size)
  389. {
  390. /* Transmission paused, nothing to send. */
  391. tmit->paused = GNUNET_YES;
  392. return;
  393. }
  394. break;
  395. case GNUNET_YES:
  396. tmit->state = GNUNET_PSYC_MESSAGE_STATE_END;
  397. break;
  398. default:
  399. LOG (GNUNET_ERROR_TYPE_ERROR,
  400. "TransmitNotifyData callback returned error when requesting data.\n");
  401. tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
  402. msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
  403. msg->size = htons (sizeof (*msg));
  404. transmit_queue_insert (tmit, msg, GNUNET_YES);
  405. tmit->in_transmit = GNUNET_NO;
  406. return;
  407. }
  408. if (0 < data_size)
  409. {
  410. GNUNET_assert (data_size <= GNUNET_PSYC_DATA_MAX_PAYLOAD);
  411. msg->size = htons (sizeof (*msg) + data_size);
  412. transmit_queue_insert (tmit, msg, !notify_ret);
  413. }
  414. /* End of message. */
  415. if (GNUNET_YES == notify_ret)
  416. {
  417. msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
  418. msg->size = htons (sizeof (*msg));
  419. transmit_queue_insert (tmit, msg, GNUNET_YES);
  420. /* FIXME: wait for ACK before setting in_transmit to no */
  421. tmit->in_transmit = GNUNET_NO;
  422. }
  423. }
  424. /**
  425. * Request a modifier from a client to transmit.
  426. *
  427. * @param tmit Transmission handle.
  428. */
  429. static void
  430. transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit)
  431. {
  432. uint16_t max_data_size = 0;
  433. uint16_t data_size = 0;
  434. char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = "";
  435. struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data;
  436. int notify_ret = GNUNET_YES;
  437. switch (tmit->state)
  438. {
  439. case GNUNET_PSYC_MESSAGE_STATE_MODIFIER:
  440. {
  441. struct GNUNET_PSYC_MessageModifier *mod
  442. = (struct GNUNET_PSYC_MessageModifier *) msg;
  443. msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
  444. msg->size = sizeof (struct GNUNET_PSYC_MessageModifier);
  445. if (NULL != tmit->notify_mod)
  446. {
  447. max_data_size = GNUNET_PSYC_MODIFIER_MAX_PAYLOAD;
  448. data_size = max_data_size;
  449. tmit->in_notify = GNUNET_YES;
  450. notify_ret = tmit->notify_mod (tmit->notify_mod_cls, &data_size, &mod[1],
  451. &mod->oper, &mod->value_size);
  452. tmit->in_notify = GNUNET_NO;
  453. }
  454. mod->name_size = strnlen ((char *) &mod[1], data_size) + 1;
  455. LOG (GNUNET_ERROR_TYPE_DEBUG,
  456. "transmit_mod (ret: %d, size: %u + %u): %.*s\n",
  457. notify_ret, mod->name_size, mod->value_size, data_size, &mod[1]);
  458. if (mod->name_size < data_size)
  459. {
  460. tmit->mod_value_remaining
  461. = mod->value_size - (data_size - mod->name_size);
  462. mod->value_size = htonl (mod->value_size);
  463. mod->name_size = htons (mod->name_size);
  464. }
  465. else if (0 < data_size)
  466. {
  467. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got invalid modifier name.\n");
  468. notify_ret = GNUNET_SYSERR;
  469. }
  470. break;
  471. }
  472. case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT:
  473. {
  474. msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT);
  475. msg->size = sizeof (struct GNUNET_MessageHeader);
  476. if (NULL != tmit->notify_mod)
  477. {
  478. max_data_size = GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD;
  479. data_size = max_data_size;
  480. tmit->in_notify = GNUNET_YES;
  481. notify_ret = tmit->notify_mod (tmit->notify_mod_cls,
  482. &data_size, &msg[1], NULL, NULL);
  483. tmit->in_notify = GNUNET_NO;
  484. }
  485. tmit->mod_value_remaining -= data_size;
  486. LOG (GNUNET_ERROR_TYPE_DEBUG,
  487. "transmit_mod (ret: %d, size: %u): %.*s\n",
  488. notify_ret, data_size, data_size, &msg[1]);
  489. break;
  490. }
  491. default:
  492. GNUNET_assert (0);
  493. }
  494. switch (notify_ret)
  495. {
  496. case GNUNET_NO:
  497. if (0 == data_size)
  498. { /* Transmission paused, nothing to send. */
  499. tmit->paused = GNUNET_YES;
  500. return;
  501. }
  502. tmit->state
  503. = (0 == tmit->mod_value_remaining)
  504. ? GNUNET_PSYC_MESSAGE_STATE_MODIFIER
  505. : GNUNET_PSYC_MESSAGE_STATE_MOD_CONT;
  506. break;
  507. case GNUNET_YES: /* End of modifiers. */
  508. GNUNET_assert (0 == tmit->mod_value_remaining);
  509. break;
  510. default:
  511. LOG (GNUNET_ERROR_TYPE_ERROR,
  512. "TransmitNotifyModifier callback returned with error.\n");
  513. tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
  514. msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
  515. msg->size = htons (sizeof (*msg));
  516. transmit_queue_insert (tmit, msg, GNUNET_YES);
  517. tmit->in_transmit = GNUNET_NO;
  518. return;
  519. }
  520. if (0 < data_size)
  521. {
  522. GNUNET_assert (data_size <= max_data_size);
  523. msg->size = htons (msg->size + data_size);
  524. transmit_queue_insert (tmit, msg, GNUNET_NO);
  525. }
  526. if (GNUNET_YES == notify_ret)
  527. {
  528. tmit->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
  529. if (0 == tmit->acks_pending)
  530. transmit_data (tmit);
  531. }
  532. else
  533. {
  534. transmit_mod (tmit);
  535. }
  536. }
  537. int
  538. transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
  539. uint32_t *full_value_size)
  540. {
  541. struct GNUNET_PSYC_TransmitHandle *tmit = cls;
  542. uint16_t name_size = 0;
  543. uint32_t value_size = 0;
  544. const char *value = NULL;
  545. if (NULL != oper)
  546. { /* New modifier */
  547. if (NULL != tmit->mod)
  548. tmit->mod = tmit->mod->next;
  549. if (NULL == tmit->mod)
  550. { /* No more modifiers, continue with data */
  551. *data_size = 0;
  552. return GNUNET_YES;
  553. }
  554. GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
  555. *full_value_size = tmit->mod->value_size;
  556. *oper = tmit->mod->oper;
  557. name_size = strlen (tmit->mod->name) + 1;
  558. if (name_size + tmit->mod->value_size <= *data_size)
  559. {
  560. value_size = tmit->mod->value_size;
  561. *data_size = name_size + value_size;
  562. }
  563. else /* full modifier does not fit in data, continuation needed */
  564. {
  565. value_size = *data_size - name_size;
  566. tmit->mod_value = tmit->mod->value + value_size;
  567. }
  568. GNUNET_memcpy (data, tmit->mod->name, name_size);
  569. GNUNET_memcpy ((char *)data + name_size, tmit->mod->value, value_size);
  570. return GNUNET_NO;
  571. }
  572. else
  573. { /* Modifier continuation */
  574. GNUNET_assert (NULL != tmit->mod_value && 0 < tmit->mod_value_remaining);
  575. value = tmit->mod_value;
  576. if (tmit->mod_value_remaining <= *data_size)
  577. {
  578. value_size = tmit->mod_value_remaining;
  579. tmit->mod_value = NULL;
  580. }
  581. else
  582. {
  583. value_size = *data_size;
  584. tmit->mod_value += value_size;
  585. }
  586. if (*data_size < value_size)
  587. {
  588. LOG (GNUNET_ERROR_TYPE_DEBUG,
  589. "Value in environment larger than buffer: %u < %zu\n",
  590. *data_size, value_size);
  591. *data_size = 0;
  592. return GNUNET_NO;
  593. }
  594. *data_size = value_size;
  595. GNUNET_memcpy (data, value, value_size);
  596. return (NULL == tmit->mod_value) ? GNUNET_YES : GNUNET_NO;
  597. }
  598. }
  599. /**
  600. * Transmit a message.
  601. *
  602. * @param tmit
  603. * Transmission handle.
  604. * @param method_name
  605. * Which method should be invoked.
  606. * @param env
  607. * Environment for the message.
  608. * Should stay available until the first call to notify_data.
  609. * Can be NULL if there are no modifiers or @a notify_mod is
  610. * provided instead.
  611. * @param notify_mod
  612. * Function to call to obtain modifiers.
  613. * Can be NULL if there are no modifiers or @a env is provided instead.
  614. * @param notify_data
  615. * Function to call to obtain fragments of the data.
  616. * @param notify_cls
  617. * Closure for @a notify_mod and @a notify_data.
  618. * @param flags
  619. * Flags for the message being transmitted.
  620. *
  621. * @return #GNUNET_OK if the transmission was started.
  622. * #GNUNET_SYSERR if another transmission is already going on.
  623. */
  624. int
  625. GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit,
  626. const char *method_name,
  627. const struct GNUNET_PSYC_Environment *env,
  628. GNUNET_PSYC_TransmitNotifyModifier notify_mod,
  629. GNUNET_PSYC_TransmitNotifyData notify_data,
  630. void *notify_cls,
  631. uint32_t flags)
  632. {
  633. if (GNUNET_NO != tmit->in_transmit)
  634. return GNUNET_SYSERR;
  635. tmit->in_transmit = GNUNET_YES;
  636. size_t size = strlen (method_name) + 1;
  637. struct GNUNET_PSYC_MessageMethod *pmeth;
  638. tmit->env = GNUNET_MQ_msg_extra (tmit->msg,
  639. GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD,
  640. GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
  641. /* store current message size in host byte order
  642. * then later switch it to network byte order before sending */
  643. tmit->msg->size = sizeof (*tmit->msg) + sizeof (*pmeth) + size;
  644. if (NULL != notify_mod)
  645. {
  646. tmit->notify_mod = notify_mod;
  647. tmit->notify_mod_cls = notify_cls;
  648. }
  649. else
  650. {
  651. tmit->notify_mod = &transmit_notify_env;
  652. tmit->notify_mod_cls = tmit;
  653. if (NULL != env)
  654. {
  655. struct GNUNET_PSYC_Modifier mod = {};
  656. mod.next = GNUNET_PSYC_env_head (env);
  657. tmit->mod = &mod;
  658. struct GNUNET_PSYC_Modifier *m = tmit->mod;
  659. while (NULL != (m = m->next))
  660. {
  661. if (m->oper != GNUNET_PSYC_OP_SET)
  662. flags |= GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY;
  663. }
  664. }
  665. else
  666. {
  667. tmit->mod = NULL;
  668. }
  669. }
  670. pmeth = (struct GNUNET_PSYC_MessageMethod *) &tmit->msg[1];
  671. pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
  672. pmeth->header.size = htons (sizeof (*pmeth) + size);
  673. pmeth->flags = htonl (flags);
  674. GNUNET_memcpy (&pmeth[1], method_name, size);
  675. tmit->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
  676. tmit->notify_data = notify_data;
  677. tmit->notify_data_cls = notify_cls;
  678. transmit_mod (tmit);
  679. return GNUNET_OK;
  680. }
  681. /**
  682. * Resume transmission.
  683. *
  684. * @param tmit Transmission handle.
  685. */
  686. void
  687. GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit)
  688. {
  689. if (GNUNET_YES != tmit->in_transmit || GNUNET_NO != tmit->in_notify)
  690. return;
  691. if (0 == tmit->acks_pending)
  692. {
  693. tmit->paused = GNUNET_NO;
  694. transmit_data (tmit);
  695. }
  696. }
  697. /**
  698. * Abort transmission request.
  699. *
  700. * @param tmit Transmission handle.
  701. */
  702. void
  703. GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit)
  704. {
  705. if (GNUNET_NO == tmit->in_transmit)
  706. return;
  707. tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
  708. tmit->in_transmit = GNUNET_NO;
  709. tmit->paused = GNUNET_NO;
  710. /* FIXME */
  711. struct GNUNET_MessageHeader msg;
  712. msg.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
  713. msg.size = htons (sizeof (msg));
  714. transmit_queue_insert (tmit, &msg, GNUNET_YES);
  715. }
  716. /**
  717. * Got acknowledgement of a transmitted message part, continue transmission.
  718. *
  719. * @param tmit Transmission handle.
  720. */
  721. void
  722. GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit)
  723. {
  724. if (0 == tmit->acks_pending)
  725. {
  726. LOG (GNUNET_ERROR_TYPE_WARNING, "Ignoring extraneous message ACK\n");
  727. GNUNET_break (0);
  728. return;
  729. }
  730. tmit->acks_pending--;
  731. if (GNUNET_YES == tmit->paused)
  732. return;
  733. switch (tmit->state)
  734. {
  735. case GNUNET_PSYC_MESSAGE_STATE_MODIFIER:
  736. case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT:
  737. transmit_mod (tmit);
  738. break;
  739. case GNUNET_PSYC_MESSAGE_STATE_DATA:
  740. transmit_data (tmit);
  741. break;
  742. case GNUNET_PSYC_MESSAGE_STATE_END:
  743. case GNUNET_PSYC_MESSAGE_STATE_CANCEL:
  744. break;
  745. default:
  746. LOG (GNUNET_ERROR_TYPE_DEBUG,
  747. "Ignoring message ACK in state %u.\n", tmit->state);
  748. }
  749. }
  750. /**** Receiving messages ****/
  751. /**
  752. * Create handle for receiving messages.
  753. */
  754. struct GNUNET_PSYC_ReceiveHandle *
  755. GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb,
  756. GNUNET_PSYC_MessagePartCallback message_part_cb,
  757. void *cb_cls)
  758. {
  759. struct GNUNET_PSYC_ReceiveHandle *recv = GNUNET_malloc (sizeof (*recv));
  760. recv->message_cb = message_cb;
  761. recv->message_part_cb = message_part_cb;
  762. recv->cb_cls = cb_cls;
  763. return recv;
  764. }
  765. /**
  766. * Destroy handle for receiving messages.
  767. */
  768. void
  769. GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv)
  770. {
  771. GNUNET_free (recv);
  772. }
  773. /**
  774. * Reset stored data related to the last received message.
  775. */
  776. void
  777. GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv)
  778. {
  779. recv->state = GNUNET_PSYC_MESSAGE_STATE_START;
  780. recv->flags = 0;
  781. recv->message_id = 0;
  782. recv->mod_value_size = 0;
  783. recv->mod_value_size_expected = 0;
  784. }
  785. static void
  786. recv_error (struct GNUNET_PSYC_ReceiveHandle *recv)
  787. {
  788. if (NULL != recv->message_part_cb)
  789. recv->message_part_cb (recv->cb_cls, NULL, NULL);
  790. if (NULL != recv->message_cb)
  791. recv->message_cb (recv->cb_cls, NULL);
  792. GNUNET_PSYC_receive_reset (recv);
  793. }
  794. /**
  795. * Handle incoming PSYC message.
  796. *
  797. * @param recv Receive handle.
  798. * @param msg The message.
  799. *
  800. * @return #GNUNET_OK on success,
  801. * #GNUNET_SYSERR on receive error.
  802. */
  803. int
  804. GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
  805. const struct GNUNET_PSYC_MessageHeader *msg)
  806. {
  807. uint16_t size = ntohs (msg->header.size);
  808. uint32_t flags = ntohl (msg->flags);
  809. GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG,
  810. (struct GNUNET_MessageHeader *) msg);
  811. if (GNUNET_PSYC_MESSAGE_STATE_START == recv->state)
  812. {
  813. recv->message_id = GNUNET_ntohll (msg->message_id);
  814. recv->flags = flags;
  815. recv->slave_pub_key = msg->slave_pub_key;
  816. recv->mod_value_size = 0;
  817. recv->mod_value_size_expected = 0;
  818. }
  819. else if (GNUNET_ntohll (msg->message_id) != recv->message_id)
  820. {
  821. // FIXME
  822. LOG (GNUNET_ERROR_TYPE_WARNING,
  823. "Unexpected message ID. Got: %" PRIu64 ", expected: %" PRIu64 "\n",
  824. GNUNET_ntohll (msg->message_id), recv->message_id);
  825. GNUNET_break_op (0);
  826. recv_error (recv);
  827. return GNUNET_SYSERR;
  828. }
  829. else if (flags != recv->flags)
  830. {
  831. LOG (GNUNET_ERROR_TYPE_WARNING,
  832. "Unexpected message flags. Got: %lu, expected: %lu\n",
  833. flags, recv->flags);
  834. GNUNET_break_op (0);
  835. recv_error (recv);
  836. return GNUNET_SYSERR;
  837. }
  838. uint16_t pos = 0, psize = 0, ptype, size_eq, size_min;
  839. for (pos = 0; sizeof (*msg) + pos < size; pos += psize)
  840. {
  841. const struct GNUNET_MessageHeader *pmsg
  842. = (const struct GNUNET_MessageHeader *) ((char *) &msg[1] + pos);
  843. psize = ntohs (pmsg->size);
  844. ptype = ntohs (pmsg->type);
  845. size_eq = size_min = 0;
  846. if (psize < sizeof (*pmsg) || sizeof (*msg) + pos + psize > size)
  847. {
  848. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  849. "Dropping message of type %u with invalid size %u.\n",
  850. ptype, psize);
  851. recv_error (recv);
  852. return GNUNET_SYSERR;
  853. }
  854. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  855. "Received message part of type %u and size %u from PSYC.\n",
  856. ptype, psize);
  857. GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
  858. switch (ptype)
  859. {
  860. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
  861. size_min = sizeof (struct GNUNET_PSYC_MessageMethod);
  862. break;
  863. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
  864. size_min = sizeof (struct GNUNET_PSYC_MessageModifier);
  865. break;
  866. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
  867. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
  868. size_min = sizeof (struct GNUNET_MessageHeader);
  869. break;
  870. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
  871. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
  872. size_eq = sizeof (struct GNUNET_MessageHeader);
  873. break;
  874. default:
  875. GNUNET_break_op (0);
  876. recv_error (recv);
  877. return GNUNET_SYSERR;
  878. }
  879. if (! ((0 < size_eq && psize == size_eq)
  880. || (0 < size_min && size_min <= psize)))
  881. {
  882. GNUNET_break_op (0);
  883. recv_error (recv);
  884. return GNUNET_SYSERR;
  885. }
  886. switch (ptype)
  887. {
  888. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
  889. {
  890. struct GNUNET_PSYC_MessageMethod *meth
  891. = (struct GNUNET_PSYC_MessageMethod *) pmsg;
  892. if (GNUNET_PSYC_MESSAGE_STATE_START != recv->state)
  893. {
  894. LOG (GNUNET_ERROR_TYPE_WARNING,
  895. "Dropping out of order message method (%u).\n",
  896. recv->state);
  897. /* It is normal to receive an incomplete message right after connecting,
  898. * but should not happen later.
  899. * FIXME: add a check for this condition.
  900. */
  901. GNUNET_break_op (0);
  902. recv_error (recv);
  903. return GNUNET_SYSERR;
  904. }
  905. if ('\0' != *((char *) meth + psize - 1))
  906. {
  907. LOG (GNUNET_ERROR_TYPE_WARNING,
  908. "Dropping message with malformed method. "
  909. "Message ID: %" PRIu64 "\n", recv->message_id);
  910. GNUNET_break_op (0);
  911. recv_error (recv);
  912. return GNUNET_SYSERR;
  913. }
  914. recv->state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
  915. break;
  916. }
  917. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
  918. {
  919. if (!(GNUNET_PSYC_MESSAGE_STATE_METHOD == recv->state
  920. || GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state
  921. || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state))
  922. {
  923. LOG (GNUNET_ERROR_TYPE_WARNING,
  924. "Dropping out of order message modifier (%u).\n",
  925. recv->state);
  926. GNUNET_break_op (0);
  927. recv_error (recv);
  928. return GNUNET_SYSERR;
  929. }
  930. struct GNUNET_PSYC_MessageModifier *mod
  931. = (struct GNUNET_PSYC_MessageModifier *) pmsg;
  932. uint16_t name_size = ntohs (mod->name_size);
  933. recv->mod_value_size_expected = ntohl (mod->value_size);
  934. recv->mod_value_size = psize - sizeof (*mod) - name_size;
  935. if (psize < sizeof (*mod) + name_size
  936. || '\0' != *((char *) &mod[1] + name_size - 1)
  937. || recv->mod_value_size_expected < recv->mod_value_size)
  938. {
  939. LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n");
  940. GNUNET_break_op (0);
  941. recv_error (recv);
  942. return GNUNET_SYSERR;
  943. }
  944. recv->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
  945. break;
  946. }
  947. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
  948. {
  949. recv->mod_value_size += psize - sizeof (*pmsg);
  950. if (!(GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state
  951. || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state)
  952. || recv->mod_value_size_expected < recv->mod_value_size)
  953. {
  954. LOG (GNUNET_ERROR_TYPE_WARNING,
  955. "Dropping out of order message modifier continuation "
  956. "!(%u == %u || %u == %u) || %lu < %lu.\n",
  957. GNUNET_PSYC_MESSAGE_STATE_MODIFIER, recv->state,
  958. GNUNET_PSYC_MESSAGE_STATE_MOD_CONT, recv->state,
  959. recv->mod_value_size_expected, recv->mod_value_size);
  960. GNUNET_break_op (0);
  961. recv_error (recv);
  962. return GNUNET_SYSERR;
  963. }
  964. break;
  965. }
  966. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
  967. {
  968. if (recv->state < GNUNET_PSYC_MESSAGE_STATE_METHOD
  969. || recv->mod_value_size_expected != recv->mod_value_size)
  970. {
  971. LOG (GNUNET_ERROR_TYPE_WARNING,
  972. "Dropping out of order message data fragment "
  973. "(%u < %u || %lu != %lu).\n",
  974. recv->state, GNUNET_PSYC_MESSAGE_STATE_METHOD,
  975. recv->mod_value_size_expected, recv->mod_value_size);
  976. GNUNET_break_op (0);
  977. recv_error (recv);
  978. return GNUNET_SYSERR;
  979. }
  980. recv->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
  981. break;
  982. }
  983. }
  984. if (NULL != recv->message_part_cb)
  985. recv->message_part_cb (recv->cb_cls, msg, pmsg);
  986. switch (ptype)
  987. {
  988. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
  989. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
  990. GNUNET_PSYC_receive_reset (recv);
  991. break;
  992. }
  993. }
  994. if (NULL != recv->message_cb)
  995. recv->message_cb (recv->cb_cls, msg);
  996. return GNUNET_OK;
  997. }
  998. /**
  999. * Check if @a data contains a series of valid message parts.
  1000. *
  1001. * @param data_size Size of @a data.
  1002. * @param data Data.
  1003. * @param[out] first_ptype Type of first message part.
  1004. * @param[out] last_ptype Type of last message part.
  1005. *
  1006. * @return Number of message parts found in @a data.
  1007. * or GNUNET_SYSERR if the message contains invalid parts.
  1008. */
  1009. int
  1010. GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data,
  1011. uint16_t *first_ptype, uint16_t *last_ptype)
  1012. {
  1013. const struct GNUNET_MessageHeader *pmsg;
  1014. uint16_t parts = 0, ptype = 0, psize = 0, pos = 0;
  1015. if (NULL != first_ptype)
  1016. *first_ptype = 0;
  1017. if (NULL != last_ptype)
  1018. *last_ptype = 0;
  1019. for (pos = 0; pos < data_size; pos += psize, parts++)
  1020. {
  1021. pmsg = (const struct GNUNET_MessageHeader *) (data + pos);
  1022. GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
  1023. psize = ntohs (pmsg->size);
  1024. ptype = ntohs (pmsg->type);
  1025. if (0 == parts && NULL != first_ptype)
  1026. *first_ptype = ptype;
  1027. if (NULL != last_ptype
  1028. && *last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END)
  1029. *last_ptype = ptype;
  1030. if (psize < sizeof (*pmsg)
  1031. || pos + psize > data_size
  1032. || ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD
  1033. || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL < ptype)
  1034. {
  1035. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1036. "Invalid message part of type %u and size %u.\n",
  1037. ptype, psize);
  1038. return GNUNET_SYSERR;
  1039. }
  1040. /** @todo FIXME: check message part order */
  1041. }
  1042. return parts;
  1043. }
  1044. struct ParseMessageClosure
  1045. {
  1046. struct GNUNET_PSYC_Environment *env;
  1047. const char **method_name;
  1048. const void **data;
  1049. uint16_t *data_size;
  1050. enum GNUNET_PSYC_MessageState msg_state;
  1051. };
  1052. static void
  1053. parse_message_part_cb (void *cls,
  1054. const struct GNUNET_PSYC_MessageHeader *msg,
  1055. const struct GNUNET_MessageHeader *pmsg)
  1056. {
  1057. struct ParseMessageClosure *pmc = cls;
  1058. if (NULL == pmsg)
  1059. {
  1060. pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
  1061. return;
  1062. }
  1063. switch (ntohs (pmsg->type))
  1064. {
  1065. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
  1066. {
  1067. struct GNUNET_PSYC_MessageMethod *
  1068. pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
  1069. *pmc->method_name = (const char *) &pmeth[1];
  1070. pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
  1071. break;
  1072. }
  1073. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
  1074. {
  1075. struct GNUNET_PSYC_MessageModifier *
  1076. pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
  1077. const char *name = (const char *) &pmod[1];
  1078. const void *value = name + ntohs (pmod->name_size);
  1079. GNUNET_PSYC_env_add (pmc->env, pmod->oper, name, value,
  1080. ntohl (pmod->value_size));
  1081. pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
  1082. break;
  1083. }
  1084. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
  1085. *pmc->data = &pmsg[1];
  1086. *pmc->data_size = ntohs (pmsg->size) - sizeof (*pmsg);
  1087. pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA;
  1088. break;
  1089. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
  1090. pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_END;
  1091. break;
  1092. default:
  1093. pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
  1094. }
  1095. }
  1096. /**
  1097. * Parse PSYC message.
  1098. *
  1099. * @param msg
  1100. * The PSYC message to parse.
  1101. * @param[out] method_name
  1102. * Pointer to the method name inside @a pmsg.
  1103. * @param env
  1104. * The environment for the message with a list of modifiers.
  1105. * @param[out] data
  1106. * Pointer to data inside @a msg.
  1107. * @param[out] data_size
  1108. * Size of @data is written here.
  1109. *
  1110. * @return #GNUNET_OK on success,
  1111. * #GNUNET_SYSERR on parse error.
  1112. */
  1113. int
  1114. GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg,
  1115. const char **method_name,
  1116. struct GNUNET_PSYC_Environment *env,
  1117. const void **data,
  1118. uint16_t *data_size)
  1119. {
  1120. struct ParseMessageClosure cls;
  1121. cls.env = env;
  1122. cls.method_name = method_name;
  1123. cls.data = data;
  1124. cls.data_size = data_size;
  1125. struct GNUNET_PSYC_ReceiveHandle *
  1126. recv = GNUNET_PSYC_receive_create (NULL, parse_message_part_cb, &cls);
  1127. int ret = GNUNET_PSYC_receive_message (recv, msg);
  1128. GNUNET_PSYC_receive_destroy (recv);
  1129. if (GNUNET_OK != ret)
  1130. return GNUNET_SYSERR;
  1131. return (GNUNET_PSYC_MESSAGE_STATE_END == cls.msg_state)
  1132. ? GNUNET_OK
  1133. : GNUNET_NO;
  1134. }
  1135. /**
  1136. * Initialize PSYC message header.
  1137. */
  1138. void
  1139. GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg,
  1140. const struct GNUNET_MULTICAST_MessageHeader *mmsg,
  1141. uint32_t flags)
  1142. {
  1143. uint16_t size = ntohs (mmsg->header.size);
  1144. uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg);
  1145. pmsg->header.size = htons (psize);
  1146. pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
  1147. pmsg->message_id = mmsg->message_id;
  1148. pmsg->fragment_offset = mmsg->fragment_offset;
  1149. pmsg->flags = htonl (flags);
  1150. GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg));
  1151. }
  1152. /**
  1153. * Create a new PSYC message header from a multicast message.
  1154. */
  1155. struct GNUNET_PSYC_MessageHeader *
  1156. GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg,
  1157. uint32_t flags)
  1158. {
  1159. struct GNUNET_PSYC_MessageHeader *pmsg;
  1160. uint16_t size = ntohs (mmsg->header.size);
  1161. uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg);
  1162. pmsg = GNUNET_malloc (psize);
  1163. GNUNET_PSYC_message_header_init (pmsg, mmsg, flags);
  1164. return pmsg;
  1165. }
  1166. /**
  1167. * Create a new PSYC message header from a PSYC message.
  1168. */
  1169. struct GNUNET_PSYC_MessageHeader *
  1170. GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg)
  1171. {
  1172. uint16_t msg_size = ntohs (msg->header.size);
  1173. struct GNUNET_PSYC_MessageHeader *
  1174. pmsg = GNUNET_malloc (sizeof (*pmsg) + msg_size - sizeof (*msg));
  1175. pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
  1176. pmsg->header.size = htons (sizeof (*pmsg) + msg_size - sizeof (*msg));
  1177. GNUNET_memcpy (&pmsg[1], &msg[1], msg_size - sizeof (*msg));
  1178. return pmsg;
  1179. }