Source

ocaml-toplevel-android / jni / start.c

#include "jp_co_itpl_ocamlandroid_Native.h"
#include "caml/callback.h"


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <android/log.h>

#define LOG_TAG "ocaml-android"
#define LOGD(...) do { __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__); } while(0)
#define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0)
#define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0)
#define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0)


/*
 * Create a UNIX-domain socket address in the Linux "abstract namespace".
 *
 * The socket code doesn't require null termination on the filename, but
 * we do it anyway so string functions work.
 */
static int makeAddr(const char* name, struct sockaddr_un* pAddr, socklen_t* pSockLen)
{
    int nameLen = strlen(name);
    if (nameLen >= (int) sizeof(pAddr->sun_path) -1)  /* too long? */
        return -1;
    pAddr->sun_path[0] = '\0';  /* abstract namespace */
    strcpy(pAddr->sun_path+1, name);
    pAddr->sun_family = AF_LOCAL;
    *pSockLen = 1 + nameLen + offsetof(struct sockaddr_un, sun_path);
    return 0;
}

static void start_caml(const jbyte *name) {
  LOGD("entry: start_caml");
  struct sockaddr_un sockAddr;
  socklen_t sockLen;

  if (makeAddr(name, &sockAddr, &sockLen) < 0) {
      LOGE("native: name creation failed");
      return;
  }

  int fd = socket(AF_LOCAL, SOCK_STREAM, PF_UNIX);
  if (fd < 0) {
      LOGE("native: socket() failed");
      return;
  }
  if (connect(fd, (const struct sockaddr*) &sockAddr, sockLen) < 0) {
      LOGE("native: connect() failed");
	  close (fd);
	  return;
  }

  dup2(fd, 0); // stdin  
  dup2(fd, 1); // stdout
  dup2(fd, 2); // stderr

  char* p = 0;
  caml_startup(&p);

  LOGD("exit successful: start_caml");
  return;
}

JNIEXPORT jboolean JNICALL Java_jp_co_itpl_ocamlandroid_Native_start (JNIEnv *env, jclass clazz, jstring name_) {
  LOGD("entry: start");
  const jbyte *name = (*env)->GetStringUTFChars(env, name_, NULL);
  if (name == NULL) {
    return JNI_FALSE;
  }
  
  start_caml(name);
  /*pid_t parent_pgid = getpgid(0);
  if(parent_pgid==-1) { LOGE("getpgid failed."); }
  
  if(fork()==0) {
    LOGI("child:forked caml process");
    int res = setpgid(0, parent_pgid);
    if(res==-1) { LOGE("setpgid failed."); }
    start_caml(name);
    exit(0);
  } else {
    LOGI("parent:forked caml process");
  }*/
  (*env)->ReleaseStringUTFChars(env, name_, name);
  LOGD("exit successful: start");
  return JNI_TRUE;
}

JNIEXPORT void JNICALL Java_jp_co_itpl_ocamlandroid_Native_chdir (JNIEnv * env, jclass clazz, jstring path_) {
  LOGD("entry: chdir");
  const jbyte *path = (*env)->GetStringUTFChars(env, path_, NULL);
  if (path == NULL) {
      return;
  }
  chdir(path);
  (*env)->ReleaseStringUTFChars(env, path_, path);
  LOGD("exit successful: chdir");
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.