tftpsubs.c 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Copyright (c) 1983 Regents of the University of California.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms are permitted
  6. * provided that the above copyright notice and this paragraph are
  7. * duplicated in all such forms and that any documentation,
  8. * advertising materials, and other materials related to such
  9. * distribution and use acknowledge that the software was developed
  10. * by the University of California, Berkeley. The name of the
  11. * University may not be used to endorse or promote products derived
  12. * from this software without specific prior written permission.
  13. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15. * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16. */
  17. #ifndef lint
  18. static char sccsid[] = "@(#)tftpsubs.c 5.4 (Berkeley) 6/29/88";
  19. #endif /* not lint */
  20. /* Simple minded read-ahead/write-behind subroutines for tftp user and
  21. server. Written originally with multiple buffers in mind, but current
  22. implementation has two buffer logic wired in.
  23. Todo: add some sort of final error check so when the write-buffer
  24. is finally flushed, the caller can detect if the disk filled up
  25. (or had an i/o error) and return a nak to the other side.
  26. Jim Guyton 10/85
  27. */
  28. #include <errno.h>
  29. #include <sys/types.h>
  30. #include <sys/socket.h>
  31. #include <sys/ioctl.h>
  32. #include <netinet/in.h>
  33. #include <arpa/tftp.h>
  34. #include <stdio.h>
  35. #define PKTSIZE (1432+4) /* SEGSIZE+4 */ /* should be moved to tftp.h */
  36. struct bf {
  37. int counter; /* size of data in buffer, or flag */
  38. char buf[PKTSIZE]; /* room for data packet */
  39. } bfs[2];
  40. /* Values for bf.counter */
  41. #define BF_ALLOC -3 /* alloc'd but not yet filled */
  42. #define BF_FREE -2 /* free */
  43. /* [-1 .. SEGSIZE] = size of data in the data buffer */
  44. extern int segsize;
  45. static int nextone; /* index of next buffer to use */
  46. static int current; /* index of buffer in use */
  47. /* control flags for crlf conversions */
  48. int newline = 0; /* fillbuf: in middle of newline expansion */
  49. int prevchar = -1; /* putbuf: previous char (cr check) */
  50. struct tftphdr *rw_init();
  51. struct tftphdr *w_init() { return rw_init(0); } /* write-behind */
  52. struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */
  53. struct tftphdr *
  54. rw_init(x) /* init for either read-ahead or write-behind */
  55. int x; /* zero for write-behind, one for read-head */
  56. {
  57. newline = 0; /* init crlf flag */
  58. prevchar = -1;
  59. bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
  60. current = 0;
  61. bfs[1].counter = BF_FREE;
  62. nextone = x; /* ahead or behind? */
  63. return (struct tftphdr *)bfs[0].buf;
  64. }
  65. /* Have emptied current buffer by sending to net and getting ack.
  66. Free it and return next buffer filled with data.
  67. */
  68. readit(file, dpp, convert)
  69. FILE *file; /* file opened for read */
  70. struct tftphdr **dpp;
  71. int convert; /* if true, convert to ascii */
  72. {
  73. struct bf *b;
  74. bfs[current].counter = BF_FREE; /* free old one */
  75. current = !current; /* "incr" current */
  76. b = &bfs[current]; /* look at new buffer */
  77. if (b->counter == BF_FREE) /* if it's empty */
  78. read_ahead(file, convert); /* fill it */
  79. /* assert(b->counter != BF_FREE); /* check */
  80. *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
  81. return b->counter;
  82. }
  83. /*
  84. * fill the input buffer, doing ascii conversions if requested
  85. * conversions are lf -> cr,lf and cr -> cr, nul
  86. */
  87. read_ahead(file, convert)
  88. FILE *file; /* file opened for read */
  89. int convert; /* if true, convert to ascii */
  90. {
  91. register int i;
  92. register char *p;
  93. register int c;
  94. struct bf *b;
  95. struct tftphdr *dp;
  96. b = &bfs[nextone]; /* look at "next" buffer */
  97. if (b->counter != BF_FREE) /* nop if not free */
  98. return;
  99. nextone = !nextone; /* "incr" next buffer ptr */
  100. dp = (struct tftphdr *)b->buf;
  101. if (convert == 0) {
  102. int i;
  103. b->counter = 0;
  104. do {
  105. i = read(fileno(file), dp->th_data + b->counter,
  106. segsize - b->counter);
  107. if (i > 0)
  108. b->counter += i;
  109. } while (i != 0 && !(i < 0 && errno != EINTR) &&
  110. b->counter < segsize);
  111. return;
  112. }
  113. p = dp->th_data;
  114. for (i = 0 ; i < segsize; i++) {
  115. if (newline) {
  116. if (prevchar == '\n')
  117. c = '\n'; /* lf to cr,lf */
  118. else c = '\0'; /* cr to cr,nul */
  119. newline = 0;
  120. }
  121. else {
  122. c = getc(file);
  123. if (c == EOF) break;
  124. if (c == '\n' || c == '\r') {
  125. prevchar = c;
  126. c = '\r';
  127. newline = 1;
  128. }
  129. }
  130. *p++ = c;
  131. }
  132. b->counter = (int)(p - dp->th_data);
  133. }
  134. /* Update count associated with the buffer, get new buffer
  135. from the queue. Calls write_behind only if next buffer not
  136. available.
  137. */
  138. writeit(file, dpp, ct, convert)
  139. FILE *file;
  140. struct tftphdr **dpp;
  141. int convert;
  142. {
  143. bfs[current].counter = ct; /* set size of data to write */
  144. current = !current; /* switch to other buffer */
  145. if (bfs[current].counter != BF_FREE) /* if not free */
  146. write_behind(file, convert); /* flush it */
  147. bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
  148. *dpp = (struct tftphdr *)bfs[current].buf;
  149. return ct; /* this is a lie of course */
  150. }
  151. /*
  152. * Output a buffer to a file, converting from netascii if requested.
  153. * CR,NUL -> CR and CR,LF => LF.
  154. * Note spec is undefined if we get CR as last byte of file or a
  155. * CR followed by anything else. In this case we leave it alone.
  156. */
  157. write_behind(file, convert)
  158. FILE *file;
  159. int convert;
  160. {
  161. char *buf;
  162. int count;
  163. register int ct;
  164. register char *p;
  165. register int c; /* current character */
  166. struct bf *b;
  167. struct tftphdr *dp;
  168. b = &bfs[nextone];
  169. if (b->counter < -1) /* anything to flush? */
  170. return 0; /* just nop if nothing to do */
  171. count = b->counter; /* remember byte count */
  172. b->counter = BF_FREE; /* reset flag */
  173. dp = (struct tftphdr *)b->buf;
  174. nextone = !nextone; /* incr for next time */
  175. buf = dp->th_data;
  176. if (count <= 0) return -1; /* nak logic? */
  177. if (convert == 0)
  178. return write(fileno(file), buf, count);
  179. p = buf;
  180. ct = count;
  181. while (ct--) { /* loop over the buffer */
  182. c = *p++; /* pick up a character */
  183. if (prevchar == '\r') { /* if prev char was cr */
  184. if (c == '\n') /* if have cr,lf then just */
  185. fseek(file, -1, 1); /* smash lf on top of the cr */
  186. else
  187. if (c == '\0') /* if have cr,nul then */
  188. goto skipit; /* just skip over the putc */
  189. /* else just fall through and allow it */
  190. }
  191. putc(c, file);
  192. skipit:
  193. prevchar = c;
  194. }
  195. return count;
  196. }
  197. /* When an error has occurred, it is possible that the two sides
  198. * are out of synch. Ie: that what I think is the other side's
  199. * response to packet N is really their response to packet N-1.
  200. *
  201. * So, to try to prevent that, we flush all the input queued up
  202. * for us on the network connection on our host.
  203. *
  204. * We return the number of packets we flushed (mostly for reporting
  205. * when trace is active).
  206. */
  207. int
  208. synchnet(f)
  209. int f; /* socket to flush */
  210. {
  211. int i, j = 0;
  212. char rbuf[PKTSIZE];
  213. struct sockaddr_in from;
  214. int fromlen;
  215. while (1) {
  216. (void) ioctl(f, FIONREAD, &i);
  217. if (i) {
  218. j++;
  219. fromlen = sizeof from;
  220. (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
  221. (struct sockaddr *)&from, &fromlen);
  222. } else {
  223. return(j);
  224. }
  225. }
  226. }