Skip to content

Instantly share code, notes, and snippets.

@indutny
Created February 6, 2014 10:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save indutny/8842007 to your computer and use it in GitHub Desktop.
Save indutny/8842007 to your computer and use it in GitHub Desktop.
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
int master(int sh) {
int s;
int err;
struct sockaddr_in addr;
struct msghdr msg;
struct cmsghdr* cmsg;
struct iovec iov;
char scratch[256];
/* Create UDP socket */
s = socket(AF_INET, SOCK_DGRAM, 0);
assert(s != -1);
/* Bind it to random port */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
err = bind(s, (struct sockaddr*) &addr, sizeof(addr));
assert(err == 0);
/* Send socket via SCM_RIGHTS */
iov.iov_base = "X";
iov.iov_len = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_control = (void*) scratch;
msg.msg_controllen = CMSG_LEN(sizeof(s));
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = msg.msg_controllen;
memcpy(CMSG_DATA(cmsg), &s, sizeof(s));
do
err = sendmsg(sh, &msg, 0);
while (err < 0 && (errno == EINTR || errno == EAGAIN));
assert(err == iov.iov_len);
/* Uncomment next line to fix EPOLLOUT in worker */
/* close(s); */
for (;;) {}
return 0;
}
int worker(int sh) {
int ep;
int err;
int received;
struct msghdr msg;
struct cmsghdr* cmsg;
struct iovec iov;
struct epoll_event ev;
char buf[256];
char space[64];
/* Receive socket via SCM_RIGHTS */
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_flags = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_controllen = sizeof(space);
msg.msg_control = space;
do
err = recvmsg(sh, &msg, 0);
while (err < 0 && (errno == EINTR || errno == EAGAIN));
cmsg = CMSG_FIRSTHDR(&msg);
assert(cmsg != NULL);
assert(cmsg->cmsg_type == SCM_RIGHTS);
assert(cmsg->cmsg_len >= sizeof(received));
received = *(int*) CMSG_DATA(cmsg);
/* Initialize epoll */
ep = epoll_create(1024);
assert(ep != -1);
/* Add received socket to epoll to poll for write events */
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLOUT;
ev.data.fd = received;
err = epoll_ctl(ep, EPOLL_CTL_ADD, received, &ev);
assert(err == 0);
/* Close socket */
close(received);
/* Wait for events */
err = epoll_wait(ep, &ev, 1, -1);
assert(err == 1);
fprintf(stdout, "Voila, got event on closed fd: %d\n", ev.data.fd);
close(ep);
return 0;
}
int main() {
int err;
int sh[2];
err = socketpair(AF_UNIX, SOCK_STREAM, 0, sh);
assert(err == 0);
err = fork();
assert(err != -1);
if (err != 0) {
close(sh[1]);
err = master(sh[0]);
close(sh[0]);
} else {
close(sh[0]);
err = worker(sh[1]);
close(sh[1]);
}
return err;
}
CFLAGS ?=
CFLAGS += -g -Wall
all: main
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
main: main.o
$(CC) $(CFLAGS) $< -o $@
.PHONY: all
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment