summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafał Miłecki <zajec5@gmail.com>2015-01-16 11:21:02 +0100
committerFelix Fietkau <nbd@openwrt.org>2015-01-18 01:41:26 +0100
commit6c222d0646fa7c07be96d729009916d5af295332 (patch)
tree3e9ea61840825fee44d1fd562cd08ca6b1eceb69
parent71ca932167085f313711d4259393c5f3441cc3a8 (diff)
downloaduclient-6c222d0646fa7c07be96d729009916d5af295332.tar.gz
support for connection timeout
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-rw-r--r--uclient-fetch.c4
-rw-r--r--uclient-http.c13
-rw-r--r--uclient.c36
-rw-r--r--uclient.h20
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;
}
diff --git a/uclient.c b/uclient.c
index ab2d5b6..d599763 100644
--- a/uclient.c
+++ b/uclient.c
@@ -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);
}
diff --git a/uclient.h b/uclient.h
index d5a0d5b..5904a38 100644
--- a/uclient.h
+++ b/uclient.h
@@ -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);