tsnetwork_buf.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <sys/time.h>
  4. #include <errno.h>
  5. #include <signal.h>
  6. #include <stdint.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include "tarsnap_opt.h"
  10. #include "tsnetwork_internal.h"
  11. #include "tvmath.h"
  12. #include "warnp.h"
  13. #include "tsnetwork.h"
  14. #define RECV 0
  15. #define SEND 1
  16. /*
  17. * If MSG_NOSIGNAL isn't defined, define it to zero; and then fiddle with
  18. * the socket options when needed.
  19. */
  20. #ifdef MSG_NOSIGNAL
  21. #define HAVE_MSG_NOSIGNAL
  22. #endif
  23. #ifndef HAVE_MSG_NOSIGNAL
  24. #define MSG_NOSIGNAL 0
  25. #endif
  26. struct network_buf_cookie {
  27. network_callback * callback;
  28. void * cookie;
  29. int fd;
  30. uint8_t * buf;
  31. size_t buflen;
  32. size_t bufpos;
  33. struct timeval timeout;
  34. struct timeval timeout_max;
  35. int sendrecv;
  36. int netop;
  37. int flags;
  38. };
  39. static int callback_buf(void * cookie, int status);
  40. static int network_buf(int fd, uint8_t * buf, size_t buflen,
  41. struct timeval * to0, struct timeval * to1,
  42. network_callback * callback, void * cookie,
  43. int sendrecv, int netop, int flags);
  44. /**
  45. * callback_buf(cookie, status):
  46. * Callback helper for tsnetwork_read and network_write.
  47. */
  48. static int
  49. callback_buf(void * cookie, int status)
  50. {
  51. struct network_buf_cookie * C = cookie;
  52. struct timeval timeo;
  53. size_t bwlimit;
  54. size_t oplen;
  55. ssize_t len;
  56. int rc = -1; /* If not callback or reset, we have an error. */
  57. #ifndef HAVE_MSG_NOSIGNAL
  58. int saved_errno;
  59. #ifdef SO_NOSIGPIPE
  60. int val;
  61. #else
  62. void (* oldsig)(int);
  63. #endif
  64. #endif
  65. if (status != NETWORK_STATUS_OK) {
  66. /* If we have no data, mark a timeout as "no data" instead. */
  67. if ((C->bufpos != 0) && (status == NETWORK_STATUS_TIMEOUT))
  68. status = NETWORK_STATUS_NODATA;
  69. goto docallback;
  70. }
  71. /* Figure out how far we have bandwidth quota for. */
  72. if (network_bwlimit_get(C->netop, &bwlimit)) {
  73. status = NETWORK_STATUS_ERR;
  74. goto docallback;
  75. }
  76. /* If we have no bandwidth, schedule another callback. */
  77. if (bwlimit == 0)
  78. goto tryagain;
  79. /* Try to read/write data to/from the buffer. */
  80. #ifndef HAVE_MSG_NOSIGNAL
  81. #ifdef SO_NOSIGPIPE
  82. val = 1;
  83. if (setsockopt(C->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int))) {
  84. status = NETWORK_STATUS_ERR;
  85. goto docallback;
  86. }
  87. #else
  88. if ((oldsig = signal(SIGPIPE, SIG_IGN)) == SIG_ERR) {
  89. warnp("signal(SIGPIPE)");
  90. status = NETWORK_STATUS_ERR;
  91. goto docallback;
  92. }
  93. #endif
  94. #endif
  95. oplen = C->buflen - C->bufpos;
  96. if (oplen > bwlimit)
  97. oplen = bwlimit;
  98. /* Send or recv. */
  99. if (C->sendrecv == SEND)
  100. len = send(C->fd, C->buf + C->bufpos, oplen, C->flags);
  101. else
  102. len = recv(C->fd, C->buf + C->bufpos, oplen, C->flags);
  103. #ifndef HAVE_MSG_NOSIGNAL
  104. /* Save errno in case it gets clobbered by setsockopt() or signal(). */
  105. saved_errno = errno;
  106. #ifdef SO_NOSIGPIPE
  107. val = 0;
  108. if (setsockopt(C->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int))) {
  109. status = NETWORK_STATUS_ERR;
  110. goto docallback;
  111. }
  112. #else
  113. if (signal(SIGPIPE, oldsig) == SIG_ERR) {
  114. warnp("signal(SIGPIPE)");
  115. status = NETWORK_STATUS_ERR;
  116. goto docallback;
  117. }
  118. #endif
  119. /* Restore saved errno. */
  120. errno = saved_errno;
  121. #endif
  122. /* Failure, closed, or success? */
  123. if (len == -1) {
  124. /* If no data is available, reset the callback. */
  125. if ((errno == EAGAIN) ||
  126. #if EAGAIN != EWOULDBLOCK
  127. (errno == EWOULDBLOCK) ||
  128. #endif
  129. (errno == EINTR))
  130. goto tryagain;
  131. /* An error occurred. Let the callback handle it. */
  132. status = NETWORK_STATUS_ERR;
  133. goto docallback;
  134. } else if (len == 0) {
  135. /* Socket has been shut down by remote host. */
  136. /* This should occur only when receiving, not when sending. */
  137. status = NETWORK_STATUS_CLOSED;
  138. goto docallback;
  139. } else {
  140. /* Adjust bandwidth limit. */
  141. if (network_bwlimit_eat(C->netop, (size_t)len)) {
  142. status = NETWORK_STATUS_ERR;
  143. goto docallback;
  144. }
  145. /* Data has been read/written into/from buffer. */
  146. C->bufpos += (size_t)len;
  147. if (C->bufpos == C->buflen) {
  148. status = NETWORK_STATUS_OK;
  149. goto docallback;
  150. }
  151. /* Fall through to resetting the callback. */
  152. }
  153. tryagain:
  154. /* We need more data. Reset the callback. */
  155. memcpy(&timeo, &C->timeout, sizeof(struct timeval));
  156. if (tvmath_subctime(&timeo)) {
  157. status = NETWORK_STATUS_ERR;
  158. goto docallback;
  159. }
  160. if (tv_lt(&C->timeout_max, &timeo))
  161. memcpy(&timeo, &C->timeout_max, sizeof(struct timeval));
  162. if (network_register(C->fd, C->netop, &timeo, callback_buf, C)) {
  163. status = NETWORK_STATUS_ERR;
  164. goto docallback;
  165. }
  166. /* Callback has been reset. */
  167. return (0);
  168. docallback:
  169. /*
  170. * If there was a network error and we're being verbose, print the
  171. * error now in case errno gets mangled later.
  172. */
  173. if ((tarsnap_opt_noisy_warnings) && (status == NETWORK_STATUS_ERR))
  174. warnp("Network error");
  175. /* Call the user callback. */
  176. rc = (C->callback)(C->cookie, status);
  177. /* Free the cookie. */
  178. free(C);
  179. /* Return error or value from user callback. */
  180. return (rc);
  181. }
  182. /**
  183. * network_buf(fd, buf, buflen, to0, to1, callback, cookie, sendrecv, netop,
  184. * flags):
  185. * Asynchronously read/write the provided buffer from/to ${fd}, and call
  186. * callback(cookie, status) where status is a NETWORK_STATUS_* value. Time
  187. * out if no data can be read/writ for a period of time to0, or if the
  188. * complete buffer has not been read/writ after time to1.
  189. */
  190. static int
  191. network_buf(int fd, uint8_t * buf, size_t buflen,
  192. struct timeval * to0, struct timeval * to1,
  193. network_callback * callback, void * cookie,
  194. int sendrecv, int netop, int flags)
  195. {
  196. struct network_buf_cookie * C;
  197. struct timeval timeo;
  198. /* Create a cookie to be passed to callback_buf. */
  199. if ((C = malloc(sizeof(struct network_buf_cookie))) == NULL)
  200. goto err0;
  201. C->callback = callback;
  202. C->cookie = cookie;
  203. C->fd = fd;
  204. C->buf = buf;
  205. C->buflen = buflen;
  206. C->bufpos = 0;
  207. C->sendrecv = sendrecv;
  208. C->netop = netop;
  209. C->flags = flags;
  210. /* Figure out when we should give up waiting. */
  211. memcpy(&C->timeout, to1, sizeof(struct timeval));
  212. if (tvmath_addctime(&C->timeout))
  213. goto err1;
  214. /* Record the maximum time that any single send/recv will wait. */
  215. memcpy(&C->timeout_max, to0, sizeof(struct timeval));
  216. /* Set up the callback. */
  217. memcpy(&timeo, to1, sizeof(struct timeval));
  218. if (tv_lt(to0, &timeo))
  219. memcpy(&timeo, to0, sizeof(struct timeval));
  220. if (network_register(fd, netop, &timeo, callback_buf, C))
  221. goto err1;
  222. /* Success! */
  223. return (0);
  224. err1:
  225. free(C);
  226. err0:
  227. /* Failure! */
  228. return (-1);
  229. }
  230. /**
  231. * tsnetwork_read(fd, buf, buflen, to0, to1, callback, cookie):
  232. * Asynchronously fill the provided buffer with data from ${fd}, and call
  233. * callback(cookie, status) where status is a NETWORK_STATUS_* value. Time
  234. * out if no data can be read for a period of time to0, or if the complete
  235. * buffer has not been read after time to1. Note that ${buflen} must be
  236. * non-zero, since otherwise deadlock would result.
  237. */
  238. int
  239. tsnetwork_read(int fd, uint8_t * buf, size_t buflen,
  240. struct timeval * to0, struct timeval * to1,
  241. network_callback * callback, void * cookie)
  242. {
  243. /* Make sure buflen is non-zero. */
  244. if (buflen == 0) {
  245. warn0("Cannot read zero-byte buffer");
  246. return (-1);
  247. }
  248. return (network_buf(fd, buf, buflen, to0, to1, callback, cookie,
  249. RECV, NETWORK_OP_READ, 0));
  250. }
  251. /**
  252. * tsnetwork_write(fd, buf, buflen, to0, to1, callback, cookie):
  253. * Asynchronously write data from the provided buffer to ${fd}, and call
  254. * callback(cookie, status) where status is a NETWORK_STATUS_* value. Time
  255. * out if no data can be written for a period of time to0, or if the complete
  256. * buffer has not been written after time to1. If ${buflen} is zero, the
  257. * callback will be invoked with a status of NETWORK_STATUS_CLOSED, even if
  258. * the connection is still open.
  259. */
  260. int
  261. tsnetwork_write(int fd, const uint8_t * buf, size_t buflen,
  262. struct timeval * to0, struct timeval * to1,
  263. network_callback * callback, void * cookie)
  264. {
  265. return (network_buf(fd, (uint8_t *)(uintptr_t)buf, buflen,
  266. to0, to1, callback, cookie,
  267. SEND, NETWORK_OP_WRITE, MSG_NOSIGNAL));
  268. }