How can I make this callback please !

231 views
Skip to first unread message

SdkSMok

unread,
Aug 25, 2022, 4:10:14 PM8/25/22
to Java Native Access
Hello everyone,

I have some problems of understanding with callbacks,
I try to use the libcurl library, it's an http client, I used Jnaeator, I generated what I need after some corrections.

I made a test with curl and it works pretty well, my only concern is when I have to retrieve the content of a web page in a java string, the curl library does not provide a callback function to write this result.
it concerns :

curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, cb);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

the callback "cb" is not part of the libcurl, you have to write it yourself.

Here is the information found :(https://curl.se/libcurl/c/CURLOPT_WRITEFUNCTION.html)

*********************************************************************************

 struct memory {
   char *response;
   size_t size;
 };
 
 static size_t cb(void *data, size_t size, size_t nmemb, void *userp)
 {
   size_t realsize = size * nmemb;
   struct memory *mem = (struct memory *)userp;
 
   char *ptr = realloc(mem->response, mem->size + realsize + 1);
   if(ptr == NULL)
     return 0; /* out of memory! */
 
   mem->response = ptr;
   memcpy(&(mem->response[mem->size]), data, realsize);
   mem->size += realsize;
   mem->response[mem->size] = 0;
 
   return realsize;
 }
 
 struct memory chunk = {0};
 
 /* send all data to this function */
 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, cb);
 
 /* we pass our 'chunk' struct to the callback function */
 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);


*********************************************************************************


How I have to write this callback for CURLOPT_WRITEFUNCTION (I tried several tricks) and how I can get the content in memory with CURLOPT_WRITEDATA


If you can help me on this I would be very grateful, this is my only blocking point.

Thanks a lot community !
Sam

Matthias Bläsing

unread,
Aug 28, 2022, 4:13:07 PM8/28/22
to jna-...@googlegroups.com
Hi,

the documentation for callbacks can be found here:

https://github.com/java-native-access/jna/blob/master/www/CallbacksAndClosures.md
and
https://java-native-access.github.io/jna/5.12.1/javadoc/ (section
Callbacks)


This should work (untested - it would have helped if you would have
prepared a sample...):


public class LibCurlSample {

// Minimal Interface definition for libcurl to show binding of callback
interface libcurl extends Library {

// load the curl library in versin 4 (for windows this needs to be specialized)
public libcurl INSTANCE = Native.load("libcurl.so.4", libcurl.class);

// define the structure of the callback curl will use to write data using
// CURLOPT_WRITEFUNCTION
interface CURL_WRITE_FUNCTION_CB {

public size_t callback(Pointer data, size_t size, size_t nmemb, Pointer userp);
}

// This assumes, that the curl HANDLE is a pointer to some internal data of curl
public class CURL extends PointerType {
}

// Constants for the CURLoption enum
public static int CURLOPTTYPE_OBJECTPOINT = 10000;
public static int CURLOPTTYPE_FUNCTIONPOINT = 20000;
public static int CURLOPTTYPE_CBPOINT = CURLOPTTYPE_OBJECTPOINT;
public static int CURLOPT_WRITEFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 11;
public static int CURLOPT_WRITEDATA = CURLOPTTYPE_CBPOINT + 1;

// bind curl_easy_setopt - the function is declared as varargs
public int curl_easy_setopt(CURL curl, int curlOption, Object... data);
}

// The idea here is to use only a single callback: BYTE_ARRAY_WRITER. That
// callback is invoked whenever data is received by curl and it writes the
// received data into a ByteArrayOutputStream. Using the CURLOPT_WRITEDATA
// option a pointer can be set per request, that is passed on to the
// callback. This pointer is used as a carrier to pass the request ID, which
// is used to find the right ByteArrayOutputStream.
private static int requestCounter = 0;
private static Map<Integer,ByteArrayOutputStream> replyBuffer = new ConcurrentHashMap<>();
private static final CURL_WRITE_FUNCTION_CB BYTE_ARRAY_WRITER = new CURL_WRITE_FUNCTION_CB() {
@Override
public size_t callback(Pointer data, size_t size, size_t nmemb, Pointer userp) {
try {
int requestId = (int) Pointer.nativeValue(userp);
replyBuffer.get(requestId).write(data.getByteArray(0, nmemb.intValue()));
} catch (IOException ex) {
throw new RuntimeException("Failed to write into ByteArrayOutputStream ...");
}
return nmemb;
}
};
private static synchronized int allocateRequestId() {
if(requestCounter > (Integer.MAX_VALUE - 1)) {
requestCounter++;
return requestCounter;
} else {
requestCounter = 0;
return requestCounter;
}
}

public static void main(String[] args) {
// Somehow the handle needs to be initialized (out of scope for the example)
CURL curl = null;

// Allocate a request ID - this assumes, that when more than
// Integer.MAX_VALUE requests were invoked, the first request is long
// done.
int requestId = allocateRequestId();

// Store the ByteArrayOutputStream inside the static buffer
replyBuffer.put(requestId, new ByteArrayOutputStream());

// Set the request ID and callback
libcurl.INSTANCE.curl_easy_setopt(curl, CURLOPT_WRITEDATA, requestId);
libcurl.INSTANCE.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, BYTE_ARRAY_WRITER);

// Execute the request
//...

// Ensure the request is done (does libcurl block?)

// Do something relevant with the result
byte[] result = replyBuffer.get(requestId).toByteArray();
replyBuffer.remove(requestId);
}

}



Having written this: My personal advice: DON'T DO IT! I don't see
anything libcurl brings to the table, that the JDK can't do itself or
with the help of pure java libraries.

Greetings

Matthias



Am Donnerstag, dem 25.08.2022 um 13:10 -0700 schrieb 'SdkSMok' via Java
Native Access:
> --
> You received this message because you are subscribed to the Google
> Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to jna-users+...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/jna-users/6be4a502-005b-48d8-8b3a-fb590a683479n%40googlegroups.com
> .

SdkSMok

unread,
Aug 28, 2022, 5:45:05 PM8/28/22
to Java Native Access
Thanks a lot ! Matthias.
and thanks fot the advice, it work ;)

Reply all
Reply to author
Forward
0 new messages