Пример #1
0
static int connect_socket(const char *socketname, int fail)
{
  int sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (sock == -1) failwith_perror("socket");

  int err;

  BEGIN_PROTECTCWD
    struct sockaddr_un address;
    int address_len;

    chdir(path_socketdir());
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, 104, "./%s", socketname);
    address_len = strlen(address.sun_path) + sizeof(address.sun_family) + 1;

    NO_EINTR(err, connect(sock, (struct sockaddr*)&address, address_len));
  END_PROTECTCWD

  if (err == -1)
  {
    if (fail) failwith_perror("connect");
    close(sock);
    return -1;
  }

  return sock;
}
Пример #2
0
static void start_server(const char *socketname, const char* ignored, const char *exec_path)
{
  int sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (sock == -1)
    failwith_perror("socket");

  int err;

  BEGIN_PROTECTCWD
    struct sockaddr_un address;
    int address_len;

    chdir(path_socketdir());
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, 104, "./%s", socketname);
    address_len = strlen(address.sun_path) + sizeof(address.sun_family) + 1;
    unlink(address.sun_path);

    NO_EINTR(err, bind(sock, (struct sockaddr*)&address, address_len));
  END_PROTECTCWD

  if (err == -1)
    failwith_perror("bind");

  if (listen(sock, 5) == -1)
    failwith_perror("listen");

  pid_t child = fork();

  if (child == -1)
    failwith_perror("fork");

  if (child == 0)
  {
    make_daemon(sock);

    char socket_fd[50], socket_path[PATHSZ];
    sprintf(socket_fd, "%d", sock);
    snprintf(socket_path, PATHSZ, "%s/%s", path_socketdir(), socketname);
    //execlp("nohup", "nohup", exec_path, "server", socket_path, socket_fd, NULL);
    execlp(exec_path, exec_path, "server", socket_path, socket_fd, NULL);
    failwith_perror("execlp");
  }

  close(sock);
  wait(NULL);
}
Пример #3
0
value ml_merlin_context_close(value context, value return_code)
{
  CAMLparam1(context);
  setup_fds(-1, -1, -1);

  char code = (char)(Int_val(return_code));

  ssize_t wrote_ = -1;
  NO_EINTR(wrote_, write(Int_val(Field(context, 0)), &code, sizeof(char)));

  // Close stdin, stdout, stderr
  close(Int_val(Field(context, 1)));
  close(Int_val(Field(context, 2)));
  close(Int_val(Field(context, 3)));

  // Close client connection
  close(Int_val(Field(context, 0)));

  CAMLreturn(Val_unit);
}
Пример #4
0
int main(int argc, char **argv)
{
  char result = 0;
  int err = 0;
  struct stat st;
#ifdef _WIN32
  HANDLE fds[3];
  ULONG pid;
  HANDLE hProcess, hServerProcess;
  DWORD dwNumberOfBytesRead;
  CHAR argv0[PATHSZ];
  GetModuleFileName(NULL, argv0, PATHSZ);
  compute_merlinpath(merlin_path, argv0, &st);
#else
  compute_merlinpath(merlin_path, argv[0], &st);
#endif
  if (argc >= 2 && strcmp(argv[1], "server") == 0)
  {
    IPC_SOCKET_TYPE sock;
    ssize_t len;
#ifdef _WIN32
    compute_socketname(socketname, eventname, merlin_path);
#else
    compute_socketname(socketname, &st);
#endif

    sock = connect_and_serve(socketname, eventname, merlin_path);
    len = prepare_args(argbuffer, sizeof(argbuffer), argc-2, argv+2);
#ifdef _WIN32
    hProcess = GetCurrentProcess();
    if (!GetNamedPipeServerProcessId(sock, &pid))
      failwith_perror("GetNamedPipeServerProcessId");
    hServerProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
    if (hServerProcess == INVALID_HANDLE_VALUE)
      failwith_perror("OpenProcess");
    if (!DuplicateHandle(hProcess, GetStdHandle(STD_INPUT_HANDLE), hServerProcess, &fds[0], 0, FALSE, DUPLICATE_SAME_ACCESS))
      failwith_perror("DuplicateHandle(stdin)");
    if (!DuplicateHandle(hProcess, GetStdHandle(STD_OUTPUT_HANDLE), hServerProcess, &fds[1], 0, FALSE, DUPLICATE_SAME_ACCESS))
      failwith_perror("DuplicateHandle(stdout)");
    CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE));
    if (!DuplicateHandle(hProcess, GetStdHandle(STD_ERROR_HANDLE), hServerProcess, &fds[2], 0, FALSE, DUPLICATE_SAME_ACCESS))
      failwith_perror("DuplicateHandle(stderr)");
#else
    int fds[3] = { STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO };
#endif
    ipc_send(sock, argbuffer, len, fds);

#ifdef _WIN32
    if (ReadFile(sock, &result, 1, &dwNumberOfBytesRead, NULL) && dwNumberOfBytesRead == 1)
      err = 1;
#else
    NO_EINTR(err, read(sock, &result, 1));
#endif
    if (err == 1)
      exit(result);

    unexpected_termination(argc, argv);
  }
  else
  {
    argv[0] = ocamlmerlin_server;
    execvp(merlin_path, argv);
    failwith_perror("execvp(ocamlmerlin-server)");
  }
}
Пример #5
0
static void ipc_send(int fd, unsigned char *buffer, size_t len, int fds[3])
{
  char msg_control[CMSG_SPACE(3 * sizeof(int))];
  struct iovec iov = { .iov_base = buffer, .iov_len = len };
  struct msghdr msg = {
    .msg_iov = &iov, .msg_iovlen = 1,
    .msg_controllen = CMSG_SPACE(3 * sizeof(int)),
  };
  msg.msg_control = &msg_control;
  memset(msg.msg_control, 0, msg.msg_controllen);

  struct cmsghdr *cm = CMSG_FIRSTHDR(&msg);
  cm->cmsg_level = SOL_SOCKET;
  cm->cmsg_type = SCM_RIGHTS;
  cm->cmsg_len = CMSG_LEN(3 * sizeof(int));

  int *fds0 = (int*)CMSG_DATA(cm);
  fds0[0] = fds[0];
  fds0[1] = fds[1];
  fds0[2] = fds[2];

  ssize_t sent;
  NO_EINTR(sent, sendmsg(fd, &msg, 0));

  if (sent == -1)
    failwith_perror("sendmsg");

  while (sent < len)
  {
    ssize_t sent_;
    NO_EINTR(sent_, send(fd, buffer + sent, len - sent, 0));

    if (sent_ == -1)
      failwith_perror("sent");

    sent += sent_;
  }
}
#endif

/* Serialize arguments */

#define byte(x,n) ((unsigned)((x) >> (n * 8)) & 0xFF)

static void append_argument(unsigned char *buffer, size_t len, ssize_t *pos, const char *p)
{
  ssize_t j = *pos;
  while (*p && j < len)
  {
    buffer[j] = *p;
    j += 1;
    p += 1;
  }

  if (j >= len)
    failwith("maximum number of arguments exceeded");

  buffer[j] = 0;
  j += 1;
  *pos = j;
}
Пример #6
0
static ssize_t recv_buffer(int fd, int fds[3])
{
  struct iovec iov = { .iov_base = buffer, .iov_len = sizeof(buffer) };
  struct msghdr msg = {
    .msg_iov = &iov, .msg_iovlen = 1,
    .msg_controllen = CMSG_SPACE(3 * sizeof(int)),
  };
  msg.msg_control = alloca(msg.msg_controllen);
  memset(msg.msg_control, 0, msg.msg_controllen);

  ssize_t recvd;
  NO_EINTR(recvd, recvmsg(fd, &msg, 0));
  if (recvd == -1)
  {
    perror("recvmsg");
    return -1;
  }

  if (recvd < 4)
  {
    ssize_t recvd_;
    do {
      NO_EINTR(recvd_, recv(fd, buffer + recvd, sizeof(buffer) - recvd, 0));
      if (recvd_ > 0)
        recvd += recvd_;
    } while (recvd_ > 0 && recvd < 4);
  }

  size_t target = -1;

  if (recvd > 4)
  {
    target =
      unbyte(buffer[0],0) | unbyte(buffer[1],1) |
      unbyte(buffer[2],2) | unbyte(buffer[3],3);

    if (recvd < target)
    {
      ssize_t recvd_;
      do {
        NO_EINTR(recvd_, recv(fd, buffer + recvd, sizeof(buffer) - recvd, 0));
        if (recvd_ > 0)
          recvd += recvd_;
      } while (recvd_ > 0 && recvd < target);
    }
  }

  struct cmsghdr *cm = CMSG_FIRSTHDR(&msg);

  int *fds0 = (int*)CMSG_DATA(cm);
  int nfds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int);

  /* Check malformed packet */
  if (nfds != 3 || recvd != target || buffer[recvd-1] != '\0')
  {
    int i;
    for (i = 0; i < nfds; ++i)
      close(fds0[i]);
    return -1;
  }

  fds[0] = fds0[0];
  fds[1] = fds0[1];
  fds[2] = fds0[2];

  return recvd;
}

