native-lib.cpp (19228B)
1 #include <fstream> 2 #include <iostream> 3 #include <jni.h> 4 #include <string> 5 #include <vector> 6 #include <android/log.h> 7 #include <android/asset_manager.h> 8 #include <android/asset_manager_jni.h> 9 #include "gnunet_util_lib.h" 10 #include <ltdl.h> 11 #include <dlfcn.h> 12 #include <sys/stat.h> 13 #include <libgen.h> 14 #include <fcntl.h> 15 #include <unistd.h> 16 17 #define TAG "GNUNET" 18 19 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 20 #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) 21 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) 22 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 23 24 extern "C" { 25 #include <unistd.h> 26 #include <gnunet_util_lib.h> 27 } 28 29 static int pfd[2]; 30 static pthread_t thr; 31 static const char *tag = "GNUNET"; 32 33 void *thread_func(void*) 34 { 35 static const size_t READ_CHUNK = 1024; 36 static const size_t MAX_LINE = 8192; // eigene Obergrenze pro „logische“ Zeile 37 std::string acc; acc.reserve(MAX_LINE); 38 std::vector<char> tmp(READ_CHUNK); 39 40 ssize_t n; 41 while ((n = read(pfd[0], tmp.data(), tmp.size())) > 0) { 42 acc.append(tmp.data(), n); 43 44 size_t pos; 45 while ((pos = acc.find('\n')) != std::string::npos) { 46 std::string line = acc.substr(0, pos); 47 acc.erase(0, pos + 1); 48 49 // Leer \r am Ende weg 50 if (!line.empty() && line.back() == '\r') line.pop_back(); 51 52 // In handliche Teile splitten, um log-Limit/ANSI zu vermeiden 53 const size_t CHUNK = 1000; 54 for (size_t i = 0; i < line.size(); i += CHUNK) { 55 std::string_view part(line.c_str() + i, std::min(CHUNK, line.size() - i)); 56 __android_log_write(ANDROID_LOG_DEBUG, tag, std::string(part).c_str()); 57 } 58 } 59 60 // Falls Zeile extrem lang wird, „notfall“ flushen: 61 if (acc.size() > MAX_LINE) { 62 __android_log_write(ANDROID_LOG_DEBUG, tag, "[truncated: line too long]"); 63 acc.clear(); 64 } 65 } 66 67 // Rest ohne Newline flushen 68 if (!acc.empty()) { 69 __android_log_write(ANDROID_LOG_DEBUG, tag, acc.c_str()); 70 } 71 return nullptr; 72 } 73 74 int start_logger(const char *app_name) 75 { 76 tag = app_name; 77 78 /* make stdout line-buffered and stderr unbuffered */ 79 setvbuf(stdout, 0, _IOLBF, 0); 80 setvbuf(stderr, 0, _IONBF, 0); 81 82 /* create the pipe and redirect stdout and stderr */ 83 pipe(pfd); 84 dup2(pfd[1], 1); 85 dup2(pfd[1], 2); 86 87 /* spawn the logging thread */ 88 if(pthread_create(&thr, 0, thread_func, 0) == -1) 89 return -1; 90 pthread_detach(thr); 91 return 0; 92 } 93 94 /** ------------------ Milestone 6-7 code. ------------------------------- 95 static void 96 run (void *cls, 97 char *const *args, 98 const char *cfgfile, 99 const struct GNUNET_CONFIGURATION_Handle *c) 100 { 101 int sockfd, newsockfd, portno; 102 socklen_t clilen; 103 char buffer[256]; 104 struct sockaddr_in serv_addr, cli_addr; 105 int n; 106 107 sockfd = socket(AF_INET, SOCK_STREAM, 0); 108 if (sockfd < 0){ 109 LOGE ("ERROR opening socket"); 110 perror("ERROR opening socket"); 111 goto shutdown; 112 } 113 bzero((char *) &serv_addr, sizeof(serv_addr)); 114 portno = 8081; 115 serv_addr.sin_family = AF_INET; 116 serv_addr.sin_addr.s_addr = INADDR_ANY; 117 serv_addr.sin_port = htons(portno); 118 if (bind(sockfd, (struct sockaddr *) &serv_addr, 119 sizeof(serv_addr)) < 0) 120 { 121 perror("ERROR on binding"); 122 goto shutdown; 123 } 124 listen(sockfd,5); 125 clilen = sizeof(cli_addr); 126 newsockfd = accept(sockfd, 127 (struct sockaddr *) &cli_addr, 128 &clilen); 129 if (newsockfd < 0) 130 { 131 perror("ERROR on accept"); 132 goto shutdown; 133 } 134 bzero(buffer,256); 135 n = read(newsockfd,buffer,255); 136 if (n < 0) 137 { 138 perror("ERROR reading from socket"); 139 goto shutdown; 140 } 141 printf("Here is the message: %s\n",buffer); 142 n = write(newsockfd,"I got your message",18); 143 if (n < 0) 144 { 145 perror("ERROR writing to socket"); 146 goto shutdown; 147 } 148 close(newsockfd); 149 close(sockfd); 150 151 shutdown: 152 GNUNET_SCHEDULER_shutdown(); 153 }*/ 154 155 // END ------------------------------ Milestone 6 - 7 Code --------------------- 156 157 static jobject android_java_asset_manager = NULL; 158 static struct GNUNET_ARM_Handle *h; 159 static struct GNUNET_CONFIGURATION_Handle *cfg; 160 static struct GNUNET_ARM_Operation *op; 161 162 /* -------------- Multi library code ----------------------------- 163 /*static void 164 start_callback (void *cls, 165 enum GNUNET_ARM_RequestStatus rs, 166 enum GNUNET_ARM_Result result) 167 { 168 (void) cls; 169 op = NULL; 170 if (GNUNET_ARM_REQUEST_SENT_OK != rs) 171 { 172 LOGE("Failed to start the ARM service."); 173 GNUNET_SCHEDULER_shutdown (); 174 return; 175 } 176 if ((GNUNET_ARM_RESULT_STARTING != result) && 177 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result)) 178 { 179 LOGE("Failed to start the ARM service."); 180 GNUNET_SCHEDULER_shutdown (); 181 return; 182 } 183 LOGD ("ARM service [re]start successful"); 184 } 185 186 187 static void 188 shutdown_task (void *cls) 189 { 190 (void) cls; 191 if (NULL != op) 192 { 193 GNUNET_ARM_operation_cancel (op); 194 op = NULL; 195 } 196 if (NULL != h) 197 { 198 GNUNET_ARM_disconnect (h); 199 h = NULL; 200 } 201 GNUNET_CONFIGURATION_destroy (cfg); 202 cfg = NULL; 203 }*/ 204 205 206 /** 207 * Function called whenever we connect to or disconnect from ARM. 208 * Termiantes the process if we fail to connect to the service on 209 * our first attempt. 210 * 211 * @param cls closure 212 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected, 213 * #GNUNET_SYSERR on error. 214 */ 215 /*static void 216 conn_status (void *cls, 217 enum GNUNET_GenericReturnValue connected) 218 { 219 static int once; 220 221 (void) cls; 222 if ( (GNUNET_SYSERR == connected) && 223 (0 == once) ) 224 { 225 LOGE("Fatal error initializing ARM API."); 226 GNUNET_SCHEDULER_shutdown (); 227 return; 228 } 229 once = 1; 230 } 231 232 233 234 static void 235 run (void *cls, 236 char *const *args, 237 const char *cfgfile, 238 const struct GNUNET_CONFIGURATION_Handle *c) 239 { 240 start_logger(tag); 241 printf("Some message.\n"); 242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 243 "Simulate error message. We do not no what is the actual log level.\n"); 244 cfg = GNUNET_CONFIGURATION_dup (c); 245 AAssetManager *mgr = static_cast<AAssetManager *>(cls); 246 AAsset *asset = AAssetManager_open(mgr, "gnunet.conf", AASSET_MODE_BUFFER); 247 char buf[AAsset_getLength(asset)]; 248 249 AAsset_read(asset, buf, AAsset_getLength(asset)); 250 251 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, buf, strlen(buf), NULL)) 252 { 253 LOGE ("Deserialization of configuration failed!"); 254 } 255 256 AAsset_close(asset); 257 258 259 if (NULL == (h = GNUNET_ARM_connect (cfg, 260 &conn_status, 261 NULL))) 262 return; 263 264 op = GNUNET_ARM_request_service_start (h, 265 "arm", 266 GNUNET_OS_INHERIT_STD_NONE, 267 &start_callback, 268 NULL); 269 270 271 } 272 END -------------- Multi library code ----------------------------- */ 273 274 void ensure_directory_exists(const char* path) { 275 struct stat st; 276 if (stat(path, &st) != 0) { 277 if (mkdir(path, 0700) != 0) { 278 __android_log_print(ANDROID_LOG_ERROR, "APP", "Failed to create dir: %s (%s)", path, strerror(errno)); 279 } else { 280 __android_log_print(ANDROID_LOG_DEBUG, "APP", "Created dir: %s", path); 281 } 282 } else { 283 __android_log_print(ANDROID_LOG_DEBUG, "APP", "Dir already exists: %s", path); 284 } 285 } 286 287 void ensure_file_exists(const char* path) { 288 struct stat st; 289 if (stat(path, &st) != 0) { 290 // Datei existiert nicht → versuchen, anzulegen 291 int fd = open(path, O_CREAT | O_WRONLY, 0600); 292 if (fd < 0) { 293 __android_log_print(ANDROID_LOG_ERROR, "APP", "Failed to create file: %s (%s)", path, strerror(errno)); 294 } else { 295 __android_log_print(ANDROID_LOG_DEBUG, "APP", "Created file: %s", path); 296 close(fd); 297 } 298 } else { 299 __android_log_print(ANDROID_LOG_DEBUG, "APP", "File already exists: %s", path); 300 } 301 } 302 303 void copy_plugins(AAssetManager* mgr, const char* dest_dir) { 304 // Zielverzeichnis erstellen 305 mkdir(dest_dir, 0700); // Ignoriert Fehler, wenn schon existiert 306 307 // Asset-Verzeichnis öffnen 308 AAssetDir* assetDir = AAssetManager_openDir(mgr, "plugins"); 309 if (!assetDir) { 310 LOGE("Could not open assets/plugins/"); 311 return; 312 } 313 314 const char* filename = nullptr; 315 while ((filename = AAssetDir_getNextFileName(assetDir)) != nullptr) { 316 LOGD("Copying %s...", filename); 317 318 // Pfad innerhalb von Assets 319 std::string asset_path = std::string("plugins/") + filename; 320 321 AAsset* asset = AAssetManager_open(mgr, asset_path.c_str(), AASSET_MODE_STREAMING); 322 if (!asset) { 323 LOGE("Failed to open asset %s", asset_path.c_str()); 324 continue; 325 } 326 327 // Zielpfad vorbereiten 328 std::string out_path = std::string(dest_dir) + "/" + filename; 329 int out_fd = open(out_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0700); 330 if (out_fd < 0) { 331 LOGE("Could not create output file %s", out_path.c_str()); 332 AAsset_close(asset); 333 continue; 334 } 335 336 // Kopieren 337 char buffer[4096]; 338 int read_bytes; 339 while ((read_bytes = AAsset_read(asset, buffer, sizeof(buffer))) > 0) { 340 write(out_fd, buffer, read_bytes); 341 } 342 343 close(out_fd); 344 AAsset_close(asset); 345 LOGD("Copied to %s", out_path.c_str()); 346 } 347 348 AAssetDir_close(assetDir); 349 } 350 351 void set_executable_permissions(const char* path) { 352 if (chmod(path, 0700) != 0) { 353 __android_log_print(ANDROID_LOG_ERROR, "GNUNET", "chmod failed for %s: %s", path, strerror(errno)); 354 } else { 355 __android_log_print(ANDROID_LOG_DEBUG, "GNUNET", "chmod OK: %s", path); 356 } 357 } 358 359 extern "C" JNIEXPORT jstring JNICALL 360 Java_org_gnu_gnunet_MainActivity_stringFromJNI( 361 JNIEnv* env, 362 jobject /* this */, 363 jobject assets, 364 jstring path) { 365 366 jboolean isCopy = JNI_FALSE; 367 const char *c_install_path = env->GetStringUTFChars(path, &isCopy); 368 const struct GNUNET_OS_ProjectData *default_pd = GNUNET_OS_project_data_gnunet(); 369 const struct GNUNET_OS_ProjectData my_pd = { 370 .libname = "libgnunetutil", 371 .project_dirname = "gnunet", 372 .binary_name = "gnunet-arm", 373 .version = default_pd->version, 374 .env_varname = "GNUNET_PREFIX", 375 .base_config_varname = "GNUNET_BASE_CONFIG", 376 .bug_email = "gnunet-developers@gnu.org", 377 .homepage = "http://www.gnu.org/s/gnunet/", 378 .config_file = "gnunet.conf", 379 .user_config_file = "~/.config/gnunet.conf", 380 .is_gnu = 1, 381 .gettext_domain = "gnunet", 382 .gettext_path = NULL, 383 .agpl_url = GNUNET_AGPL_URL, 384 .install_path_override = c_install_path 385 }; 386 387 void* handle_gnunet_util = dlopen("libgnunetutil.so", RTLD_NOW); 388 if (!handle_gnunet_util) return env->NewStringUTF("libgnunetutil.so not loaded"); 389 /* void* handle_plugin_peerstore_sqlite = dlopen("libgnunet_plugin_peerstore_sqlite.so", RTLD_NOW); 390 if (!handle_plugin_peerstore_sqlite) return env->NewStringUTF("libgnunet_plugin_peerstore_sqlite.so not loaded");*/ 391 android_java_asset_manager = (*env).NewGlobalRef(assets); 392 AAssetManager *mgr = AAssetManager_fromJava(env, android_java_asset_manager); 393 394 std::string install_path_str(c_install_path); 395 ensure_directory_exists((install_path_str + "/gnunet").c_str()); 396 ensure_directory_exists((install_path_str + "/tmp").c_str()); 397 ensure_directory_exists((install_path_str + "/share").c_str()); 398 ensure_directory_exists((install_path_str + "/share/gnunet").c_str()); 399 ensure_directory_exists((install_path_str + "/share/gnunet/hellos").c_str()); 400 ensure_directory_exists((install_path_str + "/home").c_str()); 401 ensure_directory_exists((install_path_str + "/home/data").c_str()); 402 ensure_file_exists((install_path_str + "/home/data/statistics.dat").c_str()); 403 ensure_directory_exists((install_path_str + "/home/data/nse").c_str()); 404 set_executable_permissions((install_path_str + "/home/data/nse").c_str()); 405 ensure_file_exists((install_path_str + "/home/data/nse/proof.dat").c_str()); 406 set_executable_permissions((install_path_str + "/home/data/nse/proof.dat").c_str()); 407 ensure_directory_exists((install_path_str + "/lib").c_str()); 408 ensure_directory_exists((install_path_str + "/lib/gnunet").c_str()); 409 copy_plugins(mgr, "/data/user/0/org.gnu.gnunet/files/lib/gnunet"); 410 set_executable_permissions("/data/user/0/org.gnu.gnunet/files/lib/gnunet/libgnunet_plugin_datacache_heap.so"); 411 412 struct stat st; 413 if (0 == stat("/data/user/0/org.gnu.gnunet/files/home/data/nse/proof.dat", &st)) { 414 __android_log_print(ANDROID_LOG_DEBUG, "GNUNET", "proof.dat size = %lld", (long long)st.st_size); 415 } else { 416 __android_log_print(ANDROID_LOG_ERROR, "GNUNET", "proof.dat not found after creation"); 417 } 418 419 const char* proof_path = "/data/user/0/org.gnu.gnunet/files/home/data/nse/proof.dat"; 420 FILE* f = fopen(proof_path, "a"); 421 if (!f) { 422 __android_log_print(ANDROID_LOG_ERROR, "GNUNET", "fopen() failed on %s", proof_path); 423 perror("fopen"); 424 } else { 425 fprintf(f, "Write test at %ld\n", time(nullptr)); 426 fclose(f); 427 __android_log_print(ANDROID_LOG_DEBUG, "GNUNET", "Write to %s successful", proof_path); 428 } 429 430 void* plugin = dlopen("/data/user/0/org.gnu.gnunet/files/lib/gnunet/libgnunet_plugin_datacache_heap.so", RTLD_NOW); 431 432 if (!plugin) 433 __android_log_print(ANDROID_LOG_ERROR, "DLTEST", "dlopen failed: %s", dlerror()); 434 else 435 __android_log_print(ANDROID_LOG_DEBUG, "DLTEST", "dlopen SUCCESS for libgnunet_plugin_datacache_heap"); 436 437 set_executable_permissions("/data/user/0/org.gnu.gnunet/files/lib/gnunet/libgnunet_plugin_datastore.so"); 438 439 void* plugin2 = dlopen("/data/user/0/org.gnu.gnunet/files/lib/gnunet/libgnunet_plugin_datastore.so", RTLD_NOW); 440 441 if (!plugin2) 442 __android_log_print(ANDROID_LOG_ERROR, "DLTEST", "dlopen failed: %s", dlerror()); 443 else 444 __android_log_print(ANDROID_LOG_DEBUG, "DLTEST", "dlopen SUCCESS for libgnunet_plugin_datastore"); 445 446 void* handle_util = dlopen("/data/user/0/org.gnu.gnunet/files/lib/gnunet/libgnunetutil.so", RTLD_NOW | RTLD_GLOBAL); 447 if (!handle_util) { 448 __android_log_print(ANDROID_LOG_ERROR, "DLTEST", "Failed to load libgnunetutil.so: %s", dlerror()); 449 } else { 450 __android_log_print(ANDROID_LOG_DEBUG, "DLTEST", "Loaded libgnunetutil.so successfully"); 451 } 452 453 const char* tmp = GNUNET_DISK_mktemp(&my_pd, "test"); 454 if (tmp == nullptr) { 455 // Fehlerbehandlung 456 __android_log_print(ANDROID_LOG_ERROR, "GNUNET", "mktemp failed!"); 457 return env->NewStringUTF("mktemp failed"); 458 } 459 std::string tmp_file = tmp; 460 LOGD ("Temp file is here: %s", tmp_file.c_str()); 461 int ok = lt_dlinit(); 462 LOGD("lt_dlinit return code: %d", ok); 463 LOGD ("current ltdl search path: %s", lt_dlgetsearchpath()); 464 465 lt_dlsetsearchpath ("/data/user/0/org.gnu.gnunet/files/lib/gnunet"); 466 467 LOGD ("current ltdl search path afterwards: %s", lt_dlgetsearchpath()); 468 char *const non_const_ptr = const_cast<char*>(tmp_file.c_str()); 469 470 char *const argvx[] = { 471 "BuggerAll", 472 nullptr 473 }; 474 475 476 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 477 GNUNET_GETOPT_OPTION_END 478 }; 479 480 start_logger(tag); 481 printf("Some message.\n"); 482 /* 483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 484 "Simulate error message. We do not no what is the actual log level.\n"); 485 */ 486 487 /*AAsset *plugin_asset = AAssetManager_open(mgr, "libgnunet_plugin_peerstore_sqlite.so", AASSET_MODE_BUFFER); 488 const off_t &length = AAsset_getLength(plugin_asset); 489 char plugin_buf[length]; 490 LOGD("libgnunet_plugin_peerstore_sqlite.so size is %ld bytes", length); 491 AAsset_read(plugin_asset, plugin_buf, length); 492 enum GNUNET_DISK_AccessPermissions permission = static_cast<GNUNET_DISK_AccessPermissions>( 493 GNUNET_DISK_PERM_USER_READ 494 | GNUNET_DISK_PERM_USER_WRITE 495 | GNUNET_DISK_PERM_USER_EXEC); 496 497 // This code fails to get a fileHandle. TODO work out why not. It means the write doesn't happen. 498 struct GNUNET_DISK_FileHandle *fh = GNUNET_DISK_file_open ("/data/user/0/org.gnu.gnunet/files/libgnunet_plugin_peerstore_sqlite_gnunet.so", 499 GNUNET_DISK_OPEN_WRITE, 500 permission ); 501 GNUNET_DISK_file_write (fh, 502 plugin_buf, 503 length); 504 GNUNET_DISK_file_close (fh);*/ 505 506 // The following code does work; so does the kotlin code that copies the .so file from the assets folder. 507 std::vector<int> data = {1, 2, 3, 4, 5, 6}; 508 std::ofstream outfile("/data/user/0/org.gnu.gnunet/files/output.bin", std::ios::binary); 509 if (!outfile) { 510 LOGE("Could not open output.bin for writing"); 511 } 512 513 outfile.write(reinterpret_cast<const char*>(data.data()), data.size() * sizeof(int )); 514 if (!outfile) { 515 LOGE("Write failed for output.bin"); 516 } 517 outfile.close(); 518 519 520 cfg = GNUNET_CONFIGURATION_create (GNUNET_OS_project_data_gnunet()); 521 if (cfg == nullptr) { 522 LOGE("Failed to create GNUNET configuration object"); 523 return env->NewStringUTF("Failed to create GNUNET configuration object"); 524 } 525 AAsset *asset = AAssetManager_open(mgr, "gnunet.conf", AASSET_MODE_BUFFER); 526 off_t config_file_size = AAsset_getLength(asset); 527 LOGD("gnunet.conf is %ld bytes long", config_file_size); 528 529 530 std::vector<char> buf(config_file_size); 531 532 int actually_read = AAsset_read(asset, buf.data(), config_file_size); 533 LOGD("actually read %d bytes", actually_read); 534 535 // Sicherstellen, dass der Puffer nullterminiert ist 536 buf.push_back('\0'); 537 538 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize(cfg, buf.data(), config_file_size, NULL)) 539 { 540 LOGE ("Deserialization of configuration failed!"); 541 } 542 AAsset_close(asset); 543 LOGD("about to run GNUNET_PROGRAM_monolith_main"); 544 545 GNUNET_PROGRAM_monolith_main (&my_pd, 546 1, 547 argvx, 548 cfg); 549 550 /*GNUNET_PROGRAM_run (4, 551 argvx, 552 "native-lib", 553 "native-lib", 554 options, 555 &run, 556 mgr);*/ 557 std::string hello = "Hello from C++. Temp file is here: " + tmp_file; 558 559 return env->NewStringUTF(hello.c_str()); 560 }