Search in sources :

Example 1 with ConnectCallback

use of com.koushikdutta.async.callback.ConnectCallback in project AndroidAsync by koush.

the class AsyncSocketMiddleware method getSocket.

@Override
public Cancellable getSocket(final GetSocketData data) {
    final Uri uri = data.request.getUri();
    final int port = getSchemePort(data.request.getUri());
    if (port == -1) {
        return null;
    }
    data.state.put("socket-owner", this);
    final String lookup = computeLookup(uri, port, data.request.getProxyHost(), data.request.getProxyPort());
    ConnectionInfo info = getOrCreateConnectionInfo(lookup);
    synchronized (AsyncSocketMiddleware.this) {
        if (info.openCount >= maxConnectionCount) {
            // wait for a connection queue to free up
            SimpleCancellable queueCancel = new SimpleCancellable();
            info.queue.add(data);
            return queueCancel;
        }
        info.openCount++;
        while (!info.sockets.isEmpty()) {
            IdleSocketHolder idleSocketHolder = info.sockets.pop();
            final AsyncSocket socket = idleSocketHolder.socket;
            if (idleSocketHolder.idleTime + idleTimeoutMs < System.currentTimeMillis()) {
                socket.setClosedCallback(null);
                socket.close();
                continue;
            }
            if (!socket.isOpen())
                continue;
            data.request.logd("Reusing keep-alive socket");
            data.connectCallback.onConnectCompleted(null, socket);
            // just a noop/dummy, as this can't actually be cancelled.
            SimpleCancellable ret = new SimpleCancellable();
            ret.setComplete();
            return ret;
        }
    }
    if (!connectAllAddresses || proxyHost != null || data.request.getProxyHost() != null) {
        // just default to connecting to a single address
        data.request.logd("Connecting socket");
        String unresolvedHost;
        int unresolvedPort;
        boolean proxied = false;
        if (data.request.getProxyHost() == null && proxyHost != null)
            data.request.enableProxy(proxyHost, proxyPort);
        if (data.request.getProxyHost() != null) {
            unresolvedHost = data.request.getProxyHost();
            unresolvedPort = data.request.getProxyPort();
            proxied = true;
        } else {
            unresolvedHost = uri.getHost();
            unresolvedPort = port;
        }
        if (proxied) {
            data.request.logv("Using proxy: " + unresolvedHost + ":" + unresolvedPort);
        }
        return mClient.getServer().connectSocket(unresolvedHost, unresolvedPort, wrapCallback(data, uri, port, proxied, data.connectCallback));
    }
    // try to connect to everything...
    data.request.logv("Resolving domain and connecting to all available addresses");
    return mClient.getServer().getAllByName(uri.getHost()).then(new TransformFuture<AsyncSocket, InetAddress[]>() {

        Exception lastException;

        @Override
        protected void error(Exception e) {
            super.error(e);
            wrapCallback(data, uri, port, false, data.connectCallback).onConnectCompleted(e, null);
        }

        @Override
        protected void transform(final InetAddress[] result) throws Exception {
            Continuation keepTrying = new Continuation(new CompletedCallback() {

                @Override
                public void onCompleted(Exception ex) {
                    // if it completed, that means that the connection failed
                    if (lastException == null)
                        lastException = new ConnectionFailedException("Unable to connect to remote address");
                    if (setComplete(lastException)) {
                        wrapCallback(data, uri, port, false, data.connectCallback).onConnectCompleted(lastException, null);
                    }
                }
            });
            for (final InetAddress address : result) {
                final String inetSockAddress = String.format(Locale.ENGLISH, "%s:%s", address, port);
                keepTrying.add(new ContinuationCallback() {

                    @Override
                    public void onContinue(Continuation continuation, final CompletedCallback next) throws Exception {
                        data.request.logv("attempting connection to " + inetSockAddress);
                        mClient.getServer().connectSocket(new InetSocketAddress(address, port), wrapCallback(data, uri, port, false, new ConnectCallback() {

                            @Override
                            public void onConnectCompleted(Exception ex, AsyncSocket socket) {
                                if (isDone()) {
                                    lastException = new Exception("internal error during connect to " + inetSockAddress);
                                    next.onCompleted(null);
                                    return;
                                }
                                // try the next address
                                if (ex != null) {
                                    lastException = ex;
                                    next.onCompleted(null);
                                    return;
                                }
                                // if the socket is no longer needed, just hang onto it...
                                if (isDone() || isCancelled()) {
                                    data.request.logd("Recycling extra socket leftover from cancelled operation");
                                    idleSocket(socket);
                                    recycleSocket(socket, data.request);
                                    return;
                                }
                                if (setComplete(null, socket)) {
                                    data.connectCallback.onConnectCompleted(null, socket);
                                }
                            }
                        }));
                    }
                });
            }
            keepTrying.start();
        }
    });
}
Also used : Continuation(com.koushikdutta.async.future.Continuation) CompletedCallback(com.koushikdutta.async.callback.CompletedCallback) InetSocketAddress(java.net.InetSocketAddress) Uri(android.net.Uri) AsyncSocket(com.koushikdutta.async.AsyncSocket) ContinuationCallback(com.koushikdutta.async.callback.ContinuationCallback) SimpleCancellable(com.koushikdutta.async.future.SimpleCancellable) ConnectCallback(com.koushikdutta.async.callback.ConnectCallback) InetAddress(java.net.InetAddress)

Example 2 with ConnectCallback

use of com.koushikdutta.async.callback.ConnectCallback in project AndroidAsync by koush.

the class AsyncHttpClient method executeAffinity.

private void executeAffinity(final AsyncHttpRequest request, final int redirectCount, final FutureAsyncHttpResponse cancel, final HttpConnectCallback callback) {
    assert mServer.isAffinityThread();
    if (redirectCount > 15) {
        reportConnectedCompleted(cancel, new RedirectLimitExceededException("too many redirects"), null, request, callback);
        return;
    }
    final Uri uri = request.getUri();
    final AsyncHttpClientMiddleware.OnResponseCompleteDataOnRequestSentData data = new AsyncHttpClientMiddleware.OnResponseCompleteDataOnRequestSentData();
    request.executionTime = System.currentTimeMillis();
    data.request = request;
    request.logd("Executing request.");
    for (AsyncHttpClientMiddleware middleware : mMiddleware) {
        middleware.onRequest(data);
    }
    if (request.getTimeout() > 0) {
        // set connect timeout
        cancel.timeoutRunnable = new Runnable() {

            @Override
            public void run() {
                // we've timed out, kill the connections
                if (data.socketCancellable != null) {
                    data.socketCancellable.cancel();
                    if (data.socket != null)
                        data.socket.close();
                }
                reportConnectedCompleted(cancel, new TimeoutException(), null, request, callback);
            }
        };
        cancel.scheduled = mServer.postDelayed(cancel.timeoutRunnable, getTimeoutRemaining(request));
    }
    // 2) wait for a connect
    data.connectCallback = new ConnectCallback() {

        boolean reported;

        @Override
        public void onConnectCompleted(Exception ex, AsyncSocket socket) {
            if (reported) {
                if (socket != null) {
                    socket.setDataCallback(new DataCallback.NullDataCallback());
                    socket.setEndCallback(new CompletedCallback.NullCompletedCallback());
                    socket.close();
                    throw new AssertionError("double connect callback");
                }
            }
            reported = true;
            request.logv("socket connected");
            if (cancel.isCancelled()) {
                if (socket != null)
                    socket.close();
                return;
            }
            // 3) on connect, cancel timeout
            if (cancel.timeoutRunnable != null)
                mServer.removeAllCallbacks(cancel.scheduled);
            if (ex != null) {
                reportConnectedCompleted(cancel, ex, null, request, callback);
                return;
            }
            data.socket = socket;
            cancel.socket = socket;
            executeSocket(request, redirectCount, cancel, callback, data);
        }
    };
    // set up the system default proxy and connect
    setupAndroidProxy(request);
    // set the implicit content type
    if (request.getBody() != null) {
        if (request.getHeaders().get("Content-Type") == null)
            request.getHeaders().set("Content-Type", request.getBody().getContentType());
    }
    final Exception unsupportedURI;
    for (AsyncHttpClientMiddleware middleware : mMiddleware) {
        Cancellable socketCancellable = middleware.getSocket(data);
        if (socketCancellable != null) {
            data.socketCancellable = socketCancellable;
            cancel.setParent(socketCancellable);
            return;
        }
    }
    unsupportedURI = new IllegalArgumentException("invalid uri=" + request.getUri() + " middlewares=" + mMiddleware);
    reportConnectedCompleted(cancel, unsupportedURI, null, request, callback);
}
Also used : Cancellable(com.koushikdutta.async.future.Cancellable) Uri(android.net.Uri) TimeoutException(java.util.concurrent.TimeoutException) AsyncSSLException(com.koushikdutta.async.AsyncSSLException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) AsyncSocket(com.koushikdutta.async.AsyncSocket) HttpConnectCallback(com.koushikdutta.async.http.callback.HttpConnectCallback) ConnectCallback(com.koushikdutta.async.callback.ConnectCallback) TimeoutException(java.util.concurrent.TimeoutException)

Example 3 with ConnectCallback

use of com.koushikdutta.async.callback.ConnectCallback in project AndroidAsync by koush.

the class AsyncSSLSocketMiddleware method wrapCallback.

@Override
protected ConnectCallback wrapCallback(final GetSocketData data, final Uri uri, final int port, final boolean proxied, final ConnectCallback callback) {
    return new ConnectCallback() {

        @Override
        public void onConnectCompleted(Exception ex, final AsyncSocket socket) {
            if (ex != null) {
                callback.onConnectCompleted(ex, socket);
                return;
            }
            if (!proxied) {
                tryHandshake(socket, data, uri, port, callback);
                return;
            }
            // this SSL connection is proxied, must issue a CONNECT request to the proxy server
            // http://stackoverflow.com/a/6594880/704837
            // some proxies also require 'Host' header, it should be safe to provide it every time
            String connect = String.format(Locale.ENGLISH, "CONNECT %s:%s HTTP/1.1\r\nHost: %s\r\n\r\n", uri.getHost(), port, uri.getHost());
            data.request.logv("Proxying: " + connect);
            Util.writeAll(socket, connect.getBytes(), new CompletedCallback() {

                @Override
                public void onCompleted(Exception ex) {
                    if (ex != null) {
                        callback.onConnectCompleted(ex, socket);
                        return;
                    }
                    LineEmitter liner = new LineEmitter();
                    liner.setLineCallback(new LineEmitter.StringCallback() {

                        String statusLine;

                        @Override
                        public void onStringAvailable(String s) {
                            data.request.logv(s);
                            if (statusLine == null) {
                                statusLine = s.trim();
                                if (!statusLine.matches("HTTP/1.\\d 2\\d\\d .*")) {
                                    // connect response is allowed to have any 2xx status code
                                    socket.setDataCallback(null);
                                    socket.setEndCallback(null);
                                    callback.onConnectCompleted(new IOException("non 2xx status line: " + statusLine), socket);
                                }
                            } else if (TextUtils.isEmpty(s.trim())) {
                                // skip all headers, complete handshake once empty line is received
                                socket.setDataCallback(null);
                                socket.setEndCallback(null);
                                tryHandshake(socket, data, uri, port, callback);
                            }
                        }
                    });
                    socket.setDataCallback(liner);
                    socket.setEndCallback(new CompletedCallback() {

                        @Override
                        public void onCompleted(Exception ex) {
                            if (!socket.isOpen() && ex == null)
                                ex = new IOException("socket closed before proxy connect response");
                            callback.onConnectCompleted(ex, socket);
                        }
                    });
                }
            });
        }
    };
}
Also used : AsyncSocket(com.koushikdutta.async.AsyncSocket) CompletedCallback(com.koushikdutta.async.callback.CompletedCallback) LineEmitter(com.koushikdutta.async.LineEmitter) IOException(java.io.IOException) ConnectCallback(com.koushikdutta.async.callback.ConnectCallback) IOException(java.io.IOException)

Example 4 with ConnectCallback

use of com.koushikdutta.async.callback.ConnectCallback in project AndroidAsync by koush.

the class DnsTests method testNoDomain.

public void testNoDomain() throws Exception {
    AsyncServer server = new AsyncServer();
    try {
        final Semaphore semaphore = new Semaphore(0);
        server.connectSocket("www.clockworkmod-notfound.com", 8080, new ConnectCallback() {

            @Override
            public void onConnectCompleted(Exception ex, AsyncSocket socket) {
                assertTrue(ex instanceof UnknownHostException);
                semaphore.release();
            }
        });
        assertTrue(semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS));
    } finally {
        server.stop();
    }
}
Also used : AsyncSocket(com.koushikdutta.async.AsyncSocket) UnknownHostException(java.net.UnknownHostException) AsyncServer(com.koushikdutta.async.AsyncServer) Semaphore(java.util.concurrent.Semaphore) ConnectCallback(com.koushikdutta.async.callback.ConnectCallback) UnknownHostException(java.net.UnknownHostException)

Example 5 with ConnectCallback

use of com.koushikdutta.async.callback.ConnectCallback in project AndroidAsync by koush.

the class SpdyMiddleware method wrapCallback.

@Override
protected ConnectCallback wrapCallback(final GetSocketData data, final Uri uri, final int port, final boolean proxied, ConnectCallback callback) {
    final ConnectCallback superCallback = super.wrapCallback(data, uri, port, proxied, callback);
    final String key = data.state.get("spdykey");
    if (key == null)
        return superCallback;
    // new outgoing connection, try to make this a spdy connection
    return new ConnectCallback() {

        @Override
        public void onConnectCompleted(Exception ex, AsyncSocket socket) {
            // trigger the waiters
            if (ex != null) {
                final SpdyConnectionWaiter conn = connections.remove(key);
                if (conn != null)
                    conn.setComplete(ex);
            }
            superCallback.onConnectCompleted(ex, socket);
        }
    };
}
Also used : AsyncSocket(com.koushikdutta.async.AsyncSocket) ConnectCallback(com.koushikdutta.async.callback.ConnectCallback) IOException(java.io.IOException)

Aggregations

AsyncSocket (com.koushikdutta.async.AsyncSocket)5 ConnectCallback (com.koushikdutta.async.callback.ConnectCallback)5 IOException (java.io.IOException)3 Uri (android.net.Uri)2 CompletedCallback (com.koushikdutta.async.callback.CompletedCallback)2 AsyncSSLException (com.koushikdutta.async.AsyncSSLException)1 AsyncServer (com.koushikdutta.async.AsyncServer)1 LineEmitter (com.koushikdutta.async.LineEmitter)1 ContinuationCallback (com.koushikdutta.async.callback.ContinuationCallback)1 Cancellable (com.koushikdutta.async.future.Cancellable)1 Continuation (com.koushikdutta.async.future.Continuation)1 SimpleCancellable (com.koushikdutta.async.future.SimpleCancellable)1 HttpConnectCallback (com.koushikdutta.async.http.callback.HttpConnectCallback)1 FileNotFoundException (java.io.FileNotFoundException)1 InetAddress (java.net.InetAddress)1 InetSocketAddress (java.net.InetSocketAddress)1 UnknownHostException (java.net.UnknownHostException)1 Semaphore (java.util.concurrent.Semaphore)1 TimeoutException (java.util.concurrent.TimeoutException)1