value ml_merlin_server_setup(value path, value strfd)
{
  CAMLparam2(path, strfd);
  CAMLlocal2(payload, ret);
  char *endptr = NULL;

  int fd = strtol(String_val(strfd), &endptr, 0);
  if (endptr && *endptr == '\0')
  {
    /* (path, fd) */
    payload = caml_alloc(2, 0);
    Store_field(payload, 0, path);
    Store_field(payload, 1, Val_int(fd));

    /* Some payload */
    ret = caml_alloc(1, 0);
    Store_field(ret, 0, payload);
  }
  else
  {
    fprintf(stderr, "ml_merlin_server_setup(\"%s\",\"%s\"): invalid argument\n",
        String_val(path), String_val(strfd));
    unlink(String_val(path));
    /* None */
    ret = Val_unit;
  }

  CAMLreturn(ret);
}

value ml_merlin_server_accept(value server, value val_timeout)
{
  CAMLparam2(server, val_timeout);
  CAMLlocal4(ret, client, args, context);

  // Compute timeout
  double timeout = Double_val(val_timeout);
  struct timeval tv;
  tv.tv_sec = timeout;
  tv.tv_usec = (timeout - tv.tv_sec) * 1000000;

  // Select on server
  int serverfd = Int_val(Field(server, 1));
  int selectres;
  fd_set readset;
  do {
    FD_ZERO(&readset);
    FD_SET(serverfd, &readset);
    selectres = select(serverfd + 1, &readset, NULL, NULL, &tv);
  } while (selectres == -1 && errno == EINTR);

  int fds[3], clientfd;
  ssize_t len = -1;

  if (selectres > 0)
  {
    NO_EINTR(clientfd, accept(serverfd, NULL, NULL));
    len = recv_buffer(clientfd, fds);
  }

  if (len == -1)
    ret = Val_unit; /* None */
  else {
    context = caml_alloc(4, 0); /* (clientfd, stdin, stdout, stderr) */
    Store_field(context, 0, Val_int(clientfd));
    Store_field(context, 1, Val_int(fds[0]));
    Store_field(context, 2, Val_int(fds[1]));
    Store_field(context, 3, Val_int(fds[2]));

    ssize_t i, j;
    int argc = 0;
    for (i = 4; i < len; ++i)
      if (buffer[i] == '\0')
        argc += 1;

    args = caml_alloc(argc, 0);

    argc = 0;
    for (i = 4, j = 4; i < len; ++i)
    {
      if (buffer[i] == '\0')
      {
        Store_field(args, argc, caml_copy_string((const char *)&buffer[j]));
        j = i + 1;
        argc += 1;
      }
    }

    client = caml_alloc(2, 0); /* (context, args) */
    Store_field(client, 0, context);
    Store_field(client, 1, args);

    ret = caml_alloc(1, 0); /* Some client */
    Store_field(ret, 0, client);
  }

  CAMLreturn(ret);
}