Created
February 6, 2014 10:48
-
-
Save indutny/8842007 to your computer and use it in GitHub Desktop.
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
#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; | |
} |
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
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