diff --git a/java/CurlGlue.java b/java/CurlGlue.java new file mode 100644 index 000000000..fe8f186e6 --- /dev/null +++ b/java/CurlGlue.java @@ -0,0 +1,134 @@ +/** + * The curl class is a JNI wrapper for libcurl. Please bear with me, I'm no + * true java dude (yet). Improve what you think is bad and send me the + * updates! + * daniel@haxx.se + * + * This is meant as a raw, crude and low-level interface to libcurl. If you + * want fancy stuff, build upon this. + */ + +public class CurlGlue +{ + // start of imported generated list, make a new list with + // define2java.pl on demand + public static final int CURLOPT_NOTHING = 0; + public static final int CURLOPT_FILE = 10001; + public static final int CURLOPT_URL = 10002; + public static final int CURLOPT_PORT = 3; + public static final int CURLOPT_PROXY = 10004; + public static final int CURLOPT_USERPWD = 10005; + public static final int CURLOPT_PROXYUSERPWD = 10006; + public static final int CURLOPT_RANGE = 10007; + public static final int CURLOPT_INFILE = 10009; + public static final int CURLOPT_ERRORBUFFER = 10010; + public static final int CURLOPT_WRITEFUNCTION = 20011; + public static final int CURLOPT_READFUNCTION = 20012; + public static final int CURLOPT_TIMEOUT = 13; + public static final int CURLOPT_INFILESIZE = 14; + public static final int CURLOPT_POSTFIELDS = 10015; + public static final int CURLOPT_REFERER = 10016; + public static final int CURLOPT_FTPPORT = 10017; + public static final int CURLOPT_USERAGENT = 10018; + public static final int CURLOPT_LOW_SPEED_LIMIT = 19; + public static final int CURLOPT_LOW_SPEED_TIME = 20; + public static final int CURLOPT_RESUME_FROM = 21; + public static final int CURLOPT_COOKIE = 10022; + public static final int CURLOPT_HTTPHEADER = 10023; + public static final int CURLOPT_HTTPPOST = 10024; + public static final int CURLOPT_SSLCERT = 10025; + public static final int CURLOPT_SSLCERTPASSWD = 10026; + public static final int CURLOPT_CRLF = 27; + public static final int CURLOPT_QUOTE = 10028; + public static final int CURLOPT_WRITEHEADER = 10029; + public static final int CURLOPT_COOKIEFILE = 10031; + public static final int CURLOPT_SSLVERSION = 32; + public static final int CURLOPT_TIMECONDITION = 33; + public static final int CURLOPT_TIMEVALUE = 34; + public static final int CURLOPT_HTTPREQUEST = 10035; + public static final int CURLOPT_CUSTOMREQUEST = 10036; + public static final int CURLOPT_STDERR = 10037; + public static final int CURLOPT_POSTQUOTE = 10039; + public static final int CURLOPT_WRITEINFO = 10040; + public static final int CURLOPT_VERBOSE = 41; + public static final int CURLOPT_HEADER = 42; + public static final int CURLOPT_NOPROGRESS = 43; + public static final int CURLOPT_NOBODY = 44; + public static final int CURLOPT_FAILONERROR = 45; + public static final int CURLOPT_UPLOAD = 46; + public static final int CURLOPT_POST = 47; + public static final int CURLOPT_FTPLISTONLY = 48; + public static final int CURLOPT_FTPAPPEND = 50; + public static final int CURLOPT_NETRC = 51; + public static final int CURLOPT_FOLLOWLOCATION = 52; + public static final int CURLOPT_FTPASCII = 53; + public static final int CURLOPT_TRANSFERTEXT = 53; + public static final int CURLOPT_PUT = 54; + public static final int CURLOPT_MUTE = 55; + public static final int CURLOPT_PROGRESSFUNCTION = 20056; + public static final int CURLOPT_PROGRESSDATA = 10057; + public static final int CURLOPT_AUTOREFERER = 58; + public static final int CURLOPT_PROXYPORT = 59; + public static final int CURLOPT_POSTFIELDSIZE = 60; + public static final int CURLOPT_HTTPPROXYTUNNEL = 61; + public static final int CURLOPT_INTERFACE = 10062; + public static final int CURLOPT_KRB4LEVEL = 10063; + public static final int CURLOPT_SSL_VERIFYPEER = 64; + public static final int CURLOPT_CAINFO = 10065; + public static final int CURLOPT_PASSWDFUNCTION = 20066; + public static final int CURLOPT_PASSWDDATA = 10067; + public static final int CURLOPT_MAXREDIRS = 68; + public static final int CURLOPT_FILETIME = 10069; + public static final int CURLOPT_TELNETOPTIONS = 10070; + public static final int CURLOPT_MAXCONNECTS = 71; + public static final int CURLOPT_CLOSEPOLICY = 72; + public static final int CURLOPT_CLOSEFUNCTION = 20073; + public static final int CURLOPT_FRESH_CONNECT = 74; + public static final int CURLOPT_FORBID_REUSE = 75; + public static final int CURLOPT_RANDOM_FILE = 10076; + public static final int CURLOPT_EGDSOCKET = 10077; + public static final int CURLOPT_CONNECTTIMEOUT = 78; + public static final int CURLOPT_HEADERFUNCTION = 20079; + // end of generated list + + public CurlGlue() { + javacurl_handle = jni_init(); + } + + public void finalize() { + jni_cleanup(javacurl_handle); + } + + private int javacurl_handle; + + /* constructor and destructor for the libcurl handle */ + private native int jni_init(); + private native void jni_cleanup(int javacurl_handle); + private native synchronized int jni_perform(int javacurl_handle); + + // Instead of varargs, we have different functions for each + // kind of type setopt() can take + private native int jni_setopt(int libcurl, int option, String value); + private native int jni_setopt(int libcurl, int option, int value); + private native int jni_setopt(int libcurl, int option, CurlWrite value); + + public native int getinfo(); + + public int perform() { + return jni_perform(javacurl_handle); + } + public int setopt(int option, int value) { + return jni_setopt(javacurl_handle, option, value); + } + public int setopt(int option, String value) { + return jni_setopt(javacurl_handle, option, value); + } + public int setopt(int option, CurlWrite value) { + return jni_setopt(javacurl_handle, option, value); + } + + static { + System.loadLibrary("javacurl"); + } + +} diff --git a/java/CurlWrite.java b/java/CurlWrite.java new file mode 100644 index 000000000..37c8484c0 --- /dev/null +++ b/java/CurlWrite.java @@ -0,0 +1,9 @@ +public interface CurlWrite +{ + /** + * handleString gets called by libcurl on each chunk of data + * we receive from the remote server + */ + public int handleString(byte s[]); +} + diff --git a/java/Makefile b/java/Makefile new file mode 100644 index 000000000..e05ea6004 --- /dev/null +++ b/java/Makefile @@ -0,0 +1,33 @@ + +TARGET = libjavacurl.so + +OBJS = javacurl.o + +CC = gcc +CFLAGS = -c +CPPFLAGS = -I/usr/j2se/include -I/usr/local/include -I/usr/j2se/include/solaris +LDFLAGS = -lcurl -ldl -L/usr/local/ssl/lib -lssl -lcrypto + +all: CurlGlue.h CurlGlue.class javacurl.o $(TARGET) test.class + +test: + java test + +javacurl.o: javacurl.c CurlGlue.h + $(CC) $(CPPFLAGS) $(CFLAGS) $< + +CurlGlue.h: CurlGlue.java CurlGlue.class + javah CurlGlue + touch CurlGlue.h + +test.class: CurlGlue.class javacurl.o + javac test.java + +CurlGlue.class: CurlGlue.java + javac $< + +$(TARGET): $(OBJS) + $(CC) -G -o $(TARGET) $(LDFLAGS) $(OBJS) + +clean: + rm -f javacurl.o CurlGlue.h CurlGlue.class diff --git a/java/javacurl.c b/java/javacurl.c new file mode 100644 index 000000000..2b93bc677 --- /dev/null +++ b/java/javacurl.c @@ -0,0 +1,157 @@ + +#include /* libcurl header */ +#include "CurlGlue.h" /* the JNI-generated glue header file */ + +/* + * This is a private struct allocated for every 'CurlGlue' object. + */ +struct javacurl { + void *libcurl; + void *whatever; + struct writecallback { + jmethodID mid; + JNIEnv *java; + jclass cls; + jobject obj; + } write; +}; + +JNIEXPORT jint JNICALL Java_CurlGlue_jni_1init(JNIEnv *java, + jobject myself) +{ + void *libhandle; + struct javacurl *jcurl=NULL; + + libhandle = curl_easy_init(); + + if(libhandle) { + jcurl=(struct javacurl *)malloc(sizeof(struct javacurl)); + if(jcurl) { + memset(jcurl, 0, sizeof(struct javacurl)); + jcurl->libcurl = libhandle; + + } + else { + curl_easy_cleanup(libhandle); + return (jint)0; + } + } + + return (jint) jcurl; /* nasty typecast */ +} + +JNIEXPORT void JNICALL Java_CurlGlue_jni_1cleanup(JNIEnv *java, + jobject myself, + jint jcurl) +{ + void *handle=(void *)((struct javacurl*)jcurl)->libcurl; + + curl_easy_cleanup(handle); /* cleanup libcurl stuff */ + + free((void *)jcurl); /* free the struct too */ +} + +/* + * setopt() int + string + */ +JNIEXPORT jint JNICALL Java_CurlGlue_jni_1setopt__IILjava_lang_String_2 + (JNIEnv *java, jobject myself, jint jcurl, jint option, jstring value) +{ + /* get the actual string C-style */ + const char *str = (*java)->GetStringUTFChars(java, value, 0); + + void *handle = (void *)((struct javacurl*)jcurl)->libcurl; + + puts("setopt int + string"); + + return (jint)curl_easy_setopt(handle, (CURLoption)option, str); + +} + +/* + * setopt() int + int + */ +JNIEXPORT jint JNICALL Java_CurlGlue_jni_1setopt__III + (JNIEnv *java, jobject myself, jint jcurl, jint option, jint value) +{ + void *handle = (void *)((struct javacurl*)jcurl)->libcurl; + + puts("setopt int + int"); + + return (jint)curl_easy_setopt(handle, (CURLoption)option, value); +} + +static int javacurl_write_callback(void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + struct javacurl *curl = (struct javacurl *)stream; + size_t realsize = size * nmemb; + JNIEnv *java = curl->write.java; + jbyteArray jb; + int ret; + + jb=(*java)->NewByteArray(java, realsize); + (*java)->SetByteArrayRegion(java, jb, 0, + realsize, (jbyte *)ptr); + + ret = (*java)->CallIntMethod(java, + curl->write.obj, + curl->write.mid, + jb); + + return realsize; +} + +/* + * setopt() int + object + */ + +JNIEXPORT jint JNICALL Java_CurlGlue_jni_1setopt__IILCurlWrite_2 + (JNIEnv *java, jobject myself, jint jcurl, jint option, jobject value) +{ + jclass cls = (*java)->GetObjectClass(java, value); + jmethodID mid; + struct javacurl *curl = (struct javacurl *)jcurl; + + printf("setopt int + object, option = %d cls= %p\n", option, cls); + + switch(option) { + case CURLOPT_WRITEFUNCTION: + /* this is the write callback */ + mid = (*java)->GetMethodID(java, cls, "handleString", + "([B)I"); + if(!mid) { + /* no callback method found */ + puts("no callback method found"); + return 0; + } + curl->write.mid = mid; + curl->write.java = java; + curl->write.cls = cls; + curl->write.obj = value; + + puts("setopt write callback and write file pointer"); + + curl_easy_setopt(curl->libcurl, CURLOPT_WRITEFUNCTION, + javacurl_write_callback); + curl_easy_setopt(curl->libcurl, CURLOPT_FILE, + curl); + break; + } + return 0; +} + +JNIEXPORT jint JNICALL Java_CurlGlue_getinfo + (JNIEnv *java, jobject value) +{ + return 0; +} + +JNIEXPORT jint JNICALL Java_CurlGlue_jni_1perform + (JNIEnv *java, jobject myself, jint jcurl) +{ + void *handle=(void *)((struct javacurl*)jcurl)->libcurl; + return (jint)curl_easy_perform(handle); +} diff --git a/java/test.java b/java/test.java new file mode 100644 index 000000000..33da88030 --- /dev/null +++ b/java/test.java @@ -0,0 +1,27 @@ +import CurlGlue; +import CurlWrite; + +class test implements CurlWrite { + public int handleString(byte s[]) + { + /* output everything */ + System.out.println("IIIIIIIIIII -------------- OOOOOOOOOOOOOOOOOOO"); + try { + System.out.write(s); + } + catch (java.io.IOException moo) { + // nothing + } + return 0; + } + + public static void main(String[] args) + { + CurlGlue cg = new CurlGlue(); + test cw = new test(); + cg.setopt(CurlGlue.CURLOPT_URL, "http://www.contactor.se/"); + cg.setopt(CurlGlue.CURLOPT_WRITEFUNCTION, cw); + cg.perform(); + } +} +