blob: 2296577314ba19745c0a1cec64f526faef755e1d [file] [log] [blame]
/*
Copyright 2003 by Marc J. Rochkind. All rights reserved.
May be copied only for purposes and under conditions described
on the Web page www.basepath.com/aup/copyright.htm.
The Example Files are provided "as is," without any warranty;
without even the implied warranty of merchantability or fitness
for a particular purpose. The author and his publisher are not
responsible for any damages, direct or incidental, resulting
from the use or non-use of these Example Files.
The Example Files may contain defects, and some contain deliberate
coding mistakes that were included for educational reasons.
You are responsible for determining if and how the Example Files
are to be used.
*/
#include "defs.h"
#define __EXTENSIONS__
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "JtuxNetwork.h" // generated by javah
#include "jtux_util.h"
#include "JNI_macros.h"
static bool sockaddr_jtoc(JNIEnv *env, jobject sa, struct sockaddr *sa_c,
socklen_t *sa_len_c)
{
jclass cls_s_sockaddr_un = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_un");
jclass cls_s_sockaddr_in = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_in");
jclass cls_s_sockaddr_in6 = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_in6");
jclass cls_s_in_addr = (*env)->FindClass(env, "jtux/UNetwork$s_in_addr");
jclass cls_s_in6_addr = (*env)->FindClass(env, "jtux/UNetwork$s_in6_addr");
if (cls_s_sockaddr_un == NULL || cls_s_sockaddr_in == NULL ||
cls_s_sockaddr_in6 == NULL || cls_s_in_addr == NULL || cls_s_in6_addr == NULL)
return false;
if ((*env)->IsInstanceOf(env, sa, cls_s_sockaddr_un)) {
struct sockaddr_un *sp = (struct sockaddr_un *)sa_c;
int n;
if (!field_jtoc_int(env, cls_s_sockaddr_un, "sun_family", sa, &n))
return false;
sp->sun_family = n;
if (!field_jtoc_string(env, cls_s_sockaddr_un, "sun_path", sa, sp->sun_path, sizeof(sp->sun_path)))
return false;
if (sa_len_c != NULL)
*sa_len_c = sizeof(*sp);
}
else if ((*env)->IsInstanceOf(env, sa, cls_s_sockaddr_in)) {
struct sockaddr_in *sp = (struct sockaddr_in *)sa_c;
jobject addr;
int n;
if (!field_jtoc_int(env, cls_s_sockaddr_in, "sin_family", sa, &n))
return false;
sp->sin_family = n;
if (!field_jtoc_short(env, cls_s_sockaddr_in, "sin_port", sa, &sp->sin_port))
return false;
if (!field_jtoc_object(env, cls_s_sockaddr_in, "sin_addr", "Ljtux/UNetwork$s_in_addr;",
sa, &addr))
return false;
if (!field_jtoc_int(env, cls_s_in_addr, "s_addr", addr, &sp->sin_addr.s_addr))
return false;
if (sa_len_c != NULL)
*sa_len_c = sizeof(*sp);
}
else if ((*env)->IsInstanceOf(env, sa, cls_s_sockaddr_in6)) {
// Following compiled but not tested.
struct sockaddr_in6 *sp = (struct sockaddr_in6 *)sa_c;
jobject addr;
jbyteArray ba;
char *bytes;
int n;
if (!field_jtoc_int(env, cls_s_sockaddr_in6, "sin6_family", sa, &n))
return false;
sp->sin6_family = n;
if (!field_jtoc_short(env, cls_s_sockaddr_in6, "sin6_port", sa, &sp->sin6_port))
return false;
if (!field_jtoc_int(env, cls_s_sockaddr_in6, "sin6_flowinfo", sa, &sp->sin6_flowinfo))
return false;
if (!field_jtoc_object(env, cls_s_sockaddr_in6, "sin_addr", "Ljtux/UNetwork$s_in6_addr;",
sa, &addr))
return false;
if (!field_jtoc_bytearray(env, cls_s_in6_addr, "s6_addr", addr, (void **)&bytes,
&ba))
return false;
memcpy(sp->sin6_addr.s6_addr, bytes, 16);
field_jtoc_bytearray_release_nocopy(env, ba, bytes);
if (!field_jtoc_int(env, cls_s_sockaddr_in6, "sin6_scope_id", sa, &sp->sin6_scope_id))
return false;
if (sa_len_c != NULL)
*sa_len_c = sizeof(*sp);
}
else
setup_throw_errno(env, EINVAL);
return true;
}
/*
Creates new object if *sa is NULL going in.
*/
static bool sockaddr_ctoj(JNIEnv *env, jobject *sa, struct sockaddr *sa_c)
{
jclass cls_s_sockaddr_in = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_in");
jclass cls_s_sockaddr_in6 = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_in6");
jclass cls_s_sockaddr_un = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_un");
jclass cls_s_in_addr = (*env)->FindClass(env, "jtux/UNetwork$s_in_addr");
jclass cls_s_in6_addr = (*env)->FindClass(env, "jtux/UNetwork$s_in6_addr");
if (cls_s_sockaddr_in == NULL || cls_s_sockaddr_in6 == NULL ||
cls_s_in_addr == NULL || cls_s_in6_addr == NULL)
return false;
switch (sa_c->sa_family) {
case AF_INET: {
struct sockaddr_in *saddr = (struct sockaddr_in *)sa_c;
jobject addrobj;
jmethodID mid;
if (*sa == NULL) {
if ((mid = (*env)->GetMethodID(env, cls_s_sockaddr_in, "<init>", "()V")) == NULL)
return false;
if ((*sa = (*env)->NewObject(env, cls_s_sockaddr_in, mid)) == NULL)
return false;
}
if (!field_ctoj_int(env, cls_s_sockaddr_in, "sin_family", *sa, saddr->sin_family))
return false;
if (!field_ctoj_short(env, cls_s_sockaddr_in, "sin_port", *sa, saddr->sin_port))
return false;
if ((mid = (*env)->GetMethodID(env, cls_s_in_addr, "<init>", "()V")) == NULL)
return false;
if ((addrobj = (*env)->NewObject(env, cls_s_in_addr, mid)) == NULL)
return false;
if (!field_ctoj_int(env, cls_s_in_addr, "s_addr", addrobj, saddr->sin_addr.s_addr))
return false;
if (!field_ctoj_object(env, cls_s_sockaddr_in, "sin_addr", "Ljtux/UNetwork$s_in_addr;", *sa, addrobj))
return false;
}
break;
case AF_INET6: {
// Following compiled but not tested.
struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)sa_c;
jobject addrobj;
jmethodID mid;
jbyteArray ba;
jbyte *ba_c;
if (*sa == NULL) {
if ((mid = (*env)->GetMethodID(env, cls_s_sockaddr_in6, "<init>", "()V")) == NULL)
return false;
if ((*sa = (*env)->NewObject(env, cls_s_sockaddr_in6, mid)) == NULL)
return false;
}
if (!field_ctoj_int(env, cls_s_sockaddr_in6, "sin6_family", *sa, saddr->sin6_family))
return false;
if (!field_ctoj_short(env, cls_s_sockaddr_in6, "sin6_port", *sa, saddr->sin6_port))
return false;
if (!field_ctoj_int(env, cls_s_sockaddr_in6, "sin6_flowinfo", *sa, saddr->sin6_flowinfo))
return false;
if ((mid = (*env)->GetMethodID(env, cls_s_in6_addr, "<init>", "()V")) == NULL)
return false;
if ((addrobj = (*env)->NewObject(env, cls_s_in6_addr, mid)) == NULL)
return false;
// allocate a 16-byte array and put it into the s6_addr field
if ((ba = (*env)->NewByteArray(env, 16)) == NULL)
return false;
if ((ba_c = (*env)->GetByteArrayElements(env, ba, NULL)) == NULL)
return false;
memcpy(ba_c, saddr->sin6_addr.s6_addr, 16);
(*env)->ReleaseByteArrayElements(env, ba, ba_c, 0);
if (!field_ctoj_object(env, cls_s_sockaddr_in6, "sin6_addr", "Ljtux/UNetwork$s_in6_addr;",
*sa, addrobj))
return false;
// Following needs full 32-bit C int
if (!field_ctoj_int(env, cls_s_sockaddr_in6, "sin6_scope_id", *sa, saddr->sin6_scope_id))
return false;
}
break;
case AF_UNIX: {
struct sockaddr_un *saddr = (struct sockaddr_un *)sa_c;
jmethodID mid;
if (*sa == NULL) {
if ((mid = (*env)->GetMethodID(env, cls_s_sockaddr_un, "<init>", "()V")) == NULL)
return false;
if ((*sa = (*env)->NewObject(env, cls_s_sockaddr_un, mid)) == NULL)
return false;
}
if (!field_ctoj_int(env, cls_s_sockaddr_un, "sun_family", *sa, saddr->sun_family))
return false;
if (!field_ctoj_string(env, cls_s_sockaddr_un, "sun_path", *sa, saddr->sun_path))
return false;
}
break;
default:
return false; // ??? can't deal with it
}
return true;
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_accept(JNIEnv *env, jclass obj,
jint socket_fd, jobject sa, jobject sa_len)
{
int fd;
struct sockaddr_storage sa_c;
socklen_t sa_len_c;
if(sa==NULL)
{
JTHROW_neg1(fd = accept(socket_fd, NULL, 0))
}
else
{
JTHROW_neg1(fd = accept(socket_fd, (struct sockaddr *)&sa_c, &sa_len_c))
if (fd != -1) {
if (!sockaddr_ctoj(env, &sa, (struct sockaddr *)&sa_c))
return -1;
if (!set_IntHolder_int(env, sa_len, sa_len_c))
return -1;
}
}
return fd;
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_bind(JNIEnv *env, jclass obj,
jint socket_fd, jobject sa, jint sa_len)
{
struct sockaddr_storage sa_c;
socklen_t sa_len_c;
if (!sockaddr_jtoc(env, sa, (struct sockaddr *)&sa_c, &sa_len_c))
return;
JTHROW_neg1(bind(socket_fd, (struct sockaddr *)&sa_c, sa_len_c))
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_connect(JNIEnv *env, jclass obj,
jint socket_fd, jobject sa, jint sa_len)
{
struct sockaddr_storage sa_c;
socklen_t sa_len_c;
if (!sockaddr_jtoc(env, sa, (struct sockaddr *)&sa_c, &sa_len_c))
return;
JTHROW_neg1(connect(socket_fd, (struct sockaddr *)&sa_c, sa_len_c))
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_freeaddrinfo(JNIEnv *env, jclass obj,
jobject infop)
{
// no-op -- getaddrinfo has already freed the C linked list
}
JNIEXPORT jstring JNICALL Java_jtux_UNetwork_gai_1strerror(JNIEnv *env, jclass obj,
jint code)
{
JSTR_RETURN(gai_strerror(code));
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_getaddrinfo(JNIEnv *env, jclass obj,
jstring nodename, jstring servname, jobject hint, jobject infop)
{
const char *nodename_c, *servname_c;
struct addrinfo hint_buf, *hint_c = &hint_buf, *infop_c;
jclass cls_s_addrinfo = (*env)->FindClass(env, "jtux/UNetwork$s_addrinfo");
jclass cls_AddrInfoListHead = (*env)->FindClass(env, "jtux/UNetwork$AddrInfoListHead");
jclass cls_s_sockaddr_in = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_in");
jclass cls_s_sockaddr_in6 = (*env)->FindClass(env, "jtux/UNetwork$s_sockaddr_in6");
jclass cls_s_in_addr = (*env)->FindClass(env, "jtux/UNetwork$s_in_addr");
jclass cls_s_in6_addr = (*env)->FindClass(env, "jtux/UNetwork$s_in6_addr");
int r;
if (cls_s_addrinfo == NULL || cls_AddrInfoListHead == NULL ||
cls_s_sockaddr_in == NULL || cls_s_sockaddr_in6 == NULL ||
cls_s_in_addr == NULL || cls_s_in6_addr == NULL)
return;
if (hint == NULL)
hint_c = NULL;
else {
memset(hint_c, 0, sizeof(struct addrinfo));
if (!field_jtoc_int(env, cls_s_addrinfo, "ai_flags", hint, &hint_c->ai_flags))
return;
if (!field_jtoc_int(env, cls_s_addrinfo, "ai_family", hint, &hint_c->ai_family))
return;
if (!field_jtoc_int(env, cls_s_addrinfo, "ai_socktype", hint, &hint_c->ai_socktype))
return;
if (!field_jtoc_int(env, cls_s_addrinfo, "ai_protocol", hint, &hint_c->ai_protocol))
return;
}
nodename_c = (*env)->GetStringUTFChars(env, nodename, NULL);
servname_c = (*env)->GetStringUTFChars(env, servname, NULL);
JSTR_NULLTEST(nodename_c)
JSTR_NULLTEST(servname_c)
if ((r = getaddrinfo(nodename_c, servname_c, hint_c, &infop_c)) > 0)
setup_throw_errno_type(env, r, EC_EAI);
JSTR_REL(nodename_c, nodename)
JSTR_REL(servname_c, servname)
if (r == 0) {
struct addrinfo *p;
jobject prev_node = infop;
jobject node;
for (p = infop_c; p != NULL; p = p->ai_next, prev_node = node) {
jmethodID mid = (*env)->GetMethodID(env, cls_s_addrinfo, "<init>", "()V");
jclass cls;
jobject saobj = NULL;
if (mid == NULL)
break;
if ((node = (*env)->NewObject(env, cls_s_addrinfo, mid)) == NULL)
break;
if (p == infop_c)
cls = cls_AddrInfoListHead;
else
cls = cls_s_addrinfo;
if (!field_ctoj_object(env, cls, "ai_next", "Ljtux/UNetwork$s_addrinfo;",
prev_node, node))
break;
if (!field_ctoj_int(env, cls_s_addrinfo, "ai_flags", node, p->ai_flags))
break;
if (!field_ctoj_int(env, cls_s_addrinfo, "ai_family", node, p->ai_family))
break;
if (!field_ctoj_int(env, cls_s_addrinfo, "ai_socktype", node, p->ai_socktype))
break;
if (!field_ctoj_int(env, cls_s_addrinfo, "ai_protocol", node, p->ai_protocol))
break;
if (!field_ctoj_int(env, cls_s_addrinfo, "ai_addrlen", node, p->ai_addrlen))
break;
if (!sockaddr_ctoj(env, &saobj, p->ai_addr))
break;
if (!field_ctoj_object(env, cls_s_addrinfo, "ai_addr", "Ljtux/UNetwork$s_sockaddr;",
node, saobj))
break;
if (!field_ctoj_string(env, cls_s_addrinfo, "ai_canonname", node, p->ai_canonname))
break;
}
freeaddrinfo(infop_c);
}
}
JNIEXPORT jlong JNICALL Java_jtux_UNetwork_gethostid(JNIEnv *env, jclass obj)
{
return 0;
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_gethostname(JNIEnv *env, jclass obj,
jobject name)
{
long size = 1000;
char *buf;
#ifdef _SC_HOST_NAME_MAX
errno = 0;
if ((size = sysconf(_SC_HOST_NAME_MAX)) == -1) {
if (errno == 0)
size = 1000;
else {
(void)setup_throw_errno(env, errno);
return;
}
}
#endif
JTHROW_null(buf = malloc(size))
if (buf != NULL) {
JTHROW_neg1(gethostname(buf, size))
(void)string_buffer_set(env, name, buf);
free(buf);
}
}
/*
sa_len not used
*/
JNIEXPORT void JNICALL Java_jtux_UNetwork_getnameinfo(JNIEnv *env, jclass obj,
jobject sa, jint sa_len, jobject nodename, jobject servname, jint flags)
{
struct sockaddr_storage sa_c;
socklen_t sa_len_c;
char nodename_c[1000], servname_c[1000];
int r;
if (!sockaddr_jtoc(env, sa, (struct sockaddr *)&sa_c, &sa_len_c))
return;
if ((r = getnameinfo((struct sockaddr *)&sa_c, sa_len_c, nodename_c,
sizeof(nodename_c), servname_c, sizeof(servname_c), flags)) > 0)
setup_throw_errno_type(env, r, EC_EAI);
if (nodename != NULL)
if (!string_buffer_set(env, nodename, nodename_c))
return;
if (servname != NULL)
if (!string_buffer_set(env, servname, servname_c))
return;
}
// value_len may not be needed
/*
Burden is on Java caller to supply correct object for value.
*/
JNIEXPORT void JNICALL Java_jtux_UNetwork_getsockopt(JNIEnv *env, jclass obj,
jint socket_fd, jint level, jint option, jobject value, jobject value_len)
{
jclass cls_SockOptValue_int = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_int");
jclass cls_SockOptValue_boolean = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_boolean");
jclass cls_SockOptValue_s_linger = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_s_linger");
jclass cls_s_linger = (*env)->FindClass(env, "jtux/UNetwork$s_linger");
jclass cls_SockOptValue_s_timeval = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_s_timeval");
jclass cls_s_timeval = (*env)->FindClass(env, "jtux/UProcess$s_timeval");
union {
int value_int;
int value_boolean;
struct linger value_linger;
struct timeval value_timeval;
} all_in_one, *value_c = &all_in_one;
socklen_t value_len_c;
if (cls_SockOptValue_int == NULL || cls_SockOptValue_boolean == NULL ||
cls_SockOptValue_s_linger == NULL || cls_SockOptValue_s_timeval == NULL ||
cls_s_linger == NULL || cls_s_timeval == NULL)
return;
value_len_c = sizeof(*value_c);
JTHROW_neg1(getsockopt(socket_fd, level, option, value_c, &value_len_c))
if (!set_IntHolder_int(env, value_len, value_len_c))
return;
if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_int)) {
if (!field_ctoj_int(env, cls_SockOptValue_int, "value", value, value_c->value_int))
return;
}
else if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_boolean)) {
if (!field_ctoj_boolean(env, cls_SockOptValue_boolean, "value", value, value_c->value_int))
return;
}
else if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_s_linger)) {
jobject linger;
if (!field_jtoc_object(env, cls_SockOptValue_s_linger, "value", "Ljtux/UNetwork$s_linger;", value, &linger))
return;
if (!field_ctoj_int(env, cls_s_linger, "l_onoff", linger, value_c->value_linger.l_onoff))
return;
if (!field_ctoj_int(env, cls_s_linger, "l_linger", linger, value_c->value_linger.l_linger))
return;
}
else if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_s_timeval)) {
// timeval case compiled but not tested
jobject timeval;
if (!field_jtoc_object(env, cls_SockOptValue_s_timeval, "value", "Ljtux/UProcess$s_timeval;", value, &timeval))
return;
if (!field_ctoj_long(env, cls_s_timeval, "tv_sec", timeval, value_c->value_timeval.tv_sec))
return;
if (!field_ctoj_long(env, cls_s_timeval, "tv_usec", timeval, value_c->value_timeval.tv_usec))
return;
}
else {
(void)setup_throw_errno(env, EINVAL);
return;
}
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_htonl(JNIEnv *env, jclass obj,
jint hostnum)
{
return htonl(hostnum);
}
JNIEXPORT jshort JNICALL Java_jtux_UNetwork_htons(JNIEnv *env, jclass obj,
jshort hostnum)
{
return htons(hostnum);
}
JNIEXPORT jstring JNICALL Java_jtux_UNetwork_inet_1ntop__II(JNIEnv *env, jclass obj,
jint domain, jint src)
{
const char *s;
uint32_t ipv4 = src;
char dst[INET_ADDRSTRLEN];
JTHROW_null(s = inet_ntop(domain, &ipv4, dst, sizeof(dst)))
JSTR_RETURN(s);
}
JNIEXPORT jstring JNICALL Java_jtux_UNetwork_inet_1ntop__I_3B(JNIEnv *env, jclass obj,
jint domain, jbyteArray src)
{
return 0;
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_inet_1pton__ILjava_lang_String_2Ljtux_UUtil_00024IntHolder_2(JNIEnv *env, jclass obj,
jint domain, jstring src, jobject dst)
{
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_inet_1pton__ILjava_lang_String_2_3B(JNIEnv *env, jclass obj,
jint domain, jstring src, jbyteArray dst)
{
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_listen(JNIEnv *env, jclass obj,
jint socket_fd, jint backlog)
{
JTHROW_neg1(listen(socket_fd, backlog))
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_ntohl(JNIEnv *env, jclass obj,
jint netnum)
{
return ntohl(netnum);
}
JNIEXPORT jshort JNICALL Java_jtux_UNetwork_ntohs(JNIEnv *env, jclass obj,
jshort netnum)
{
return ntohs(netnum);
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_recv(JNIEnv *env, jclass obj,
jint socket_fd, jbyteArray buffer, jint length, jint flags)
{
void *buffer_c;
ssize_t nrcv;
if ((buffer_c = (*env)->GetByteArrayElements(env, buffer, NULL)) == NULL)
return -1;
JTHROW_neg1(nrcv = recv(socket_fd, buffer_c, length, flags))
(*env)->ReleaseByteArrayElements(env, buffer, buffer_c, 0);
return nrcv;
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_recvfrom(JNIEnv *env, jclass obj,
jint socket_fd, jbyteArray buffer, jint length, jint flags, jobject sa, jobject sa_len)
{
struct sockaddr_storage sa_c;
socklen_t sa_len_c = sizeof(sa_c);
void *buffer_c;
ssize_t nrcv;
if ((buffer_c = (*env)->GetByteArrayElements(env, buffer, NULL)) == NULL)
return -1;
JTHROW_neg1(nrcv = recvfrom(socket_fd, buffer_c, length, flags,
(struct sockaddr *)&sa_c, &sa_len_c))
(*env)->ReleaseByteArrayElements(env, buffer, buffer_c, 0);
if (nrcv != -1) {
if (!set_IntHolder_int(env, sa_len, sa_len_c))
return -1;
if (!sockaddr_ctoj(env, &sa, (struct sockaddr *)&sa_c))
return -1;
}
return nrcv;
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_recvmsg(JNIEnv *env, jclass obj,
jint socket_fd, jobject message, jint flags)
{
jclass cls_s_msghdr = (*env)->FindClass(env, "jtux/UNetwork$s_msghdr");
struct msghdr msg_c;
jobject msg_name, msg_control, msg_iov;
struct sockaddr_storage sa_c;
ssize_t nrcv;
jbyteArray *v_bytearray;
msg_c.msg_name = &sa_c;
if (!field_jtoc_object(env, cls_s_msghdr, "msg_iov", "[Ljtux/UFile$s_iovec;", message, &msg_iov))
return -1;
if (!field_jtoc_int(env, cls_s_msghdr, "msg_iovlen", message, &msg_c.msg_iovlen))
return -1;
if (!field_jtoc_object(env, cls_s_msghdr, "msg_control", "[B", message, &msg_control))
return -1;
if (!field_jtoc_int(env, cls_s_msghdr, "msg_controllen", message, &msg_c.msg_controllen))
return -1;
if (!field_jtoc_int(env, cls_s_msghdr, "msg_flags", message, &msg_c.msg_flags))
return -1;
if ((msg_c.msg_iov = iovec_jtoc(env, msg_iov, msg_c.msg_iovlen, &v_bytearray)) == NULL)
return -1;
if (msg_control == NULL)
msg_c.msg_control = NULL;
else if ((msg_c.msg_control = (*env)->GetByteArrayElements(env, msg_control, NULL)) == NULL) {
iovec_jtoc_release(env, msg_c.msg_iov, msg_c.msg_iovlen, v_bytearray);
return -1;
}
JTHROW_neg1(nrcv = recvmsg(socket_fd, &msg_c, flags))
iovec_jtoc_release(env, msg_c.msg_iov, msg_c.msg_iovlen, v_bytearray);
if (msg_control != NULL)
(*env)->ReleaseByteArrayElements(env, msg_control, msg_c.msg_control, JNI_ABORT);
if (!field_jtoc_object(env, cls_s_msghdr, "msg_name", "Ljtux/UNetwork$s_sockaddr;", message, &msg_name))
return -1;
if (msg_name != NULL)
if (!sockaddr_ctoj(env, &msg_name, (struct sockaddr *)&sa_c))
return -1;
return nrcv;
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_send(JNIEnv *env, jclass obj,
jint socket_fd, jbyteArray data, jint length, jint flags)
{
void *data_c;
ssize_t nsent;
if ((data_c = (*env)->GetByteArrayElements(env, data, NULL)) == NULL)
return -1;
JTHROW_neg1(nsent = send(socket_fd, data_c, length, flags))
(*env)->ReleaseByteArrayElements(env, data, data_c, JNI_ABORT);
return nsent;
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_sendmsg(JNIEnv *env, jclass obj,
jint socket_fd, jobject message, jint flags)
{
jclass cls_s_msghdr = (*env)->FindClass(env, "jtux/UNetwork$s_msghdr");
struct msghdr msg_c;
jobject msg_name, msg_control, msg_iov;
struct sockaddr_storage sa_c;
ssize_t nsent;
jbyteArray *v_bytearray;
if (!field_jtoc_object(env, cls_s_msghdr, "msg_name", "Ljtux/UNetwork$s_sockaddr;", message, &msg_name))
return -1;
if (!sockaddr_jtoc(env, msg_name, (struct sockaddr *)&sa_c, &msg_c.msg_namelen))
return -1;
msg_c.msg_name = &sa_c;
if (!field_jtoc_object(env, cls_s_msghdr, "msg_iov", "[Ljtux/UFile$s_iovec;", message, &msg_iov))
return -1;
if (!field_jtoc_int(env, cls_s_msghdr, "msg_iovlen", message, &msg_c.msg_iovlen))
return -1;
if (!field_jtoc_object(env, cls_s_msghdr, "msg_control", "[B", message, &msg_control))
return -1;
if (!field_jtoc_int(env, cls_s_msghdr, "msg_controllen", message, &msg_c.msg_controllen))
return -1;
if (!field_jtoc_int(env, cls_s_msghdr, "msg_flags", message, &msg_c.msg_flags))
return -1;
if ((msg_c.msg_iov = iovec_jtoc(env, msg_iov, msg_c.msg_iovlen, &v_bytearray)) == NULL)
return -1;
if (msg_control == NULL)
msg_c.msg_control = NULL;
else if ((msg_c.msg_control = (*env)->GetByteArrayElements(env, msg_control, NULL)) == NULL) {
iovec_jtoc_release_nocopy(env, msg_c.msg_iov, msg_c.msg_iovlen, v_bytearray);
return -1;
}
JTHROW_neg1(nsent = sendmsg(socket_fd, &msg_c, flags))
iovec_jtoc_release_nocopy(env, msg_c.msg_iov, msg_c.msg_iovlen, v_bytearray);
if (msg_control != NULL)
(*env)->ReleaseByteArrayElements(env, msg_control, msg_c.msg_control, JNI_ABORT);
return nsent;
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_sendto(JNIEnv *env, jclass obj,
jint socket_fd, jbyteArray message, jint length, jint flags, jobject sa, jint sa_len)
{
struct sockaddr_storage sa_c;
socklen_t sa_len_c;
void *message_c;
ssize_t nsent;
if (!sockaddr_jtoc(env, sa, (struct sockaddr *)&sa_c, &sa_len_c))
return -1;
if ((message_c = (*env)->GetByteArrayElements(env, message, NULL)) == NULL)
return -1;
JTHROW_neg1(nsent = sendto(socket_fd, message_c, length, flags,
(struct sockaddr *)&sa_c, sa_len_c))
(*env)->ReleaseByteArrayElements(env, message, message_c, JNI_ABORT);
return nsent;
}
JNIEXPORT void JNICALL Java_jtux_UNetwork_setsockopt(JNIEnv *env, jclass obj,
jint socket_fd, jint level, jint option, jobject value, jint value_len)
{
jclass cls_SockOptValue_int = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_int");
jclass cls_SockOptValue_boolean = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_boolean");
jclass cls_SockOptValue_s_linger = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_s_linger");
jclass cls_s_linger = (*env)->FindClass(env, "jtux/UNetwork$s_linger");
jclass cls_SockOptValue_s_timeval = (*env)->FindClass(env, "jtux/UNetwork$SockOptValue_s_timeval");
jclass cls_s_timeval = (*env)->FindClass(env, "jtux/UProcess$s_timeval");
void *value_c;
int value_int;
struct linger value_linger;
struct timeval value_timeval;
if (cls_SockOptValue_int == NULL || cls_SockOptValue_boolean == NULL ||
cls_SockOptValue_s_linger == NULL || cls_SockOptValue_s_timeval == NULL ||
cls_s_linger == NULL || cls_s_timeval == NULL)
return;
if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_int)) {
if (!field_jtoc_int(env, cls_SockOptValue_int, "value", value, &value_int))
return;
value_c = &value_int;
value_len = sizeof(value_int);
}
else if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_boolean)) {
if (!field_jtoc_boolean(env, cls_SockOptValue_boolean, "value", value, &value_int))
return;
value_c = &value_int;
value_len = sizeof(value_int);
}
else if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_s_linger)) {
jobject linger;
if (!field_jtoc_object(env, cls_SockOptValue_s_linger, "value", "Ljtux/UNetwork$s_linger;", value, &linger))
return;
if (!field_jtoc_int(env, cls_s_linger, "l_onoff", linger, &value_linger.l_onoff))
return;
if (!field_jtoc_int(env, cls_s_linger, "l_linger", linger, &value_linger.l_linger))
return;
value_c = &value_linger;
value_len = sizeof(value_linger);
}
else if ((*env)->IsInstanceOf(env, value, cls_SockOptValue_s_timeval)) {
// timeval case compiled but not tested
jobject timeval;
long n;
if (!field_jtoc_object(env, cls_SockOptValue_s_timeval, "value", "Ljtux/UProcess$s_timeval;", value, &timeval))
return;
if (!field_jtoc_long(env, cls_s_timeval, "tv_sec", timeval, &n))
return;
value_timeval.tv_sec = (time_t)n;
if (!field_jtoc_long(env, cls_s_timeval, "tv_usec", timeval, &n))
return;
value_timeval.tv_usec = (suseconds_t)n;
value_c = &value_timeval;
value_len = sizeof(value_timeval);
}
else {
(void)setup_throw_errno(env, EINVAL);
return;
}
JTHROW_neg1(setsockopt(socket_fd, level, option, value_c, value_len))
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_sockatmark(JNIEnv *env, jclass obj,
jint socket_fd)
{
#if _XOPEN_VERSION >= 600
// Following compiled but not tested
int r;
JTHROW_neg1(r = sockatmark(socket_fd))
return r;
#else
(void)setup_throw_errno(env, ENOSYS);
return -1;
#endif
}
JNIEXPORT jint JNICALL Java_jtux_UNetwork_socket(JNIEnv *env, jclass obj,
jint domain, jint type, jint protocol)
{
int fd;
JTHROW_neg1(fd = socket(domain, type, protocol));
return fd;
}