#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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) { vppcom_data_segment_t seg[8]; size_t readlen = vppcom_session_read_segments( events[i].data.fd, seg, sizeof(seg)/sizeof(seg[0]), message_size ); if (readlen > 0) { size_t left = readlen; for (int i = 0; left > 0; i++) { vppcom_session_write(events[i].data.fd, seg[i].data, seg[i].len); left -= seg[i].len; } // FIXME: I'm not sure if I can do that. Maybe the buffer can't be freed until it's really sent vppcom_session_free_segments(events[i].data.fd, 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 */ printf("Error event\n"); 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) { vppcom_data_segment_t seg[8]; len = vppcom_session_read_segments( events[i].data.fd, seg, sizeof(seg)/sizeof(seg[0]), to_read ); if (len > 0) to_read = to_read > len ? to_read-len : 0; // FIXME: I'm not sure if I can do that. Maybe the buffer can't be freed until it's really sent vppcom_session_free_segments(events[i].data.fd, len); 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|EPOLLET; 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; }