Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define __USE_MISC
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <stdint.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/time.h>
- #include <linux/net_tstamp.h>
- #include <linux/errqueue.h>
- #include <linux/sockios.h>
- #include <net/if.h>
- #include <sys/ioctl.h>
- const int UDP_MAX_LENGTH = 1500;
- typedef struct {
- int fd, port, err_no;
- struct sockaddr_in local, remote;
- struct timeval time_kernel, time_user;
- int64_t prev_serialnum; // Message serialnum corresponding to timestamps
- } socket_info;
- int setup_udp_receiver(socket_info *inf, int port)
- {
- int r;
- int timestampOn;
- int on = 1;
- struct ifreq ifr;
- struct hwtstamp_config hwc;
- inf->port = port;
- inf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (inf->fd < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: socket failed: %s\n", strerror(inf->err_no));
- return inf->fd;
- }
- /*memset(&ifr, 0, sizeof(ifr));
- hwc.flags = 0;
- hwc.tx_type = HWTSTAMP_TX_ON;
- hwc.rx_filter = HWTSTAMP_FILTER_ALL;
- ifr.ifr_data = (char*)&hwc;
- r = ioctl(inf->fd, SIOCSHWTSTAMP, &ifr);
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: ioctl failed: %s\n", strerror(inf->err_no));
- return r;
- }*/
- //timestampOn = SOF_TIMESTAMPING_RX_SOFTWARE;
- timestampOn = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE;
- r = setsockopt(inf->fd, SOL_SOCKET, SO_TIMESTAMPING, ×tampOn, sizeof(timestampOn));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: setsockopt failed: %s\n", strerror(inf->err_no));
- return r;
- }
- r = setsockopt(inf->fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: setsockopt2 failed: %s\n", strerror(inf->err_no));
- return r;
- }
- memset(&(inf->local), 0, sizeof(struct sockaddr_in));
- inf->local.sin_family = AF_INET;
- inf->local.sin_port = htons(port);
- inf->local.sin_addr.s_addr = htonl(INADDR_ANY);
- r = bind(inf->fd, (struct sockaddr *)&(inf->local), sizeof(struct sockaddr_in));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: bind failed: %s\n", strerror(inf->err_no));
- return r;
- }
- inf->prev_serialnum = -1;
- return 0;
- }
- int setup_udp_sender(socket_info *inf, int port, char *address)
- {
- int r;
- int timestampOn;
- int on = 1;
- struct ifreq ifr;
- struct hwtstamp_config hwc;
- inf->port = port;
- inf->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (inf->fd < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_client: socket failed: %s\n", strerror(inf->err_no));
- return inf->fd;
- }
- /*memset(&ifr, 0, sizeof(ifr));
- hwc.flags = 0;
- hwc.tx_type = HWTSTAMP_TX_ON;
- hwc.rx_filter = HWTSTAMP_FILTER_ALL;
- ifr.ifr_data = (char*)&hwc;
- r = ioctl(inf->fd, SIOCSHWTSTAMP, &ifr);
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: ioctl failed: %s\n", strerror(inf->err_no));
- return r;
- }*/
- memset(&(inf->remote), 0, sizeof(struct sockaddr_in));
- inf->remote.sin_family = AF_INET;
- inf->remote.sin_port = htons(port);
- timestampOn = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE;
- //timestampOn = SOF_TIMESTAMPING_TX_SOFTWARE;
- r = setsockopt(inf->fd, SOL_SOCKET, SO_TIMESTAMPING, ×tampOn, sizeof(timestampOn));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: setsockopt failed: %s\n", strerror(inf->err_no));
- return r;
- }
- /*r = setsockopt(inf->fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: setsockopt2 failed: %s\n", strerror(inf->err_no));
- return r;
- }*/
- r = setsockopt(inf->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: setsockopt3 failed: %s\n", strerror(inf->err_no));
- return r;
- }
- r = inet_aton(address, &(inf->remote.sin_addr));
- if (r == 0) {
- fprintf(stderr, "setup_udp_client: inet_aton failed\n");
- inf->err_no = 0;
- return -1;
- }
- memset(&(inf->local), 0, sizeof(struct sockaddr_in));
- inf->local.sin_family = AF_INET;
- inf->local.sin_port = htons(0);
- inf->local.sin_addr.s_addr = htonl(INADDR_ANY);
- /*r = bind(inf->fd, (struct sockaddr *)&(inf->local), sizeof(struct sockaddr_in));
- if (r < 0) {
- inf->err_no = errno;
- fprintf(stderr, "setup_udp_server: bind failed: %s\n", strerror(inf->err_no));
- return r;
- }*/
- inf->prev_serialnum = -1;
- return 0;
- }
- void handle_time(struct msghdr* msg)
- {
- struct timespec* ts = NULL;
- struct cmsghdr* cmsg;
- struct sock_extended_err *ext;
- for( cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg,cmsg) ) {
- printf("level=%d, type=%d, len=%zu\n", cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_len);
- if ( cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) {
- ext = (struct sock_extended_err *)CMSG_DATA(cmsg);
- printf("errno=%d, origin=%d\n", ext->ee_errno, ext->ee_origin);
- continue;
- }
- if( cmsg->cmsg_level != SOL_SOCKET )
- continue;
- switch( cmsg->cmsg_type ) {
- case SO_TIMESTAMPNS:
- ts = (struct timespec*) CMSG_DATA(cmsg);
- break;
- case SO_TIMESTAMPING:
- ts = (struct timespec*) CMSG_DATA(cmsg);
- break;
- default:
- /* Ignore other cmsg options */
- break;
- }
- }
- printf("End messages\n");
- //print_time(ts);
- }
- int udp_receive(socket_info *inf, char *buf, int len)
- {
- int recv_len;
- struct msghdr msg;
- struct iovec iov;
- memset(&msg, 0, sizeof(msg));
- memset(&iov, 0, sizeof(iov));
- // Space for control message info plus timestamp
- char ctrl[2048];
- memset(ctrl, 0, sizeof(ctrl));
- //struct cmsghdr *cmsg = (struct cmsghdr *) &ctrl;
- // Ancillary data buffer and length
- msg.msg_control = (char *) ctrl;
- msg.msg_controllen = sizeof(ctrl);
- // Dest address info
- msg.msg_name = (struct sockaddr *) &(inf->remote);
- msg.msg_namelen = sizeof(struct sockaddr_in);
- // Array of data buffers (scatter/gather)
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- // Data buffer pointer and length
- iov.iov_base = buf;
- iov.iov_len = len;
- // recv_len = recvfrom(inf->fd, buf, len, 0, (struct sockaddr *) &(inf->remote), &(inf->remote_len));
- recv_len = recvmsg(inf->fd, &msg, 0);
- gettimeofday(&(inf->time_user), NULL);
- if (recv_len < 0) {
- inf->err_no = errno;
- fprintf(stderr, "udp_receive: recvfrom failed: %s\n", strerror(inf->err_no));
- }
- handle_time(&msg);
- /*if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_TIMESTAMP &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
- memcpy(&(inf->time_kernel), CMSG_DATA(cmsg), sizeof(struct timeval));
- } else {
- fprintf(stderr, "Didn't get kernel time: level=%d, type=%d, len=%zu\n", cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_len);
- }*/
- //inf->remote_len = msg.msg_namelen;
- return recv_len;
- }
- char junk_buf[65536];
- int udp_send(socket_info *inf, char *buf, int len)
- {
- int send_len, r, i;
- struct msghdr msg;
- struct iovec iov;
- memset(&msg, 0, sizeof(msg));
- memset(&iov, 0, sizeof(iov));
- // Space for control message info plus timestamp
- char ctrl[2048];
- memset(ctrl, 0, sizeof(ctrl));
- //struct cmsghdr *cmsg = (struct cmsghdr *) &ctrl;
- // Ancillary data buffer and length
- //msg.msg_control = (char *) ctrl;
- //msg.msg_controllen = sizeof(ctrl);
- // Dest address info
- msg.msg_name = (struct sockaddr *) &(inf->remote);
- msg.msg_namelen = sizeof(struct sockaddr_in);
- // Array of data buffers (scatter/gather)
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- // Data buffer pointer and length
- iov.iov_base = buf;
- iov.iov_len = len;
- // send_len = sendto(inf->fd, buf, len, 0, (struct sockaddr *) &(inf->local), sizeof(struct sockaddr_in));
- gettimeofday(&(inf->time_user), NULL);
- send_len = sendmsg(inf->fd, &msg, 0);
- if (send_len < 0) {
- inf->err_no = errno;
- fprintf(stderr, "udp_send: sendmsg failed: %s\n", strerror(inf->err_no));
- }
- memset(&msg, 0, sizeof(msg));
- memset(&iov, 0, sizeof(iov));
- memset(ctrl, 0, sizeof(ctrl));
- msg.msg_control = (char *) ctrl;
- msg.msg_controllen = sizeof(ctrl);
- msg.msg_name = (struct sockaddr *) &(inf->remote);
- msg.msg_namelen = sizeof(struct sockaddr_in);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- iov.iov_base = junk_buf;
- iov.iov_len = sizeof(junk_buf);
- for (;;) {
- r = recvmsg(inf->fd, &msg, MSG_ERRQUEUE);
- /*for (i=0; i<2048; i++) {
- printf("%02X ", ctrl[i]);
- if ((i & 31) == 31) printf("\n");
- }*/
- if (r<0) {
- fprintf(stderr, "Didn't get kernel time\n");
- return send_len;
- }
- printf("recvmsg returned %d\n", r);
- handle_time(&msg);
- }
- /*if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_TIMESTAMP &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
- memcpy(&(inf->time_kernel), CMSG_DATA(cmsg), sizeof(struct timeval));
- } else {
- fprintf(stderr, "Didn't get kernel time: level=%d, type=%d, len=%zu\n", cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_len);
- }*/
- return send_len;
- }
- typedef struct {
- int64_t serialnum; // Message index, incremented by sender for each message
- int64_t user_time_serialnum; // Serial number of earlier message
- int64_t user_time; // Microsecond system time before sender called sendto()
- int64_t kernel_time_serialnum; // Serial number of earlier message
- int64_t kernel_time; // Kernel timestamp of when earlier packet was sent
- uint16_t message_bytes; // Length of random payload following header
- } message_header;
- const int payload_max = UDP_MAX_LENGTH - sizeof(message_header);
- int64_t serial_num = 0;
- int generate_random_message(char *buf, socket_info *inf)
- {
- int payload_len, i, total;
- message_header *header = (message_header *)buf;
- char *payload = buf + sizeof(message_header);
- header->user_time_serialnum = inf->prev_serialnum;
- header->user_time = inf->time_user.tv_sec * 1000000000L + inf->time_user.tv_usec;
- header->kernel_time_serialnum = inf->prev_serialnum;
- header->kernel_time = inf->time_kernel.tv_sec * 1000000000L + inf->time_kernel.tv_usec;
- header->serialnum = serial_num;
- payload_len = random() % (payload_max+1);
- for (i=0; i<payload_len; i++) {
- payload[i] = random();
- }
- header->message_bytes = payload_len;
- total = payload_len + sizeof(message_header);
- printf("%5ld: kt=%ld, ut=%ld %5ld: s=%d\n", header->user_time_serialnum, header->kernel_time, header->user_time, header->serialnum, total);
- inf->prev_serialnum = serial_num;
- serial_num++;
- return total;
- }
- typedef struct {
- int64_t sender_user_time, sender_kernel_time;
- int64_t receiver_user_time, receiver_kernel_time;
- uint16_t message_bytes;
- } time_record;
- time_record records[10000];
- int num_records = 0;
- void clear_records()
- {
- memset(records, 0, sizeof(records));
- num_records = 0;
- }
- char packet_buffer[65536];
- int fetch_message(socket_info *inf)
- {
- int msg_size, i;
- message_header *header = (message_header *)packet_buffer;
- msg_size = udp_receive(inf, packet_buffer, 65536);
- if (msg_size < 0) exit(0);
- if (msg_size != header->message_bytes + sizeof(message_header)) {
- fprintf(stderr, "Message size mismatch\n");
- exit(0);
- }
- records[header->serialnum].message_bytes = msg_size;
- records[header->serialnum].receiver_user_time = inf->time_user.tv_sec * 1000000000L + inf->time_user.tv_usec;
- records[header->serialnum].receiver_kernel_time = inf->time_kernel.tv_sec * 1000000000L + inf->time_kernel.tv_usec;
- records[header->user_time_serialnum].sender_user_time = header->user_time;
- records[header->kernel_time_serialnum].sender_kernel_time = header->kernel_time;
- i = header->user_time_serialnum;
- printf("%5d: sut=%ld, skt=%ld, rkt=%ld, rut=%ld, s=%d\n", i, records[i].sender_user_time, records[i].sender_kernel_time,
- records[i].receiver_kernel_time, records[i].receiver_user_time, (int)records[i].message_bytes);
- int num = header->user_time_serialnum + 1;
- if (num > num_records) num_records = num;
- return 0;
- }
- void sender_loop()
- {
- int i, len, t;
- socket_info inf;
- t = setup_udp_sender(&inf, 8000, "192.168.1.255");
- if (t<0) exit(0);
- for (i=0; i<2000; i++) {
- t = random() % 2000000;
- usleep(t);
- len = generate_random_message(packet_buffer, &inf);
- udp_send(&inf, packet_buffer, len);
- }
- }
- void receiver_loop()
- {
- int i;
- socket_info inf;
- setup_udp_receiver(&inf, 8000);
- for (int i=0; 1000; i++) {
- fetch_message(&inf);
- }
- }
- int main(int argc, char *argv[])
- {
- clear_records();
- if (argc != 2) {
- fprintf(stderr, "Missing option\n");
- return 0;
- }
- if (0==strcmp(argv[1], "-s")) {
- sender_loop();
- } else
- if (0==strcmp(argv[1], "-r")) {
- receiver_loop();
- } else {
- fprintf(stderr, "Unknown option\n");
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement