Skip to content

Instantly share code, notes, and snippets.

@jim3ma
Forked from kokjo/sendfd.c
Last active August 21, 2018 06:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jim3ma/93c41ac2bdf347579524b81064b5b03d to your computer and use it in GitHub Desktop.
Save jim3ma/93c41ac2bdf347579524b81064b5b03d to your computer and use it in GitHub Desktop.
Send a file descriptor over an abstract unix domain socket
// compile with: gcc -static -o recvfd recvfd.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <strings.h>
/**
* Receives file descriptor using given socket
*
* @param socket to be used for fd recepion
* @return received file descriptor; -1 if failed
*
* @note socket should be (PF_UNIX, SOCK_DGRAM)
*/
int recvfd(int socket) {
int len;
int fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_control = (caddr_t) cms;
msg.msg_controllen = sizeof cms;
len = recvmsg(socket, &msg, 0);
if (len < 0) {
LOGE("recvmsg failed with %s", strerror(errno));
return -1;
}
if (len == 0) {
LOGE("recvmsg failed no data");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
// compile with: gcc -static -o sendfd sendfd.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <strings.h>
/**
* Sends given file descriptior via given socket
*
* @param socket to be used for fd sending
* @param fd to be sent
* @return sendmsg result
*
* @note socket should be (PF_UNIX, SOCK_DGRAM)
*/
int send_fd(int sock, int fd){
// This function does the arcane magic for sending
// file descriptors over unix domain sockets
struct msghdr msg;
struct iovec iov[1];
struct cmsghdr *cmsg = NULL;
char ctrl_buf[CMSG_SPACE(sizeof(int))];
char data[1];
memset(&msg, 0, sizeof(struct msghdr));
memset(ctrl_buf, 0, CMSG_SPACE(sizeof(int)));
data[0] = ' ';
iov[0].iov_base = data;
iov[0].iov_len = sizeof(data);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_controllen = CMSG_SPACE(sizeof(int));
msg.msg_control = ctrl_buf;
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*((int *) CMSG_DATA(cmsg)) = fd;
return sendmsg(sock, &msg, 0);
}
int main(int argc, char **argv){
struct sockaddr_un addr;
int sock;
int conn;
int fd;
// Create a unix domain socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
// Bind it to a abstract address
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(&addr.sun_path[1], argv[1]);
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
// Open the file descriptor we want to send
fd = open(argv[2], 0);
// Listen
listen(sock, 1);
// Just send the file descriptor to anyone who connects
for(;;){
conn = accept(sock, NULL, 0);
send_fd(conn, fd);
close(conn);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment