Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbbea2e1 authored by Nick Pelly's avatar Nick Pelly
Browse files

Workaround for bug 5082381 (EALREADY on ACL collision).

If connect() fails with EALREADY, then retry.

Unfortunately we also need to switch to a new FD. This is currently
safe, but its a little fragile to changes in the code (especially
if we ever expose the fd to applications) so it would be great to
fix this issue properly in the kernel sometime and revert this
commit.

Change-Id: I12fb6b7f2b8ca40f425f66b504754048c9460329
parent 3ebdb489
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -57,6 +57,9 @@ static const int TYPE_L2CAP = 3; // TODO: Test l2cap code paths

static const int RFCOMM_SO_SNDBUF = 70 * 1024;  // 70 KB send buffer

static void abortNative(JNIEnv *env, jobject obj);
static void destroyNative(JNIEnv *env, jobject obj);

static struct asocket *get_socketData(JNIEnv *env, jobject obj) {
    struct asocket *s =
            (struct asocket *) env->GetIntField(obj, field_mSocketData);
@@ -172,6 +175,7 @@ static void connectNative(JNIEnv *env, jobject obj) {
    socklen_t addr_sz;
    struct sockaddr *addr;
    struct asocket *s = get_socketData(env, obj);
    int retry = 0;

    if (!s)
        return;
@@ -226,10 +230,30 @@ static void connectNative(JNIEnv *env, jobject obj) {
        return;
    }

connect:
    ret = asocket_connect(s, addr, addr_sz, -1);
    LOGV("...connect(%d, %s) = %d (errno %d)",
            s->fd, TYPE_AS_STR(type), ret, errno);

    if (ret && errno == EALREADY && retry < 2) {
        /* workaround for bug 5082381 (EALREADY on ACL collision):
         * retry the connect. Unfortunately we have to create a new fd.
         * It's not ideal to switch the fd underneath the object, but
         * is currently safe */
        LOGD("Hit bug 5082381 (EALREADY on ACL collision), trying workaround");
        usleep(100000);
        retry++;
        abortNative(env, obj);
        destroyNative(env, obj);
        initSocketNative(env, obj);
        if (env->ExceptionOccurred()) {
            return;
        }
        goto connect;
    }
    if (!ret && retry > 0)
        LOGD("...workaround ok");

    if (ret)
        jniThrowIOException(env, errno);