Last active
July 11, 2018 20:10
-
-
Save jonas-schievink/cb6e6584a055539d2113f22d91068e2d to your computer and use it in GitHub Desktop.
Passing multiple control messages at once over a Unix socket
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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