Skip to content

Instantly share code, notes, and snippets.

@pandax381
Last active February 22, 2017 08:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pandax381/05a721ae415d49e362d8c9a3ba021334 to your computer and use it in GitHub Desktop.
Save pandax381/05a721ae415d49e362d8c9a3ba021334 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#define SRC_PORT 54321
#define DST_PORT 111
#define SRC_HOST "10.10.0.3"
#define DST_HOST "10.10.0.2"
static int counter = 0;
struct pseudo_ip_header {
unsigned int src_ip;
unsigned int dst_ip;
unsigned char zero;
unsigned char protocol;
unsigned short len;
};
struct pseudo_header {
struct pseudo_ip_header iphdr;
struct tcphdr ptcphdr;
};
static unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum = 0;
while (size > 1) {
cksum += *buffer++;
size -= sizeof(unsigned short);
}
if (size)
cksum += *(char *)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (unsigned short)(~cksum);
}
static void check_port_raw_socket(int max)
{
int src_port = SRC_PORT;
int dst_port = DST_PORT;
char srcip[] = SRC_HOST;
char dstip[] = DST_HOST;
struct tcphdr tcphdr;
struct pseudo_header pheader;
struct sockaddr_in peer;
struct sockaddr *peer_ptr;
int sock;
int saddr_size;
int windowsize = 4321;
int tcphdr_size = sizeof(struct tcphdr);
int iphdr_size = sizeof(struct ip);
printf("bench type: %s bench num: %d\n", __func__, max);
tcphdr.source = htons(src_port);
tcphdr.dest = htons(dst_port);
tcphdr.window = htons(windowsize);
tcphdr.seq = 1;
tcphdr.fin = 0;
tcphdr.syn = 1;
tcphdr.doff = 5;
tcphdr.rst = 0;
tcphdr.urg = 0;
tcphdr.urg_ptr = 0;
tcphdr.psh = 0;
tcphdr.ack_seq = 0;
tcphdr.ack = 0;
tcphdr.check = 0;
tcphdr.res1 = 0;
tcphdr.res2 = 0;
inet_aton(srcip, (struct in_addr *)&pheader.iphdr.src_ip);
inet_aton(dstip, (struct in_addr *)&pheader.iphdr.dst_ip);
pheader.iphdr.zero = 0;
pheader.iphdr.protocol = 6;
pheader.iphdr.len = htons(sizeof(struct ip));
inet_aton(dstip, &peer.sin_addr);
peer.sin_port = htons(dst_port);
peer.sin_family = AF_INET;
saddr_size = sizeof(peer);
peer_ptr = (struct sockaddr *)&peer;
bcopy((char *)&tcphdr, (char *)&pheader.ptcphdr, sizeof(struct ip));
tcphdr.check = checksum((unsigned short *)&pheader, 32);
counter = 0;
while (counter < max) {
sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
sendto(sock, &tcphdr, tcphdr_size, 0, peer_ptr, saddr_size);
while (1) {
struct tcphdr *tcp;
unsigned char buffer[4096] = {0};
recvfrom(sock, buffer, 4096, 0, peer_ptr, &saddr_size);
tcp = (struct tcphdr *)(buffer + iphdr_size);
if (tcp->syn == 1 && tcp->ack == 1) {
counter++;
break;
}
}
close(sock);
}
}
static void check_port_sysconnect_so_linger(int max)
{
int src_port = SRC_PORT;
int dst_port = DST_PORT;
char srcip[] = SRC_HOST;
char dstip[] = DST_HOST;
struct linger so_linger;
struct sockaddr_in peer;
struct sockaddr *peer_ptr;
int sock, peer_size;
int so_linger_size = sizeof(so_linger);
printf("bench type: %s bench num: %d\n", __func__, max);
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
inet_aton(dstip, &peer.sin_addr);
peer.sin_port = htons(dst_port);
peer.sin_family = AF_INET;
peer_size = sizeof(peer);
peer_ptr = (struct sockaddr *)&peer;
counter = 0;
while (counter < max) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connect(sock, peer_ptr, peer_size) != -1) {
counter++;
}
setsockopt(sock, SOL_SOCKET, SO_LINGER, &so_linger, so_linger_size);
close(sock);
}
}
static void check_port_sysconnect_so_linger_poll(int max)
{
int src_port = SRC_PORT;
int dst_port = DST_PORT;
char srcip[] = SRC_HOST;
char dstip[] = DST_HOST;
struct linger so_linger;
struct sockaddr_in peer;
struct sockaddr *peer_ptr;
int sock, peer_size;
int so_linger_size = sizeof(so_linger);
int opt = 1;
struct pollfd pfds[1];
printf("bench type: %s bench num: %d\n", __func__, max);
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
inet_aton(dstip, &peer.sin_addr);
peer.sin_port = htons(dst_port);
peer.sin_family = AF_INET;
peer_size = sizeof(peer);
peer_ptr = (struct sockaddr *)&peer;
pfds[0].events = POLLIN | POLLOUT;
counter = 0;
while (counter < max) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ioctl(sock, FIONBIO, &opt);
connect(sock, peer_ptr, peer_size);
setsockopt(sock, SOL_SOCKET, SO_LINGER, &so_linger, so_linger_size);
pfds[0].fd = sock;
if (poll(pfds, 1, -1) > 0) {
counter++;
}
close(sock);
}
}
static void check_port_sysconnect_so_linger_epoll(int max)
{
int src_port = SRC_PORT;
int dst_port = DST_PORT;
char srcip[] = SRC_HOST;
char dstip[] = DST_HOST;
struct linger so_linger;
struct sockaddr_in peer;
struct sockaddr *peer_ptr;
int sock, peer_size;
int so_linger_size = sizeof(so_linger);
int opt = 1;
int epfd;
struct epoll_event ev, events[1];
printf("bench type: %s bench num: %d\n", __func__, max);
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
inet_aton(dstip, &peer.sin_addr);
peer.sin_port = htons(dst_port);
peer.sin_family = AF_INET;
peer_size = sizeof(peer);
peer_ptr = (struct sockaddr *)&peer;
epfd = epoll_create(1);
ev.events = EPOLLIN | EPOLLOUT;
counter = 0;
while (counter < max) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ioctl(sock, FIONBIO, &opt);
connect(sock, peer_ptr, peer_size);
setsockopt(sock, SOL_SOCKET, SO_LINGER, &so_linger, so_linger_size);
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);
if (epoll_wait(epfd, events, 1, -1) > 0) {
counter++;
}
close(sock);
}
}
static void check_port_sysconnect(int max)
{
int src_port = SRC_PORT;
int dst_port = DST_PORT;
char srcip[] = SRC_HOST;
char dstip[] = DST_HOST;
struct sockaddr_in peer;
struct sockaddr *peer_ptr;
int sock, peer_size;
printf("bench type: %s bench num: %d\n", __func__, max);
inet_aton(dstip, &peer.sin_addr);
peer.sin_port = htons(dst_port);
peer.sin_family = AF_INET;
peer_size = sizeof(peer);
peer_ptr = (struct sockaddr *)&peer;
counter = 0;
while (counter < max) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connect(sock, peer_ptr, peer_size) != -1) {
counter++;
}
close(sock);
}
}
int main(int argc, const char **argv)
{
int max;
if (argc != 3) {
printf("type('raw' or 'connect') check_num\n");
return 1;
}
max = atoi(argv[2]);
if (strcmp(argv[1], "raw") == 0) {
check_port_raw_socket(max);
}
if (strcmp(argv[1], "connect") == 0) {
check_port_sysconnect(max);
}
if (strcmp(argv[1], "so_linger_connect") == 0) {
check_port_sysconnect_so_linger(max);
}
if (strcmp(argv[1], "so_linger_connect_poll") == 0) {
check_port_sysconnect_so_linger_poll(max);
}
if (strcmp(argv[1], "so_linger_connect_epoll") == 0) {
check_port_sysconnect_so_linger_epoll(max);
}
return 0;
}
@pandax381
Copy link
Author

