aboutsummaryrefslogtreecommitdiff
path: root/java/javacurl.c
blob: 1623c624d4908598bcef79d3f4cb483888d27e6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

#include <curl/curl.h> /* 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; /* global reference */
    jobject object;
  } 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)
{

  struct javacurl *curl = (struct javacurl*)jcurl;

  if(curl->write.cls) {
    /* a global reference we must delete */
    (*java)->DeleteGlobalRef(java, curl->write.cls);
    (*java)->DeleteGlobalRef(java, curl->write.object);
  }

  curl_easy_cleanup(curl->libcurl); /* cleanup libcurl stuff */

  free((void *)curl); /* 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;
  CURLoption opt = (CURLoption)option;

  puts("setopt int + int");

  switch(opt) {
  case CURLOPT_FILE:
    /* silently ignored, we don't need user-specified callback data when
       we have an object, and besides the CURLOPT_FILE is not exported
       to the java interface */
    return 0;
  }

  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=NULL;
  int ret=0;

  fprintf(stderr, "%d bytes data received in callback:\n"
          "ptr=%p, java=%p cls=%p\n",
          realsize, curl, java, curl->write.cls);

  jb=(*java)->NewByteArray(java, realsize);
  (*java)->SetByteArrayRegion(java, jb, 0, 
                              realsize, (jbyte *)ptr);

  fprintf(stderr, "created byte-array\n");

  ret = (*java)->CallIntMethod(java,
                               curl->write.object,
                               curl->write.mid,
                               jb);

  fprintf(stderr, "java-method returned %d\n", ret);

  return realsize;
}

/*
 * setopt() int + object
 */

JNIEXPORT jint JNICALL Java_CurlGlue_jni_1setopt__IILCurlWrite_2
  (JNIEnv *java, jobject myself, jint jcurl, jint option, jobject object)
{
  jclass cls_local = (*java)->GetObjectClass(java, object);
  jmethodID mid;
  struct javacurl *curl = (struct javacurl *)jcurl;
  jclass cls;
  jobject obj_global;

  switch(option) {
  case CURLOPT_WRITEFUNCTION:
    /* this makes a reference that'll be alive until we kill it! */
    cls = (*java)->NewGlobalRef(java, cls_local);

    printf("setopt int + object, option = %d cls= %p\n",
           option, cls);

    if(!cls) {
      puts("couldn't make local reference global");
      return 0;
    }

    /* this is the write callback */
    mid = (*java)->GetMethodID(java, cls, "handleString", "([B)I");
    if(!mid) {
      puts("no callback method found");
      return 0;
    }

    obj_global = (*java)->NewGlobalRef(java, object);

    curl->write.mid = mid;
    curl->write.cls = cls;
    curl->write.object = obj_global;
    /*curl->write.java = java; stored on perform */

    fprintf(stderr, "setopt write callback and write file pointer %p, java = %p\n",
            curl, java);

    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)
{
  struct javacurl *curl=(struct javacurl*)jcurl;
  curl->write.java = java;
  return (jint)curl_easy_perform(curl->libcurl);
}