2011-11-15 12 views
1

SWIG経由でJavaを使用して呼び出したいC関数がありますが、どのようにsockaddr_in C構造体を処理するのかは分かりません。誰でも私がsockaddr_inをどのように扱うことができるかについての例がありますか?SWIGを使用してSockaddr_in C構造体をJavaにマップする方法

+0

既存の 'java.net.InetAddress'クラスと互換性を持たせたいのですか、' sockaddr_in'を使用可能なインタフェースでラップするだけですか? – Flexo

+0

私は使用可能なインターフェイスでそれをラップしたいと思っています... – c12

答えて

2

それは今少し古い見えますが、swig.orgsockaddr_inを包む上の記事は、実際にあります。

基本的には、あなたのために新しいsockaddr_inを作成する関数を作成し、Javaで簡単に渡すことができるものとして記入する必要がある値の引数を取っていました。

%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); 

しかしSWIGでこれをラップのよりよい方法はあり、私たちは「はるかに感じるであろう、代わりにjava.net.InetSocketAddressを使用するタイプマップを書くことができます。これは、リンク先の記事のバージョンをトリミングし、少し更新ですインタフェースのJava側の「ナチュラル:

%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. 私たちはあまりにも適切にAF_INET6をサポートするべきである私は
  2. 右ここでバイト順序を持って100%わからない - 私たちは見て与えられたInetSocketAddressを検査する必要があるだろうそのサブクラスは型マップ自体にあります。
  3. タイプマップはありません。outこれは基本的に逆の手順ですが、JNIコードは新しいJavaオブジェクトを作成します。
  4. アサーションはかなり醜いです。

は完全にするためにも、何のJNIを含まないどの本を、ラップが、Javaの少しを書くの第3の可能な方法があります。最初の例のようにSWIGでstruct sockaddrをラップした後、sockaddrを使用してラップされた関数を返すと、java.net.InetSocketAddressオブジェクトが返され、2つの間で変換するコードが提供されます。私は、 "out"タイプマップ、すなわち関数から戻るための例を挙げます。

は考える:

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))。タイプマップでも同様のことができます。これはAF_INET6のアドレスを正しく処理しません - IPv6アドレスにはInetAddress.getByAddress()と同等のものがありません。そのため、おそらくアサート/例外が存在するはずです。

+0

私はこれをより良い方法でやろうとします。これのために – Flexo

+0

ありがとうございます。 – c12

+0

@ c12私は、より良い方法を考えています。肉付けの時間を見つけようとします。 – Flexo

-1

java.net.InetSocketAddressを使用します。

+0

それは本当にswigラッピングの問題に対処していません。 – 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; 
}; 
関連する問題