ayanami03:~/LOCAL/src/sandbox# ping -c 5 10.10.0.2
PING 10.10.0.2 (10.10.0.2) 56(84) bytes of data.
64 bytes from 10.10.0.2: icmp_seq=1 ttl=64 time=0.205 ms
64 bytes from 10.10.0.2: icmp_seq=2 ttl=64 time=0.220 ms
64 bytes from 10.10.0.2: icmp_seq=3 ttl=64 time=0.220 ms
64 bytes from 10.10.0.2: icmp_seq=4 ttl=64 time=0.265 ms
64 bytes from 10.10.0.2: icmp_seq=5 ttl=64 time=0.215 ms

--- 10.10.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3997ms
rtt min/avg/max/mdev = 0.205/0.225/0.265/0.020 ms

raw socket

ayanami03:~/LOCAL/src/sandbox# time ./a.out raw 10000
bench type: check_port_raw_socket bench num: 10000

real	0m1.281s
user	0m0.032s
sys	0m0.304s

connect + SO_LINGER

ayanami03:~/LOCAL/src/sandbox# time ./a.out so_linger_connect 100000
bench type: check_port_sysconnect_so_linger bench num: 100000

real	0m14.001s
user	0m0.096s
sys	0m4.208s

non blocking connect + SO_LINGER + poll

ayanami03:~/LOCAL/src/sandbox# time ./a.out so_linger_connect_poll 100000
bench type: check_port_sysconnect_so_linger_poll bench num: 100000

real	0m13.188s
user	0m0.144s
sys	0m4.252s

non blocking connect + SO_LINGER + epoll

ayanami03:~/LOCAL/src/sandbox# time ./a.out so_linger_connect_epoll 100000
bench type: check_port_sysconnect_so_linger_epoll bench num: 100000

real	0m13.514s
user	0m0.172s
sys	0m4.324s

@pandax381
Copy link
Author

あ、raw socket のやつだけ試行回数が一桁少ない...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment