netproto.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include <sys/time.h>
  2. #include <errno.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include "crypto.h"
  6. #include "tsnetwork.h"
  7. #include "warnp.h"
  8. #include "netproto.h"
  9. #include "netproto_internal.h"
  10. static network_callback callback_sleep;
  11. /**
  12. * netproto_printerr_internal(status):
  13. * Print the error message associated with the given status code.
  14. */
  15. void
  16. netproto_printerr_internal(int status)
  17. {
  18. switch (status) {
  19. case NETWORK_STATUS_CONNERR:
  20. /* Could not connect. */
  21. warn0("Error connecting to server");
  22. break;
  23. case NETWORK_STATUS_ERR:
  24. /* Error is specified in errno. */
  25. warnp("Network error");
  26. break;
  27. case NETWORK_STATUS_NODATA:
  28. case NETWORK_STATUS_TIMEOUT:
  29. /* Server timed out. */
  30. warn0("Timeout communicating with server");
  31. break;
  32. case NETWORK_STATUS_CTIMEOUT:
  33. /* Server timed out. */
  34. warn0("Timeout connecting to server");
  35. break;
  36. case NETWORK_STATUS_CLOSED:
  37. /* Server closed connection. */
  38. warn0("Connection closed by server");
  39. break;
  40. case NETWORK_STATUS_CANCEL:
  41. /* Operation cancelled; no error message. */
  42. break;
  43. case NETPROTO_STATUS_PROTERR:
  44. /* Protocol violation by server. */
  45. warn0("Network protocol violation by server");
  46. break;
  47. }
  48. }
  49. /**
  50. * netproto_alloc(callback, cookie):
  51. * Allocate a network protocol connection cookie. If the connection is closed
  52. * before netproto_setfd is called, netproto_close will call callback(cookie)
  53. * in lieu of performing callback cancels on a socket.
  54. */
  55. struct netproto_connection_internal *
  56. netproto_alloc(int (* callback)(void *), void * cookie)
  57. {
  58. struct netproto_connection_internal * C;
  59. /* Allocate memory. */
  60. if ((C = malloc(sizeof(struct netproto_connection_internal))) == NULL)
  61. goto err0;
  62. /* Record connect-cancel callback and cookie. */
  63. C->cancel = callback;
  64. C->cookie = cookie;
  65. /* We have no state yet. */
  66. C->fd = -1;
  67. C->keys = NULL;
  68. C->sleepcookie.handle = -1;
  69. C->bytesin = C->bytesout = C->bytesqueued = 0;
  70. C->broken = 0;
  71. C->Q = NULL;
  72. /* Success! */
  73. return (C);
  74. err0:
  75. /* Failure! */
  76. return (NULL);
  77. }
  78. /**
  79. * netproto_setfd(C, fd):
  80. * Set the network protocol connection cookie ${C} to use connected socket
  81. * ${fd}. This function must be called exactly once after netproto_alloc
  82. * before calling any other functions aside from netproto_free.
  83. */
  84. int
  85. netproto_setfd(struct netproto_connection_internal * C, int fd)
  86. {
  87. /* The connect is no longer pending. */
  88. C->cancel = NULL;
  89. C->cookie = NULL;
  90. /* We have a file descriptor. */
  91. C->fd = fd;
  92. /* Create a network layer write queue. */
  93. if ((C->Q = network_writeq_init(fd)) == NULL)
  94. goto err0;
  95. /* Success! */
  96. return (0);
  97. err0:
  98. /* Failure! */
  99. return (-1);
  100. }
  101. /**
  102. * netproto_getstats(C, in, out, queued):
  103. * Obtain the number of bytes received and sent via the connection, and the
  104. * number of bytes ${queued} to be written.
  105. */
  106. void
  107. netproto_getstats(NETPROTO_CONNECTION * C, uint64_t * in, uint64_t * out,
  108. uint64_t * queued)
  109. {
  110. *in = C->bytesin;
  111. *out = C->bytesout;
  112. *queued = C->bytesqueued;
  113. }
  114. /**
  115. * netproto_sleep(C, secs, callback, cookie):
  116. * Call the provided callback after ${secs} seconds.
  117. */
  118. int
  119. netproto_sleep(NETPROTO_CONNECTION * C, int secs,
  120. network_callback * callback, void * cookie)
  121. {
  122. struct timeval timeo;
  123. /* Set timeout. */
  124. timeo.tv_sec = secs;
  125. timeo.tv_usec = 0;
  126. /* Make sure this connection isn't already sleeping. */
  127. if (C->sleepcookie.handle != -1) {
  128. warn0("Connection is already sleeping!");
  129. goto err0;
  130. }
  131. /* Record callback parameters. */
  132. C->sleepcookie.callback = callback;
  133. C->sleepcookie.cookie = cookie;
  134. /* Ask for a wake-up call. */
  135. if ((C->sleepcookie.handle =
  136. network_sleep(&timeo, callback_sleep, C)) == -1)
  137. goto err0;
  138. /* Success! */
  139. return (0);
  140. err0:
  141. /* Failure! */
  142. return (-1);
  143. }
  144. /**
  145. * callback_sleep(cookie, status):
  146. * Helper function for netproto_sleep.
  147. */
  148. static int
  149. callback_sleep(void * cookie, int status)
  150. {
  151. NETPROTO_CONNECTION * C = cookie;
  152. /*
  153. * Our wake-up call is happening right now; record that there is no
  154. * pending callback so that we don't try to deregister it when the
  155. * connection is closed later.
  156. */
  157. C->sleepcookie.handle = -1;
  158. /* Call the requested callback. */
  159. return ((C->sleepcookie.callback)(C->sleepcookie.cookie, status));
  160. }
  161. /**
  162. * netproto_flush(C):
  163. * Cancel all pending writes and any in-progress read.
  164. */
  165. int
  166. netproto_flush(NETPROTO_CONNECTION * C)
  167. {
  168. int rc, rc2;
  169. /* Cancel pending writes. */
  170. if (C->Q != NULL)
  171. rc = network_writeq_cancel(C->Q);
  172. else
  173. rc = 0;
  174. /*
  175. * Mark this connection as being broken. The upstream caller should
  176. * never try to write any packets after calling netproto_flush --
  177. * this allows us to detect and print a warning if it does.
  178. */
  179. C->broken = 1;
  180. /* Cancel any in-progress read. */
  181. if (C->fd != -1) {
  182. rc2 = network_deregister(C->fd, NETWORK_OP_READ);
  183. if (rc == 0)
  184. rc = rc2;
  185. }
  186. /* Return success or the first nonzero callback value. */
  187. return (rc);
  188. }
  189. /**
  190. * netproto_close(C):
  191. * Cancel all pending writes and any in-progress read, and free memory.
  192. */
  193. int
  194. netproto_close(NETPROTO_CONNECTION * C)
  195. {
  196. int rc, rc2;
  197. /* If we were connecting, cancel that. */
  198. if (C->cancel != NULL)
  199. rc = (C->cancel)(C->cookie);
  200. else
  201. rc = 0;
  202. /* Cancel pending writes. */
  203. if (C->Q != NULL) {
  204. rc2 = network_writeq_cancel(C->Q);
  205. rc = rc ? rc : rc2;
  206. }
  207. /* Free the write queue. */
  208. if (C->Q != NULL)
  209. network_writeq_free(C->Q);
  210. /* Cancel any in-progress read. */
  211. if (C->fd != -1) {
  212. rc2 = network_deregister(C->fd, NETWORK_OP_READ);
  213. rc = rc ? rc : rc2;
  214. }
  215. /* Free cryptographic keys, if any exist. */
  216. crypto_session_free(C->keys);
  217. /* Close the socket. */
  218. while (C->fd != -1 && close(C->fd)) {
  219. if (errno == ECONNRESET) {
  220. /*
  221. * You can't dump me! I'm dumping you! We don't
  222. * care about the connection dying since we're
  223. * done with it anyway.
  224. */
  225. break;
  226. }
  227. if (errno != EINTR) {
  228. warnp("close()");
  229. goto err1;
  230. }
  231. }
  232. /* Free the network protocol cookie. */
  233. free(C);
  234. /* Return success or the first nonzero callback value. */
  235. return (rc);
  236. err1:
  237. free(C);
  238. /* Failure! */
  239. return (-1);
  240. }