Environment:
PC sys:windows xp
jdk:1.6
ndk:android-ndk-r9b
compile env:MinGW
Descrpiton:
I'm developing a sip endpoint app, which is based on the opensource sip stack "doubango", in Android device. The socket functions are called using NDK but not directly JAVA. When normally use, it's OK. Then clean the device's memory using some software, or stop Service manully, and make it exit abnormally. Seems that it stops without call function close(socket). Next time when I use, it will throw error calling socket function :sendto(),the errno=1 which means "operation not permitted".
I've added "uses-permission android:name="android.permission.INTERNET""
Does anyone can give me a hand?
PS:I test in devices without ROOT permission, and this issue will happen. But I test a device with ROOT permission, it doesn't happen. Does it matter?
Job Is Done. There are sth mistakes i made in the Java layer. Some parameters i set in Sip stack are wrong.
Here follows the code segment:
int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size)
{
tsk_size_t sent = 0;
int ret = -1;
if(fd == TNET_INVALID_FD){
TSK_DEBUG_ERROR("Using invalid FD to send data.");
goto bail;
}
if(!buf || !size){
TSK_DEBUG_ERROR("Using invalid BUFFER.");
ret = -2;
goto bail;
}
while(sent < size){
int try_guard = 10;
#if TNET_UNDER_WINDOWS
WSABUF wsaBuffer;
DWORD numberOfBytesSent = 0;
wsaBuffer.buf = ((CHAR*)buf) + sent;
wsaBuffer.len = (size - sent);
try_again:
ret = WSASendTo(fd, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0); // returns zero if succeed
if(ret == 0){
ret = numberOfBytesSent;
}
#else
try_again:
ret = sendto(fd, (((const uint8_t*)buf)+sent), (size-sent), 0, to, tnet_get_sockaddr_size(to)); // returns number of sent bytes if succeed
#endif
if(ret <= 0){
if(tnet_geterrno() == TNET_ERROR_WOULDBLOCK){
TSK_DEBUG_INFO("SendUdp() - WouldBlock. Retrying...");
if(try_guard--){
tsk_thread_sleep(10);
goto try_again;
}
}
else{
***/* Just throw error here*/***
TSK_DEBUG_INFO("errno: %d",tnet_geterrno());
TNET_PRINT_LAST_ERROR("sendto() failed");
}
goto bail;
}
else{
sent += ret;
}
}
bail:
return (size == sent) ? sent : ret;
}
#define tnet_soccket(family, type, protocol) socket((family), (type), (protocol))
tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_,tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)
{
tnet_socket_t *sock;
if((sock = tsk_object_new(tnet_socket_def_t))){
int status;
tsk_istr_t port;
struct addrinfo *result = tsk_null;
struct addrinfo *ptr = tsk_null;
struct addrinfo hints;
tnet_host_t local_hostname;
sock->port = port_;
tsk_itoa(sock->port, &port);
sock->type = type;
memset(local_hostname, 0, sizeof(local_hostname));
/* Get the local host name */
if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host));
}
else{
if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
memcpy(local_hostname, "::", 2);
}
else{
memcpy(local_hostname, "0.0.0.0", 7);
}
}
TSK_DEBUG_INFO("local_hostname: %s",local_hostname);
/* hints address info structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE
#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
| AI_ADDRCONFIG
#endif
;
/* Performs getaddrinfo */
if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){
TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]",
hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
goto bail;
}
/* Find our address. */
for(ptr = result; ptr; ptr = ptr->ai_next){
sock->fd = tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
continue;
}
/* To avoid "Address already in use" error
* Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS.
*/
//
if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
TSK_DEBUG_INFO("Socket Type: Stream");
if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) {
// do not break...continue
}
}
if(bindsocket){
/* Bind the socket */
if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){
TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port);
tnet_socket_close(sock);
continue;
}
/* Get local IP string. */
if((status = tnet_get_ip_n_port(sock->fd , tsk_true/*local*/, &sock->ip, &sock->port))) /* % */
//if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
{
TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
tnet_socket_close(sock);
continue;
}
}
/* sets the real socket type (if ipv46) */
if(ptr->ai_family == AF_INET6) {
TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
}
else{
TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
}
break;
}
/* Check socket validity. */
if(!TNET_SOCKET_IS_VALID(sock)) {
TNET_PRINT_LAST_ERROR("Invalid socket.");
goto bail;
}
#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
/* disable SIGPIPE signal */
{
int yes = 1;
if(setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed.");
}
}
#endif /* TNET_UNDER_IPHONE */
/* Sets the socket to nonblocking mode */
if(nonblocking){
if((status = tnet_sockfd_set_nonblocking(sock->fd))){
goto bail;
}
}
bail:
/* Free addrinfo */
tnet_freeaddrinfo(result);
/* Close socket if failed. */
if(status){
if(TNET_SOCKET_IS_VALID(sock)){
tnet_socket_close(sock);
}
return tsk_null;
}
}
return sock;
}
int tnet_sockfd_reuseaddr(tnet_fd_t fd, int reuseAddr)
{
if (fd != TNET_INVALID_FD) {
int ret;
#if defined(SOLARIS)
static const char yes = '1';
static const char no = '0';
#else
static const int yes = 1;
static const int no = 0;
#endif
if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR, fd=%d) have failed", fd);
return ret;
}
// #if defined(SO_REUSEPORT)
if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEPORT, fd=%d) have failed", fd);
return ret;
}
// #endif
return 0;
}
return -1;
}
#define tnet_sockfd_set_nonblocking(fd) tnet_sockfd_set_mode(fd, 1)
int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking)
{
if(fd != TNET_INVALID_FD)
{
#if TNET_UNDER_WINDOWS
ULONG mode = nonBlocking;
if(ioctlsocket(fd, FIONBIO, &mode))
//if(WSAIoctl(fd, FIONBIO, &nonblocking, sizeof(nonblocking), NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
{
TNET_PRINT_LAST_ERROR("ioctlsocket(FIONBIO) have failed.");
return -1;
}
#else
int flags;
if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed.");
return -1;
}
if(fcntl(fd, F_SETFL, flags | (nonBlocking ? O_NONBLOCK : ~O_NONBLOCK)) < 0){
TNET_PRINT_LAST_ERROR("fcntl(O_NONBLOCK/O_NONBLOCK) have failed.");
return -1;
}
#endif
// int on = 1;
// ioctl(fd, FIONBIO, (char *)&on);
}
return 0;
}
Related
I have an idea and it's kind of complicated and you must be familiar with assembly and multithreading to understand why I want to do this.
Did you ever notice that the cancel button never does anything when the program you are running is in a hot loop? But if you put an if statement in the hot loop you slow it down drastically.
In the Linux kernel, processes are scheduled by a timer onto the CPU by an interrupt when the timeslice has expired. See the schedule method in kernel/sched/core.c
Now in user space in Java and C programs, you have a thread in a hot loop unless you put an if statement inside the hot loop to check an aborted flag you cannot interrupt the hot loop from user space.
Only the kernel can preempt a thread.
But I have an idea on how we can preempt a thread in C programming from a userspace.
We can disassemble a function address to a RET to get its assembly. We can therefore identify the conditional jumps of the loop. We can introduce a go-to statement of __sched_yield() after the hot loop we can identify where in memory the relative address of the Sched yield from the disassembly.
From this, we can virtually interrupt a user thread from user space. Shall need to madvise/memprotect the executable code to update the conditional jump statement to jump to the goto statement.
What do you think? How easy is this?
How to learn the size of a function
How to disassemble a function with libopcodes
How to update memory of functions
In Java, C and Rust you can preempt a thread in a hot loop by directly changing the looped variable to go beyond the loop invariant. You can do this from any thread.
You can create cancellable APIs with this approach, your cancel token can represent all the loops indexes that the code is in. So you can create profoundly responsive code. Even if you are deep in encryption or compression or uploading data. As long as you're not in a syscall.
I also pasted a C version of this sourcecode below the Java version. The Rust version is below the C version
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Scheduler {
public static class KernelThread extends Thread {
public Map<LightWeightThread, Boolean> scheduled = new HashMap<>();
public void preempt() {
for (LightWeightThread thread : scheduled.keySet()) {
scheduled.put(thread, false);
for (int loop = 0 ; loop < thread.getLoops(); loop++) {
thread.preempt(loop);
}
}
}
public void addLightWeightThread(LightWeightThread thread) {
scheduled.put(thread, false);
}
public boolean isScheduled(LightWeightThread lightWeightThread) {
return scheduled.get(lightWeightThread);
}
public void run() {
while (true) {
LightWeightThread previous = null;
for (LightWeightThread thread : scheduled.keySet()) {
scheduled.put(thread, false);
}
for (LightWeightThread thread : scheduled.keySet()) {
if (previous != null) {
scheduled.put(previous, false);
}
scheduled.put(thread, true);
thread.run();
previous = thread;
}
}
}
}
public interface Preemptible {
void registerLoop(int name, int defaultValue, int limit);
int increment(int name);
boolean isPreempted(int name);
int getLimit(int name);
int getValue(int name);
void preempt(int id);
int getLoops();
}
public static abstract class LightWeightThread implements Preemptible {
public int kernelThreadId;
public int threadId;
public KernelThread parent;
AtomicInteger[] values = new AtomicInteger[1];
int[] limits = new int[1];
boolean[] preempted = new boolean[1];
int[] remembered = new int[1];
public LightWeightThread(int kernelThreadId, int threadId, KernelThread parent) {
this.kernelThreadId = kernelThreadId;
this.threadId = threadId;
this.parent = parent;
for (int i = 0 ; i < values.length; i++) {
values[i] = new AtomicInteger();
}
}
public void run() {
}
public void registerLoop(int name, int defaultValue, int limit) {
if (preempted.length > name && remembered[name] < limit) {
values[name].set(remembered[name]);
limits[name] = limit;
} else {
values[name].set(defaultValue);
limits[name] = limit;
}
preempted[name] = false;
}
public int increment(int name) {
return values[name].incrementAndGet();
}
public boolean isPreempted(int name) {
return preempted[name];
}
public int getLimit(int name) {
return limits[name];
}
public int getValue(int name) {
return values[name].get();
}
public int initialVar(int name, int value) {
values[name].set(value);
return value;
}
public void preempt(int id) {
remembered[id] = values[id].get();
preempted[id] = true;
while (!values[id].compareAndSet(values[id].get(), limits[id])){};
}
public int getLoops() {
return values.length;
}
}
public static void main(String[] args) throws InterruptedException {
List<KernelThread> kernelThreads = new ArrayList<>();
for (int i = 0; i < 5; i++) {
KernelThread kt = new KernelThread();
for (int j = 0 ; j < 5; j++) {
LightWeightThread lightWeightThread = new LightWeightThread(i, j, kt) {
#Override
public void run() {
while (this.parent.isScheduled(this)) {
System.out.println(String.format("%d %d", this.kernelThreadId, this.threadId));
registerLoop(0, 0, 10000000);
for (initialVar(0, 0); getValue(0) < getLimit(0); increment(0)) {
Math.sqrt(getValue(0));
}
if (isPreempted(0)) {
System.out.println(String.format("%d %d: %d was preempted !%d < %d", this.kernelThreadId, this.threadId, 0, values[0].get(), limits[0]));
}
}
}
};
kt.addLightWeightThread(lightWeightThread);
}
kernelThreads.add(kt);
}
for (KernelThread kt : kernelThreads) {
kt.start();
}
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
for (KernelThread kt : kernelThreads) {
kt.preempt();
}
}
}, 10, 10);
for (KernelThread kt : kernelThreads) {
kt.join();
}
}
}
This is the C version of the same thing:
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct lightweight_thread {
int thread_num;
volatile int preempted;
int num_loops;
int *limit;
volatile int *value;
int *remembered;
int kernel_thread_num;
struct lightweight_thread* (*user_function) (struct lightweight_thread*);
};
struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id; /* ID returned by pthread_create() */
int thread_num; /* Application-defined thread # */
char *argv_string; /* From command-line argument */
int lightweight_threads_num;
struct lightweight_thread *user_threads;
volatile int running;
};
struct timer_thread {
pthread_t thread_id;
struct thread_info *all_threads;
int num_threads;
int lightweight_threads_num;
int delay;
volatile int running;
};
static void *
timer_thread_start(void *arg) {
int iterations = 0;
struct timer_thread *timer_thread = arg;
int msec = 0, trigger = timer_thread->delay; /* 10ms */
clock_t before = clock();
while (timer_thread->running == 1 && iterations < 100000) {
do {
for (int i = 0 ; i < timer_thread->num_threads; i++) {
for (int j = 0 ; j < timer_thread->all_threads[i].lightweight_threads_num; j++) {
// printf("Preempting kernel thread %d user thread %d\n", i, j);
timer_thread->all_threads[i].user_threads[j].preempted = 0;
}
}
for (int i = 0 ; i < timer_thread->num_threads; i++) {
for (int j = 0 ; j < timer_thread->all_threads[i].lightweight_threads_num; j++) {
// printf("Preempting kernel thread %d user thread %d\n", i, j);
for (int loop = 0; loop < timer_thread->all_threads[i].user_threads[j].num_loops; loop++) {
timer_thread->all_threads[i].user_threads[j].remembered[loop] = timer_thread->all_threads[i].user_threads[j].value[loop];
timer_thread->all_threads[i].user_threads[j].value[loop] = timer_thread->all_threads[i].user_threads[j].limit[loop];
}
}
}
clock_t difference = clock() - before;
msec = difference * 1000 / CLOCKS_PER_SEC;
iterations++;
} while ( msec < trigger && iterations < 100000 );
// printf("Time taken %d seconds %d milliseconds (%d iterations)\n",
// msec/1000, msec%1000, iterations);
}
return 0;
}
/* Thread start function: display address near top of our stack,
and return upper-cased copy of argv_string. */
static void *
thread_start(void *arg)
{
struct thread_info *tinfo = arg;
char *uargv;
printf("Thread %d: top of stack near %p; argv_string=%s\n",
tinfo->thread_num, (void *) &tinfo, tinfo->argv_string);
uargv = strdup(tinfo->argv_string);
if (uargv == NULL)
handle_error("strdup");
for (char *p = uargv; *p != '\0'; p++) {
*p = toupper(*p);
}
while (tinfo->running == 1) {
for (int i = 0 ; i < tinfo->lightweight_threads_num; i++) {
tinfo->user_threads[i].preempted = 0;
}
int previous = -1;
for (int i = 0 ; i < tinfo->lightweight_threads_num; i++) {
if (previous != -1) {
tinfo->user_threads[previous].preempted = 0;
}
tinfo->user_threads[i].preempted = 1;
tinfo->user_threads[i].user_function(&tinfo->user_threads[i]);
previous = i;
}
}
return uargv;
}
void
register_loop(int index, int value, struct lightweight_thread* m, int limit) {
if (m->remembered[index] == -1) {
m->limit[index] = limit;
m->value[index] = value;
} else {
m->limit[index] = limit;
m->value[index] = m->remembered[index];
}
}
int
lightweight_thread_function(struct lightweight_thread* m)
{
while (m->preempted != 0) {
register_loop(0, 0, m, 100000000);
for (; m->value[0] < m->limit[0]; m->value[0]++) {
sqrt(m->value[0]);
}
printf("Kernel thread %d User thread %d ran\n", m->kernel_thread_num, m->thread_num);
}
return 0;
}
struct lightweight_thread*
create_lightweight_threads(int kernel_thread_num, int num_threads) {
struct lightweight_thread *lightweight_threads =
calloc(num_threads, sizeof(*lightweight_threads));
if (lightweight_threads == NULL)
handle_error("calloc lightweight threads");
for (int i = 0 ; i < num_threads ; i++) {
lightweight_threads[i].kernel_thread_num = kernel_thread_num;
lightweight_threads[i].thread_num = i;
lightweight_threads[i].num_loops = 1;
lightweight_threads[i].user_function = lightweight_thread_function;
int *remembered = calloc(lightweight_threads[i].num_loops, sizeof(*remembered));
int *value = calloc(lightweight_threads[i].num_loops, sizeof(*value));
int *limit = calloc(lightweight_threads[i].num_loops, sizeof(*limit));
lightweight_threads[i].remembered = remembered;
lightweight_threads[i].value = value;
lightweight_threads[i].limit = limit;
for (int j = 0 ; j < lightweight_threads[i].num_loops ; j++) {
lightweight_threads[i].remembered[j] = -1;
}
}
return lightweight_threads;
}
int
main(int argc, char *argv[])
{
int s, timer_s, opt, num_threads;
pthread_attr_t attr;
pthread_attr_t timer_attr;
ssize_t stack_size;
void *res;
int timer_result;
/* The "-s" option specifies a stack size for our threads. */
stack_size = 16384ul;
num_threads = 5;
while ((opt = getopt(argc, argv, "t:")) != -1) {
switch (opt) {
case 't':
num_threads = strtoul(optarg, NULL, 0);
break;
default:
fprintf(stderr, "Usage: %s [-t thread-size] arg...\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
/* Initialize thread creation attributes. */
s = pthread_attr_init(&attr);
if (s != 0)
handle_error_en(s, "pthread_attr_init");
timer_s = pthread_attr_init(&timer_attr);
if (timer_s != 0)
handle_error_en(s, "pthread_attr_init timer_s");
if (stack_size > 0) {
s = pthread_attr_setstacksize(&attr, stack_size);
int t = pthread_attr_setstacksize(&timer_attr, stack_size);
if (t != 0)
handle_error_en(t, "pthread_attr_setstacksize timer");
if (s != 0)
handle_error_en(s, "pthread_attr_setstacksize");
}
/* Allocate memory for pthread_create() arguments. */
struct thread_info *tinfo = calloc(num_threads, sizeof(*tinfo));
if (tinfo == NULL)
handle_error("calloc");
for (int tnum = 0 ; tnum < num_threads; tnum++) {
tinfo[tnum].running = 1;
}
struct timer_thread *timer_info = calloc(1, sizeof(*timer_info));
timer_info->running = 1;
timer_info->delay = 10;
timer_info->num_threads = num_threads;
if (timer_info == NULL)
handle_error("calloc timer thread");
/* Create one thread for each command-line argument. */
timer_info->all_threads = tinfo;
for (int tnum = 0; tnum < num_threads; tnum++) {
tinfo[tnum].thread_num = tnum + 1;
tinfo[tnum].argv_string = argv[0];
struct lightweight_thread *lightweight_threads = create_lightweight_threads(tnum, num_threads);
tinfo[tnum].user_threads = lightweight_threads;
tinfo[tnum].lightweight_threads_num = num_threads;
/* The pthread_create() call stores the thread ID into
corresponding element of tinfo[]. */
s = pthread_create(&tinfo[tnum].thread_id, &attr,
&thread_start, &tinfo[tnum]);
if (s != 0)
handle_error_en(s, "pthread_create");
}
s = pthread_create(&timer_info[0].thread_id, &timer_attr,
&timer_thread_start, &timer_info[0]);
if (s != 0)
handle_error_en(s, "pthread_create");
/* Destroy the thread attributes object, since it is no
longer needed. */
s = pthread_attr_destroy(&attr);
if (s != 0)
handle_error_en(s, "pthread_attr_destroy");
s = pthread_attr_destroy(&timer_attr);
if (s != 0)
handle_error_en(s, "pthread_attr_destroy timer");
/* Now join with each thread, and display its returned value. */
s = pthread_join(timer_info->thread_id, &timer_result);
if (s != 0)
handle_error_en(s, "pthread_join");
printf("Joined timer thread");
for (int tnum = 0; tnum < num_threads; tnum++) {
tinfo[tnum].running = 0;
s = pthread_join(tinfo[tnum].thread_id, &res);
if (s != 0)
handle_error_en(s, "pthread_join");
printf("Joined with thread %d; returned value was %s\n",
tinfo[tnum].thread_num, (char *) res);
free(res); /* Free memory allocated by thread */
for (int user_thread_num = 0 ; user_thread_num < num_threads; user_thread_num++) {
free(tinfo[tnum].user_threads[user_thread_num].remembered);
free(tinfo[tnum].user_threads[user_thread_num].value);
free(tinfo[tnum].user_threads[user_thread_num].limit);
}
free(tinfo[tnum].user_threads);
}
free(timer_info);
free(tinfo);
exit(EXIT_SUCCESS);
}
The Rust version uses unsafe.
extern crate timer;
extern crate chrono;
use std::sync::Arc;
use std::thread;
use std::sync::atomic::{AtomicI32, Ordering};
use std::{time};
struct LightweightThread {
thread_num: i32,
preempted: AtomicI32,
num_loops: i32,
limit: Vec<AtomicI32>,
value: Vec<AtomicI32>,
remembered: Vec<AtomicI32>,
kernel_thread_num: i32,
lightweight_thread: fn(&mut LightweightThread)
}
fn register_loop(loopindex: usize, initialValue: i32, limit: i32, _thread: &mut LightweightThread) {
if _thread.remembered[loopindex].load(Ordering::Relaxed) < _thread.limit[loopindex].load(Ordering::Relaxed) {
_thread.value[loopindex].store( _thread.remembered[loopindex].load(Ordering::Relaxed), Ordering::Relaxed);
_thread.limit[loopindex].store(limit, Ordering::Relaxed);
} else {
_thread.value[loopindex].store(initialValue, Ordering::Relaxed);
_thread.limit[loopindex].store(limit, Ordering::Relaxed);
}
}
fn lightweight_thread(_thread: &mut LightweightThread) {
register_loop(0usize, 0, 1000000, _thread);
while _thread.preempted.load(Ordering::Relaxed) == 1 {
while _thread.value[0].load(Ordering::Relaxed) < _thread.limit[0].load(Ordering::Relaxed) {
let i = _thread.value[0].load(Ordering::Relaxed);
f64::sqrt(i.into());
_thread.value[0].fetch_add(1, Ordering::Relaxed);
}
}
println!("Kernel thread {} User thread {}", _thread.kernel_thread_num, _thread.thread_num)
}
fn main() {
println!("Hello, world!");
let timer = timer::Timer::new();
static mut threads:Vec<LightweightThread> = Vec::new();
let mut thread_handles = Vec::new();
for kernel_thread_num in 1..=5 {
let thread_join_handle = thread::spawn(move || {
for i in 1..=5 {
let mut lthread = LightweightThread {
thread_num: i,
preempted: AtomicI32::new(0),
num_loops: 1,
limit: Vec::new(),
value: Vec::new(),
remembered: Vec::new(),
kernel_thread_num: kernel_thread_num.clone(),
lightweight_thread: lightweight_thread
};
lthread.limit.push(AtomicI32::new(-1));
lthread.value.push(AtomicI32::new(-1));
lthread.remembered.push(AtomicI32::new(1));
unsafe {
threads.push(lthread);
}
}
loop {
let mut previous:Option<&mut LightweightThread> = None;
unsafe {
for (_pos, current_thread) in threads.iter_mut().enumerate() {
if current_thread.kernel_thread_num != kernel_thread_num {
continue;
}
if !previous.is_none() {
previous.unwrap().preempted.store(0, Ordering::Relaxed)
}
current_thread.preempted.store(1, Ordering::Relaxed);
(current_thread.lightweight_thread)(current_thread);
previous = Some(current_thread);
// println!("Running")
}
}
} // loop forever
}); // thread
thread_handles.push(thread_join_handle);
} // thread generation
let timer_handle = thread::spawn(move || {
unsafe {
loop {
for thread in threads.iter() {
thread.preempted.store(0, Ordering::Relaxed);
}
let mut previous:Option<usize> = None;
for (index, thread) in threads.iter_mut().enumerate() {
if !previous.is_none() {
threads[previous.unwrap()].preempted.store(0, Ordering::Relaxed);
}
previous = Some(index);
for loopindex in 0..thread.num_loops {
thread.remembered[loopindex as usize].store(thread.value[loopindex as usize].load(Ordering::Relaxed), Ordering::Relaxed);
thread.value[loopindex as usize].store(thread.limit[loopindex as usize].load(Ordering::Relaxed), Ordering::Relaxed);
}
thread.preempted.store(1, Ordering::Relaxed);
}
let ten_millis = time::Duration::from_millis(10);
thread::sleep(ten_millis);
} // loop
} // unsafe
}); // end of thread
timer_handle.join();
for thread in thread_handles {
thread.join();
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I know that java needs 3rd party libraries to use unix sockets. Im using junixsocket.
How do i send an unconnected datagram on a unix socket in java without a specific filepathname?
I need to send some data (say an ip address) to an application which acks as a server and is written in c. My java code would be a client. I dont want it to be dependent on a path, as on the server side the c code is not listening on a particular path but is polling on a raw unix socket defined as socket(AF_UNIX, SOCK_RAW, 0); which does'nt have a specific filepath name. Thanks!
This is a part of the server code in c that listens on the raw unix socket with a poll() function. The main functions is at the bottom and the poll is int the event_loop() function just above the main.
#include "lib.h"
#include "udp.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
struct eid_lookup {
union sockunion eid; /* Destination EID */
int rx; /* Receiving socket */
// more parameters.
struct timespec start; /* Start time of lookup */
uint64_t active; /* Unique lookup identifier, 0 if inactive */
union sockunion * mr; /* Point to mapresolver */
};
struct eid_lookup lookups[MAX_LOOKUPS];
struct pollfd fds[MAX_LOOKUPS + 1];
int fds_idx[MAX_LOOKUPS +1];
nfds_t nfds = 0;
struct protoent *proto;
int udpproto;
int seq;
int openlispsck;
static void map_message_handler(union sockunion * mr);
int check_eid(union sockunion *eid);
void new_lookup(union sockunion *eid, union sockunion * mr);
int send_mr(int idx);
int read_rec(union map_reply_record_generic * rec);
size_t
_get_sock_size(union sockunion * eid)
{
size_t ss_len;
switch (eid->sa.sa_family){
case AF_INET:
ss_len = sizeof(struct sockaddr_in);
break;
default:
fprintf(OUTPUT_ERROR, "AF not support::%d\n",eid->sa.sa_family);
return -1;
}
return ss_len;
}
int
sockunioncmp(void * m, void * n)
{
union sockunion * sp, * dp;
sp = m; dp = n;
if(sp->sa.sa_family != dp->sa.sa_family)
return -1;
switch (sp->sa.sa_family){
case AF_INET:
return memcmp(&sp->sin.sin_addr, &dp->sin.sin_addr,sizeof(struct in_addr));
break;
default:
return -1;
}
return -1;
}
/* Process message from Openlis socket */
static void
map_message_handler(union sockunion * mr)
{
struct timespec now;
char msg[PSIZE]; /* buffer for mapping messages */
int n = 0; /* number of bytes received on mapping socket */
union sockunion *eid;
n = read(lookups[0].rx, msg, PSIZE);
clock_gettime(CLOCK_REALTIME, &now);
printf("%" PRIu16 "\n",((struct map_msghdr *)msg)->map_type);
eid = (union sockunion *)CO(msg,sizeof(struct map_msghdr));
printf("map_type: %" PRIu16 "\n",((struct map_msghdr *)msg)->map_type);
//i Added this, but im not sure its fully required. It has some propertyies of the map db
if (((struct map_msghdr *)msg)->map_type == MAPM_MISS_EID) {
printf("Im in the 1 if\n");
eid = (union sockunion *)CO(msg,sizeof(struct map_msghdr));
if (check_eid(eid)) {
printf("Im in the 2 if\n");
new_lookup(eid, mr);
}
}
}
/*Check if an EID-prefix exist in poll */
int
check_eid(union sockunion *eid)
{
int i;
for (i = 1; i < MAX_LOOKUPS; i++)
if (lookups[i].active)
if (!memcmp(eid, &lookups[i].eid, _get_sock_size(eid))){
return 0;
}
return 1;
}
/*Add new EID to poll*/
void
new_lookup(union sockunion *eid, union sockunion * mr)
{
int i,e,r;
uint16_t sport; /* inner EMR header source port */
char sport_str[NI_MAXSERV]; /* source port in string format */
struct addrinfo hints;
struct addrinfo *res;
/* Find an inactive slot in the lookup table */
for (i = 1; i < MAX_LOOKUPS; i++)
if (!lookups[i].active)
break;
if (i >= MAX_LOOKUPS) {
return;
}
/*new socket for map-request */
if ((r = socket(mr->sa.sa_family, SOCK_DGRAM, udpproto)) < 0) {
fprintf(OUTPUT_ERROR, "Error when create new socket\n");
return;
}
/*random source port of map-request */
e = -1;
while (e == -1){
sport = MIN_EPHEMERAL_PORT + random() % (MAX_EPHEMERAL_PORT - MIN_EPHEMERAL_PORT);
sprintf(sport_str, "%d", sport);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = mr->sa.sa_family;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
if ((e = getaddrinfo(NULL, sport_str, &hints, &res)) != 0) {
fprintf(OUTPUT_ERROR, "getaddrinfo: %s\n", gai_strerror(e));
e = -1;
continue;
}
if ((e = bind(r, res->ai_addr, res->ai_addrlen)) == -1) {
fprintf(OUTPUT_ERROR, "bind error to port %s\n", sport_str);
e = -1;
continue;
}
freeaddrinfo(res);
}
memcpy(&lookups[i].eid, eid, _get_sock_size(eid));
lookups[i].rx = r;
lookups[i].sport = sport;
clock_gettime(CLOCK_REALTIME, &lookups[i].start);
lookups[i].count = 0;
lookups[i].active = 1;
if(mr->sa.sa_family == AF_INET)
mr->sin.sin_port = htons(LISP_CP_PORT);
lookups[i].mr = mr;
send_mr(i);
}
/* Send map-request */
int
send_mr(int idx)
{
uint32_t nonce0, nonce1;
int cnt;
union sockunion *eid;
char buf[PSIZE];
struct lisp_control_hdr * lh;
struct ip * ih;
struct ip6_hdr *ih6;
struct udphdr * udp ;
struct map_request_hdr * lcm;
union afi_address_generic * itr_rloc;
union map_request_record_generic * rec;
union afi_address_generic afi_addr_src;
union afi_address_generic afi_addr_dst;
uint8_t * ptr;
int sockaddr_len;
size_t itr_size, ip_len;
char ip[INET6_ADDRSTRLEN];
int mask;
eid = &lookups[idx].eid;
if (lookups[idx].count >= COUNT) {
lookups[idx].active = 0;
close(lookups[idx].rx);
return 0;
}
bzero(buf,PSIZE);
lh = (struct lisp_control_hdr *)buf;
ih = (struct ip *)CO(lh, sizeof(struct lisp_control_hdr));
ih6 = (struct ip6_hdr *)CO(lh, sizeof(struct lisp_control_hdr));
/*choose source/destionation ip */
switch (lookups[idx].mr->sa.sa_family ){
case AF_INET:
afi_addr_dst.ip.afi = AF_INET;
memcpy(&afi_addr_dst.ip.address,(struct in_addr *)&(lookups[idx].mr->sin.sin_addr),sizeof(struct in_addr));
afi_addr_src.ip.afi = AF_INET;
memcpy(&afi_addr_src.ip.address,(struct in_addr *)(src_addr[0]),sizeof(struct in_addr));
udp = (struct udphdr *)CO(ih, sizeof(struct ip));
sockaddr_len = sizeof(struct sockaddr_in);
break;
default:
fprintf(OUTPUT_ERROR,"AF not support\n");
return -1;
}
lcm = (struct map_request_hdr*)CO(udp, sizeof(struct udphdr));
/*build message header*/
/* set all the LISP flags */
uint64_t nonce;
_make_nonce(&nonce);
nonce0 = (uint32_t)(*(uint32_t *)&nonce);
nonce1 = (uint32_t)(*(uint32_t *)(&nonce0+1));
/* set no source EID <AFI=0, addres is empty> -> jump of 2 bytes */
/* nothing to do as bzero of the packet at init */
itr_rloc = (union afi_address_generic *)CO(lcm, sizeof(struct map_request_hdr) + 2);
itr_size = SA_LEN(afi_addr_src.ip.afi);
memcpy(itr_rloc, &afi_addr_src, itr_size);
/* set source ITR */
switch(afi_addr_src.ip.afi){
case AF_INET:
itr_rloc->ip.afi = htons(LISP_AFI_IP);
itr_size = sizeof(struct afi_address);
break;
default:
printf("not supported\n");
return (FALSE);
}
rec = (union map_request_record_generic *)CO(itr_rloc, itr_size);
/* assign correctly the EID prefix */
switch(eid->sa.sa_family){
case AF_INET:
/* EID prefix is an IPv4 so 32 bits (4 bytes) */
rec->record.eid_mask_len = mask = 32;
rec->record.eid_prefix_afi = htons(LISP_AFI_IP);
memcpy(&rec->record.eid_prefix, &(eid->sin.sin_addr), sizeof(struct in_addr));
inet_ntop(AF_INET, (void *)&rec->record.eid_prefix, ip, INET6_ADDRSTRLEN);
ptr = (uint8_t *)CO(rec,4+4);
break;
default:
printf("not supported\n");
return (FALSE);
}
/* set the UDP parameters */
udp->source = htons(lookups[idx].sport);
udp->dest = htons(LISP_CP_PORT);
udp->len = htons((uint8_t *)ptr - (uint8_t *) udp );
udp->check = 0;
/* setup the IP parameters */
switch (lookups[idx].mr->sin.sin_family ){
case AF_INET:
ip_len = (uint8_t *)ptr - (uint8_t *) ih;
ih->ip_hl = 5;
ih->ip_v = 4;
ih->ip_tos = 0;
ih->ip_len = htons(ip_len);
ih->ip_id = htons(0);
ih->ip_off = 0;
ih->ip_ttl = 255;
ih->ip_p = IPPROTO_UDP;
ih->ip_sum = 0;
ih->ip_src.s_addr = afi_addr_src.ip.address.s_addr;
ih->ip_dst.s_addr = eid->sin.sin_addr.s_addr;
ih->ip_sum = ip_checksum((unsigned short *)ih, ip_len);
break;
}
if (sendto(lookups[idx].rx, (void *)buf, (uint8_t *)ptr - (uint8_t *)lh, 0, &(lookups[idx].mr->sa), sockaddr_len) < 0) {
return 0;
} else {
cnt = lookups[idx].count;
lookups[idx].nonce0[cnt] = nonce0;
lookups[idx].nonce1[cnt] = nonce1;
lookups[idx].count++;
char ip2[INET6_ADDRSTRLEN];
if(_debug == LLOG || _debug == LDEBUG){
fprintf(OUTPUT_STREAM, "\n#Send Map-Request to %s:%d <nonce=0x%x - 0x%x>\n", \
sk_get_ip(lookups[idx].mr, ip2) , sk_get_port(lookups[idx].mr),\
nonce0, nonce1);
if(_debug == LDEBUG)
fprintf(OUTPUT_STREAM," EID %s/%d\n",ip,mask);
}
}
return 1;
}
/* Process with map-reply */
int
read_rec(union map_reply_record_generic * rec)
{
fprintf(OUTPUT_STREAM, "\n");
fprintf(OUTPUT_STREAM, "---------------Begin----------------\n");
size_t rlen;
union map_reply_locator_generic * loc;
char buf[BSIZE];
size_t len;
struct map_entry * entry;
uint8_t lcount;
struct prefix eid;
struct mapping_flags mflags;
void * mapping;
struct db_node node;
struct lcaf_hdr *lcaf;
union rloc_te_generic *hop;
void *barr;
node.flags = NULL;
rlen = 0;
bzero(buf, BSIZE);
mapping = NULL;
bzero(&eid, sizeof(struct prefix));
switch(ntohs(rec->record.eid_prefix_afi)){
case LISP_AFI_IP:
eid.family = AF_INET;
eid.u.prefix4 = rec->record.eid_prefix;
inet_ntop(AF_INET, (void *)&eid.u.prefix4, buf, BSIZE);
rlen += sizeof(struct map_reply_record);
break;
default:
fprintf(OUTPUT_STREAM, "unsuported family\n");
return (0);
}
eid.prefixlen = rec->record.eid_mask_len;
lcount = rec->record.locator_count;
bzero(&mflags, sizeof(struct mapping_flags));
mflags.act = rec->record.act;
mflags.A = rec->record.a;
mflags.version = rec->record.version;
mflags.ttl = ntohl(rec->record.ttl);
memcpy(&node.p, &eid, sizeof(struct prefix));
generic_mapping_set_flags(&node, &mflags);
node.info = list_init();
return EXIT_SUCCESS;
loc = (union map_reply_locator_generic *)CO(rec, rlen);
/* ==================== RLOCs ========================= */
while(lcount--){
bzero(buf, BSIZE);
entry = (struct map_entry *)calloc(1, sizeof(struct map_entry));
entry->priority = loc->rloc.priority;
entry->weight = loc->rloc.weight;
entry->m_priority = loc->rloc.m_priority;
entry->m_weight = loc->rloc.m_weight;
entry->r = loc->rloc.R;
entry->L =loc->rloc.L;
entry->p = loc->rloc.p;
lcaf = (struct lcaf_hdr *)&loc->rloc.rloc_afi;
if(ntohs(lcaf->afi) == LCAF_AFI && lcaf->type == LCAF_TE){
struct sockaddr_in hop_inet;
struct sockaddr_in6 hop_inet6;
int pec = 0;
int rtr = 0;
barr = (void *)CO(lcaf,sizeof(struct lcaf_hdr)+ntohs(lcaf->payload_len));
hop = (union rloc_te_generic *)CO(lcaf,sizeof(struct lcaf_hdr));
/* run over pe
if lisp_te
if xTR --> get the first hop
if RTR --> get the hop after RTR
if not lisp_te --> get last hop
*/
hop = (union rloc_te_generic *)CO(lcaf,sizeof(struct lcaf_hdr));
while((char *)hop < (char *)barr){
switch(ntohs(hop->rloc.afi)){
case LISP_AFI_IP:
/* xTR get first hop in pe */
if(!pec && lisp_te && (_fncs & _FNC_XTR)){
entry->rloc.sin.sin_family = AF_INET;
memcpy(&entry->rloc.sin.sin_addr, &hop->rloc.hop_addr, sizeof(struct in_addr));
hop = loc = barr;
continue;
}
/* RTR get next hop after it in pe */
if(lisp_te && (_fncs & _FNC_RTR)){
if(!rtr){
/* check if hop's ip is rtr's ip */
hop_inet.sin_family = AF_INET;
hop_inet.sin_addr.s_addr = hop->rloc.hop_addr.s_addr;
if (is_my_addr((union sockunion *)&hop_inet))
rtr = 1;
}
else{
entry->rloc.sin.sin_family = AF_INET;
memcpy(&entry->rloc.sin.sin_addr, &hop->rloc.hop_addr,sizeof(struct in_addr));
hop = loc = barr;
rtr = 0;
continue;
}
}
/* not lisp_te function get last hop */
if( !lisp_te && (CO(hop,sizeof(struct rloc_te) >= (char *)barr )) ){
entry->rloc.sin.sin_family = AF_INET;
memcpy(&entry->rloc.sin.sin_addr, &hop->rloc.hop_addr,sizeof(struct in_addr));
hop = loc = barr;
continue;
}
hop = CO(hop,sizeof(struct rloc_te));
break;
case LISP_AFI_IPV6:
/* xTR get first hop in pe */
if(lisp_te && !pec && (_fncs & _FNC_XTR)){
entry->rloc.sin6.sin6_family = AF_INET6;
memcpy(&entry->rloc.sin6.sin6_addr, &hop->rloc6.hop_addr, sizeof(struct in6_addr));
hop = loc = barr;
continue;
}
/* RTR get next hop after it in pe */
if(lisp_te && (_fncs & _FNC_RTR)){
if(!rtr){
hop_inet6.sin6_family = AF_INET6;
memcpy(&hop_inet6.sin6_addr,&hop->rloc6.hop_addr,sizeof(struct in6_addr));
if (is_my_addr((union sockunion *)&hop_inet6))
rtr = 1;
}
else{
entry->rloc.sin6.sin6_family = AF_INET6;
memcpy(&entry->rloc.sin6.sin6_addr, &hop->rloc6.hop_addr,sizeof(struct in6_addr));
hop = loc = barr;
rtr = 0;
continue;
}
}
/* not lisp_te function get last hop */
if( (char *)(hop + sizeof(struct rloc6_te)) > (char *)barr){
entry->rloc.sin6.sin6_family = AF_INET6;
memcpy(&entry->rloc.sin6.sin6_addr, &hop->rloc6.hop_addr,sizeof(struct in6_addr));
hop = loc = barr;
continue;
}
hop = (union rloc_te_generic *)CO(hop,sizeof(struct rloc6_te));
break;
default:
fprintf(OUTPUT_STREAM, "unsuported family\n");
free(entry);
return (0);
}
pec++;
}
loc = barr;
}
else{
switch(ntohs(loc->rloc.rloc_afi)){
case LISP_AFI_IP:
entry->rloc.sin.sin_family = AF_INET;
memcpy(&entry->rloc.sin.sin_addr, &loc->rloc.rloc, sizeof(struct in_addr));
len = sizeof(struct map_reply_locator);
break;
case LISP_AFI_IPV6:
entry->rloc.sin6.sin6_family = AF_INET6;
memcpy(&entry->rloc.sin6.sin6_addr, &loc->rloc6.rloc, sizeof(struct in6_addr));
len = sizeof(struct map_reply_locator6);
break;
default:
fprintf(OUTPUT_STREAM, "unsuported family\n");
free(entry);
return (0);
}
loc = (union map_reply_locator_generic *)CO(loc, len);
}
/* add the locator to the table */
rlen = (char *)loc - (char *)rec;
assert((struct list_t *)node.info);
struct list_entry_t *m;
struct map_entry *n_entry;
if(entry->rloc.sa.sa_family){
if(!(m = list_search(node.info, entry,entrycmp))){
list_insert((struct list_t *)node.info, entry, NULL);
}
else{
/* new rloc exist, only updat priority and pe */
n_entry = (struct map_entry *)m->data;
if(n_entry->priority > entry->priority){
m->data = entry;
free(n_entry);
}
else
free(entry);
}
}
else{
free(entry);
return 0;
}
}
fprintf(OUTPUT_STREAM, " =====================3=====================");
/* add to OpenLISP mapping cache */
if(node.info)
list_destroy((struct list_t *)node.info, NULL);
return (rlen);
}
/* get map-reply */
int
read_mr(int idx)
{
fprintf(OUTPUT_STREAM, "0000000 Im in plugin_openlisp.c 10 000000");
int i;
int rcvl;
char buf[PSIZE];
union sockunion si;
struct map_reply_hdr * lh;
union map_reply_record_generic * lcm;
uint32_t nonce0, nonce1;
socklen_t sockaddr_len;
int rec_len;
char ip[INET6_ADDRSTRLEN];
//printf("get reply\n");
if(lookups[idx].mr->sa.sa_family == AF_INET)
sockaddr_len = sizeof(struct sockaddr_in);
else
sockaddr_len = sizeof(struct sockaddr_in6);
/* read package */
if ((rcvl = recvfrom(lookups[idx].rx,
buf,
PSIZE,
0,
(struct sockaddr *)&(si.sa),
&sockaddr_len)) < 0) {
return 0;
}
/*only accept map-reply with not empty record */
lh = (struct map_reply_hdr *)buf;
if (lh->lisp_type != LISP_TYPE_MAP_REPLY) {
return 0;
}
/* check nonce to see reply for what */
nonce0 = ntohl(lh->lisp_nonce0);
nonce1 = ntohl(lh->lisp_nonce1);
fprintf(OUTPUT_STREAM, "---------------p2--------------\n");
if(_debug == LLOG || _debug == LDEBUG)
fprintf(OUTPUT_STREAM, "\n#Received Map-Reply from %s:%d <nonce=0x%x - 0x%x>\n",\
sk_get_ip(&si, ip) , sk_get_port(&si),\
nonce0,nonce1);
for (i = 0;i <= MAX_COUNT ; i++) {
if (lookups[idx].nonce0[i] == nonce0 && lookups[idx].nonce1[i] == nonce1)
break;
}
if (i > MAX_COUNT)
return 0;
if (lh->record_count <= 0)
return 0;
/* process map-reply */
lcm = (union map_reply_record_generic *)CO(lh,sizeof(struct map_reply_hdr));
for (i = 0; i < lh->record_count; i++){
if( (rec_len = read_rec(lcm)) < 0){
if(_debug == LDEBUG)
fprintf(OUTPUT_ERROR, "Record error\n");
return -1;
}
lcm = (union map_reply_record_generic * )CO(lcm,rec_len);
}
lookups[idx].active = 0;
close(lookups[idx].rx);
return 0;
}
/* Main poll function */
static void
event_loop(void)
{
for (;;) {
int e, i, j, l = -1;
int poll_timeout = INFTIM; /* poll() timeout in milliseconds. We initialize
to INFTIM = -1 (infinity). If there are no
active lookups, we wait in poll() until a
mapping socket event is received. */
struct timespec now, deadline, delta, to, tmp;
//printf("start event_loop\n");
to.tv_sec = timeout;
to.tv_nsec = 0;
nfds = 1;
clock_gettime(CLOCK_REALTIME, &now);
//If lookups inactive continue/salta!
if (!(lookups[i].active)) continue;
deadline.tv_sec = lookups[i].start.tv_sec + (lookups[i].count +1) * timeout;
deadline.tv_nsec = lookups[i].start.tv_nsec;
timespec_subtract(&delta, &deadline, &now);
fds[nfds].fd = lookups[i].rx;
fds[nfds].events = POLLIN;
fds_idx[nfds] = i;
nfds++;
/* Find the minimum delta */
if (timespec_subtract(&tmp, &delta, &to)) {
printf("delta.tv_sec: %d\n",delta.tv_sec);
to.tv_sec = delta.tv_sec;
to.tv_nsec = delta.tv_nsec;
poll_timeout = to.tv_sec * 1000 + to.tv_nsec / 1000000;
printf("poll_timeout = %d \n", poll_timeout);
if (to.tv_sec < 0) poll_timeout = 0;
l = i;
}
} /* Finished iterating through all lookups */
printf("--------------\n");
printf("time_out:%d\n",poll_timeout);
printf("fds:%d\n",fds);
printf("nfds:%d\n",nfds);
printf("Waiting.....\n");
printf("--------------\n");
e = poll(fds, nfds, poll_timeout);
printf("e = %d\n",e);
printf("l = %d\n",l);
if (e < 0) continue;
if (e == 0) // If timeout expires
if (l >= 0) // and slot is defined
send_mr(l); // retry Map-Request
for (j = nfds - 1; j >= 0; j--) {
printf("Type of event that actually occurred = %d\n",fds[j].revents);
if (fds[j].revents == POLLIN) {
printf("j = %d\n",j);
if (j == 0)
map_message_handler(_get_mr());
else
read_mr(fds_idx[j]);
}
}
}
}
/* Main function of thread with intergrate with OpenLisp */
/* Size of socket must be multiple of long (from OpenLISP code)
so size of sockaddr_in6 is 32 instead 28
*/
#define SS_SIZE(ss) \
( (!(ss) || ((struct sockaddr_storage *)(ss))->ss_len == 0) ? \
sizeof(long) : \
1 + ( (((struct sockaddr_storage *)(ss))->ss_len - 1) | (sizeof(long) - 1) ) )
//MAIN
void main(void * data)
{
int i;
struct protoent *proto;
if ((proto = getprotobyname("UDP")) == NULL) {
perror ("getprotobyname");
exit(0);
}
udpproto = proto->p_proto;
openlispsck = socket(AF_UNIX, SOCK_RAW, 0); // The sysem will chose the most appropriate when specifying set to 0
lookups[0].rx = fds[0].fd = openlispsck;
fds[0].events = POLLIN;
fds_idx[0] = -1;
nfds = 1;
/* Initialize lookups[]: all inactive */
for (i = 0; i < MAX_LOOKUPS; i++){
lookups[i].active = 0;
}
event_loop();
pthread_exit(NULL);
return 0;
}
This ULSE answer says that, in general, name-less resources (such as your socket) can only be connected-to from children of the same process, via their resource-descriptor (a process-internal integer ID assigned by the kernel on creation).
In your c-code, openlispsck (the server AF_UNIX, SOCK_RAW resource-descriptor for the socket that you wish to connect to) is a global variable, and therefore available to other running pthreads spawned from the same process (it is also copied over to the lookups and fds global arrays). Client pthreads can then communicate with the server pthread via sendto calls that use this socket's resource-descriptor; the server pthread, which is listening on the socket, will then process whatever is sent.
Therefore, you are highly unlikely to manage to communicate with that socket from another process in Java or anything else. Even if you know the resource-descriptor, it is useless from outside the same process. If you can modify the C-code, give your socket a path. If you can't modify the C-code, you can still find the target socket somewhere in the /proc entry of the server process; but I have no idea how you will manage to access it from another process.
Okay, I'm all out of ideas on this one. Does anyone have any idea how I can hook into Java's exception pipeline in order to catch (and log to a text file) all exceptions that are occurring?
The situation is this: I have a library in a JAR file (A) which in turn depends on a second JAR file (B). A has no main class, as it's simply a class library, which I'm accessing and invoking through the JNI. The problem I'm having is this. When I attempt to initialise the JNI with A loaded, the JNI returns an unspecified error.
I strongly suspect that this error originates from an instantiation of Log4J's logger unit, which is occurring in static code (outside of a method) in B, which I believe is throwing an IOException as a result of permissions problems on the log file. I'm having issues finding out what's going on, however, as the exception (which I suspect is the cause of the problem) is being thrown during the linking stage (when A imports B) and so cannot be caught by a try-catch block. Also, since there is no main method there is no obvious place to put a try-catch block in order to catch this exception.
I would like some way of catching all exceptions that arise in either JAR and dumping them into a text file. I cannot (easily) modify B (I do not have the decompiled JAR). Any ideas?
Here is the C code which invokes the JNI with the specified libraries and options:
_DLL_EXPORT PyObject *initVM(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwnames[] = {
"classpath", "initialheap", "maxheap", "maxstack",
"vmargs", NULL
};
char *classpath = NULL;
char *initialheap = NULL, *maxheap = NULL, *maxstack = NULL;
char *vmargs = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzzzz", kwnames,
&classpath,
&initialheap, &maxheap, &maxstack,
&vmargs))
return NULL;
if (env->vm)
{
PyObject *module_cp = NULL;
if (initialheap || maxheap || maxstack || vmargs)
{
PyErr_SetString(PyExc_ValueError,
"JVM is already running, options are ineffective");
return NULL;
}
if (classpath == NULL && self != NULL)
{
module_cp = PyObject_GetAttrString(self, "CLASSPATH");
if (module_cp != NULL)
classpath = PyString_AsString(module_cp);
}
if (classpath && classpath[0])
env->setClassPath(classpath);
Py_XDECREF(module_cp);
return getVMEnv(self);
}
else
{
JavaVMInitArgs vm_args;
JavaVMOption vm_options[32];
JNIEnv *vm_env;
JavaVM *vm;
unsigned int nOptions = 0;
PyObject *module_cp = NULL;
vm_args.version = JNI_VERSION_1_4;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
if (classpath == NULL && self != NULL)
{
module_cp = PyObject_GetAttrString(self, "CLASSPATH");
if (module_cp != NULL)
classpath = PyString_AsString(module_cp);
}
#ifdef _jcc_lib
PyObject *jcc = PyImport_ImportModule("jcc");
PyObject *cp = PyObject_GetAttrString(jcc, "CLASSPATH");
if (classpath)
add_paths("-Djava.class.path=", PyString_AsString(cp), classpath,
&vm_options[nOptions++]);
else
add_option("-Djava.class.path=", PyString_AsString(cp),
&vm_options[nOptions++]);
Py_DECREF(cp);
Py_DECREF(jcc);
#else
if (classpath)
add_option("-Djava.class.path=", classpath,
&vm_options[nOptions++]);
#endif
Py_XDECREF(module_cp);
if (initialheap)
add_option("-Xms", initialheap, &vm_options[nOptions++]);
if (maxheap)
add_option("-Xmx", maxheap, &vm_options[nOptions++]);
if (maxstack)
add_option("-Xss", maxstack, &vm_options[nOptions++]);
if (vmargs)
{
#ifdef _MSC_VER
char *buf = _strdup(vmargs);
#else
char *buf = strdup(vmargs);
#endif
char *sep = ",";
char *option;
for (option = strtok(buf, sep); option; option = strtok(NULL, sep))
{
if (nOptions < sizeof(vm_options) / sizeof(JavaVMOption))
add_option("", option, &vm_options[nOptions++]);
else
{
free(buf);
for (unsigned int i = 0; i < nOptions; i++)
delete vm_options[i].optionString;
PyErr_Format(PyExc_ValueError, "Too many options (> %d)",
nOptions);
return NULL;
}
}
free(buf);
}
//vm_options[nOptions++].optionString = "-verbose:gc";
//vm_options[nOptions++].optionString = "-Xcheck:jni";
vm_args.nOptions = nOptions;
vm_args.ignoreUnrecognized = JNI_FALSE;
vm_args.options = vm_options;
if (JNI_CreateJavaVM(&vm, (void **) &vm_env, &vm_args) < 0)
{
for (unsigned int i = 0; i < nOptions; i++)
delete vm_options[i].optionString;
PyErr_Format(PyExc_ValueError,
"An error occurred while creating Java VM");
return NULL;
}
env->set_vm(vm, vm_env);
for (unsigned int i = 0; i < nOptions; i++)
delete vm_options[i].optionString;
t_jccenv *jccenv = (t_jccenv *) PY_TYPE(JCCEnv).tp_alloc(&PY_TYPE(JCCEnv), 0);
jccenv->env = env;
#ifdef _jcc_lib
registerNatives(vm_env);
#endif
return (PyObject *) jccenv;
}
}
Okay, so I've got the solution I was after. The solution is an update to the following segment of the code listed in the question:
if (JNI_CreateJavaVM(&vm, (void **) &vm_env, &vm_args) < 0)
{
for (unsigned int i = 0; i < nOptions; i++)
delete vm_options[i].optionString;
PyErr_Format(PyExc_ValueError,
"An error occurred while creating Java VM");
return NULL;
}
The adaptation supports the construction of a more detailed error message which adds two specific pieces of information:
The error code (if any) which is returned by the JNI_CreateJavaVM method;
The detailed Java exception which occurs in the event that such an error code arises.
The above snippet from the original code was replaced with the following:
vmInitSuccess = JNI_CreateJavaVM(&vm, (void **) &vm_env, &vm_args);
if (vmInitSuccess < 0)
{
for (unsigned int i = 0; i < nOptions; i++)
delete vm_options[i].optionString;
//Set up basic error message
sprintf(strVMInitSuccess, "%d", vmInitSuccess);
strcpy(strVMError, "An error occurred while creating Java VM (No Exception): ");
strcat(strVMError, strVMInitSuccess);
//Get exception if there is one
if((exc = vm_env->ExceptionOccurred()))
{
//Clear the exception since we have it now
vm_env->ExceptionClear();
//Get the getMessage() method
if ((java_class = vm_env->FindClass ("java/lang/Throwable")))
{
if ((method = vm_env->GetMethodID(java_class, "getMessage", "()Ljava/lang/String;")))
{
int size;
strExc = static_cast<jstring>(vm_env->CallObjectMethod(exc, method));
charExc = vm_env->GetStringUTFChars(strExc, NULL);
size = sizeof(strVMError) + sizeof(charExc);
char strVMException[size];
strcpy(strVMException, "An error occurred while creating Java VM (Exception): ");
strcat(strVMException, charExc);
PyErr_Format(PyExc_ValueError, strVMException);
return NULL;
}
}
}
PyErr_Format(PyExc_ValueError, strVMError);
return NULL;
}
Thanks to #Parsifal for help with this solution.
I have another question :) I have a simple UDP server in C that reads some bytes applies some decode to those bytes and when it has a STRING of the form ################ he sends it throug UDP to another server in C. Here is the code for my C server that is called preprocesamiento.c Im posting the whole thing cos is easyer but maybe this has nothing to do with my problem.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#define MAXBUF 512
#define SENDING 0x52
#define RESIVING 0xB4
#define TYPE 0xA3F0
int createSocket();
char *unbase64(unsigned char *input, int length);
/* This function recives bytes(ASCII numbers) and returns the char */
void cambiarAChars(char* bytes, char* result)
{
unsigned int ch;
char a[4];
char buff[50];
strcpy(result,"");
int i=0;
while(i<strlen(bytes))
{
if(bytes[i]=='1')
{
a[0]=bytes[i];
a[1]=bytes[i+1];
a[2]=bytes[i+2];
a[3]='\0';
i=i+3;
}
else
{
a[0]=bytes[i];
a[1]=bytes[i+1];
a[2]='\0';
i=i+2;
}
ch = atoi(a);
sprintf(buff,"%c",ch);
strcat(result,buff);
}
}
/*this is the message that is going to be sent to the other server*/
char msg[MAXBUF];
/*this is the bytes recived*/
char bytes[MAXBUF];
void loadConfig(struct sockaddr_in *udpServer,struct sockaddr_in *thisServer,unsigned char *file);
int sendDataToServerXX(struct sockaddr_in *udpServer, int udpSocket);
int *useStdrr;
int *maxRequests;
int returnStatus;
int main(int argc, char* argv[])
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s <file.config adress>\n", argv[0]);
exit(1);
}
useStdrr=malloc(sizeof(int));
maxRequests=malloc(sizeof(int));
struct sockaddr_in udpServer,thisServer,udpClient;
loadConfig(&udpServer,&thisServer, argv[1]);
int thisServerSocket = createSocket();
int udpSocket=createSocket();
int addrlen;
printf("Listening on.. %d \n",thisServer.sin_port);
thisServer.sin_family = AF_INET;
returnStatus = bind(thisServerSocket, (struct sockaddr*)&thisServer, sizeof(thisServer));
if (returnStatus == 0) {
fprintf(stderr, "Bind completed!\n");
}
else {
fprintf(stderr, "Could not bind to address \n" );
close(thisServerSocket);
exit(1);
}
/*En este while infinito estamos esperando los datos de las tramas*/
while (1)
{
addrlen = sizeof(udpClient);
/* How to resive a struct? */
returnStatus = recvfrom(thisServerSocket,(char*)&bytes, sizeof(bytes), 0,
(struct sockaddr*)&udpClient, &addrlen);
if (returnStatus == -1) {
fprintf(stderr, "Could not receive message!\n");
}
else {
printf("Lo que llego: %s \n",bytes);
/*Primero quitamos el 0 y 1 y guardamos el nuevo arreglo en p*/
bytes[strlen(bytes)-1]='\0';
char p[strlen(bytes)];
int i=0;
while(bytes[i+1]!='\0'){
p[i]=bytes[i+1];
i++;
}
/*esto simula la cambiada a base10 de base64*/
char *result=malloc(512);
char *p2=malloc(sizeof(p)+1);
strcpy(p2,p);
cambiarAChars(p2,result);
strcat(result,"\n\0");
printf("TAMANO: %d \n",strlen(result));
char *output = unbase64(result, strlen(result));
printf("Unbase64: %s\n", output);
msg[0]='%';
strcat(msg,output);
int f=strlen(msg);
msg[f]='%';
msg[f+1]='\0';
printf("Voy a mandar: %s \n",msg);
sendDataToServerXX(&udpServer,udpSocket);
free(output);
}
}
close(thisServerSocket);
close(udpSocket);
}
int createSocket()
{
/* create a socket */
int Socket;
Socket = socket(AF_INET, SOCK_DGRAM, 0);
if (Socket == -1)
{
if(*useStdrr)
{
fprintf(stderr, "Could not create a socket!\n");
}
exit(1);
}
else {
printf("Socket created.\n");
}
return Socket;
}
void loadConfig(struct sockaddr_in *udpServer,struct sockaddr_in *thisServer, unsigned char *file)
{
char line[256];
int linenum=0;
FILE* f = fopen(file, "r");
while(fgets(line, 256, f) != NULL)
{
char atribute[256], value[256];
linenum++;
if(line[0] == '#'||line[0] == ' ') {
continue;
}
else{
if(sscanf(line, "%s %s", atribute, value) != 2)
{
fprintf(stderr, "Syntax error, line %d\n", linenum);
continue;
}
if(!strcmp(atribute,"server_address" ))
{
if(!strcmp(value,""))
{
udpServer->sin_addr.s_addr = htonl(INADDR_ANY);
}
else{
udpServer->sin_addr.s_addr = inet_addr(value);
}
}
else if(!strcmp(atribute,"server_port"))
{
udpServer->sin_port = htons(atoi(value));
}
else if(!strcmp(atribute,"print_message_details"))
{
if(!strcmp(value,"ON"))
{
*useStdrr=1;
}
else
{
*useStdrr=0;
}
}
else if(!strcmp(atribute,"request_count"))
{
*maxRequests=5;
}
else if(!strcmp(atribute,"valor_que_viene_del_cohete_simulado"))
{
}
else if(!strcmp(atribute,"this_server_address"))
{
if(!strcmp(value,""))
{
thisServer->sin_addr.s_addr = htonl(INADDR_ANY);
}
else{
thisServer->sin_addr.s_addr = inet_addr(value);
}
}
else if(!strcmp(atribute,"this_server_port"))
{
thisServer->sin_port = htons(atoi(value));
}
}
}
}
int sendDataToServerXX(struct sockaddr_in *udpServer, int udpSocket)
{
udpServer->sin_family = AF_INET;
int in=0;
int boolv=0;
while(in<*maxRequests)
{
in++;
returnStatus = sendto(udpSocket,(char*) &msg, sizeof(msg), 0,
(struct sockaddr*)udpServer, sizeof(*udpServer));
if (returnStatus == -1) {
if(*useStdrr)
{
fprintf(stderr, "Could not send message!\n");
}
}
else {
printf("Datos enviados al servidor xx.\n");
memset(msg, 0, strlen(msg));
in=*maxRequests;
boolv=1;
}
}
if(!boolv)
{
if(*useStdrr)
{
fprintf(stderr, "fixed number of requests finished.. no reply.\n");
}
}
return 0;
}
char *unbase64(unsigned char *input, int length)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
Ok so i made a simulator that sends data to this server... basically a UDP client that sends bytes as i want them. And the connection and the whole thing works very nice :). Now im trying to connect to the real tester, which is a java jar that sends data as my server wants it through UDP. The only problem is that i dont have the java source code, because its not mine... But the program seems to run smoothly (the java jar) But when i check my server no connections where recived. And yeah im waiting in the right port and both programs the C and Java are running in the same machine (UBUNTU).
I post my client simulator made in C that works very nice with this server.
Sorry its a bit long cos i load from a config file:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAXBUF 1024
#define SENDING 0x52
#define RESIVING 0xB4
#define TYPE 0xA3F0
int createSocket();
char msg[MAXBUF];
void loadConfig(struct sockaddr_in *udpServer, char *file);
int *useStdrr;
int *maxRequests;
int *timeOut;
int main(int argc, char* argv[])
{
int returnStatus;
int addrlen;
struct sockaddr_in udpClient, udpServer;
char buf[MAXBUF];
useStdrr=malloc(sizeof(int));
maxRequests=malloc(sizeof(int));
timeOut=malloc(sizeof(int));
/*ms.timezone="AES";*/
if (argc < 2)
{
fprintf(stderr, "Usage: %s <file.config adress>\n", argv[0]);
exit(1);
}
int udpSocket=createSocket();
udpServer.sin_family = AF_INET;
loadConfig(&udpServer, argv[1]);
/*how to send a struct here?*/
int in=0;
int boolv=0;
printf("Request number %i\n",*maxRequests);
while(in<*maxRequests)
{
in++;
printf("Request number %i\n",in);
printf("Adresss::: %d\n",udpServer.sin_addr.s_addr);
printf("PORT:::: %i\n",udpServer.sin_port);
returnStatus = sendto(udpSocket,(char*) &msg, sizeof(msg), 0,
(struct sockaddr*)&udpServer, sizeof(udpServer));
if (returnStatus == -1) {
if(*useStdrr)
{
fprintf(stderr, "Could not send message!\n");
}
}
else {
printf("Message sent.\n");
/* message sent: look for confirmation */
/*
addrlen = sizeof(udpServer);
returnStatus = recvfrom(udpSocket, (char*) &msg, sizeof(msg), 0,
(struct sockaddr*)&udpServer, &addrlen);
if (returnStatus == -1) {
if(*useStdrr)
{
fprintf(stderr, "Did not receive confirmation!\n");
}
}
else {
printf("Second: %s\n", msg);
*/
in=*maxRequests;
boolv=1;
/*
}*/
}
}
if(!boolv)
{
if(*useStdrr)
{
fprintf(stderr, "fixed number of requests finished.. no reply.\n");
}
}
close(udpSocket);
return 0;
}
int createSocket()
{
/* create a socket */
int Socket;
Socket = socket(AF_INET, SOCK_DGRAM, 0);
if (Socket == -1)
{
if(*useStdrr)
{
fprintf(stderr, "Could not create a socket!\n");
}
exit(1);
}
else {
printf("Socket created.\n");
}
return Socket;
}
void loadConfig(struct sockaddr_in *udpServer, char *file)
{
char line[256];
int linenum=0;
FILE* f = fopen(file, "r");
while(fgets(line, 256, f) != NULL)
{
char atribute[256], value[256];
linenum++;
if(line[0] == '#'||line[0] == ' ') {
continue;
}
else{
if(sscanf(line, "%s %s", atribute, value) != 2)
{
fprintf(stderr, "Syntax error, line %d\n", linenum);
continue;
}
printf("Atribute: %s\n",atribute);
printf("Value: %s\n",value);
if(!strcmp(atribute,"server_address" ))
{
if(!strcmp(value,""))
{
udpServer->sin_addr.s_addr = htonl(INADDR_ANY);
}
else{
udpServer->sin_addr.s_addr = inet_addr(value);
}
}
else if(!strcmp(atribute,"server_port"))
{
udpServer->sin_port = htons(atoi(value));
}
else if(!strcmp(atribute,"print_message_details"))
{
if(!strcmp(value,"ON"))
{
*useStdrr=1;
}
else
{
*useStdrr=0;
}
}
else if(!strcmp(atribute,"request_count"))
{
*maxRequests=atoi(value);
}
else if(!strcmp(atribute,"request_*timeOut"))
{
*timeOut=atoi(value);
}
}
}
}
Now the real QUESTION: Do i have to do something different to connect froma java client to a C from the C server than what i do to connect to another C client? If the answer is no then the problem is in the java project? they tell me its working fine but I think they have tested it with a JAVA server.. Is there any diference? If the problem is in the java project what should i tell them to change for it to work with my C server?
Many thx !!!
Alejandro Casas
There is no such thing as a UDP connection. In UDP, a program just tosses packets at a given port at a given IP. If there is nothing listening at that IP/port, or the receiving program decides to ignore the UDP packets, it gets dropped. If you want an actual connection, you would use TCP.
In addition, some ISP block some types of UDP packets by default
In Java, a TCP socket is called a Socket and a UDP socket is called a DatagramSocket. Make sure you are sending from a DatagramSocket on your Java client.
I haven't done socket programming in C though.
Finally, it would help if you posted some of your Java code.
This is a great example on how to start developing a Java client/server.
Notice it comes from "Computer Networking: A Top Down Approach", by Kurose and Ross
The book has both UDP/TCP examples in JAVA, which are great and I recommend you.
The UDP server/client:
http://systembash.com/content/a-simple-java-udp-server-and-udp-client/
The TCP server/client:
http://systembash.com/content/a-simple-java-tcp-server-and-tcp-client/
I need to wrap a BSD-like C socket API to Java with JNA. It has basically the same functions as standard BSD socket API.
Wrapping select() is problematic because of the fd_set-structure required in its arguments and the FD_* masking functions (macros) that are needed to handle fd_sets. I tried to crawl through the header files (e.g. sys/select.h in Ubuntu 8.04) but the definitions are not so straightforward. Especially I found it difficult to find the implementation of FD_*-macros, which is needed when wrapping them with JNA's InvocationMapper.
Note: I'm not trying to wrap the standard TCP or unix-socket API, but a custom one. Thus built-in sockets in Java do not fit the bill.
Especially I found it difficult to find the implementation of FD_*-macros, which is needed when wrapping them with JNA's InvocationMapper.
The C pre-processor cpp is useful to find out how macros are expanded. Write a dummy program that uses the relevant macros (it should be lexically correct, but needn't compile), run it through cpp and watch what happens.
I use a byte array for the fd_set structure and some arithmetic to find the right byte position within the array:
private static final int FD_SETSIZE = 1024;
private static final boolean isBigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
private static interface Libc extends Library {
int select (int nfds, byte[] readfds, byte[] writefds, byte[] errfds, TimeVal timeout);
//...
}
private static class FdSet {
byte[] a;
FdSet() {
a = new byte[FD_SETSIZE / 8]; }
void set (int fd) {
a[getBytePos(fd)] |= getBitMask(fd); }
boolean isSet (int fd) {
return (a[getBytePos(fd)] & getBitMask(fd)) != 0; }
private static int getBytePos (int fd) {
if (fd < 0 || fd >= LibcDefs.FD_SETSIZE) {
throw new RuntimeException("File handle out of range for fd_set."); }
if (isBigEndian) {
return (fd / 8 / Native.LONG_SIZE + 1) * Native.LONG_SIZE - 1 -
fd / 8 % Native.LONG_SIZE; }
else {
return fd / 8; }}
private static int getBitMask (int fd) {
return 1 << (fd % 8); }}
private static class TimeVal extends Structure {
public NativeLong tv_sec;
public NativeLong tv_usec;
TimeVal (int ms) {
set(ms); }
void set (int ms) {
tv_sec.setValue(ms / 1000);
tv_usec.setValue(ms % 1000 * 1000); }
#Override protected List<?> getFieldOrder() {
return Arrays.asList("tv_sec", "tv_usec"); }}
public boolean waitInputReady (int timeoutMs) throws IOException {
TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
FdSet rxSet = new FdSet();
FdSet errorSet = new FdSet();
rxSet.set(fileHandle);
errorSet.set(fileHandle);
int rc = libc.select(fileHandle + 1, rxSet.a, null, errorSet.a, timeVal);
checkSelectErrors(rc, errorSet);
if (rc == 0) {
return false; }
if (!rxSet.isSet(fileHandle)) {
throw new RuntimeException("rxSet bit is not set after select()."); }
return true; }
public boolean waitOutputReady (int timeoutMs) throws IOException {
TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
FdSet txSet = new FdSet();
FdSet errorSet = new FdSet();
txSet.set(fileHandle);
errorSet.set(fileHandle);
int rc = libc.select(fileHandle + 1, null, txSet.a, errorSet.a, timeVal);
checkSelectErrors(rc, errorSet);
if (rc == 0) {
return false; }
if (!txSet.isSet(fileHandle)) {
throw new RuntimeException("txSet bit is not set after select()."); }
return true; }
private void checkSelectErrors (int rc, FdSet errorSet) throws IOException {
if (rc == -1) {
throw new IOException("Error in select(), errno=" + Native.getLastError() + "."); }
boolean error = errorSet.isSet(fileHandle);
if (!(rc == 0 && !error || rc == 1 || rc == 2 && error)) {
throw new RuntimeException("Invalid return code received from select(), rc=" + rc + ", error=" + error + "."); }
if (error) {
throw new IOException("Channel error state detected"); }}