Refactor native code and implement our own JNI wrapper around zlib.

The previous native cipher code has been refactored so that it may be loaded and used slightly more generically, allowing more native components to be easily added as time goes on.
I have also written a new native code compression module, which wraps around zlib in the same manner that Inflater / Deflater does, however it operates directly on the memory addresses of it's input / output buffers which means that we can save one, or maybe even two copies. To support this, the VarInt decoder has been adjusted to always use a native buffer.
This commit is contained in:
md_5
2015-02-01 21:05:16 +11:00
parent e6da9cbba8
commit 0d569ac0d1
29 changed files with 599 additions and 148 deletions

View File

@@ -1,11 +1,12 @@
#include <openssl/evp.h>
#include "net_md_5_bungee_NativeCipherImpl.h"
#include "net_md_5_bungee_jni_cipher_NativeCipherImpl.h"
typedef unsigned char byte;
jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init(JNIEnv* env, jobject obj, jboolean forEncryption, jbyteArray key) {
jlong JNICALL Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_init(JNIEnv* env, jobject obj, jboolean forEncryption, jbyteArray key) {
jbyte *keyBytes = env->GetByteArrayElements(key, NULL);
// TODO: Perhaps we need to throw some exceptions in the unlikely event this fails?
EVP_CIPHER_CTX *cipherCtx = EVP_CIPHER_CTX_new();
EVP_CipherInit(cipherCtx, EVP_aes_128_cfb8(), (byte*) keyBytes, (byte*) keyBytes, forEncryption);
@@ -13,10 +14,12 @@ jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init(JNIEnv* env, jobject o
return (jlong) cipherCtx;
}
void Java_net_md_15_bungee_NativeCipherImpl_free(JNIEnv* env, jobject obj, jlong ctx) {
void Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_free(JNIEnv* env, jobject obj, jlong ctx) {
// TODO: Perhaps we need to throw some exceptions in the unlikely event this fails?
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*) ctx);
}
void Java_net_md_15_bungee_NativeCipherImpl_cipher(JNIEnv* env, jobject obj, jlong ctx, jlong in, jlong out, jint length) {
void Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_cipher(JNIEnv* env, jobject obj, jlong ctx, jlong in, jlong out, jint length) {
// TODO: Perhaps we need to throw some exceptions in the unlikely event this fails?
EVP_CipherUpdate((EVP_CIPHER_CTX*) ctx, (byte*) out, &length, (byte*) in, length);
}

View File

@@ -0,0 +1,82 @@
#include <string>
#include <zlib.h>
#include "net_md_5_bungee_jni_zlib_NativeCompressImpl.h"
using namespace std;
typedef unsigned char byte;
jint throwException(JNIEnv *env, string message) {
jclass exClass = env->FindClass("java/lang/RuntimeException");
// Can never actually happen on a sane JVM, but better be safe anyway
if (exClass == NULL) {
return -1;
}
return env->ThrowNew(exClass, message.c_str());
}
static jfieldID consumedID;
static jfieldID finishedID;
void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_initFields(JNIEnv* env, jclass clazz) {
// We trust that these fields will be there
consumedID = env->GetFieldID(clazz, "consumed", "I");
finishedID = env->GetFieldID(clazz, "finished", "Z");
}
void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_reset(JNIEnv* env, jobject obj, jlong ctx, jboolean compress) {
z_stream* stream = (z_stream*) ctx;
int ret = (compress) ? deflateReset(stream) : inflateReset(stream);
if (ret != Z_OK) {
throwException(env, "Could not reset z_stream: " + to_string(ret));
}
}
void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_end(JNIEnv* env, jobject obj, jlong ctx, jboolean compress) {
z_stream* stream = (z_stream*) ctx;
int ret = (compress) ? deflateEnd(stream) : inflateEnd(stream);
free(stream);
if (ret != Z_OK) {
throwException(env, "Could not free z_stream: " + to_string(ret));
}
}
jlong JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_init(JNIEnv* env, jobject obj, jboolean compress, jint level) {
z_stream* stream = (z_stream*) calloc(1, sizeof (z_stream));
int ret = (compress) ? deflateInit(stream, level) : inflateInit(stream);
if (ret != Z_OK) {
throwException(env, "Could not init z_stream: " + to_string(ret));
}
return (jlong) stream;
}
jint JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_process(JNIEnv* env, jobject obj, jlong ctx, jlong in, jint inLength, jlong out, jint outLength, jboolean compress) {
z_stream* stream = (z_stream*) ctx;
stream->avail_in = inLength;
stream->next_in = (byte*) in;
stream->avail_out = outLength;
stream->next_out = (byte*) out;
int ret = (compress) ? deflate(stream, Z_FINISH) : inflate(stream, Z_PARTIAL_FLUSH);
switch (ret) {
case Z_STREAM_END:
env->SetBooleanField(obj, finishedID, true);
break;
case Z_OK:
break;
default:
throwException(env, "Unknown z_stream return code: " + to_string(ret));
}
env->SetIntField(obj, consumedID, inLength - stream->avail_in);
return outLength - stream->avail_out;
}

View File

@@ -1,37 +0,0 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_md_5_bungee_NativeCipherImpl */
#ifndef _Included_net_md_5_bungee_NativeCipherImpl
#define _Included_net_md_5_bungee_NativeCipherImpl
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_md_5_bungee_NativeCipherImpl
* Method: init
* Signature: (Z[B)J
*/
JNIEXPORT jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init
(JNIEnv *, jobject, jboolean, jbyteArray);
/*
* Class: net_md_5_bungee_NativeCipherImpl
* Method: free
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_free
(JNIEnv *, jobject, jlong);
/*
* Class: net_md_5_bungee_NativeCipherImpl
* Method: cipher
* Signature: (JJJI)V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_cipher
(JNIEnv *, jobject, jlong, jlong, jlong, jint);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,37 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_md_5_bungee_jni_cipher_NativeCipherImpl */
#ifndef _Included_net_md_5_bungee_jni_cipher_NativeCipherImpl
#define _Included_net_md_5_bungee_jni_cipher_NativeCipherImpl
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_md_5_bungee_jni_cipher_NativeCipherImpl
* Method: init
* Signature: (Z[B)J
*/
JNIEXPORT jlong JNICALL Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_init
(JNIEnv *, jobject, jboolean, jbyteArray);
/*
* Class: net_md_5_bungee_jni_cipher_NativeCipherImpl
* Method: free
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_free
(JNIEnv *, jobject, jlong);
/*
* Class: net_md_5_bungee_jni_cipher_NativeCipherImpl
* Method: cipher
* Signature: (JJJI)V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_cipher
(JNIEnv *, jobject, jlong, jlong, jlong, jint);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,53 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_md_5_bungee_jni_zlib_NativeCompressImpl */
#ifndef _Included_net_md_5_bungee_jni_zlib_NativeCompressImpl
#define _Included_net_md_5_bungee_jni_zlib_NativeCompressImpl
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: initFields
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_initFields
(JNIEnv *, jclass);
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: end
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_end
(JNIEnv *, jobject, jlong, jboolean);
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: reset
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_reset
(JNIEnv *, jobject, jlong, jboolean);
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: init
* Signature: (ZI)J
*/
JNIEXPORT jlong JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_init
(JNIEnv *, jobject, jboolean, jint);
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: process
* Signature: (JJIJIZ)I
*/
JNIEXPORT jint JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_process
(JNIEnv *, jobject, jlong, jlong, jint, jlong, jint, jboolean);
#ifdef __cplusplus
}
#endif
#endif