Keeping a native (C) pointer into an object instance — and cleaning it up afterwards

For one of my projects, I want to implement a complete PAM implementation for Java (application side and module side as well).

Right now, I'm on the application side. I took jpam as a base but I stumble upon a problem, and after some hours of searching around I still cannot find the solution to my problem :/

This is the current code:

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;
}

What I want here is keep a reference to pamh for all instances of PamHandle. How is this done?

edit: OK, I have the answer to this, and now there's the cleanup part: do I use finalize() to call a native cleanup method then super.finalize();, or is there a JNI function which is triggered by the GC which I can/must implement?

Answers


Use a long to store a pointer to pam_handle_t.

Java-side it would look like

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

Of course you could encapsulate this inside a class, so you could have the interface.

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

C side it would look like this:

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
}

This would allow you to have one pam_handle_t per instance. It is also alot more performant to manually pass the integer each time, rather than passing an object, and then having to access the object's field.

EDIT

Also, if you are worried about the jlong not being able to hold a pointer correctly, a jlong is guaranteed to be 64-bit. So, a jlong will work for this case all the way until we start getting 128-bit integers( a long long way away).


There are two cases here: Currently, Your pointer is local to the function and it cannot be used beyond the scope of the function. Note that if all your newly created functions will be called through a function which will be called through the function in which you currently declared pamh then you can just keep on passing the pointer as function parameters.

However,If your case is not as mentioned above then you will have to make pamh glbal so that it remains valid throughout the life of the program and then you can use it accross different functions.

You will have to declare,

pam_handle_t *pamh = NULL; 

as a global.

Note that making it global would mean you ensure access to it is synchronized in case your program is multithreaded.


Need Your Help

how to display different codes/tags to mobile devices?

jquery wordpress mobile

I am using wordpress responsive theme and I have a long content on the main page.

Learning how to use UML

c++ compiler-construction uml

I just started C++ recently and now I am learning the concept of UML. Would UML be included in any C++ compilers or it should be run in a different software? What tools do I need to create an UML

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.