commit
22e71c2c12
@ -0,0 +1,2 @@ |
||||
all: pingpong.c |
||||
gcc -g -O3 -o vpp-pingpong pingpong.c -lvppcom
|
@ -0,0 +1,319 @@ |
||||
#include <stdio.h> |
||||
#include <time.h> |
||||
#include <sys/ioctl.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <strings.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <arpa/inet.h> |
||||
#include <netinet/tcp.h> |
||||
#include <errno.h> |
||||
#include <assert.h> |
||||
#include <signal.h> |
||||
|
||||
#include <vcl/vppcom.h> |
||||
|
||||
#define MAX_EVENTS 512 |
||||
|
||||
struct epoll_event ev; |
||||
struct epoll_event events[MAX_EVENTS]; |
||||
|
||||
static int message_size = 4096; |
||||
static char *buf = NULL; |
||||
|
||||
static int epfd = -1; |
||||
static int sockfd = -1; |
||||
static int is_client = 0; |
||||
|
||||
/* Echo server */ |
||||
int loop(void *arg) |
||||
{ |
||||
/* Wait for events to happen */ |
||||
int nevents = vppcom_epoll_wait(epfd, events, MAX_EVENTS, 0); |
||||
if (nevents < 0) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int i; |
||||
|
||||
for (i = 0; i < nevents; ++i) |
||||
{ |
||||
/* Handle new connection */ |
||||
if (events[i].data.fd == sockfd) |
||||
{ |
||||
while (1) |
||||
{ |
||||
int nclientfd = vppcom_session_accept(sockfd, NULL, 0); |
||||
if (nclientfd < 0) |
||||
{ |
||||
break; |
||||
} |
||||
/* Add to event list */ |
||||
ev.data.fd = nclientfd; |
||||
ev.events = EPOLLIN; |
||||
int rv = vppcom_epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev); |
||||
if (rv) |
||||
{ |
||||
printf("vppcom_epoll_ctl failed: %d\n", rv); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (events[i].events & (EPOLLERR|EPOLLHUP)) |
||||
{ |
||||
/* Simply close socket */ |
||||
vppcom_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); |
||||
vppcom_session_close(events[i].data.fd); |
||||
} |
||||
else if (events[i].events & EPOLLIN) |
||||
{ |
||||
size_t readlen = vppcom_session_read(events[i].data.fd, buf, message_size); |
||||
if (readlen > 0) |
||||
vppcom_session_write(events[i].data.fd, buf, readlen); |
||||
else |
||||
{ |
||||
vppcom_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); |
||||
vppcom_session_close(events[i].data.fd); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
printf("unknown event: %8.8X\n", events[i].events); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static uint64_t sum_us = 0, count_us = 0; |
||||
static int to_write = 0; |
||||
static int to_read = 0; |
||||
static int connected = 0; |
||||
static struct timespec connect_time; |
||||
static struct timespec start, end; |
||||
|
||||
void sigint_handler(int signum) |
||||
{ |
||||
if (sockfd >= 0) |
||||
{ |
||||
vppcom_session_close(sockfd); |
||||
sockfd = 0; |
||||
} |
||||
if (is_client) |
||||
{ |
||||
struct timespec stop_time; |
||||
clock_gettime(CLOCK_REALTIME, &stop_time); |
||||
double duration_sec = ((stop_time.tv_nsec - connect_time.tv_nsec)/1000000000.0 + 1.0*(stop_time.tv_sec - connect_time.tv_sec)); |
||||
uint64_t mps = count_us/duration_sec; |
||||
printf( |
||||
"%lu messages in %.2f seconds (%lu messages per second), %lu us avg ping-pong\n", count_us, |
||||
duration_sec, mps, sum_us/(count_us == 0 ? 1 : count_us) |
||||
); |
||||
} |
||||
exit(0); |
||||
} |
||||
|
||||
int loop_client(void *arg) |
||||
{ |
||||
ssize_t len = 0; |
||||
int nevents = vppcom_epoll_wait(epfd, events, MAX_EVENTS, 0); |
||||
int i; |
||||
for (i = 0; i < nevents; ++i) |
||||
{ |
||||
if (events[i].events & (EPOLLHUP|EPOLLERR)) |
||||
{ |
||||
/* Simply close socket */ |
||||
vppcom_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); |
||||
vppcom_session_close(events[i].data.fd); |
||||
sigint_handler(SIGINT); |
||||
exit(0); |
||||
} |
||||
else if (events[i].events & EPOLLIN) |
||||
{ |
||||
/* Read everything back */ |
||||
if (to_read > 0) |
||||
{ |
||||
len = vppcom_session_read(events[i].data.fd, buf, message_size); |
||||
if (len > 0) |
||||
to_read = to_read > len ? to_read-len : 0; |
||||
if (to_read == 0) |
||||
{ |
||||
/* Calculate latency */ |
||||
clock_gettime(CLOCK_REALTIME, &end); |
||||
sum_us += (end.tv_nsec - start.tv_nsec)/1000 + (end.tv_sec - start.tv_sec)*1000000; |
||||
count_us++; |
||||
/* Send next request */ |
||||
start = end; |
||||
memset(buf, 0xab, message_size); |
||||
to_write = message_size; |
||||
len = vppcom_session_write(events[i].data.fd, buf, to_write); |
||||
if (len > 0) |
||||
to_write -= len; |
||||
if (to_write == 0) |
||||
to_read = message_size; |
||||
} |
||||
} |
||||
} |
||||
else if (events[i].events & EPOLLOUT) |
||||
{ |
||||
/* Connected or buffer available */ |
||||
if (!connected) |
||||
{ |
||||
connected = 1; |
||||
printf("Connected, starting ping-pong, press Ctrl-C to interrupt\n"); |
||||
clock_gettime(CLOCK_REALTIME, &connect_time); |
||||
start = connect_time; |
||||
memset(buf, 0xab, message_size); |
||||
to_write = message_size; |
||||
} |
||||
if (to_write > 0) |
||||
{ |
||||
len = vppcom_session_write(events[i].data.fd, buf, to_write); |
||||
if (len > 0) |
||||
to_write -= len; |
||||
if (to_write == 0) |
||||
to_read = message_size; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
printf("unknown event: %8.8X\n", events[i].events); |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
char *server = NULL; |
||||
char **f_argv = malloc(sizeof(char*) * (argc+1)); |
||||
int f_argidx = 1; |
||||
int rv; |
||||
f_argv[0] = argv[0]; |
||||
for (int i = 1; i < argc; i++) |
||||
{ |
||||
if (!strcmp(argv[i], "--size")) |
||||
{ |
||||
if (i < argc-1) |
||||
message_size = atoi(argv[++i]); |
||||
if (message_size < 4) |
||||
{ |
||||
printf("invalid argument for --size\n"); |
||||
exit(1); |
||||
} |
||||
} |
||||
else if (argv[i][0] == '-') |
||||
{ |
||||
f_argv[f_argidx++] = argv[i++]; |
||||
f_argv[f_argidx++] = argv[i]; |
||||
} |
||||
else |
||||
{ |
||||
server = argv[i]; |
||||
break; |
||||
} |
||||
} |
||||
f_argv[f_argidx] = NULL; |
||||
|
||||
buf = malloc(message_size); |
||||
if (!buf) |
||||
{ |
||||
printf("failed to allocate buffer\n"); |
||||
exit(1); |
||||
} |
||||
|
||||
rv = vppcom_app_create("pingpong"); |
||||
if (rv) |
||||
{ |
||||
printf("vppcom_app_create() failed: %d\n", rv); |
||||
exit(1); |
||||
} |
||||
|
||||
sockfd = vppcom_session_create(VPPCOM_PROTO_TCP, 1/* is_nonblocking */); |
||||
if (sockfd < 0) |
||||
{ |
||||
printf("vppcom_session_create failed: %d\n", sockfd); |
||||
exit(1); |
||||
} |
||||
|
||||
if (server) |
||||
{ |
||||
printf("Client mode, message size %d, connecting to %s port 7777\n", message_size, server); |
||||
is_client = 1; |
||||
|
||||
struct sockaddr_in my_addr; |
||||
bzero(&my_addr, sizeof(my_addr)); |
||||
my_addr.sin_family = AF_INET; |
||||
my_addr.sin_port = htons(7777); |
||||
my_addr.sin_addr.s_addr = inet_addr(server); |
||||
|
||||
vppcom_endpt_t endpt; |
||||
endpt.is_ip4 = 1; |
||||
endpt.ip = (uint8_t *)&my_addr.sin_addr; |
||||
endpt.port = (uint16_t)my_addr.sin_port; |
||||
|
||||
rv = vppcom_session_connect(sockfd, &endpt); |
||||
if (rv < 0 && rv != VPPCOM_EINPROGRESS) |
||||
{ |
||||
printf("vppcom_session_connect failed: %d\n", rv); |
||||
exit(1); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
printf("Server mode, listening on port 7777 and echoing everything back\n"); |
||||
|
||||
struct sockaddr_in my_addr; |
||||
bzero(&my_addr, sizeof(my_addr)); |
||||
my_addr.sin_family = AF_INET; |
||||
my_addr.sin_port = htons(7777); |
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
||||
|
||||
vppcom_endpt_t endpt; |
||||
endpt.is_ip4 = 1; |
||||
endpt.ip = (uint8_t *)&my_addr.sin_addr; |
||||
endpt.port = (uint16_t)my_addr.sin_port; |
||||
|
||||
rv = vppcom_session_bind(sockfd, &endpt); |
||||
if (rv < 0) |
||||
{ |
||||
printf("vppcom_session_bind() failed: %d", rv); |
||||
exit(1); |
||||
} |
||||
|
||||
rv = vppcom_session_listen(sockfd, MAX_EVENTS); |
||||
if (rv < 0) |
||||
{ |
||||
printf("vppcom_session_listen() failed: %d", rv); |
||||
exit(1); |
||||
} |
||||
} |
||||
|
||||
assert((epfd = vppcom_epoll_create()) > 0); |
||||
ev.data.fd = sockfd; |
||||
ev.events = (server ? EPOLLOUT : 0) | EPOLLIN|EPOLLHUP; |
||||
rv = vppcom_epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); |
||||
if (rv < 0) |
||||
{ |
||||
printf("vppcom_epoll_ctl() failed: %d", rv); |
||||
exit(1); |
||||
} |
||||
signal(SIGINT, sigint_handler); |
||||
|
||||
if (server) |
||||
while (1) |
||||
loop_client(NULL); |
||||
else |
||||
while (1) |
||||
loop(NULL); |
||||
|
||||
vppcom_app_destroy(); |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue