Отправка и получение файловых дескрипторов через LIBUV Pipe

Мне нужно отправить файловые дескрипторы некоторых буферов общей памяти из одного процесса в другой. Я могу передать fds напрямую через сокеты домена UNIX, как показано ниже:

Отправить ФД:

static void send_fds(int socket, int* fds, int n)  // send fd by socket
{
  struct msghdr msg = {0};
  struct cmsghdr* cmsg;
  char buf[CMSG_SPACE(n * sizeof(int))], dup[256];
  memset(buf, '\0', sizeof(buf));
  struct iovec io = {.iov_base = &dup, .iov_len = sizeof(dup)};

  msg.msg_iov = &io;
  msg.msg_iovlen = 1;
  msg.msg_control = buf;
  msg.msg_controllen = sizeof(buf);

  cmsg = CMSG_FIRSTHDR(&msg);
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_RIGHTS;
  cmsg->cmsg_len = CMSG_LEN(n * sizeof(int));

  memcpy((int*)CMSG_DATA(cmsg), fds, n * sizeof(int));

  if (sendmsg(socket, &msg, 0) < 0)
    printf("Failed to send message\n");
}

Получить ФД:

static int* recv_fds(int socket, int n) {
  int* fds = (int*)malloc(n * sizeof(int));
  struct msghdr msg = {0};
  struct cmsghdr* cmsg;
  char buf[CMSG_SPACE(n * sizeof(int))], dup[256];
  memset(buf, '\0', sizeof(buf));
  struct iovec io = {.iov_base = &dup, .iov_len = sizeof(dup)};

  msg.msg_iov = &io;
  msg.msg_iovlen = 1;
  msg.msg_control = buf;
  msg.msg_controllen = sizeof(buf);

  if (recvmsg(socket, &msg, 0) < 0)
    printf("Failed to receive message\n");

  cmsg = CMSG_FIRSTHDR(&msg);

  memcpy(fds, (int*)CMSG_DATA(cmsg), n * sizeof(int));

  return fds;
}

Но когда я использую доменные сокеты через абстракцию libuv_pipe_t, предоставленную libuv, я не смог передать fds. Предоставляет ли libuv какой-либо способ передачи файловых дескрипторов между серверным каналом и клиентским каналом? Если да, то как именно отправлять и получать fds?

сервер uv_pipe_t:

#include <assert.h>
#include <memory.h>
#include <stdlib.h>
#include <unistd.h>

#include <uv.h>

#define SOCKET_NAME "socket_name"

void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
  static char buffer[1024];
  buf->base = buffer;
  buf->len = sizeof(buffer);
}

void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
  if (nread < 0) {
    uv_stop(stream->loop);
    uv_close((uv_handle_t*)stream, NULL);
  }
  printf("message received : %s\n", buf->base);
}

static void connection_cb(uv_stream_t* server, int status) {
  printf("new connection recevied\n");
  int r;
  uv_pipe_t connection;
  r = uv_pipe_init(server->loop, &connection, 0);
  assert(r == 0);
  r = uv_accept(server, (uv_stream_t*)&connection);
  assert(r == 0);

  r = uv_read_start((uv_stream_t*)&connection, alloc_buffer, read_cb);
  assert(r == 0);
}

int main() {
  uv_pipe_t p;
  int r;

  r = uv_pipe_init(uv_default_loop(), &p, 0);
  assert(r == 0);

  unlink(SOCKET_NAME);
  r = uv_pipe_bind(&p, SOCKET_NAME);
  assert(r == 0);

  r = uv_listen((uv_stream_t*)&p, 128, connection_cb);
  assert(r == 0);

  printf("listening...\n");
  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  uv_loop_close(uv_default_loop());
}

клиент uv_pipe_t:

#include <assert.h>
#include <memory.h>

#include <uv.h>

#define SOCKET_NAME "socket_name"

static void connect_cb(uv_connect_t* connect_req, int status) {
  printf("connected!");

  // send file descriptor
  int fds[2];
  fds[0] = fileno(fopen("fd_test_0.txt", "w"));
  fds[1] = fileno(fopen("fd_test_1.txt", "w"));
  
  // how to send "fds" array to server ?
}

int main() {
  uv_pipe_t p;
  uv_connect_t conn_req;
  int r;
  r = uv_pipe_init(uv_default_loop(), &p, 0);
  assert(r == 0);

  uv_pipe_connect(&conn_req, &p, SOCKET_NAME, connect_cb);

  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  uv_loop_close(uv_default_loop());
}

этот пример показывает, как передавать pipe обрабатывает трубы, но это не полностью решает мою проблему.

Любая помощь приветствуется !!!


person manish reddy    schedule 14.09.2020    source источник


Ответы (1)


Это объясняется здесь, в документации libuv: http://docs.libuv.org/en/v1.x/guide/processes.html#sending-file-descriptors-over-pipes

Тебе следует:

  • установите для параметра ipc значение 1 в uv_pipe_init с обеих сторон
  • на клиенте используйте uv_write2 для отправки дескриптора файла
  • принять его на сервере через uv_accept, затем взять фактически переданный номер fd из uv_stream_t принять параметр с uv_fileno.

Но док также говорит:

На данный момент libuv поддерживает только отправку сокетов TCP или других каналов по каналам.

Таким образом, это может не работать с вашим дескриптором файла буфера памяти.

person emgee    schedule 30.01.2021