sigar/bindings/java/src/jni/javasigar.c
2007-09-16 18:35:25 +00:00

1618 lines
40 KiB
C

/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
#include <jni.h>
#include "sigar.h"
#include "sigar_fileinfo.h"
#include "sigar_log.h"
#include "sigar_private.h"
#include "sigar_ptql.h"
#include "sigar_util.h"
#include "sigar_os.h"
#include "sigar_format.h"
#include <string.h>
#ifdef WIN32
#include <winsock.h>
#else
#include <errno.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#endif
#include "javasigar_generated.h"
#include "javasigar.h"
#ifdef SIGAR_64BIT
#define SIGAR_POINTER_LONG
#endif
typedef struct {
jclass classref;
jfieldID *ids;
} jsigar_field_cache_t;
typedef struct {
JNIEnv *env;
jobject logger;
sigar_t *sigar;
jsigar_field_cache_t *fields[JSIGAR_FIELDS_MAX];
int open_status;
jthrowable not_impl;
} jni_sigar_t;
#define dSIGAR_GET \
jni_sigar_t *jsigar = sigar_get_jpointer(env, sigar_obj); \
sigar_t *sigar
#define dSIGAR_VOID \
dSIGAR_GET; \
if (!jsigar) return; \
sigar = jsigar->sigar; \
jsigar->env = env
#define dSIGAR(val) \
dSIGAR_GET; \
if (!jsigar) return val; \
sigar = jsigar->sigar; \
jsigar->env = env
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved)
{
#ifdef DMALLOC
char *options =
getenv("DMALLOC_OPTIONS");
if (!options) {
options =
"debug=0x4f47d03,"
"lockon=20,"
"log=dmalloc-sigar.log";
}
dmalloc_debug_setup(options);
#endif
return JNI_VERSION_1_2;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved)
{
#ifdef DMALLOC
dmalloc_shutdown();
#endif
}
static void sigar_throw_exception(JNIEnv *env, char *msg)
{
jclass errorClass = SIGAR_FIND_CLASS("SigarException");
JENV->ThrowNew(env, errorClass, msg);
}
#define SIGAR_NOTIMPL_EX "SigarNotImplementedException"
static void sigar_throw_notimpl(JNIEnv *env, char *msg)
{
jclass errorClass = SIGAR_FIND_CLASS(SIGAR_NOTIMPL_EX);
JENV->ThrowNew(env, errorClass, msg);
}
static void sigar_throw_ptql_malformed(JNIEnv *env, char *msg)
{
jclass errorClass = SIGAR_FIND_CLASS("ptql/MalformedQueryException");
JENV->ThrowNew(env, errorClass, msg);
}
static void sigar_throw_error(JNIEnv *env, jni_sigar_t *jsigar, int err)
{
jclass errorClass;
int err_type = err;
/*
* support:
* #define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES)
* this allows for os impl specific message
* (e.g. Failed to open /dev/kmem) but still map to the proper
* Sigar*Exception
*/
if (err_type > SIGAR_OS_START_ERROR) {
err_type -= SIGAR_OS_START_ERROR;
}
switch (err_type) {
case SIGAR_ENOENT:
errorClass = SIGAR_FIND_CLASS("SigarFileNotFoundException");
break;
case SIGAR_EACCES:
errorClass = SIGAR_FIND_CLASS("SigarPermissionDeniedException");
break;
case SIGAR_ENOTIMPL:
if (jsigar->not_impl == NULL) {
jfieldID id;
jthrowable not_impl;
errorClass = SIGAR_FIND_CLASS(SIGAR_NOTIMPL_EX);
id = JENV->GetStaticFieldID(env, errorClass,
"INSTANCE",
SIGAR_CLASS_SIG(SIGAR_NOTIMPL_EX));
not_impl = JENV->GetStaticObjectField(env, errorClass, id);
jsigar->not_impl = JENV->NewGlobalRef(env, not_impl);
}
JENV->Throw(env, jsigar->not_impl);
return;
default:
errorClass = SIGAR_FIND_CLASS("SigarException");
break;
}
JENV->ThrowNew(env, errorClass,
sigar_strerror(jsigar->sigar, err));
}
static void *sigar_get_pointer(JNIEnv *env, jobject obj) {
jfieldID pointer_field;
jclass cls = JENV->GetObjectClass(env, obj);
#ifdef SIGAR_POINTER_LONG
pointer_field = JENV->GetFieldID(env, cls, "longSigarWrapper", "J");
return (void *)JENV->GetLongField(env, obj, pointer_field);
#else
pointer_field = JENV->GetFieldID(env, cls, "sigarWrapper", "I");
return (void *)JENV->GetIntField(env, obj, pointer_field);
#endif
}
static jni_sigar_t *sigar_get_jpointer(JNIEnv *env, jobject obj) {
jni_sigar_t *jsigar =
(jni_sigar_t *)sigar_get_pointer(env, obj);
if (!jsigar) {
sigar_throw_exception(env, "sigar has been closed");
return NULL;
}
if (jsigar->open_status != SIGAR_OK) {
sigar_throw_error(env, jsigar,
jsigar->open_status);
return NULL;
}
return jsigar;
}
static void sigar_set_pointer(JNIEnv *env, jobject obj, const void *ptr) {
jfieldID pointer_field;
jclass cls = JENV->GetObjectClass(env, obj);
#ifdef SIGAR_POINTER_LONG
pointer_field = JENV->GetFieldID(env, cls, "longSigarWrapper", "J");
JENV->SetLongField(env, obj, pointer_field, (jlong)ptr);
#else
pointer_field = JENV->GetFieldID(env, cls, "sigarWrapper", "I");
JENV->SetIntField(env, obj, pointer_field, (int)ptr);
#endif
}
JNIEXPORT jstring SIGAR_JNIx(formatSize)
(JNIEnv *env, jclass cls, jlong size)
{
char buf[56];
sigar_format_size(size, buf);
return JENV->NewStringUTF(env, buf);
}
JNIEXPORT jstring SIGAR_JNIx(getNativeVersion)
(JNIEnv *env, jclass cls)
{
sigar_version_t *version = sigar_version_get();
return JENV->NewStringUTF(env, version->version);
}
JNIEXPORT jstring SIGAR_JNIx(getNativeBuildDate)
(JNIEnv *env, jclass cls)
{
sigar_version_t *version = sigar_version_get();
return JENV->NewStringUTF(env, version->build_date);
}
JNIEXPORT void SIGAR_JNIx(open)
(JNIEnv *env, jobject obj)
{
jni_sigar_t *jsigar = malloc(sizeof(*jsigar));
memset(jsigar, '\0', sizeof(*jsigar));
sigar_set_pointer(env, obj, jsigar);
/* this method is called by the constructor.
* if != SIGAR_OK save status and throw exception
* when methods are invoked (see sigar_get_pointer).
*/
if ((jsigar->open_status = sigar_open(&jsigar->sigar)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, jsigar->open_status);
return;
}
}
JNIEXPORT jint SIGAR_JNIx(nativeClose)
(JNIEnv *env, jobject sigar_obj)
{
jint status;
int i;
dSIGAR(0);
/* only place it is possible this would be something other than
* SIGAR_OK is on win32 if RegCloseKey fails, which i don't think
* is possible either.
*/
status = sigar_close(sigar);
if (jsigar->logger != NULL) {
JENV->DeleteGlobalRef(env, jsigar->logger);
}
if (jsigar->not_impl != NULL) {
JENV->DeleteGlobalRef(env, jsigar->not_impl);
}
for (i=0; i<JSIGAR_FIELDS_MAX; i++) {
if (jsigar->fields[i]) {
JENV->DeleteGlobalRef(env,
jsigar->fields[i]->classref);
free(jsigar->fields[i]->ids);
free(jsigar->fields[i]);
}
}
free(jsigar);
sigar_set_pointer(env, sigar_obj, NULL);
return status;
}
JNIEXPORT jlong SIGAR_JNIx(getPid)
(JNIEnv *env, jobject sigar_obj)
{
dSIGAR(0);
return sigar_pid_get(sigar);
}
JNIEXPORT void SIGAR_JNIx(kill)
(JNIEnv *env, jobject sigar_obj, jlong pid, jint signum)
{
int status;
dSIGAR_VOID;
if ((status = sigar_proc_kill(pid, signum)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
}
}
JNIEXPORT jint SIGAR_JNIx(getSigNum)
(JNIEnv *env, jclass cls_obj, jstring jname)
{
jboolean is_copy;
const char *name;
int num;
name = JENV->GetStringUTFChars(env, jname, &is_copy);
num = sigar_signum_get((char *)name);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, jname, name);
}
return num;
}
#define SetStringField(env, obj, fieldID, val) \
SetObjectField(env, obj, fieldID, JENV->NewStringUTF(env, val))
static jstring jnet_address_to_string(JNIEnv *env, sigar_t *sigar, sigar_net_address_t *val) {
char addr_str[SIGAR_INET6_ADDRSTRLEN];
sigar_net_address_to_string(sigar, val, addr_str);
return JENV->NewStringUTF(env, addr_str);
}
#define SetNetAddressField(env, obj, fieldID, val) \
SetObjectField(env, obj, fieldID, jnet_address_to_string(env, sigar, &val))
#include "javasigar_generated.c"
#define SIGAR_ALLOC_OBJECT(name) \
JENV->AllocObject(env, SIGAR_FIND_CLASS(name))
enum {
FS_FIELD_DIRNAME,
FS_FIELD_DEVNAME,
FS_FIELD_SYS_TYPENAME,
FS_FIELD_TYPE,
FS_FIELD_TYPENAME,
FS_FIELD_MAX
};
#define STRING_SIG "Ljava/lang/String;"
JNIEXPORT jobjectArray SIGAR_JNIx(getFileSystemListNative)
(JNIEnv *env, jobject sigar_obj)
{
int status;
unsigned int i;
sigar_file_system_list_t fslist;
jobjectArray fsarray;
jfieldID ids[FS_FIELD_MAX];
jclass nfs_cls=NULL, cls = SIGAR_FIND_CLASS("FileSystem");
dSIGAR(NULL);
if ((status = sigar_file_system_list_get(sigar, &fslist)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
ids[FS_FIELD_DIRNAME] =
JENV->GetFieldID(env, cls, "dirName", STRING_SIG);
ids[FS_FIELD_DEVNAME] =
JENV->GetFieldID(env, cls, "devName", STRING_SIG);
ids[FS_FIELD_TYPENAME] =
JENV->GetFieldID(env, cls, "typeName", STRING_SIG);
ids[FS_FIELD_SYS_TYPENAME] =
JENV->GetFieldID(env, cls, "sysTypeName", STRING_SIG);
ids[FS_FIELD_TYPE] =
JENV->GetFieldID(env, cls, "type", "I");
fsarray = JENV->NewObjectArray(env, fslist.number, cls, 0);
for (i=0; i<fslist.number; i++) {
sigar_file_system_t *fs = &(fslist.data)[i];
jobject fsobj;
jclass obj_cls;
#ifdef WIN32
obj_cls = cls;
#else
if ((fs->type == SIGAR_FSTYPE_NETWORK) &&
(strcmp(fs->sys_type_name, "nfs") == 0) &&
strstr(fs->dev_name, ":/"))
{
if (!nfs_cls) {
nfs_cls = SIGAR_FIND_CLASS("NfsFileSystem");
}
obj_cls = nfs_cls;
}
else {
obj_cls = cls;
}
#endif
fsobj = JENV->AllocObject(env, obj_cls);
JENV->SetStringField(env, fsobj,
ids[FS_FIELD_DIRNAME],
fs->dir_name);
JENV->SetStringField(env, fsobj,
ids[FS_FIELD_DEVNAME],
fs->dev_name);
JENV->SetStringField(env, fsobj,
ids[FS_FIELD_SYS_TYPENAME],
fs->sys_type_name);
JENV->SetStringField(env, fsobj,
ids[FS_FIELD_TYPENAME],
fs->type_name);
JENV->SetIntField(env, fsobj,
ids[FS_FIELD_TYPE],
fs->type);
JENV->SetObjectArrayElement(env, fsarray, i, fsobj);
}
sigar_file_system_list_destroy(sigar, &fslist);
return fsarray;
}
JNIEXPORT jint SIGAR_JNI(RPC_ping)
(JNIEnv *env, jclass cls_obj, jstring jhostname,
jint protocol, jlong program, jlong version)
{
#ifdef WIN32
return JNI_FALSE; /*XXX*/
#else
jboolean is_copy;
const char *hostname;
int status;
if (!jhostname) {
return 13; /* RPC_UNKNOWNHOST */
}
hostname = JENV->GetStringUTFChars(env, jhostname, &is_copy);
status =
sigar_rpc_ping((char *)hostname,
protocol, program, version);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, jhostname, hostname);
}
return status;
#endif
}
JNIEXPORT jstring SIGAR_JNI(RPC_strerror)
(JNIEnv *env, jclass cls_obj, jint err)
{
#ifdef WIN32
return NULL;
#else
return JENV->NewStringUTF(env, sigar_rpc_strerror(err));
#endif
}
JNIEXPORT jobjectArray SIGAR_JNIx(getCpuInfoList)
(JNIEnv *env, jobject sigar_obj)
{
int status;
unsigned int i;
sigar_cpu_info_list_t cpu_infos;
jobjectArray cpuarray;
jclass cls = SIGAR_FIND_CLASS("CpuInfo");
dSIGAR(NULL);
if ((status = sigar_cpu_info_list_get(sigar, &cpu_infos)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
JAVA_SIGAR_INIT_FIELDS_CPUINFO(cls);
cpuarray = JENV->NewObjectArray(env, cpu_infos.number, cls, 0);
for (i=0; i<cpu_infos.number; i++) {
jobject info_obj = JENV->AllocObject(env, cls);
JAVA_SIGAR_SET_FIELDS_CPUINFO(cls, info_obj,
cpu_infos.data[i]);
JENV->SetObjectArrayElement(env, cpuarray, i, info_obj);
}
sigar_cpu_info_list_destroy(sigar, &cpu_infos);
return cpuarray;
}
JNIEXPORT jobjectArray SIGAR_JNIx(getCpuListNative)
(JNIEnv *env, jobject sigar_obj)
{
int status;
unsigned int i;
sigar_cpu_list_t cpulist;
jobjectArray cpuarray;
jclass cls = SIGAR_FIND_CLASS("Cpu");
dSIGAR(NULL);
if ((status = sigar_cpu_list_get(sigar, &cpulist)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
JAVA_SIGAR_INIT_FIELDS_CPU(cls);
cpuarray = JENV->NewObjectArray(env, cpulist.number, cls, 0);
for (i=0; i<cpulist.number; i++) {
jobject info_obj = JENV->AllocObject(env, cls);
JAVA_SIGAR_SET_FIELDS_CPU(cls, info_obj,
cpulist.data[i]);
JENV->SetObjectArrayElement(env, cpuarray, i, info_obj);
}
sigar_cpu_list_destroy(sigar, &cpulist);
return cpuarray;
}
JNIEXPORT jlongArray SIGAR_JNIx(getProcList)
(JNIEnv *env, jobject sigar_obj)
{
int status;
jlongArray procarray;
sigar_proc_list_t proclist;
jlong *pids = NULL;
dSIGAR(NULL);
if ((status = sigar_proc_list_get(sigar, &proclist)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
procarray = JENV->NewLongArray(env, proclist.number);
if (sizeof(jlong) == sizeof(sigar_pid_t)) {
pids = (jlong *)proclist.data;
}
else {
unsigned int i;
pids = (jlong *)malloc(sizeof(jlong) * proclist.number);
for (i=0; i<proclist.number; i++) {
pids[i] = proclist.data[i];
}
}
JENV->SetLongArrayRegion(env, procarray, 0,
proclist.number, pids);
if (pids != (jlong *)proclist.data) {
free(pids);
}
sigar_proc_list_destroy(sigar, &proclist);
return procarray;
}
JNIEXPORT jobjectArray SIGAR_JNIx(getProcArgs)
(JNIEnv *env, jobject sigar_obj, jlong pid)
{
int status;
unsigned int i;
sigar_proc_args_t procargs;
jobjectArray argsarray;
jclass stringclass = JENV->FindClass(env, "java/lang/String");
dSIGAR(NULL);
if ((status = sigar_proc_args_get(sigar, pid, &procargs)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
argsarray = JENV->NewObjectArray(env, procargs.number, stringclass, 0);
for (i=0; i<procargs.number; i++) {
jstring s = JENV->NewStringUTF(env, procargs.data[i]);
JENV->SetObjectArrayElement(env, argsarray, i, s);
}
sigar_proc_args_destroy(sigar, &procargs);
return argsarray;
}
typedef struct {
JNIEnv *env;
jobject map;
jmethodID id;
} jni_env_put_t;
static int jni_env_getall(void *data,
const char *key, int klen,
char *val, int vlen)
{
jni_env_put_t *put = (jni_env_put_t *)data;
JNIEnv *env = put->env;
JENV->CallObjectMethod(env, put->map, put->id,
JENV->NewStringUTF(env, key),
JENV->NewStringUTF(env, val));
return SIGAR_OK;
}
JNIEXPORT jobject SIGAR_JNI(ProcEnv_getAll)
(JNIEnv *env, jobject cls, jobject sigar_obj, jlong pid)
{
int status;
sigar_proc_env_t procenv;
jobject hashmap;
jni_env_put_t put;
jclass mapclass =
JENV->FindClass(env, "java/util/HashMap");
jmethodID mapid =
JENV->GetMethodID(env, mapclass, "<init>", "()V");
jmethodID putid =
JENV->GetMethodID(env, mapclass, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)"
"Ljava/lang/Object;");
dSIGAR(NULL);
hashmap = JENV->NewObject(env, mapclass, mapid);
put.env = env;
put.id = putid;
put.map = hashmap;
procenv.type = SIGAR_PROC_ENV_ALL;
procenv.env_getter = jni_env_getall;
procenv.data = &put;
if ((status = sigar_proc_env_get(sigar, pid, &procenv)) != SIGAR_OK) {
JENV->DeleteLocalRef(env, hashmap);
sigar_throw_error(env, jsigar, status);
return NULL;
}
return hashmap;
}
typedef struct {
JNIEnv *env;
const char *key;
int klen;
jstring val;
} jni_env_get_t;
static int jni_env_getvalue(void *data,
const char *key, int klen,
char *val, int vlen)
{
jni_env_get_t *get = (jni_env_get_t *)data;
JNIEnv *env = get->env;
if ((get->klen == klen) &&
(strcmp(get->key, key) == 0))
{
get->val = JENV->NewStringUTF(env, val);
return !SIGAR_OK; /* foundit; stop iterating */
}
return SIGAR_OK;
}
JNIEXPORT jstring SIGAR_JNI(ProcEnv_getValue)
(JNIEnv *env, jobject cls, jobject sigar_obj, jlong pid, jstring key)
{
int status;
sigar_proc_env_t procenv;
jni_env_get_t get;
dSIGAR(NULL);
get.env = env;
get.key = JENV->GetStringUTFChars(env, key, 0);
get.klen = JENV->GetStringUTFLength(env, key);
get.val = NULL;
procenv.type = SIGAR_PROC_ENV_KEY;
procenv.key = get.key;
procenv.klen = get.klen;
procenv.env_getter = jni_env_getvalue;
procenv.data = &get;
if ((status = sigar_proc_env_get(sigar, pid, &procenv)) != SIGAR_OK) {
JENV->ReleaseStringUTFChars(env, key, get.key);
sigar_throw_error(env, jsigar, status);
return NULL;
}
JENV->ReleaseStringUTFChars(env, key, get.key);
return get.val;
}
typedef struct {
JNIEnv *env;
jobject listobj;
jmethodID id;
} jni_proc_module_t;
static int jni_proc_module_get(void *data,
char *name, int len)
{
jni_proc_module_t *module = (jni_proc_module_t *)data;
JNIEnv *env = module->env;
JENV->CallBooleanMethod(env, module->listobj, module->id,
JENV->NewStringUTF(env, name));
return SIGAR_OK;
}
JNIEXPORT jobject SIGAR_JNIx(getProcModulesNative)
(JNIEnv *env, jobject sigar_obj, jlong pid)
{
int status;
sigar_proc_modules_t procmods;
jobject listobj;
jni_proc_module_t module;
jclass listclass =
JENV->FindClass(env, "java/util/ArrayList");
jmethodID listid =
JENV->GetMethodID(env, listclass, "<init>", "()V");
jmethodID addid =
JENV->GetMethodID(env, listclass, "add",
"(Ljava/lang/Object;)"
"Z");
dSIGAR(NULL);
listobj = JENV->NewObject(env, listclass, listid);
module.env = env;
module.id = addid;
module.listobj = listobj;
procmods.module_getter = jni_proc_module_get;
procmods.data = &module;
if ((status = sigar_proc_modules_get(sigar, pid, &procmods)) != SIGAR_OK) {
JENV->DeleteLocalRef(env, listobj);
sigar_throw_error(env, jsigar, status);
return NULL;
}
return listobj;
}
JNIEXPORT jdoubleArray SIGAR_JNIx(getLoadAverage)
(JNIEnv *env, jobject sigar_obj)
{
int status;
jlongArray avgarray;
sigar_loadavg_t loadavg;
dSIGAR(NULL);
if ((status = sigar_loadavg_get(sigar, &loadavg)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
avgarray = JENV->NewDoubleArray(env, 3);
JENV->SetDoubleArrayRegion(env, avgarray, 0,
3, loadavg.loadavg);
return avgarray;
}
JNIEXPORT jobjectArray SIGAR_JNIx(getNetRouteList)
(JNIEnv *env, jobject sigar_obj)
{
int status;
unsigned int i;
jarray routearray;
jclass cls = SIGAR_FIND_CLASS("NetRoute");
sigar_net_route_list_t routelist;
dSIGAR(NULL);
if ((status = sigar_net_route_list_get(sigar, &routelist)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
JAVA_SIGAR_INIT_FIELDS_NETROUTE(cls);
routearray = JENV->NewObjectArray(env, routelist.number, cls, 0);
for (i=0; i<routelist.number; i++) {
jobject obj = JENV->AllocObject(env, cls);
JAVA_SIGAR_SET_FIELDS_NETROUTE(cls, obj, routelist.data[i]);
JENV->SetObjectArrayElement(env, routearray, i, obj);
}
sigar_net_route_list_destroy(sigar, &routelist);
return routearray;
}
JNIEXPORT jstring SIGAR_JNI(NetFlags_getIfFlagsString)
(JNIEnv *env, jclass cls, jlong flags)
{
char buf[1024];
sigar_net_interface_flags_to_string(flags, buf);
return JENV->NewStringUTF(env, buf);
}
JNIEXPORT jobjectArray SIGAR_JNIx(getNetConnectionList)
(JNIEnv *env, jobject sigar_obj, jint flags)
{
int status;
unsigned int i;
jarray connarray;
jclass cls = SIGAR_FIND_CLASS("NetConnection");
sigar_net_connection_list_t connlist;
dSIGAR(NULL);
status = sigar_net_connection_list_get(sigar, &connlist, flags);
if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
JAVA_SIGAR_INIT_FIELDS_NETCONNECTION(cls);
connarray = JENV->NewObjectArray(env, connlist.number, cls, 0);
for (i=0; i<connlist.number; i++) {
jobject obj = JENV->AllocObject(env, cls);
JAVA_SIGAR_SET_FIELDS_NETCONNECTION(cls, obj, connlist.data[i]);
JENV->SetObjectArrayElement(env, connarray, i, obj);
}
sigar_net_connection_list_destroy(sigar, &connlist);
return connarray;
}
static int jbyteArray_to_sigar_net_address(JNIEnv *env, jbyteArray jaddress,
sigar_net_address_t *address)
{
jsize len = JENV->GetArrayLength(env, jaddress);
JENV->GetByteArrayRegion(env, jaddress, 0, len,
(jbyte *)&address->addr.in6);
switch (len) {
case 4:
address->family = SIGAR_AF_INET;
break;
case 4*4:
address->family = SIGAR_AF_INET6;
break;
default:
return EINVAL;
}
return SIGAR_OK;
}
JNIEXPORT void SIGAR_JNI(NetStat_stat)
(JNIEnv *env, jobject obj, jobject sigar_obj, jint flags,
jbyteArray jaddress, jlong port)
{
int status;
sigar_net_stat_t netstat;
jclass cls;
jfieldID id;
jintArray states;
jint tcp_states[SIGAR_TCP_UNKNOWN];
sigar_net_address_t address;
jboolean has_port = (port != -1);
dSIGAR_VOID;
if (has_port) {
status = jbyteArray_to_sigar_net_address(env, jaddress, &address);
if (status == SIGAR_OK) {
status = sigar_net_stat_port_get(sigar, &netstat, flags,
&address, port);
}
}
else {
status = sigar_net_stat_get(sigar, &netstat, flags);
}
if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return;
}
cls = JENV->GetObjectClass(env, obj);
JAVA_SIGAR_INIT_FIELDS_NETSTAT(cls);
JAVA_SIGAR_SET_FIELDS_NETSTAT(cls, obj, netstat);
if (sizeof(tcp_states[0]) == sizeof(netstat.tcp_states[0])) {
memcpy(&tcp_states[0], &netstat.tcp_states[0],
sizeof(netstat.tcp_states));
}
else {
int i;
for (i=0; i<SIGAR_TCP_UNKNOWN; i++) {
tcp_states[i] = netstat.tcp_states[i];
}
}
states = JENV->NewIntArray(env, SIGAR_TCP_UNKNOWN);
JENV->SetIntArrayRegion(env, states, 0,
SIGAR_TCP_UNKNOWN,
tcp_states);
id = JENV->GetFieldID(env, cls, "tcpStates", "[I");
JENV->SetObjectField(env, obj, id, states);
}
JNIEXPORT jstring SIGAR_JNIx(getNetListenAddress)
(JNIEnv *env, jobject sigar_obj, jlong port)
{
int status;
sigar_net_address_t address;
dSIGAR(NULL);
status = sigar_net_listen_address_get(sigar, port, &address);
if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
return jnet_address_to_string(env, sigar, &address);
}
JNIEXPORT jstring SIGAR_JNIx(getNetServicesName)
(JNIEnv *env, jobject sigar_obj, jint protocol, jlong port)
{
char *name;
dSIGAR(NULL);
if ((name = sigar_net_services_name_get(sigar, protocol, port))) {
return JENV->NewStringUTF(env, name);
}
else {
return NULL;
}
}
JNIEXPORT jstring SIGAR_JNI(NetConnection_getTypeString)
(JNIEnv *env, jobject obj)
{
jclass cls = JENV->GetObjectClass(env, obj);
jfieldID field = JENV->GetFieldID(env, cls, "type", "I");
jint type = JENV->GetIntField(env, obj, field);
return JENV->NewStringUTF(env,
sigar_net_connection_type_get(type));
}
JNIEXPORT jstring SIGAR_JNI(NetConnection_getStateString)
(JNIEnv *env, jobject cls, jint state)
{
return JENV->NewStringUTF(env,
sigar_net_connection_state_get(state));
}
JNIEXPORT jobjectArray SIGAR_JNIx(getWhoList)
(JNIEnv *env, jobject sigar_obj)
{
int status;
unsigned int i;
sigar_who_list_t wholist;
jobjectArray whoarray;
jclass cls = SIGAR_FIND_CLASS("Who");
dSIGAR(NULL);
if ((status = sigar_who_list_get(sigar, &wholist)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
JAVA_SIGAR_INIT_FIELDS_WHO(cls);
whoarray = JENV->NewObjectArray(env, wholist.number, cls, 0);
for (i=0; i<wholist.number; i++) {
jobject info_obj = JENV->AllocObject(env, cls);
JAVA_SIGAR_SET_FIELDS_WHO(cls, info_obj,
wholist.data[i]);
JENV->SetObjectArrayElement(env, whoarray, i, info_obj);
}
sigar_who_list_destroy(sigar, &wholist);
return whoarray;
}
/* XXX perhaps it would be better to duplicate these strings
* in java land as static final so we dont create a new String
* everytime.
*/
JNIEXPORT jstring SIGAR_JNI(FileInfo_getTypeString)
(JNIEnv *env, jclass cls, jint type)
{
return JENV->NewStringUTF(env,
sigar_file_attrs_type_string_get(type));
}
JNIEXPORT jstring SIGAR_JNI(FileInfo_getPermissionsString)
(JNIEnv *env, jclass cls, jlong perms)
{
char str[24];
return JENV->NewStringUTF(env,
sigar_file_attrs_permissions_string_get(perms,
str));
}
JNIEXPORT jint SIGAR_JNI(FileInfo_getMode)
(JNIEnv *env, jclass cls, jlong perms)
{
return sigar_file_attrs_mode_get(perms);
}
/*
* copy of the generated FileAttrs_gather function
* but we call the lstat wrapper instead.
*/
JNIEXPORT void SIGAR_JNI(FileInfo_gatherLink)
(JNIEnv *env, jobject obj, jobject sigar_obj, jstring name)
{
sigar_file_attrs_t s;
int status;
jclass cls = JENV->GetObjectClass(env, obj);
const char *utf;
dSIGAR_VOID;
utf = JENV->GetStringUTFChars(env, name, 0);
status = sigar_link_attrs_get(sigar, utf, &s);
JENV->ReleaseStringUTFChars(env, name, utf);
if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return;
}
JAVA_SIGAR_INIT_FIELDS_FILEATTRS(cls);
JAVA_SIGAR_SET_FIELDS_FILEATTRS(cls, obj, s);
}
JNIEXPORT jlong SIGAR_JNIx(getProcPort)
(JNIEnv *env, jobject sigar_obj, jint protocol, jlong port)
{
int status;
sigar_pid_t pid;
dSIGAR(0);
status = sigar_proc_port_get(sigar, protocol,
(unsigned long)port, &pid);
if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return -1;
}
return pid;
}
JNIEXPORT jobjectArray SIGAR_JNIx(getNetInterfaceList)
(JNIEnv *env, jobject sigar_obj)
{
int status;
unsigned int i;
sigar_net_interface_list_t iflist;
jobjectArray ifarray;
jclass stringclass = JENV->FindClass(env, "java/lang/String");
dSIGAR(NULL);
if ((status = sigar_net_interface_list_get(sigar, &iflist)) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
ifarray = JENV->NewObjectArray(env, iflist.number, stringclass, 0);
for (i=0; i<iflist.number; i++) {
jstring s = JENV->NewStringUTF(env, iflist.data[i]);
JENV->SetObjectArrayElement(env, ifarray, i, s);
}
sigar_net_interface_list_destroy(sigar, &iflist);
return ifarray;
}
JNIEXPORT jstring SIGAR_JNIx(getPasswordNative)
(JNIEnv *env, jclass classinstance, jstring prompt)
{
const char *prompt_str;
char *password;
if (getenv("NO_NATIVE_GETPASS")) {
sigar_throw_notimpl(env, "disabled with $NO_NATIVE_GETPASS");
return NULL;
}
prompt_str = JENV->GetStringUTFChars(env, prompt, 0);
password = sigar_password_get(prompt_str);
JENV->ReleaseStringUTFChars(env, prompt, prompt_str);
return JENV->NewStringUTF(env, password);
}
JNIEXPORT jstring SIGAR_JNIx(getFQDN)
(JNIEnv *env, jobject sigar_obj)
{
char fqdn[SIGAR_FQDN_LEN];
int status;
dSIGAR(NULL);
if ((status = sigar_fqdn_get(sigar, fqdn, sizeof(fqdn))) != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
return JENV->NewStringUTF(env, fqdn);
}
typedef struct {
JNIEnv *env;
jobject obj;
jclass cls;
jmethodID id;
} jni_ptql_re_data_t;
static int jsigar_ptql_re_impl(void *data,
char *haystack, char *needle)
{
jni_ptql_re_data_t *re = (jni_ptql_re_data_t *)data;
JNIEnv *env = re->env;
if (!re->cls) {
re->cls = JENV->GetObjectClass(env, re->obj);
re->id =
JENV->GetStaticMethodID(env, re->cls, "re",
"(Ljava/lang/String;Ljava/lang/String;)"
"Z");
if (!re->id) {
return 0;
}
}
return JENV->CallStaticBooleanMethod(env, re->cls, re->id,
JENV->NewStringUTF(env, haystack),
JENV->NewStringUTF(env, needle));
}
static void re_impl_set(JNIEnv *env, sigar_t *sigar, jobject obj, jni_ptql_re_data_t *re)
{
re->env = env;
re->cls = NULL;
re->obj = obj;
re->id = NULL;
sigar_ptql_re_impl_set(sigar, re, jsigar_ptql_re_impl);
}
JNIEXPORT jboolean SIGAR_JNI(ptql_SigarProcessQuery_match)
(JNIEnv *env, jobject obj, jobject sigar_obj, jlong pid)
{
int status;
jni_ptql_re_data_t re;
sigar_ptql_query_t *query =
(sigar_ptql_query_t *)sigar_get_pointer(env, obj);
dSIGAR(JNI_FALSE);
re_impl_set(env, sigar, obj, &re);
status = sigar_ptql_query_match(sigar, query, pid);
sigar_ptql_re_impl_set(sigar, NULL, NULL);
if (status == SIGAR_OK) {
return JNI_TRUE;
}
else {
return JNI_FALSE;
}
}
JNIEXPORT void SIGAR_JNI(ptql_SigarProcessQuery_create)
(JNIEnv *env, jobject obj, jstring jptql)
{
int status;
jboolean is_copy;
const char *ptql;
sigar_ptql_query_t *query;
ptql = JENV->GetStringUTFChars(env, jptql, &is_copy);
status = sigar_ptql_query_create(&query, (char *)ptql);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, jptql, ptql);
}
if (status != SIGAR_OK) {
char buf[1024], *msg=buf;
if (status == SIGAR_PTQL_MALFORMED_QUERY) {
msg = "Malformed query";
}
else {
sigar_strerror_get(status, buf, sizeof(buf));
}
sigar_throw_ptql_malformed(env, msg);
}
else {
sigar_set_pointer(env, obj, query);
}
}
JNIEXPORT void SIGAR_JNI(ptql_SigarProcessQuery_destroy)
(JNIEnv *env, jobject obj)
{
sigar_ptql_query_t *query =
(sigar_ptql_query_t *)sigar_get_pointer(env, obj);
if (query) {
sigar_ptql_query_destroy(query);
sigar_set_pointer(env, obj, 0);
}
}
JNIEXPORT jlong SIGAR_JNI(ptql_SigarProcessQuery_findProcess)
(JNIEnv *env, jobject obj, jobject sigar_obj)
{
sigar_pid_t pid;
int status;
jni_ptql_re_data_t re;
sigar_ptql_query_t *query =
(sigar_ptql_query_t *)sigar_get_pointer(env, obj);
dSIGAR(0);
re_impl_set(env, sigar, obj, &re);
status = sigar_ptql_query_find_process(sigar, query, &pid);
sigar_ptql_re_impl_set(sigar, NULL, NULL);
if (status < 0) {
sigar_throw_exception(env, sigar->errbuf);
}
else if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
}
return pid;
}
JNIEXPORT jlongArray SIGAR_JNI(ptql_SigarProcessQuery_find)
(JNIEnv *env, jobject obj, jobject sigar_obj)
{
int status;
jlongArray procarray;
sigar_proc_list_t proclist;
jlong *pids = NULL;
jni_ptql_re_data_t re;
sigar_ptql_query_t *query =
(sigar_ptql_query_t *)sigar_get_pointer(env, obj);
dSIGAR(NULL);
re_impl_set(env, sigar, obj, &re);
status = sigar_ptql_query_find(sigar, query, &proclist);
sigar_ptql_re_impl_set(sigar, NULL, NULL);
if (status < 0) {
sigar_throw_exception(env, sigar->errbuf);
return NULL;
}
else if (status != SIGAR_OK) {
sigar_throw_error(env, jsigar, status);
return NULL;
}
procarray = JENV->NewLongArray(env, proclist.number);
if (sizeof(jlong) == sizeof(sigar_pid_t)) {
pids = (jlong *)proclist.data;
}
else {
unsigned int i;
pids = (jlong *)malloc(sizeof(jlong) * proclist.number);
for (i=0; i<proclist.number; i++) {
pids[i] = proclist.data[i];
}
}
JENV->SetLongArrayRegion(env, procarray, 0,
proclist.number, pids);
if (pids != (jlong *)proclist.data) {
free(pids);
}
sigar_proc_list_destroy(sigar, &proclist);
return procarray;
}
#include "sigar_getline.h"
JNIEXPORT jboolean SIGAR_JNI(util_Getline_isatty)
(JNIEnv *env, jclass cls)
{
return sigar_isatty(sigar_fileno(stdin)) ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT jstring SIGAR_JNI(util_Getline_getline)
(JNIEnv *env, jobject sigar_obj, jstring prompt)
{
const char *prompt_str;
char *line;
jboolean is_copy;
prompt_str = JENV->GetStringUTFChars(env, prompt, &is_copy);
line = sigar_getline((char *)prompt_str);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, prompt, prompt_str);
}
if ((line == NULL) ||
sigar_getline_eof())
{
jclass eof_ex = JENV->FindClass(env, "java/io/EOFException");
JENV->ThrowNew(env, eof_ex, "");
return NULL;
}
return JENV->NewStringUTF(env, line);
}
JNIEXPORT void SIGAR_JNI(util_Getline_histadd)
(JNIEnv *env, jobject sigar_obj, jstring hist)
{
const char *hist_str;
jboolean is_copy;
hist_str = JENV->GetStringUTFChars(env, hist, &is_copy);
sigar_getline_histadd((char *)hist_str);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, hist, hist_str);
}
}
JNIEXPORT void SIGAR_JNI(util_Getline_histinit)
(JNIEnv *env, jobject sigar_obj, jstring hist)
{
const char *hist_str;
jboolean is_copy;
hist_str = JENV->GetStringUTFChars(env, hist, &is_copy);
sigar_getline_histinit((char *)hist_str);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, hist, hist_str);
}
}
static struct {
JNIEnv *env;
jobject obj;
jmethodID id;
jclass clazz;
} jsigar_completer;
static int jsigar_getline_completer(char *buffer, int offset, int *pos)
{
JNIEnv *env = jsigar_completer.env;
jstring jbuffer;
jstring completion;
const char *line;
int len, cur;
jboolean is_copy;
jbuffer = JENV->NewStringUTF(env, buffer);
completion =
JENV->CallObjectMethod(env, jsigar_completer.obj,
jsigar_completer.id, jbuffer);
if (JENV->ExceptionOccurred(env)) {
JENV->ExceptionDescribe(env);
return 0;
}
if (!completion) {
return 0;
}
line = JENV->GetStringUTFChars(env, completion, &is_copy);
len = JENV->GetStringUTFLength(env, completion);
cur = *pos;
if (len != cur) {
strcpy(buffer, line);
*pos = len;
}
if (is_copy) {
JENV->ReleaseStringUTFChars(env, completion, line);
}
return cur;
}
JNIEXPORT void SIGAR_JNI(util_Getline_setCompleter)
(JNIEnv *env, jclass classinstance, jobject completer)
{
if (completer == NULL) {
sigar_getline_completer_set(NULL);
return;
}
jsigar_completer.env = env;
jsigar_completer.obj = completer;
jsigar_completer.clazz = JENV->GetObjectClass(env, completer);
jsigar_completer.id =
JENV->GetMethodID(env, jsigar_completer.clazz,
"complete",
"(Ljava/lang/String;)Ljava/lang/String;");
sigar_getline_completer_set(jsigar_getline_completer);
}
JNIEXPORT void SIGAR_JNI(util_Getline_redraw)
(JNIEnv *env, jobject obj)
{
sigar_getline_redraw();
}
JNIEXPORT void SIGAR_JNI(util_Getline_reset)
(JNIEnv *env, jobject obj)
{
sigar_getline_reset();
}
static const char *log_methods[] = {
"fatal", /* SIGAR_LOG_FATAL */
"error", /* SIGAR_LOG_ERROR */
"warn", /* SIGAR_LOG_WARN */
"info", /* SIGAR_LOG_INFO */
"debug", /* SIGAR_LOG_DEBUG */
/* XXX trace is only in commons-logging??? */
"debug", /* SIGAR_LOG_TRACE */
};
static void jsigar_log_impl(sigar_t *sigar, void *data,
int level, char *message)
{
jni_sigar_t *jsigar = (jni_sigar_t *)data;
JNIEnv *env = jsigar->env;
jobject logger = jsigar->logger;
jobject message_obj;
/* XXX should cache method id lookups */
jmethodID id =
JENV->GetMethodID(env, JENV->GetObjectClass(env, logger),
log_methods[level],
"(Ljava/lang/Object;)V");
if (JENV->ExceptionOccurred(env)) {
JENV->ExceptionDescribe(env);
return;
}
message_obj = (jobject)JENV->NewStringUTF(env, message);
JENV->CallVoidMethod(env, logger, id, message_obj);
}
JNIEXPORT void SIGAR_JNI(SigarLog_setLogger)
(JNIEnv *env, jclass classinstance, jobject sigar_obj, jobject logger)
{
dSIGAR_VOID;
if (jsigar->logger != NULL) {
JENV->DeleteGlobalRef(env, jsigar->logger);
jsigar->logger = NULL;
}
if (logger) {
jsigar->logger = JENV->NewGlobalRef(env, logger);
sigar_log_impl_set(sigar, jsigar, jsigar_log_impl);
}
else {
sigar_log_impl_set(sigar, NULL, NULL);
}
}
JNIEXPORT void SIGAR_JNI(SigarLog_setLevel)
(JNIEnv *env, jclass classinstance, jobject sigar_obj, jint level)
{
dSIGAR_VOID;
sigar_log_level_set(sigar, level);
}
JNIEXPORT jlong SIGAR_JNIx(getServicePid)
(JNIEnv *env, jobject sigar_obj, jstring jname)
{
#ifdef WIN32
const char *name;
jboolean is_copy;
jlong pid = 0;
int status;
dSIGAR(0);
name = JENV->GetStringUTFChars(env, jname, &is_copy);
status =
sigar_service_pid_get(sigar, (char *)name, &pid);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, jname, name);
}
if (status != ERROR_SUCCESS) {
sigar_throw_error(env, jsigar, status);
}
return pid;
#else
dSIGAR(0);
sigar_throw_error(env, jsigar, SIGAR_ENOTIMPL);
return 0;
#endif
}
JNIEXPORT jlong SIGAR_JNI(ResourceLimit_INFINITY)
(JNIEnv *env, jclass cls)
{
#ifdef WIN32
return 0x7fffffff;
#else
#include <sys/time.h>
#include <sys/resource.h>
return RLIM_INFINITY;
#endif
}
JNIEXPORT jstring SIGAR_JNI(win32_Win32_findExecutable)
(JNIEnv *env, jclass sigar_class, jstring jname)
{
#ifdef WIN32
#include "shellapi.h"
const char *name;
jboolean is_copy;
char exe[MAX_PATH];
LONG result;
jstring jexe = NULL;
name = JENV->GetStringUTFChars(env, jname, &is_copy);
if ((result = (LONG)FindExecutable(name, ".", exe)) > 32) {
jexe = JENV->NewStringUTF(env, exe);
}
if (is_copy) {
JENV->ReleaseStringUTFChars(env, jname, name);
}
return jexe;
#else
sigar_throw_notimpl(env, "win32 only");
return NULL;
#endif
}