netproto_connect.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #include "platform.h"
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include <unistd.h>
  8. #include "netproto_internal.h"
  9. #include "network.h"
  10. #include "sock.h"
  11. #include "sock_util.h"
  12. #include "tsnetwork.h"
  13. #include "warnp.h"
  14. #include "netproto.h"
  15. struct netproto_connect_cookie {
  16. struct sock_addr ** sas;
  17. char * useragent;
  18. network_callback * callback;
  19. void * cookie;
  20. void * connect_cookie;
  21. NETPROTO_CONNECTION * NC;
  22. };
  23. static struct sock_addr ** srv_addr = NULL;
  24. static void netproto_connect_atexit(void);
  25. static void
  26. netproto_connect_atexit(void)
  27. {
  28. sock_addr_freelist(srv_addr);
  29. }
  30. static int
  31. callback_connect(void * cookie, int s)
  32. {
  33. struct netproto_connect_cookie * C = cookie;
  34. int rc;
  35. /* The connect is no longer pending. */
  36. C->connect_cookie = NULL;
  37. /* Did the connection attempt fail? */
  38. if (s == -1) {
  39. /*
  40. * Call the upstream callback. Upon being informed that the
  41. * connect has failed, the upstream code is responsible for
  42. * calling netproto_close, which (since we haven't called
  43. * netproto_setfd yet) will call into callback_cancel and let
  44. * us clean up.
  45. */
  46. return ((C->callback)(C->cookie, NETWORK_STATUS_CONNERR));
  47. }
  48. /* Inform the netproto code that we have a socket. */
  49. if (netproto_setfd(C->NC, s))
  50. goto err2;
  51. /* Perform key exchange. */
  52. if (netproto_keyexchange(C->NC, C->useragent, C->callback, C->cookie))
  53. goto err1;
  54. /* Free the cookie. */
  55. sock_addr_freelist(C->sas);
  56. free(C->useragent);
  57. free(C);
  58. /* Success! */
  59. return (0);
  60. err2:
  61. /* Drop the socket since we can't use it properly. */
  62. if (close(s))
  63. warnp("close");
  64. err1:
  65. /* Call the upstream callback. */
  66. rc = (C->callback)(C->cookie, NETWORK_STATUS_ERR);
  67. /*
  68. * We've called netproto_setfd, so callback_cancel won't happen; we
  69. * are responsible for cleaning up after ourselves.
  70. */
  71. sock_addr_freelist(C->sas);
  72. free(C->useragent);
  73. free(C);
  74. /* Return value from user callback. */
  75. return (rc);
  76. }
  77. static int
  78. callback_cancel(void * cookie)
  79. {
  80. struct netproto_connect_cookie * C = cookie;
  81. int rc;
  82. /* Cancel the connection attempt if still pending. */
  83. if (C->connect_cookie != NULL)
  84. network_connect_cancel(C->connect_cookie);
  85. /* We were cancelled. */
  86. rc = (C->callback)(C->cookie, NETWORK_STATUS_CANCEL);
  87. /* Free our cookie. */
  88. sock_addr_freelist(C->sas);
  89. free(C->useragent);
  90. free(C);
  91. /* Return value from user callback. */
  92. return (rc);
  93. }
  94. static struct sock_addr **
  95. getserveraddr(void)
  96. {
  97. static time_t srv_time = (time_t)(-1);
  98. struct sock_addr ** tmp_addr;
  99. time_t tmp_time;
  100. /*
  101. * If we haven't done a DNS lookup already, or our cached value is
  102. * more than 60 seconds old, do a DNS lookup.
  103. */
  104. tmp_time = time(NULL);
  105. if ((srv_time == (time_t)(-1)) || (tmp_time > srv_time + 60)) {
  106. tmp_addr = sock_resolve(TSSERVER "-server.tarsnap.com:9279");
  107. if (tmp_addr == NULL) {
  108. if (srv_addr != NULL)
  109. warn0("Using cached DNS lookup");
  110. else
  111. warn0("Cannot obtain server address");
  112. }
  113. } else {
  114. tmp_addr = NULL;
  115. }
  116. /* If we have a new lookup, update the cache. */
  117. if (tmp_addr != NULL) {
  118. /* First time we have an address to cache, register atexit. */
  119. if ((srv_addr == NULL) && (atexit(netproto_connect_atexit))) {
  120. warnp("Could not initialize atexit");
  121. return (NULL);
  122. }
  123. /* Update the cache. */
  124. sock_addr_freelist(srv_addr);
  125. srv_addr = tmp_addr;
  126. srv_time = tmp_time;
  127. }
  128. /* Return a duplicate of the cached value. */
  129. return (srv_addr ? sock_addr_duplist(srv_addr) : NULL);
  130. }
  131. /**
  132. * netproto_connect(useragent, callback, cookie):
  133. * Create a socket, connect to the tarsnap server, and perform the necessary
  134. * key exchange. Return a network protocol connection cookie; note that
  135. * this cookie must not be used until the callback is called.
  136. */
  137. NETPROTO_CONNECTION *
  138. netproto_connect(const char * useragent,
  139. network_callback * callback, void * cookie)
  140. {
  141. struct netproto_connect_cookie * C;
  142. struct timeval timeo;
  143. /* Create a cookie to be passed to callback_connect. */
  144. if ((C = malloc(sizeof(struct netproto_connect_cookie))) == NULL)
  145. goto err0;
  146. if ((C->useragent = strdup(useragent)) == NULL)
  147. goto err1;
  148. C->callback = callback;
  149. C->cookie = cookie;
  150. /* Look up the server's IP address. */
  151. if ((C->sas = getserveraddr()) == NULL)
  152. goto err2;
  153. /* Try to connect to server, waiting up to 5 seconds per address. */
  154. timeo.tv_sec = 5;
  155. timeo.tv_usec = 0;
  156. if ((C->connect_cookie = network_connect_timeo(C->sas, &timeo,
  157. callback_connect, C)) == NULL) {
  158. netproto_printerr(NETWORK_STATUS_CONNERR);
  159. goto err3;
  160. }
  161. /* Create a network protocol connection cookie. */
  162. if ((C->NC = netproto_alloc(callback_cancel, C)) == NULL)
  163. goto err4;
  164. /* Success! */
  165. return (C->NC);
  166. err4:
  167. network_connect_cancel(C->connect_cookie);
  168. err3:
  169. sock_addr_freelist(C->sas);
  170. err2:
  171. free(C->useragent);
  172. err1:
  173. free(C);
  174. err0:
  175. /* Failure! */
  176. return (NULL);
  177. }