Skip to content

Instantly share code, notes, and snippets.

@kazu-yamamoto
Created January 8, 2013 05:25
Show Gist options
  • Save kazu-yamamoto/4481465 to your computer and use it in GitHub Desktop.
Save kazu-yamamoto/4481465 to your computer and use it in GitHub Desktop.
A program to check which socket flags are inherited.
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define HOST "::1"
#define PORT "7000"
void display_flags(int fd, char *msg) {
printf("%s:\n", msg);
int reuseaddr;
socklen_t reuseaddr_len = sizeof(reuseaddr);
getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, &reuseaddr_len);
printf("\tSO_REUSEADDR is %d.\n", reuseaddr != 0);
int nodelay;
socklen_t nodelay_len = sizeof(nodelay);
getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, &nodelay_len);
printf("\tTCP_NODELAY is %d.\n", nodelay != 0);
int v6only;
socklen_t v6only_len = sizeof(v6only);
getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, &v6only_len);
printf("\tIPV6_V6ONLY is %d.\n", v6only != 0);
int nonblock = fcntl(fd, F_GETFL);
printf("\tO_NONBLOCK is %d.\n", ((nonblock & O_NONBLOCK) != 0));
int cloexec = fcntl(fd, F_GETFD);
printf("\tFD_CLOEXEC is %d.\n", ((cloexec & FD_CLOEXEC) != 0));
}
////////////////////////////////////////////////////////////////
void exit_error(int ret, char *msg) {
if (ret < 0) {
perror(msg);
exit(EXIT_FAILURE);
}
}
void exit_gai_error(int ret) {
if (ret != 0) {
fprintf(stderr, "%s\n", gai_strerror(ret));
exit(EXIT_FAILURE);
}
}
////////////////////////////////////////////////////////////////
struct addrinfo *get_my_addr(char *port) {
struct addrinfo hints, *addr;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
int ret = getaddrinfo(NULL, port, &hints, &addr);
exit_gai_error(ret);
return addr;
}
int get_server_socket(struct addrinfo *addr) {
int sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
exit_error(sock, "socket");
return sock;
}
int get_socket() {
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
exit_error(sock, "socket");
return sock;
}
////////////////////////////////////////////////////////////////
void set_reuseaddr(int sock) {
int on = 1;
int ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
exit_error(ret, "setsockopt REUSEADDR");
}
void set_nodelay(int sock) {
int on = 1;
int ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
exit_error(ret, "setsockopt NODELAY");
}
void unset_v6only(int sock) {
int off = 0;
int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
exit_error(ret, "setsockopt IPV6_V6ONLY");
}
void set_nonblock(int sock) {
int flags = fcntl(sock, F_GETFL);
int ret = fcntl(sock, F_SETFL, (flags | O_NONBLOCK));
exit_error(ret, "NONBLOCK");
}
void set_cloexec(int sock) {
int flags = fcntl(sock, F_GETFD);
int ret = fcntl(sock, F_SETFD, (flags | FD_CLOEXEC));
exit_error(ret, "CLOEXEC");
}
void set_flags(int sock) {
set_reuseaddr(sock);
set_nodelay(sock);
unset_v6only(sock);
set_nonblock(sock);
set_cloexec(sock);
}
////////////////////////////////////////////////////////////////
void bind_socket(int sock, struct addrinfo *addr) {
int ret = bind(sock, addr->ai_addr, addr->ai_addrlen);
exit_error(ret, "bind");
}
void listen_socket(int sock, int qlen) {
int ret = listen(sock, qlen);
exit_error(ret, "socket");
}
int prepare_server(char *port) {
struct addrinfo *addr = get_my_addr(port);
int sock = get_server_socket(addr);
display_flags(sock, "vanilla listen socket");
set_flags(sock);
display_flags(sock, "cooked listen socket");
bind_socket(sock, addr);
listen_socket(sock, SOMAXCONN);
freeaddrinfo(addr);
return sock;
}
////////////////////////////////////////////////////////////////
int accept_client(int sock) {
int ssock= accept(sock, NULL, NULL);
exit_error(ssock, "accept");
return ssock;
}
void run_server(int sock) {
int ssock = accept_client(sock);
display_flags(ssock, "accepted socket");
}
////////////////////////////////////////////////////////////////
struct addrinfo *get_peer_addr(char *host, char *port) {
struct addrinfo hints, *addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
int ret = getaddrinfo(host, port, &hints, &addr);
exit_gai_error(ret);
return addr;
}
int get_client_socket(struct addrinfo *addr) {
int sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
exit_error(sock, "socket");
return sock;
}
void connect_to_peer(int sock, struct addrinfo *addr) {
int res = connect(sock, addr->ai_addr, addr->ai_addrlen);
exit_error(res, "connect");
}
void run_client(char *host, char *port) {
struct addrinfo *addr = get_peer_addr(host, port);
int sock = get_client_socket(addr);
connect_to_peer(sock, addr);
freeaddrinfo(addr);
}
////////////////////////////////////////////////////////////////
int main() {
int sock = prepare_server(PORT);
sleep(1);
run_client(HOST, PORT);
sleep(1);
run_server(sock);
exit(EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment