rawio.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /* functions for shifting data between lists in memory and raw format files
  2. Copyright (C) 2006 Dennis Furey
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. #include <netdb.h>
  16. #include <stdint.h>
  17. #include <errno.h>
  18. #include <poll.h>
  19. #include <netinet/in.h>
  20. #include <sys/socket.h>
  21. #include <avm/common.h>
  22. #include <avm/error.h>
  23. #include <avm/lists.h>
  24. #include <avm/branches.h>
  25. #include <avm/chrcodes.h>
  26. #include <avm/rawio.h>
  27. #if HAVE_GCRYPT
  28. #include <gcrypt.h>
  29. #endif
  30. /* This is number of characters between line breaks in raw
  31. output. Feel free to change it. */
  32. #define file_width 79
  33. #define WORD_SIZE 8 /* for binary transfers; at most sizeof char */
  34. #define PACKET_SIZE 1024
  35. #define OFFSET 0 /* can be set to 60 with a WORD_SIZE of 6 to match printable format */
  36. /* non-zero means static variables are initialized */
  37. static int initialized = 0;
  38. #if HAVE_GCRYPT
  39. static gcry_md_hd_t hash_context;
  40. #endif
  41. static int
  42. sent_bit (repository, bit, filename, spool, spoke, column)
  43. FILE *repository;
  44. int bit;
  45. char *filename;
  46. int *spool;
  47. int *spoke;
  48. int *column;
  49. /* This puts a bit into a file, using a byte to spool them
  50. between calls. This has to be called a bunch of times at the
  51. end of the data in order to ensure that any unwritten bits get
  52. flushed. */
  53. {
  54. int ioerror;
  55. ioerror = 0;
  56. (*spool) = ((*spool) << 1) + bit;
  57. if (((*spoke)++) == 5)
  58. {
  59. (*spool) += 60;
  60. if (ioerror = (putc (*spool, repository) != (*spool)))
  61. avm_non_fatal_io_error ("can't write to", filename, errno);
  62. else if (++(*column) == file_width)
  63. {
  64. if (ioerror = (putc ('\n', repository) != '\n'))
  65. avm_non_fatal_io_error ("can't write to", filename, errno);
  66. *column = 0;
  67. }
  68. *spool = *spoke = 0;
  69. }
  70. return !ioerror;
  71. }
  72. static int
  73. received_bit (object, filename, spoke, spool)
  74. FILE *object;
  75. char *filename;
  76. int *spoke;
  77. int *spool;
  78. /* This gets the next bit from the file, dealing with the hassle
  79. of unpacking them from characters. */
  80. {
  81. int last_character;
  82. if (!((*spoke)--))
  83. {
  84. do
  85. {
  86. (*spool) = getc (object);
  87. if ((*spool) == '#')
  88. {
  89. do
  90. {
  91. last_character = *spool;
  92. (*spool) = getc (object);
  93. }
  94. while ((*spool) == EOF ? 0 : (*spool) == '\n' ? (last_character == '\\') : 1);
  95. }
  96. }
  97. while ((*spool) == EOF ? 0 : ((*spool) == '\n' ? 1 : 0));
  98. if ((*spool) == EOF ? 1 : (*spool) < 60 ? 1 : ((*spool) = (*spool) - 60) & 0xffc0)
  99. avm_fatal_io_error ("invalid raw file format in", filename, 0);
  100. (*spoke) = 5;
  101. }
  102. return (((*spool) >> (*spoke)) & 1);
  103. }
  104. void
  105. avm_send_list (repository, operand, filename)
  106. FILE *repository;
  107. list operand;
  108. char *filename;
  109. /* This puts a list into a raw format file. */
  110. {
  111. list front, queue, old;
  112. int spool, spoke, column;
  113. if (!initialized)
  114. avm_initialize_rawio (); /* if the caller didn't do what it should */
  115. front = queue = NULL;
  116. spool = spoke = column = 0;
  117. avm_enqueue (&front, &queue, avm_copied (operand));
  118. while (front ? sent_bit (repository, front->head ? 1 : 0, filename, &spool, &spoke, &column) : 0)
  119. {
  120. if (front->head)
  121. {
  122. avm_enqueue (&front, &queue, avm_copied (front->head->head));
  123. avm_enqueue (&front, &queue, avm_copied (front->head->tail));
  124. }
  125. front = avm_copied ((old = front)->tail);
  126. avm_dispose (old);
  127. }
  128. while (spoke ? sent_bit (repository, 0, filename, &spool, &spoke, &column) : 0);
  129. if (front)
  130. avm_dispose (front);
  131. else if (putc ('\n', repository) != '\n')
  132. avm_non_fatal_io_error ("can't write to", filename, errno);
  133. }
  134. void
  135. avm_recoverable_send_list (sockfd, operand, crc, timeout, closed, fault)
  136. int sockfd;
  137. list operand;
  138. char **crc;
  139. int *timeout;
  140. int *closed;
  141. int *fault;
  142. /* differs from avm_send_list by using a socket descriptor rather
  143. than a file, using binary rather than printable characters,
  144. and setting the fault parameter rather than aborting or
  145. writing an error message in the event of a fault; also
  146. computes a 32 bit cyclic redundancy check, which should be
  147. freed by the caller */
  148. {
  149. char packet_buffer[PACKET_SIZE];
  150. char *cursor;
  151. list front, back, old;
  152. int words, bits, next_bit, sent, last_packet_size;
  153. #if HAVE_GCRYPT
  154. if (!initialized)
  155. avm_initialize_rawio ();
  156. gcry_md_reset (hash_context);
  157. front = back = NULL;
  158. *closed = *timeout = words = bits = (int) (*(cursor = packet_buffer) = 0);
  159. avm_recoverable_enqueue (&front, &back, avm_copied (operand), fault);
  160. while (*fault ? NULL : *timeout ? NULL: front)
  161. {
  162. if (next_bit = (front->head ? 1 : 0))
  163. {
  164. avm_recoverable_enqueue (&front, &back, avm_copied (front->head->head), fault);
  165. avm_recoverable_enqueue (&front, &back, avm_copied (front->head->tail), fault);
  166. }
  167. if (!*fault)
  168. {
  169. front = avm_copied ((old = front)->tail);
  170. avm_dispose (old);
  171. if (bits++ == WORD_SIZE)
  172. {
  173. bits = 1;
  174. (*(cursor++)) += OFFSET;
  175. if (words++ == PACKET_SIZE)
  176. {
  177. words = sent = 0;
  178. gcry_md_write (hash_context, packet_buffer, PACKET_SIZE);
  179. while ((*timeout = (*timeout ? 1 : (sent < 0))) ? 0 : ((words += sent) < PACKET_SIZE))
  180. {
  181. sent = send (sockfd, &(packet_buffer[words]), PACKET_SIZE - words, MSG_NOSIGNAL | MSG_MORE);
  182. *timeout = !sent;
  183. }
  184. *closed = (!*timeout ? 0 : !sent ? 1 : (errno == ENOTCONN) ? 1 : (errno == ECONNREFUSED));
  185. words = (int) ((*(cursor = packet_buffer)) = 0);
  186. }
  187. }
  188. (*cursor) = ((*cursor) << 1) | next_bit;
  189. }
  190. }
  191. avm_dispose (front);
  192. (*cursor) = ((*cursor) << (WORD_SIZE - bits)) + OFFSET;
  193. if (last_packet_size = words + (bits ? 1 : 0))
  194. gcry_md_write (hash_context, packet_buffer, last_packet_size);
  195. if (!(*crc = strdup (gcry_md_read (hash_context, GCRY_MD_CRC32_RFC1510))))
  196. *fault = 1;
  197. words = sent = 0;
  198. if (*fault ? 0 : !(*timeout))
  199. while ((*timeout = (*timeout ? 1 : (sent < 0))) ? 0 : ((words += sent) < last_packet_size))
  200. *timeout = !(sent = send (sockfd, &(packet_buffer[words]), last_packet_size - words, MSG_NOSIGNAL));
  201. *closed = (*closed ? 1 : !*timeout ? 0 : (sent == 0) ? 1 : (errno == ENOTCONN) ? 1 : (errno == ECONNREFUSED));
  202. return;
  203. #endif
  204. avm_error ("I need avram built with libgcrypt.");
  205. }
  206. list
  207. avm_recoverable_received_list (sockfd, crc, timeout, closed, fault)
  208. int sockfd;
  209. char **crc;
  210. int *timeout;
  211. int *closed;
  212. int *fault;
  213. /* like received_list but using sockets and not aborting; also
  214. checks for the absence of spurious trailing input and computes
  215. a 32 bit crc, which should be freed by the caller */
  216. {
  217. struct pollfd fds;
  218. list result;
  219. char packet_buffer[PACKET_SIZE];
  220. char *cursor;
  221. branch_queue front,back;
  222. int bits,words,received,last_packet_size;
  223. #if HAVE_GCRYPT
  224. if (!initialized)
  225. avm_initialize_rawio ();
  226. gcry_md_reset (hash_context);
  227. front = back = NULL;
  228. words = bits = 0;
  229. cursor = packet_buffer;
  230. avm_recoverable_anticipate (&front, &back, &result, fault);
  231. *closed = *timeout = (*fault ? 0 : ((received = recv (sockfd, packet_buffer, PACKET_SIZE, MSG_NOSIGNAL)) <= 0));
  232. gcry_md_write (hash_context, packet_buffer, received);
  233. (*cursor) -= OFFSET;
  234. while (*fault ? NULL : *timeout ? NULL : front)
  235. {
  236. if (bits++ == WORD_SIZE)
  237. {
  238. bits = 1;
  239. cursor++;
  240. if (++words == received)
  241. {
  242. cursor = packet_buffer;
  243. *timeout = ((received = recv (sockfd, packet_buffer, PACKET_SIZE, MSG_NOSIGNAL)) <= 0);
  244. gcry_md_write (hash_context, packet_buffer, received);
  245. *closed = (!*timeout ? 0 : (received == 0) ? 1 : (errno == ENOTCONN) ? 1 : (errno == ECONNREFUSED));
  246. words = 0;
  247. }
  248. (*cursor) -= OFFSET;
  249. }
  250. avm_recoverable_enqueue_branch(&front, &back, ((*cursor) >> (WORD_SIZE - bits)) & 1, fault);
  251. }
  252. avm_dispose_branch_queue (front);
  253. if (!(*crc = strdup (gcry_md_read (hash_context, GCRY_MD_CRC32_RFC1510))))
  254. *fault = 1;
  255. fds.fd = sockfd;
  256. fds.events = POLLIN;
  257. *fault = (*fault ? 1 : (*timeout = (*timeout ? 1 : ((words + (bits ? 1 : 0)) != received))));
  258. if (*fault = (*fault ? 1 : (poll (&fds, 1, 0) < 0) ? 1 : (fds.revents & POLLIN)))
  259. {
  260. avm_dispose (result);
  261. while ((poll (&fds, 1, 0) == 0) ? (fds.revents & POLLIN) : 0)
  262. received = recv (sockfd, packet_buffer, PACKET_SIZE, MSG_NOSIGNAL); /* flush spurious trailing data */
  263. return NULL;
  264. }
  265. return result;
  266. #endif
  267. avm_error ("I need avram built with libgcrypt.");
  268. }
  269. list
  270. avm_received_list (object, filename)
  271. FILE *object;
  272. char *filename;
  273. /* This reads a list from a file that better be in raw format. */
  274. {
  275. list result;
  276. int spoke, spool;
  277. branch_queue old, front, back;
  278. if (!initialized)
  279. avm_initialize_rawio (); /* if the caller didn't do what it should */
  280. spoke = spool = 0;
  281. front = back = NULL;
  282. avm_anticipate (&front, &back, &result);
  283. while (front)
  284. {
  285. if (*(front->above) = (received_bit (object, filename, &spoke, &spool) ? avm_join (NULL, NULL) : NULL))
  286. {
  287. avm_anticipate (&front, &back, &((*(front->above))->head));
  288. avm_anticipate (&front, &back, &((*(front->above))->tail));
  289. }
  290. front = (old = front)->following;
  291. avm_dispose_branch (old);
  292. }
  293. return result;
  294. }
  295. void
  296. avm_initialize_rawio ()
  297. /* This is called at the beginning before any of the others, if
  298. the calling program is conforming to the specs. */
  299. {
  300. int fault;
  301. if (initialized)
  302. return;
  303. initialized = 1;
  304. avm_initialize_lists ();
  305. avm_initialize_branches ();
  306. avm_initialize_chrcodes ();
  307. #if HAVE_GCRYPT
  308. fault = ! gcry_check_version (NULL);
  309. fault = (fault ? 1 : (gcry_control (GCRYCTL_DISABLE_SECMEM) != GPG_ERR_NO_ERROR));
  310. fault = (fault ? 1 : (gcry_control (GCRYCTL_SET_VERBOSITY, 0) != GPG_ERR_NO_ERROR));
  311. fault = (fault ? 1 : (gcry_control (GCRYCTL_INITIALIZATION_FINISHED) != GPG_ERR_NO_ERROR));
  312. fault = (fault ? 1 : (gcry_md_open (&hash_context, GCRY_MD_CRC32_RFC1510, 0) != GPG_ERR_NO_ERROR));
  313. if (fault = (fault ? 1 : ! gcry_md_is_enabled (hash_context, GCRY_MD_CRC32_RFC1510)))
  314. avm_error ("unable to initialize libgcrypt");
  315. #endif
  316. }
  317. void
  318. avm_count_rawio ()
  319. /* This is just a hook if you want to put something here; client
  320. programs are supposed to call this at the end of a run. */
  321. {
  322. if (!initialized)
  323. return;
  324. initialized = 0;
  325. #if HAVE_GCRYPT
  326. gcry_md_close (hash_context);
  327. #endif
  328. }