Skip to content

Instantly share code, notes, and snippets.

@jonas-schievink
Last active July 11, 2018 20:10
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 jonas-schievink/cb6e6584a055539d2113f22d91068e2d to your computer and use it in GitHub Desktop.
Save jonas-schievink/cb6e6584a055539d2113f22d91068e2d to your computer and use it in GitHub Desktop.
Passing multiple control messages at once over a Unix socket
creating socketpair
fds: 3 4
encoded cmsgs into 40 byte buf:
18 00 00 00 01 00 00 00 02 00 00 00 a7 2c 00 00 e8 03 00 00 e8 03 00 00 10 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00
re-decode msgs without going through socket:
raw control buffer size: 40 bytes
cmsg 1:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 2 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 24 (for 1 int = 16, for ucred = 24)
cmsg 2:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 1 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 16 (for 1 int = 16, for ucred = 24)
flags = 0x00
received msgs:
raw control buffer size: 40 bytes
cmsg 1:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 2 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 24 (for 1 int = 16, for ucred = 24)
cmsg 2:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 1 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 16 (for 1 int = 16, for ucred = 24)
creating socketpair
fds: 3 4
encoded cmsgs into 56 byte buf:
1c 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 f3 21 00 00 e8 03 00 00 e8 03 00 00 00 00 00 00 14 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00
re-decode msgs without going through socket:
raw control buffer size: 56 bytes
cmsg 1:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 2 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 28 (for 1 int = 20, for ucred = 28)
cmsg 2:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 1 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 20 (for 1 int = 20, for ucred = 28)
flags = 0x00
received msgs:
raw control buffer size: 56 bytes
cmsg 1:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 2 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 28 (for 1 int = 20, for ucred = 28)
cmsg 2:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 1 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 20 (for 1 int = 20, for ucred = 28)
creating socketpair
fds: 3 4
encoded cmsgs into 56 byte buf:
1c 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 e1 22 00 00 e8 03 00 00 e8 03 00 00 00 00 00 00 14 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00
re-decode msgs without going through socket:
raw control buffer size: 56 bytes
cmsg 1:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 2 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 28 (for 1 int = 20, for ucred = 28)
cmsg 2:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 1 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 20 (for 1 int = 20, for ucred = 28)
flags = 0x00
received msgs:
raw control buffer size: 32 bytes
cmsg 1:
cmsg lvl: 1 (SOL_SOCKET = 1)
cmsg type: 2 (SCM_RIGHTS = 1, SCM_CREDENTIALS = 2)
cmsg len: 28 (for 1 int = 20, for ucred = 28)
#define _GNU_SOURCE
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#define MSG_SPACE CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred))
void decode_msgs(struct msghdr* hdr);
void encode_msgs(struct msghdr* hdr)
{
struct cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDENTIALS;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
struct ucred* cred = (struct ucred*) CMSG_DATA(cmsg);
cred->pid = getpid();
cred->uid = getuid();
cred->gid = getgid();
cmsg = CMSG_NXTHDR(hdr, cmsg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
int* fd = (int*) CMSG_DATA(cmsg);
*fd = STDOUT_FILENO;
printf("encoded cmsgs into %zd byte buf:\n", hdr->msg_controllen);
for (int i = 0; i < hdr->msg_controllen; i++)
{
printf("%.2x ", ((unsigned char*) hdr->msg_control)[i]);
}
printf("\n");
printf("re-decode msgs without going through socket:\n");
decode_msgs(hdr);
}
void decode_msgs(struct msghdr* hdr)
{
printf("raw control buffer size: %zd bytes\n", hdr->msg_controllen);
struct cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
for (int i = 1; cmsg; i++)
{
printf("cmsg %d:\n", i);
printf("cmsg lvl: %d (SOL_SOCKET = %d)\n", cmsg->cmsg_level, SOL_SOCKET);
printf("cmsg type: %d (SCM_RIGHTS = %d, SCM_CREDENTIALS = %d)\n", cmsg->cmsg_type, SCM_RIGHTS, SCM_CREDENTIALS);
printf("cmsg len: %zd (for 1 int = %zd, for ucred = %zd)\n", cmsg->cmsg_len, CMSG_LEN(sizeof(int)), CMSG_LEN(sizeof(struct ucred)));
cmsg = CMSG_NXTHDR(hdr, cmsg);
}
}
int main()
{
char sendbuf[MSG_SPACE];
char recvbuf[MSG_SPACE];
memset(sendbuf, 0, MSG_SPACE);
memset(recvbuf, 0, MSG_SPACE);
int fds[2];
printf("creating socketpair\n");
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) == -1)
{
perror("socketpair");
return 1;
}
printf("fds: %d %d\n", fds[0], fds[1]);
// 1-byte dummy transfer
char dummy = '!';
struct iovec iov;
iov.iov_base = &dummy;
iov.iov_len = 1;
struct msghdr hdr;
hdr.msg_name = NULL;
hdr.msg_flags = 0;
hdr.msg_namelen = 0;
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
hdr.msg_control = sendbuf;
hdr.msg_controllen = sizeof(sendbuf);
encode_msgs(&hdr);
int val = 1;
if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &val, sizeof(int)) != 0)
{
perror("setsockopt");
return 1;
}
ssize_t sent = sendmsg(fds[0], &hdr, 0);
switch (sent)
{
case 1:
break;
case -1:
perror("sendmsg");
return 1;
default:
printf("expected to send 1 byte, actual: %zd\n", sent);
return 1;
}
// recv from other fd back into same buffer
hdr.msg_control = recvbuf;
hdr.msg_controllen = sizeof(recvbuf);
ssize_t recvd = recvmsg(fds[1], &hdr, 0);
switch (recvd)
{
case 1:
break;
case -1:
perror("recvmsg");
return 1;
default:
printf("expected to recv 1 byte, got %zd\n", recvd);
return 1;
}
printf("flags = 0x%.2x\n", hdr.msg_flags);
if ((hdr.msg_flags & MSG_TRUNC != 0) || (hdr.msg_flags & MSG_CTRUNC != 0))
{
printf("truncated! flags = %x\n", hdr.msg_flags);
return 1;
}
printf("received msgs:\n");
decode_msgs(&hdr);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment