Сохранение нативного (C) указателя в экземпляре объекта и последующая очистка - PullRequest
0 голосов
/ 17 декабря 2011

Для одного из моих проектов я хочу реализовать полную реализацию PAM для Java (как на стороне приложения, так и на стороне модуля).

Сейчас я нахожусь на стороне приложения.Я взял за основу jpam, но наткнулся на проблему, и после нескольких часов поисков я все еще не могу найти решение своей проблемы: /

Это текущий код:

JNIEXPORT jint JNICALL Java_org_eel_kitchen_pam_PamHandle_authenticate(
    JNIEnv *pEnv, jobject pObj, jstring pServiceName, jstring pUsername,
    jstring pPassword, jboolean debug)
{
    pam_handle_t *pamh = NULL;
    int retval;

    /*
     * TODO: unclear, see what's what
     *
     * With my first tests, it appears that GetStringUTFChars() makes the JVM
     * crash if memory cannot be allocated... But an array copy was made. See
     * what happens if the JVM decides NOT to make a copy. Right now it is
     * assumed that allocations succeed. And the JNI spec says
     * GetStringUTFChars() does NOT throw an OOM on failure.
     */
    service_name = (*pEnv)->GetStringUTFChars(pEnv, pServiceName, NULL);
    username = (*pEnv)->GetStringUTFChars(pEnv, pUsername, NULL);
    password = (*pEnv)->GetStringUTFChars(pEnv, pPassword, NULL);

    /* Get a handle to a PAM instance */
    retval = pam_start(service_name, username, &PAM_converse, &pamh);

    if (retval != PAM_SUCCESS) {
        pr_debug("pam_start failed for service %s: %s\n", service_name,
            pam_strerror(NULL, retval));
        goto out_nohandle;
    }

    pam_set_item(pamh, PAM_AUTHTOK, password);
    retval = pam_authenticate(pamh, 0);

    /* Is user permitted access? */
    if (retval != PAM_SUCCESS) {
        pr_debug("failed to authenticate user %s: %s\n", username,
            pam_strerror(NULL, retval));
        goto out_free;
    }

    retval = pam_acct_mgmt(pamh, 0);

    if (retval != PAM_SUCCESS)
        pr_debug("failed to setup account for user %s: %s\n", username,
            pam_strerror(NULL, retval));

out_free:
    /* Clean up our handles and variables */
    if (pam_end(pamh, retval) != PAM_SUCCESS) {
        pamh = NULL;
        pr_debug("Fuchs! Failed to release PAM handle\n");
    }

out_nohandle:
    (*pEnv)->ReleaseStringUTFChars(pEnv, pServiceName, service_name);
    (*pEnv)->ReleaseStringUTFChars(pEnv, pUsername, username);
    (*pEnv)->ReleaseStringUTFChars(pEnv, pPassword, password);

    return retval;
}

Здесь я хочу сохранить ссылку на pamh для всех случаев PamHandle.Как это сделать?

edit : ОК, у меня есть ответ на этот вопрос, и теперь есть часть очистки: я использую finalize(), чтобы вызвать собственный метод очистки, тогда super.finalize(); или есть функция JNI, которая запускается GC, которую я могу / должен реализовать?

Ответы [ 2 ]

3 голосов
/ 17 декабря 2011

Используйте long для хранения указателя на pam_handle_t.

на стороне Java это будет выглядеть как

long handle = Pam.create();
Pam.DoSomething(handle,arg1,arg2);

Конечно, вы можете инкапсулировать это внутри класса, чтобы вы моглиinterface.

PamHandle p = new PamHandle();
p.DoSomething(arg1,arg2);

C сторона это будет выглядеть так:

JNIEXPORT jlong JNICALL Java_org_Create(
    JNIEnv *pEnv)
{
    pam_handle_t *pamh = createNew pam_handle somehow
    jlong result = (jlong) pamh;
    return result;
}

JNIEXPORT jint JNICALL Java_org_Blah_Blah_blah(
    JNIEnv *pEnv, jlong handle, jstring arg1,jstring arg2)
{
    pam_handle_t *pamh = (pam_handle_t*)handle;
 // ... Do rest of stuff
}

Это позволит вам иметь один pam_handle_t на экземпляр.Кроме того, гораздо эффективнее каждый раз вручную передавать целое число, а не передавать объект, а затем обращаться к полю объекта.

РЕДАКТИРОВАТЬ

Кроме того,если вы беспокоитесь о том, что jlong ​​не может правильно удерживать указатель, jlong ​​гарантированно будет 64-битным.Таким образом, jlong ​​будет работать в этом случае до тех пор, пока мы не начнем получать 128-битные целые числа (очень далеко).

1 голос
/ 17 декабря 2011

Здесь есть два случая:
В настоящее время Ваш указатель является локальным для функции и не может использоваться за пределами функции.Обратите внимание, что если все ваши вновь созданные функции будут вызываться через функцию, которая будет вызываться через функцию, в которой вы в настоящее время объявили pamh, тогда вы можете просто продолжать передавать указатель в качестве параметров функции.

Однако, если ваш случай не такой, как упомянуто выше, вам нужно будет сделать pamh glbal, чтобы он оставался действительным на протяжении всей жизни программы, и затем вы можете использовать его в различных функциях.

Вы должны будете объявить,

pam_handle_t *pamh = NULL; 

как глобальное.

Обратите внимание, что если вы сделаете его глобальным, вы обеспечите синхронизацию доступа к нему, если ваша программа многопоточная.

...