2011-11-15 2 views
1

SWIG를 통해 Java를 사용하여 호출하고자하는 C 함수가 있지만 sockaddr_in C 구조를 처리하는 방법이 확실하지 않습니다. 누구나 내가 sockaddr_in을 어떻게 처리 할 수 ​​있는지에 대한 예제가 있습니까?Sockaddr_in C 구조를 SWIG를 사용하여 Java로 매핑

+0

기존의'java.net.InetAddress' 클래스와 호환 가능하게 만드시겠습니까, 아니면'sockaddr_in'을 사용 가능한 인터페이스로 감싸 주시겠습니까? – Flexo

+0

사용 가능한 인터페이스로 포장하고 싶습니다 ... – c12

답변

2

지금 약간 오래된 보이지만 swig.orgsockaddr_in 포장에 관한 기사가 사실이있다.

기본적으로 Java에서 전달하기 쉬운 것으로 채워야하는 값에 대한 인수를 취하여 새로운 sockaddr_in을 만드는 함수를 작성했습니다. 이 링크 된 문서의 약간 업데이트, 손질 버전입니다 : 우리가 느낄 수있는 대신 java.net.InetSocketAddress을 사용하는 타입 맵을 작성할 수 있습니다

%module sock   // Name of our module 
%{ 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 

/* Set some values in the sockaddr_in structure */ 
struct sockaddr *new_sockaddr_in(short family, unsigned long hostid, int port) { 
     struct sockaddr_in *addr; 
     addr = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in)); 
     bzero((char *) addr, sizeof(struct sockaddr_in)); 
     addr->sin_family = family; 
     addr->sin_addr.s_addr = hostid; 
     addr->sin_port = htons(port); 
     return (struct sockaddr *) addr; 
} 
%} 

// Add these constants 
enum {AF_UNIX, AF_INET, SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, 
     IPPROTO_UDP, IPPROTO_TCP, INADDR_ANY}; 

#define SIZEOF_SOCKADDR sizeof(struct sockaddr) 

// Wrap these functions 
struct sockaddr *new_sockaddr_in(short family, unsigned long, int port); 

하지만 꿀꺽 꿀꺽로이 포장의 더 좋은 방법이있다 "훨씬 더 인터페이스의 자바 측 "자연 :

%typemap(jni) sockaddr_in *ADDR "jobject" 
%typemap(jtype) sockaddr_in *ADDR "java.net.InetSocketAddress" 
%typemap(jstype) sockaddr_in *ADDR "java.net.InetSocketAddress" 

%typemap(in) (sockaddr_in *ADDR) { 
    $1 = new sockaddr_in; 
    $1->sin_family = AF_INET; 
    jclass inetsockaddr = jenv->FindClass("java/net/InetSocketAddress"); 
    assert(inetsockaddr); 
    // TODO: check return 
    jmethodID pmid,addrmid,ipbytemid; 
    pmid = jenv->GetMethodID(inetsockaddr, "getPort", "()I"); 
    assert(pmid); 
    jint port = jenv->CallIntMethod($input, pmid); 
    $1->sin_port = htons(port); 
    jclass inetaddr = jenv->FindClass("java/net/InetAddress"); 
    assert(inetaddr); 
    addrmid = jenv->GetMethodID(inetsockaddr, "getAddress", "()Ljava/net/InetAddress;"); 
    assert(addrmid); 
    jobject addrobj = jenv->CallObjectMethod($input, addrmid); 
    assert(addrobj); 
    ipbytemid = jenv->GetMethodID(inetaddr, "getAddress", "()[B"); 
    assert(ipbytemid); 
    jbyteArray barr = static_cast<jbyteArray>(jenv->CallObjectMethod(addrobj, ipbytemid)); 
    assert(barr); 
    jbyte *bytes = jenv->GetByteArrayElements(barr, 0); 
    assert(bytes); 
    memcpy(&$1->sin_addr.s_addr, bytes, 4); 
    $1->sin_addr.s_addr = htonl($1->sin_addr.s_addr); 
    jenv->ReleaseByteArrayElements(barr, bytes, JNI_ABORT); // No changes copied back 
} 

%typemap(freearg) (sockaddr_in *ADDR) { 
    delete $1; 
} 

