X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuclient.git;a=blobdiff_plain;f=uclient.c;h=21f6f5dafdb5b1d3d6423de9819ba64060f0bb79;hp=a5c416e3005eddd86fdc1728ea59afb4623e262b;hb=4edb1426cef9eb07aa52dab2c34ab51f64e10f74;hpb=c280d54e1bc79de4424fabc3fad011cc15587b81 diff --git a/uclient.c b/uclient.c index a5c416e..21f6f5d 100644 --- a/uclient.c +++ b/uclient.c @@ -1,9 +1,54 @@ +/* + * uclient - ustream based protocol client library + * + * Copyright (C) 2014 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include #include #include "uclient.h" #include "uclient-utils.h" #include "uclient-backend.h" -static struct uclient_url *uclient_get_url(const char *url_str) +char *uclient_get_addr(char *dest, int *port, union uclient_addr *a) +{ + int portval; + void *ptr; + + switch(a->sa.sa_family) { + case AF_INET: + ptr = &a->sin.sin_addr; + portval = a->sin.sin_port; + break; + case AF_INET6: + ptr = &a->sin6.sin6_addr; + portval = a->sin6.sin6_port; + break; + default: + return strcpy(dest, "Unknown"); + } + + inet_ntop(a->sa.sa_family, ptr, dest, INET6_ADDRSTRLEN); + if (port) + *port = ntohs(portval); + + return dest; +} + + +struct uclient_url __hidden * +uclient_get_url(const char *url_str, const char *auth_str) { static const struct uclient_backend *backends[] = { &uclient_backend_http, @@ -12,8 +57,9 @@ static struct uclient_url *uclient_get_url(const char *url_str) const struct uclient_backend *backend; const char * const *prefix = NULL; struct uclient_url *url; - char *url_buf, *next; - int i; + const char *location; + char *host_buf, *uri_buf, *auth_buf, *next; + int i, host_len; for (i = 0; i < ARRAY_SIZE(backends); i++) { int prefix_len = 0; @@ -36,30 +82,40 @@ static struct uclient_url *uclient_get_url(const char *url_str) if (!*prefix) return NULL; - url = calloc_a(sizeof(*url), &url_buf, strlen(url_str) + 1); - url->backend = backend; - strcpy(url_buf, url_str); - - next = strchr(url_buf, '/'); + next = strchr(url_str, '/'); if (next) { - *next = 0; - url->location = next + 1; + location = next; + host_len = next - url_str; } else { - url->location = "/"; + location = "/"; + host_len = strlen(url_str); } - url->host = url_buf; - next = strchr(url_buf, '@'); + url = calloc_a(sizeof(*url), + &host_buf, host_len + 1, + &uri_buf, strlen(location) + 1, + &auth_buf, auth_str ? strlen(auth_str) + 1 : 0); + + url->backend = backend; + url->location = strcpy(uri_buf, location); + url->prefix = prefix - backend->prefix; + + url->host = strncpy(host_buf, url_str, host_len); + + next = strchr(host_buf, '@'); if (next) { *next = 0; url->host = next + 1; - if (uclient_urldecode(url_buf, url_buf, false) < 0) + if (uclient_urldecode(host_buf, host_buf, false) < 0) goto free; - url->auth = url_buf; + url->auth = host_buf; } + if (!url->auth && auth_str) + url->auth = strcpy(auth_buf, auth_str); + /* Literal IPv6 address */ if (*url->host == '[') { url->host++; @@ -72,8 +128,10 @@ static struct uclient_url *uclient_get_url(const char *url_str) url->port = next + 1; } else { next = strrchr(url->host, ':'); - if (next) + if (next) { + *next = 0; url->port = next + 1; + } } return url; @@ -83,12 +141,22 @@ free: return NULL; } -struct uclient *uclient_new(const char *url_str, const struct uclient_cb *cb) +static void uclient_connection_timeout(struct uloop_timeout *timeout) +{ + struct uclient *cl = container_of(timeout, struct uclient, connection_timeout); + + if (cl->backend->disconnect) + cl->backend->disconnect(cl); + + uclient_backend_set_error(cl, UCLIENT_ERROR_TIMEDOUT); +} + +struct uclient *uclient_new(const char *url_str, const char *auth_str, const struct uclient_cb *cb) { struct uclient *cl; struct uclient_url *url; - url = uclient_get_url(url_str); + url = uclient_get_url(url_str, auth_str); if (!url) return NULL; @@ -99,26 +167,45 @@ struct uclient *uclient_new(const char *url_str, const struct uclient_cb *cb) cl->backend = url->backend; cl->cb = cb; cl->url = url; + cl->timeout_msecs = UCLIENT_DEFAULT_TIMEOUT_MS; + cl->connection_timeout.cb = uclient_connection_timeout; return cl; } -int uclient_connect_url(struct uclient *cl, const char *url_str) +int uclient_set_url(struct uclient *cl, const char *url_str, const char *auth_str) { + const struct uclient_backend *backend = cl->backend; struct uclient_url *url = cl->url; - if (url_str) { - url = uclient_get_url(url_str); - if (!url) - return -1; + url = uclient_get_url(url_str, auth_str); + if (!url) + return -1; + + if (url->backend != cl->backend) + return -1; - if (url->backend != cl->backend) - return -1; + free(cl->url); + cl->url = url; - free(cl->url); - cl->url = url; - } + if (backend->update_url) + backend->update_url(cl); + return 0; +} + +int uclient_set_timeout(struct uclient *cl, int msecs) +{ + if (msecs <= 0) + return -EINVAL; + + cl->timeout_msecs = msecs; + + return 0; +} + +int uclient_connect(struct uclient *cl) +{ return cl->backend->connect(cl); } @@ -134,7 +221,7 @@ void uclient_free(struct uclient *cl) free(url); } -int uclient_write(struct uclient *cl, char *buf, int len) +int uclient_write(struct uclient *cl, const char *buf, int len) { if (!cl->backend->write) return -1; @@ -144,10 +231,18 @@ int uclient_write(struct uclient *cl, char *buf, int len) int uclient_request(struct uclient *cl) { + int err; + if (!cl->backend->request) return -1; - return cl->backend->request(cl); + err = cl->backend->request(cl); + if (err) + return err; + + uloop_timeout_set(&cl->connection_timeout, cl->timeout_msecs); + + return 0; } int uclient_read(struct uclient *cl, char *buf, int len) @@ -158,12 +253,22 @@ int uclient_read(struct uclient *cl, char *buf, int len) return cl->backend->read(cl, buf, len); } +void uclient_disconnect(struct uclient *cl) +{ + uloop_timeout_cancel(&cl->connection_timeout); + + if (!cl->backend->disconnect) + return; + + cl->backend->disconnect(cl); +} + static void __uclient_backend_change_state(struct uloop_timeout *timeout) { struct uclient *cl = container_of(timeout, struct uclient, timeout); - if (cl->error && cl->cb->error) - cl->cb->error(cl); + if (cl->error_code && cl->cb->error) + cl->cb->error(cl, cl->error_code); else if (cl->eof && cl->cb->data_eof) cl->cb->data_eof(cl); } @@ -174,27 +279,30 @@ static void uclient_backend_change_state(struct uclient *cl) uloop_timeout_set(&cl->timeout, 1); } -void uclient_backend_set_error(struct uclient *cl) +void __hidden uclient_backend_set_error(struct uclient *cl, int code) { - if (cl->error) + if (cl->error_code) return; - cl->error = true; + uloop_timeout_cancel(&cl->connection_timeout); + cl->error_code = code; uclient_backend_change_state(cl); } void __hidden uclient_backend_set_eof(struct uclient *cl) { - if (cl->eof || cl->error) + if (cl->eof || cl->error_code) return; + uloop_timeout_cancel(&cl->connection_timeout); cl->eof = true; uclient_backend_change_state(cl); } void __hidden uclient_backend_reset_state(struct uclient *cl) { - cl->error = false; + cl->data_eof = false; cl->eof = false; + cl->error_code = 0; uloop_timeout_cancel(&cl->timeout); }