uclient.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * uclient - ustream based protocol client library
  3. *
  4. * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include <arpa/inet.h>
  19. #include <libubox/ustream-ssl.h>
  20. #include "uclient.h"
  21. #include "uclient-utils.h"
  22. #include "uclient-backend.h"
  23. char *uclient_get_addr(char *dest, int *port, union uclient_addr *a)
  24. {
  25. int portval;
  26. void *ptr;
  27. switch(a->sa.sa_family) {
  28. case AF_INET:
  29. ptr = &a->sin.sin_addr;
  30. portval = a->sin.sin_port;
  31. break;
  32. case AF_INET6:
  33. ptr = &a->sin6.sin6_addr;
  34. portval = a->sin6.sin6_port;
  35. break;
  36. default:
  37. return strcpy(dest, "Unknown");
  38. }
  39. inet_ntop(a->sa.sa_family, ptr, dest, INET6_ADDRSTRLEN);
  40. if (port)
  41. *port = ntohs(portval);
  42. return dest;
  43. }
  44. struct uclient_url __hidden *
  45. uclient_get_url(const char *url_str, const char *auth_str)
  46. {
  47. static const struct uclient_backend *backends[] = {
  48. &uclient_backend_http,
  49. };
  50. const struct uclient_backend *backend;
  51. const char * const *prefix = NULL;
  52. struct uclient_url *url;
  53. const char *location;
  54. char *host_buf, *uri_buf, *auth_buf, *next;
  55. int i, host_len;
  56. for (i = 0; i < ARRAY_SIZE(backends); i++) {
  57. int prefix_len = 0;
  58. for (prefix = backends[i]->prefix; *prefix; prefix++) {
  59. prefix_len = strlen(*prefix);
  60. if (!strncmp(url_str, *prefix, prefix_len))
  61. break;
  62. }
  63. if (!*prefix)
  64. continue;
  65. url_str += prefix_len;
  66. backend = backends[i];
  67. break;
  68. }
  69. if (!*prefix)
  70. return NULL;
  71. next = strchr(url_str, '/');
  72. if (next) {
  73. location = next;
  74. host_len = next - url_str;
  75. } else {
  76. location = "/";
  77. host_len = strlen(url_str);
  78. }
  79. url = calloc_a(sizeof(*url),
  80. &host_buf, host_len + 1,
  81. &uri_buf, strlen(location) + 1,
  82. &auth_buf, auth_str ? strlen(auth_str) + 1 : 0);
  83. url->backend = backend;
  84. url->location = strcpy(uri_buf, location);
  85. url->prefix = prefix - backend->prefix;
  86. url->host = strncpy(host_buf, url_str, host_len);
  87. next = strchr(host_buf, '@');
  88. if (next) {
  89. *next = 0;
  90. url->host = next + 1;
  91. if (uclient_urldecode(host_buf, host_buf, false) < 0)
  92. goto free;
  93. url->auth = host_buf;
  94. }
  95. if (!url->auth && auth_str)
  96. url->auth = strcpy(auth_buf, auth_str);
  97. /* Literal IPv6 address */
  98. if (*url->host == '[') {
  99. url->host++;
  100. next = strrchr(url->host, ']');
  101. if (!next)
  102. goto free;
  103. *(next++) = 0;
  104. if (*next == ':')
  105. url->port = next + 1;
  106. } else {
  107. next = strrchr(url->host, ':');
  108. if (next) {
  109. *next = 0;
  110. url->port = next + 1;
  111. }
  112. }
  113. return url;
  114. free:
  115. free(url);
  116. return NULL;
  117. }
  118. struct uclient *uclient_new(const char *url_str, const char *auth_str, const struct uclient_cb *cb)
  119. {
  120. struct uclient *cl;
  121. struct uclient_url *url;
  122. url = uclient_get_url(url_str, auth_str);
  123. if (!url)
  124. return NULL;
  125. cl = url->backend->alloc();
  126. if (!cl)
  127. return NULL;
  128. cl->backend = url->backend;
  129. cl->cb = cb;
  130. cl->url = url;
  131. return cl;
  132. }
  133. int uclient_set_url(struct uclient *cl, const char *url_str, const char *auth_str)
  134. {
  135. const struct uclient_backend *backend = cl->backend;
  136. struct uclient_url *url = cl->url;
  137. url = uclient_get_url(url_str, auth_str);
  138. if (!url)
  139. return -1;
  140. if (url->backend != cl->backend)
  141. return -1;
  142. free(cl->url);
  143. cl->url = url;
  144. if (backend->update_url)
  145. backend->update_url(cl);
  146. return 0;
  147. }
  148. int uclient_connect(struct uclient *cl)
  149. {
  150. return cl->backend->connect(cl);
  151. }
  152. void uclient_free(struct uclient *cl)
  153. {
  154. struct uclient_url *url = cl->url;
  155. if (cl->backend->free)
  156. cl->backend->free(cl);
  157. else
  158. free(cl);
  159. free(url);
  160. }
  161. int uclient_write(struct uclient *cl, char *buf, int len)
  162. {
  163. if (!cl->backend->write)
  164. return -1;
  165. return cl->backend->write(cl, buf, len);
  166. }
  167. int uclient_request(struct uclient *cl)
  168. {
  169. if (!cl->backend->request)
  170. return -1;
  171. return cl->backend->request(cl);
  172. }
  173. int uclient_read(struct uclient *cl, char *buf, int len)
  174. {
  175. if (!cl->backend->read)
  176. return -1;
  177. return cl->backend->read(cl, buf, len);
  178. }
  179. void uclient_disconnect(struct uclient *cl)
  180. {
  181. if (!cl->backend->disconnect)
  182. return;
  183. cl->backend->disconnect(cl);
  184. }
  185. static void __uclient_backend_change_state(struct uloop_timeout *timeout)
  186. {
  187. struct uclient *cl = container_of(timeout, struct uclient, timeout);
  188. if (cl->error_code && cl->cb->error)
  189. cl->cb->error(cl, cl->error_code);
  190. else if (cl->eof && cl->cb->data_eof)
  191. cl->cb->data_eof(cl);
  192. }
  193. static void uclient_backend_change_state(struct uclient *cl)
  194. {
  195. cl->timeout.cb = __uclient_backend_change_state;
  196. uloop_timeout_set(&cl->timeout, 1);
  197. }
  198. void __hidden uclient_backend_set_error(struct uclient *cl, int code)
  199. {
  200. if (cl->error_code)
  201. return;
  202. cl->error_code = code;
  203. uclient_backend_change_state(cl);
  204. }
  205. void __hidden uclient_backend_set_eof(struct uclient *cl)
  206. {
  207. if (cl->eof || cl->error_code)
  208. return;
  209. cl->eof = true;
  210. uclient_backend_change_state(cl);
  211. }
  212. void __hidden uclient_backend_reset_state(struct uclient *cl)
  213. {
  214. cl->data_eof = false;
  215. cl->eof = false;
  216. cl->error_code = 0;
  217. uloop_timeout_cancel(&cl->timeout);
  218. }