%typemap(javain) sockaddr_in *ADDR "$javainput" 

기본적으로이 java.net.InetSocketAddressgetAddress()getPort() 방법을 호출하고 호출에 대한 struct sockaddr_in를 만드는 결과를 사용합니다.

주 :

  1. 내가 여기 바이트 순서를 가지고 있는지 100 % 아니에요
  2. 우리는 제대로 너무 AF_INET6를 지원한다고
  3. - 우리가 볼 수있는 주어진 InetSocketAddress을 검사해야하는 것 어떤 하위 클래스는 typemap 자체에있다.
  4. 입력란에 out이 없습니다. 이것은 기본적으로 역순입니다. JNI 코드는 새로운 Java 객체를 생성합니다.
  5. 어설 션은 꽤 추합니다.

완성도를 들어도 더 JNI를 포함하지 않는이, 포장,하지만 자바의 조금 쓰기의 세 번째 가능한 방법이있다. 우리가하는 일은 SWIG가 첫 번째 예제에서와 같이 struct sockaddr을 랩핑 한 다음 sockaddr을 사용하는 랩핑 된 함수를 가지고 있고 java.net.InetSocketAddress 오브젝트를 여전히 반환하고 둘 사이의 변환을위한 코드를 제공합니다. "out"typemap, 즉 함수에서 반환하는 예제를 보여 드리겠습니다.

sockaddr_in *make_stuff(); 

우리가 그것을 포장 할 수 있습니다 :

이 주어

%typemap(jstype) sockaddr_in *make_stuff "java.net.InetSocketAddress" 
%typemap(javaout) sockaddr_in *make_stuff { 
    long cPtr = $jnicall; 
    sockaddr_in s = new sockaddr_in(cPtr, true); 
    byte[] bytes = new byte[4]; 
    for (int i = 0; i < 4; ++i) { 
    bytes[i] = (byte)s.getAddr(i); 
    } 
    java.net.InetAddress addr = null; 
    try { 
    addr = java.net.InetAddress.getByAddress(bytes); 
    } 
    catch (java.net.UnknownHostException e) { 
    return null; 
    } 
    return new java.net.InetSocketAddress(addr, s.getPort()); 
} 

%immutable; 
struct sockaddr_in{ 
    %rename(family) sin_family; 
    short sin_family; 
    %extend { 
    unsigned short getPort() const { 
     return ntohs($self->sin_port); 
    } 
    char getAddr(int byte) const { 
     const char *ptr = reinterpret_cast<const char*>(&$self->sin_addr.s_addr); 
     return ptr[byte]; 
    } 
    } 
}; 
%mutable; 

void do_stuff(sockaddr_in *ADDR); 

우리는 지정한 직접 sockaddr_in을 포장하는 방법뿐만 아니라 더 할 함수 자체의 반환을 지시 적절한 Java 유형 (%typemap(jstype))을 사용하고 변환을 수행하는 소량의 Java를 제공합니다 (%typemap(javaout)). 우리는 typemap에서도 비슷하게 할 수 있습니다. 이것은 AF_INET6 주소를 제대로 처리하지 못합니다 - IPv6 주소에 대해 InetAddress.getByAddress()과 동등한 항목을 찾을 수 없으므로이 경우 어설 션/예외가 있어야합니다.

+0

나는 이것을 시도하고 더 좋은 방법을 시도 할 것이다. 이것에 대해 – Flexo

+0

감사합니다. – c12

+0

@ c12 나는 더 나은 방법에 대한 아이디어를 가지고있다. 나는 육식을 입을 시간을 찾는다. – Flexo

-1

java.net.InetSocketAddress를 사용하십시오.

+0

그건 포장 문제를 해결하는 데 정말로 도움이되지 않습니다. – Flexo

1

나는 더 좋은 대답이있을 것이라고 확신합니다. 나는 그것을보기를 고대합니다. 그러나 이것은 처음에는 효과가있는 것으로 보인다. 당신의 module.i에서

:

%include "stdint.i" 

%{ 
#include <arpa/inet.h> 
%} 

struct in_addr { 
    uint32_t s_addr; 
}; 

struct sockaddr_in { 
    uint16_t sin_port; 
    struct in_addr sin_addr; 
}; 
관련 문제