将本机(C)指针保存到对象实例中 - 然后将其清理干净

时间:2011-12-17 13:00:39

标签: java c java-native-interface pam

对于我的一个项目,我想为Java实现一个完整的PAM实现(应用程序端和模块端)。

现在,我正在申请方面。我把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的引用。这是怎么做到的?

编辑:好的,我有答案,现在有清理部分:我是否使用finalize()调用本机清理方法,然后super.finalize();,或者是否存在由GC触发的JNI功能,我可以/必须实现?

2 个答案:

答案 0 :(得分:3)

使用long来存储指向pam_handle_t的指针。

Java端看起来像

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

当然你可以将它封装在一个类中,这样你就可以拥有接口了。

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 :(得分:1)

这里有两种情况:
目前,您的指针是函数的本地指针,并且不能在函数范围之外使用。请注意,如果所有新创建的函数都将通过一个函数调用,该函数将通过当前声明为pamh的函数调用,那么您可以继续将指针作为函数参数传递。

但是,如果你的情况不是如上所述,那么你必须使pamh glbal,以便它在程序的整个生命周期内保持有效,然后你可以在不同的功能中使用它。

你必须申报,

pam_handle_t *pamh = NULL; 

作为一个全球性的。

请注意,将其设置为全局意味着您确保在程序是多线程的情况下同步对它的访问。