2011-12-17 3 views
0

내 프로젝트 중 하나는 자바 (애플리케이션 측 및 모듈 측)에 대한 완벽한 PAM 구현을 구현하고자한다.객체 인스턴스에 네이티브 (C) 포인터 유지 - 이후에 정리하기

지금 당장은 응용 프로그램을 사용하고 있습니다. 나는 도심 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; 
} 

를 내가 여기에 PamHandle의 모든 인스턴스에 대해 pamh에 대한 참조를 유지하고 싶습니다. 어떻게 이뤄지나요?

편집 : OK,이 답을 가지고 있고, 지금이 정리 부분이다 : 다음 super.finalize();을 기본 정리 메서드를 호출 finalize()을 사용합니까, 또는 GC에 의해 트리거되는 JNI 기능이있는 나는 구현할 수 있습니까?

+1

원하는 것이 명확하지 않습니다. Java 오브젝트에 C 포인터를 보관하려면 일반적으로이를 'long'에 지정하십시오. –

+0

@HotLicks 나는'PamHandle'의 각 인스턴스가 처분으로서 유일한'pamh'를 갖도록하고 싶습니다. 만약 내가 @Als를 올바르게 이해한다면, 나는 그 파일의 범위를 변경할 수 있으며, 각 인스턴스는 자신의 것을 가질 것이다. ... – fge

+1

@fge GC는 그 포인터를 안정적으로 정리할 수 없다. Java에서이 작업을 수행하는 한 가지 일반적인 방법은 [Closable] (http://docs.oracle.com/javase/1.5.0/docs/api/java/io/Closeable.html)에서 파생시키는 것입니다. 그런 다음 파이널 라이저에서 당신은 가까이에 전화를 걸지 만 단지 들어오지 못하게합니다. – Lalaland

답변

3

pam_handle_t에 대한 포인터를 저장하려면 long을 사용하십시오. 당신이 인터페이스를 가질 수 있도록 물론

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 비트 정수를 얻을 때까지이 경우에 대해 계속 작동 할 것입니다 (긴 먼 길).

+0

대단히 감사합니다! 이제 GC를 트리거하여 해당 포인터를 정리하는 방법에 대해 다른 질문을해야합니다 ... – fge

+0

jlong에 대해 알고 있지만 어쨌든 고맙습니다;) – fge

+0

실제로 IBM System/38은 80 비트 포인터를 사용했습니다. –

1

여기에는 두 가지 경우가 있습니다.
현재 포인터는 기능에 국한되어 있으며 기능 범위를 벗어나서는 사용할 수 없습니다. 새로 생성 된 모든 함수가 현재 pamh으로 선언 된 함수를 통해 호출되는 함수를 통해 호출되는 경우 포인터를 함수 매개 변수로 계속 전달할 수 있습니다.

그러나 귀하의 케이스가 위에서 언급 한 것과 같지 않은 경우 pamh 글램을 작성해야 프로그램의 전체 수명 동안 유효하며 다른 기능을 사용할 수 있습니다. 당신은 선언해야합니다

, 글로벌로

pam_handle_t *pamh = NULL; 

.

전역으로 설정한다는 것은 프로그램이 다중 스레드 인 경우에 액세스가 동기화된다는 것을 의미합니다.

+0

좋아, C에서 변수 범위 지정에 대해 알고 ...하지만 JNI별로. 인스턴스화 된 각 객체에 대해 새로운'pamh '가 생성된다는 것을 의미합니까? – fge

+0

@ fge : 아니요, 모든 객체에 대해 새로운 'pamh'가 만들어지지 않았다면 그 목적을 이길 수 없었을 것입니다. 글로벌을 사용한다면 그 전역에서 동일한 'pamh'가 생겨납니다. 프로 그마. –

+0

왜 이것을 downvoted입니까? –