diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2015-01-16 11:21:02 +0100 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2015-01-18 01:41:26 +0100 |
commit | 6c222d0646fa7c07be96d729009916d5af295332 (patch) | |
tree | 3e9ea61840825fee44d1fd562cd08ca6b1eceb69 | |
parent | 71ca932167085f313711d4259393c5f3441cc3a8 (diff) | |
download | uclient-6c222d0646fa7c07be96d729009916d5af295332.tar.gz |
support for connection timeout
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-rw-r--r-- | uclient-fetch.c | 4 | ||||
-rw-r--r-- | uclient-http.c | 13 | ||||
-rw-r--r-- | uclient.c | 36 | ||||
-rw-r--r-- | uclient.h | 20 |
4 files changed, 70 insertions, 3 deletions
diff --git a/uclient-fetch.c b/uclient-fetch.c index 22f15c6..0617a02 100644 --- a/uclient-fetch.c +++ b/uclient-fetch.c @@ -194,6 +194,10 @@ static void handle_uclient_error(struct uclient *cl, int code) type = "Connection failed"; error_ret = 4; break; + case UCLIENT_ERROR_TIMEDOUT: + type = "Connection timed out"; + error_ret = 4; + break; case UCLIENT_ERROR_SSL_INVALID_CERT: type = "Invalid SSL certificate"; ignore = !verify; diff --git a/uclient-http.c b/uclient-http.c index c25e52f..af43b05 100644 --- a/uclient-http.c +++ b/uclient-http.c @@ -689,8 +689,13 @@ static void __uclient_notify_read(struct uclient_http *uh) if (uh->eof) return; - if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read) - uc->cb->data_read(uc); + if (uh->state == HTTP_STATE_RECV_DATA) { + /* Now it's uclient user turn to read some data */ + uloop_timeout_cancel(&uc->connection_timeout); + + if (uc->cb->data_read) + uc->cb->data_read(uc); + } } static void __uclient_notify_write(struct uclient_http *uh) @@ -1030,6 +1035,10 @@ uclient_http_read(struct uclient *cl, char *buf, unsigned int len) uclient_notify_eof(uh); + /* Now that we consumed something and if this isn't EOF, start timer again */ + if (!uh->uc.eof && !cl->connection_timeout.pending) + uloop_timeout_set(&cl->connection_timeout, cl->timeout_msecs); + return len; } @@ -141,6 +141,16 @@ free: return NULL; } +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; @@ -157,6 +167,8 @@ struct uclient *uclient_new(const char *url_str, const char *auth_str, const str 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; } @@ -182,6 +194,16 @@ int uclient_set_url(struct uclient *cl, const char *url_str, const char *auth_st 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); @@ -209,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) @@ -225,6 +255,8 @@ int uclient_read(struct uclient *cl, char *buf, int len) void uclient_disconnect(struct uclient *cl) { + uloop_timeout_cancel(&cl->connection_timeout); + if (!cl->backend->disconnect) return; @@ -252,6 +284,7 @@ void __hidden uclient_backend_set_error(struct uclient *cl, int code) if (cl->error_code) return; + uloop_timeout_cancel(&cl->connection_timeout); cl->error_code = code; uclient_backend_change_state(cl); } @@ -261,6 +294,7 @@ void __hidden uclient_backend_set_eof(struct uclient *cl) if (cl->eof || cl->error_code) return; + uloop_timeout_cancel(&cl->connection_timeout); cl->eof = true; uclient_backend_change_state(cl); } @@ -24,12 +24,15 @@ #include <libubox/ustream.h> #include <libubox/ustream-ssl.h> +#define UCLIENT_DEFAULT_TIMEOUT_MS 30000 + struct uclient_cb; struct uclient_backend; enum uclient_error_code { UCLIENT_ERROR_UNKNOWN, UCLIENT_ERROR_CONNECT, + UCLIENT_ERROR_TIMEDOUT, UCLIENT_ERROR_SSL_INVALID_CERT, UCLIENT_ERROR_SSL_CN_MISMATCH, UCLIENT_ERROR_MISSING_SSL_CONTEXT, @@ -59,6 +62,7 @@ struct uclient { union uclient_addr local_addr, remote_addr; struct uclient_url *url; + int timeout_msecs; void *priv; bool eof; @@ -67,6 +71,7 @@ struct uclient { int status_code; struct blob_attr *meta; + struct uloop_timeout connection_timeout; struct uloop_timeout timeout; }; @@ -82,6 +87,21 @@ struct uclient *uclient_new(const char *url, const char *auth_str, const struct void uclient_free(struct uclient *cl); int uclient_set_url(struct uclient *cl, const char *url, const char *auth); + +/** + * Sets connection timeout. + * + * Provided timeout value will be used for: + * 1) Receiving HTTP response + * 2) Receiving data + * + * In case of timeout uclient will use error callback with + * UCLIENT_ERROR_TIMEDOUT code. + * + * @param msecs timeout in milliseconds + */ +int uclient_set_timeout(struct uclient *cl, int msecs); + int uclient_connect(struct uclient *cl); void uclient_disconnect(struct uclient *cl); |