На самом деле есть статья об упаковке sockaddr_in
на swig.org , хотя сейчас она выглядит немного старой.
По сути, они написали функцию, которая создает новый 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"
В основном это вызывает getAddress()
и getPort()
методы java.net.InetSocketAddress
и использует результат длясоздайте struct sockaddr_in
для вызова.
Примечания:
- Я не уверен на 100%, у меня есть порядок байтов прямо здесь
- Мы должныдля правильной поддержки AF_INET6 - нам нужно проверить заданный
InetSocketAddress
, чтобы увидеть, какой подкласс находится в самой карте типов. - Там нет
out
карты типов.Это в основном обратная процедура, код JNI создаст для нас новые объекты Java. - Утверждения довольно уродливы.
Для полноты есть и третий возможный способобернуть это, что не требует JNI, но немного написания на Java.Мы делаем SWIG-обертку struct sockaddr
, как в первом примере, но затем имеем обернутые функции, которые используют sockaddr
, возвращают объект java.net.InetSocketAddress
и предоставляют некоторый код для преобразования между ними.Я приведу пример с типовой картой «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)
).).Мы могли бы сделать то же самое для in typemap тоже.Это не обрабатывает AF_INET6
адреса должным образом - я не могу найти эквивалент InetAddress.getByAddress()
для адресов IPv6, поэтому, вероятно, должно быть утверждение / исключение для этого случая.