http: add support for specifying ipv4/ipv6 preference
authorFelix Fietkau <nbd@openwrt.org>
Sun, 24 Jan 2016 23:18:33 +0000 (00:18 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 24 Jan 2016 23:18:33 +0000 (00:18 +0100)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
uclient-fetch.c
uclient-http.c
uclient.h

index 851994f47b841668ca066a294e9268afff07a123..f65fab21f1cb46a30fe10f8a48637f3b95cf1320 100644 (file)
@@ -18,6 +18,7 @@
 
 #define _GNU_SOURCE
 #include <sys/stat.h>
+#include <sys/socket.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <dlfcn.h>
@@ -439,6 +440,8 @@ static int usage(const char *progname)
        fprintf(stderr,
                "Usage: %s [options] <URL>\n"
                "Options:\n"
+               "       -4:                             Use IPv4 only\n"
+               "       -6:                             Use IPv6 only\n"
                "       -q:                             Turn off status messages\n"
                "       -O <file>:                      Redirect output to file (use \"-\" for stdout)\n"
                "       -P <dir>:                       Set directory for output files\n"
@@ -530,11 +533,12 @@ int main(int argc, char **argv)
        bool has_cert = false;
        int i, ch;
        int rc;
+       int af = -1;
 
        signal(SIGPIPE, SIG_IGN);
        init_ustream_ssl();
 
-       while ((ch = getopt_long(argc, argv, "cO:P:qsT:U:Y:", longopts, &longopt_idx)) != -1) {
+       while ((ch = getopt_long(argc, argv, "46cO:P:qsT:U:Y:", longopts, &longopt_idx)) != -1) {
                switch(ch) {
                case 0:
                        switch (longopt_idx) {
@@ -584,6 +588,12 @@ int main(int argc, char **argv)
                                return usage(progname);
                        }
                        break;
+               case '4':
+                       af = AF_INET;
+                       break;
+               case '6':
+                       af = AF_INET6;
+                       break;
                case 'c':
                        resume = true;
                        break;
@@ -652,7 +662,8 @@ int main(int argc, char **argv)
        proxy_url = get_proxy_url(argv[0]);
        if (proxy_url) {
                cl = uclient_new(proxy_url, auth_str, &cb);
-               uclient_set_proxy_url(cl, argv[0], NULL);
+               if (cl)
+                   uclient_set_proxy_url(cl, argv[0], NULL);
        } else {
                cl = uclient_new(argv[0], auth_str, &cb);
        }
@@ -660,6 +671,8 @@ int main(int argc, char **argv)
                fprintf(stderr, "Failed to allocate uclient context\n");
                return 1;
        }
+       if (af >= 0)
+           uclient_http_set_address_family(cl, af);
 
        if (ssl_ctx && default_certs)
                init_ca_cert();
index 5e5f9961e20d6ffc56de980123f1e2d35862c53a..f080e41239218fe18a3cf4b5a97d950f03e02367 100644 (file)
@@ -15,6 +15,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+#include <sys/socket.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <unistd.h>
@@ -90,6 +91,8 @@ struct uclient_http {
        long read_chunked;
        long content_length;
 
+       int usock_flags;
+
        uint32_t nc;
 
        struct blob_buf headers;
@@ -120,7 +123,7 @@ static int uclient_do_connect(struct uclient_http *uh, const char *port)
 
        memset(&uh->uc.remote_addr, 0, sizeof(uh->uc.remote_addr));
 
-       fd = usock_inet(USOCK_TCP, uh->uc.url->host, port, &uh->uc.remote_addr);
+       fd = usock_inet(USOCK_TCP | uh->usock_flags, uh->uc.url->host, port, &uh->uc.remote_addr);
        if (fd < 0)
                return -1;
 
@@ -1129,6 +1132,28 @@ int uclient_http_set_ssl_ctx(struct uclient *cl, const struct ustream_ssl_ops *o
        return 0;
 }
 
+int uclient_http_set_address_family(struct uclient *cl, int af)
+{
+       struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
+
+       if (cl->backend != &uclient_backend_http)
+               return -1;
+
+       switch (af) {
+       case AF_INET:
+               uh->usock_flags = USOCK_IPV4ONLY;
+               break;
+       case AF_INET6:
+               uh->usock_flags = USOCK_IPV6ONLY;
+               break;
+       default:
+               uh->usock_flags = 0;
+               break;
+       }
+
+       return 0;
+}
+
 const struct uclient_backend uclient_backend_http = {
        .prefix = uclient_http_prefix,
 
index 504fc3535c50b82ab381680f326889425278f8ce..e3695db6409b8069a0081c43ce3abde72b7f20ed 100644 (file)
--- a/uclient.h
+++ b/uclient.h
@@ -125,5 +125,6 @@ int uclient_http_redirect(struct uclient *cl);
 
 int uclient_http_set_ssl_ctx(struct uclient *cl, const struct ustream_ssl_ops *ops,
                             struct ustream_ssl_ctx *ctx, bool require_validation);
+int uclient_http_set_address_family(struct uclient *cl, int af);
 
 #endif