Skip to content
This repository was archived by the owner on Jun 22, 2021. It is now read-only.
This repository was archived by the owner on Jun 22, 2021. It is now read-only.

Send file descriptors of text files over libuv pipe #168

Open
@manishmanu

Description

@manishmanu

I have to send file descriptors of some shared memory buffers from one process to another. I'm able to transfer the fds directly over UNIX Domain Sockets as below:

Send FDs:

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");
}

Receive FDs:

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;
}

But when i use domain sockets through abstraction libuv_pipe_t provided by libuv, I was not able to transfer the fds. Does libuv provides any way to transfer file descriptors between server pipe and client pipe ? If yes how to send and receive fds exactly ?

uv_pipe_t server:

#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);

 // 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 client ?
}

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 client:

#include <assert.h>
#include <memory.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) {
   // read file descriptors
}

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

  int r =
      uv_read_start((uv_stream_t*)connect_req->handle, alloc_buffer, read_cb);
}

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());
}

this example shows how to transfer pipe handles over pipes but it's doesn't completely solve my problem.

Any help is appreciated !!!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions