Created
January 8, 2013 05:25
-
-
Save kazu-yamamoto/4481465 to your computer and use it in GitHub Desktop.
A program to check which socket flags are inherited.
This file contains hidden or 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 <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