Advertisement
4da

NetBSD timestamp testing

4da
May 30th, 2011
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.87 KB | None | 0 0
  1. /*
  2.   Demonstration of NetBSD timestamping features
  3.  
  4.   Redistribution and use in source and binary forms, with or without
  5.   modification, are permitted provided that the following conditions
  6.   are met:
  7.   1. Redistributions of source code must retain the above copyright
  8.   notice, this list of conditions and the following disclaimer.
  9.   2. Redistributions in binary form must reproduce the above copyright
  10.   notice, this list of conditions and the following disclaimer in the
  11.   documentation and/or other materials provided with the distribution.
  12.   3. Neither the name of the project nor the names of its contributors
  13.   may be used to endorse or promote products derived from this software
  14.   without specific prior written permission.
  15.  
  16.   THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  17.   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18.   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19.   ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  20.   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21.   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22.   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23.   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24.   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25.   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26.   SUCH DAMAGE.
  27.  
  28.   Author: 2011 Dmitry Cherkassov <dcherkassov@gmail.com>
  29. */
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <errno.h>
  34. #include <string.h>
  35.    
  36. #include <sys/time.h>
  37. #include <sys/socket.h>
  38. #include <sys/select.h>
  39. #include <sys/ioctl.h>
  40. #include <arpa/inet.h>
  41. #include <net/if.h>
  42.  
  43. #ifndef SO_TIMESTAMPNS
  44. #define SO_TIMESTAMPNS 0x4000
  45. #endif
  46.  
  47. #ifndef SCM_TIMESTAMPNS
  48. #define SCM_TIMESTAMPNS 0x10
  49. #endif
  50.  
  51. static void fail(const char *error)
  52. {
  53.     printf("%s: %s\n", error, strerror(errno));
  54.     exit(1);
  55. }
  56.  
  57. static const unsigned char sync[] = {
  58.     0x00, 0x01, 0x00, 0x01,
  59.     0x5f, 0x44, 0x46, 0x4c,
  60.     0x54, 0x00, 0x00, 0x00,
  61.     0x00, 0x00, 0x00, 0x00,
  62.     0x00, 0x00, 0x00, 0x00,
  63.     0x01, 0x01,
  64.  
  65.     /* fake uuid */
  66.     0x00, 0x01,
  67.     0x02, 0x03, 0x04, 0x05,
  68.  
  69.     0x00, 0x01, 0x00, 0x37,
  70.     0x00, 0x00, 0x00, 0x08,
  71.     0x00, 0x00, 0x00, 0x00,
  72.     0x49, 0x05, 0xcd, 0x01,
  73.     0x29, 0xb1, 0x8d, 0xb0,
  74.     0x00, 0x00, 0x00, 0x00,
  75.     0x00, 0x01,
  76.  
  77.     /* fake uuid */
  78.     0x00, 0x01,
  79.     0x02, 0x03, 0x04, 0x05,
  80.  
  81.     0x00, 0x00, 0x00, 0x37,
  82.     0x00, 0x00, 0x00, 0x04,
  83.     0x44, 0x46, 0x4c, 0x54,
  84.     0x00, 0x00, 0xf0, 0x60,
  85.     0x00, 0x01, 0x00, 0x00,
  86.     0x00, 0x00, 0x00, 0x01,
  87.     0x00, 0x00, 0xf0, 0x60,
  88.     0x00, 0x00, 0x00, 0x00,
  89.     0x00, 0x00, 0x00, 0x04,
  90.     0x44, 0x46, 0x4c, 0x54,
  91.     0x00, 0x01,
  92.  
  93.     /* fake uuid */
  94.     0x00, 0x01,
  95.     0x02, 0x03, 0x04, 0x05,
  96.  
  97.     0x00, 0x00, 0x00, 0x00,
  98.     0x00, 0x00, 0x00, 0x00,
  99.     0x00, 0x00, 0x00, 0x00,
  100.     0x00, 0x00, 0x00, 0x00
  101. };
  102.  
  103. static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len)
  104. {
  105.     struct timeval now;
  106.     int res;
  107.  
  108.     res = sendto(sock, sync, sizeof(sync), 0,
  109.                  addr, addr_len);
  110.     gettimeofday(&now, 0);
  111.     if (res < 0)
  112.         printf("%s: %s\n", "send", strerror(errno));
  113.     else
  114.         printf("%ld.%06ld: sent %d bytes\n",
  115.                (long)now.tv_sec, (long)now.tv_usec,
  116.                res);
  117. }
  118.  
  119. static void printpacket(struct msghdr *msg, int res,
  120.                         char *data,
  121.                         int sock, int recvmsg_flags,
  122.                         int siocgstamp, int siocgstampns)
  123. {
  124.     struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
  125.     struct cmsghdr *cmsg;
  126.     struct timeval tv;
  127.     struct timespec ts;
  128.     struct timeval now;
  129.  
  130.     gettimeofday(&now, 0);
  131.  
  132.     printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
  133.            (long)now.tv_sec, (long)now.tv_usec,
  134.            /* (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular", */
  135.            "regular",
  136.            res,
  137.            inet_ntoa(from_addr->sin_addr),
  138.            msg->msg_controllen);
  139.     for (cmsg = CMSG_FIRSTHDR(msg);
  140.          cmsg;
  141.          cmsg = CMSG_NXTHDR(msg, cmsg)) {
  142.         printf("   cmsg len %zu: ", cmsg->cmsg_len);
  143.         switch (cmsg->cmsg_level) {
  144.         case SOL_SOCKET:
  145.             printf("SOL_SOCKET ");
  146.             switch (cmsg->cmsg_type) {
  147.             /* case SO_TIMESTAMP: { */
  148.             case SCM_TIMESTAMP: {
  149.                 struct timeval *stamp =
  150.                     (struct timeval *)CMSG_DATA(cmsg);
  151.                 printf("TIMESTAMP %ld.%06ld",
  152.                        (long)stamp->tv_sec,
  153.                        (long)stamp->tv_usec);
  154.                 break;
  155.             }
  156.             case SCM_TIMESTAMPNS: {
  157.                 struct timespec *stamp =
  158.                     (struct timespec *)CMSG_DATA(cmsg);
  159.  
  160.                 if (stamp->tv_nsec == 0)
  161.                     printf ("[zeronsecs] ");
  162.                
  163.                 printf("TIMESTAMPNS %ld.%09ld",
  164.                        (long)stamp->tv_sec,
  165.                        (long)stamp->tv_nsec);
  166.                 break;
  167.             }
  168.            
  169.             default: {
  170.                 printf("type %d", cmsg->cmsg_type);
  171.                 break;
  172.             }
  173.             }
  174.             break;
  175.         case IPPROTO_IP:
  176.             printf("IPPROTO_IP ");
  177.             switch (cmsg->cmsg_type) {
  178. /*          case IP_RECVERR: { */
  179. /*              struct sock_extended_err *err = */
  180. /*                  (struct sock_extended_err *)CMSG_DATA(cmsg); */
  181. /*              printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s", */
  182. /*                     strerror(err->ee_errno), */
  183. /*                     err->ee_origin, */
  184. /* #ifdef SO_EE_ORIGIN_TIMESTAMPING */
  185. /*                     err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ? */
  186. /*                     "bounced packet" : "unexpected origin" */
  187. /* #else */
  188. /*                     "probably SO_EE_ORIGIN_TIMESTAMPING" */
  189. /* #endif */
  190. /*                  ); */
  191. /*              if (res < sizeof(sync)) */
  192. /*                  printf(" => truncated data?!"); */
  193. /*              else if (!memcmp(sync, data + res - sizeof(sync), */
  194. /*                               sizeof(sync))) */
  195. /*                  printf(" => GOT OUR DATA BACK (HURRAY!)"); */
  196. /*              break; */
  197. /*          } */
  198.             /* case IP_PKTINFO: { */
  199.             /*  struct in_pktinfo *pktinfo = */
  200.             /*      (struct in_pktinfo *)CMSG_DATA(cmsg); */
  201.             /*  printf("IP_PKTINFO interface index %u", */
  202.             /*         pktinfo->ipi_ifindex); */
  203.             /*  break; */
  204.             /* } */
  205.             default:
  206.                 printf("type %d", cmsg->cmsg_type);
  207.                 break;
  208.             }
  209.             break;
  210.         default:
  211.             printf("level %d type %d",
  212.                    cmsg->cmsg_level,
  213.                    cmsg->cmsg_type);
  214.             break;
  215.         }
  216.         printf("\n");
  217.     }
  218.  
  219.     /* if (siocgstamp) { */
  220.     /*  if (ioctl(sock, SIOCGSTAMP, &tv)) */
  221.     /*      printf("   %s: %s\n", "SIOCGSTAMP", strerror(errno)); */
  222.     /*  else */
  223.     /*      printf("SIOCGSTAMP %ld.%06ld\n", */
  224.     /*             (long)tv.tv_sec, */
  225.     /*             (long)tv.tv_usec); */
  226.     /* } */
  227.     /* if (siocgstampns) { */
  228.     /*  if (ioctl(sock, SIOCGSTAMPNS, &ts)) */
  229.     /*      printf("   %s: %s\n", "SIOCGSTAMPNS", strerror(errno)); */
  230.     /*  else */
  231.     /*      printf("SIOCGSTAMPNS %ld.%09ld\n", */
  232.     /*             (long)ts.tv_sec, */
  233.     /*             (long)ts.tv_nsec); */
  234.     /* } */
  235. }
  236.  
  237.  
  238. static void recvpacket(int sock, int recvmsg_flags,
  239.                        int siocgstamp, int siocgstampns)
  240. {
  241.     char data[256];
  242.     struct msghdr msg;
  243.     struct iovec entry;
  244.     struct sockaddr_in from_addr;
  245.     struct {
  246.         struct cmsghdr cm;
  247.         char control[512];
  248.     } control;
  249.     int res;
  250.  
  251.     memset(&msg, 0, sizeof(msg));
  252.     msg.msg_iov = &entry;
  253.     msg.msg_iovlen = 1;
  254.     entry.iov_base = data;
  255.     entry.iov_len = sizeof(data);
  256.     msg.msg_name = (caddr_t)&from_addr;
  257.     msg.msg_namelen = sizeof(from_addr);
  258.     msg.msg_control = &control;
  259.     msg.msg_controllen = sizeof(control);
  260.  
  261.     res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
  262.  
  263.     if (res < 0) {
  264.         printf("%s %s: %s\n",
  265.                "recvmsg",
  266.                "regular",
  267.                strerror(errno));
  268.     } else {
  269.         printpacket(&msg, res, data,
  270.                     sock, recvmsg_flags,
  271.                     siocgstamp, siocgstampns);
  272.     }
  273. }
  274.  
  275. static void usage(const char *error)
  276. {
  277.     if (error)
  278.         printf("invalid option: %s\n", error);
  279.     printf("timestamping interface option*\n\n"
  280.            "Options:\n"
  281.            /* "  IP_MULTICAST_LOOP - looping outgoing multicasts\n" */
  282.            "  SO_TIMESTAMP - normal software time stamping, ms resolution\n"
  283.            "  SO_TIMESTAMPNS - more accurate software time stamping\n"
  284.            /* "  SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n" */
  285.            /* "  SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n" */
  286.            /* "  SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n" */
  287.            /* "  SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n" */
  288.            /* "  SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n" */
  289.            /* "  SOF_TIMESTAMPING_SYS_HARDWARE - request reporting of transformed HW time stamps\n" */
  290.            /* "  SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n" */
  291.            /* "  SIOCGSTAMP - check last socket time stamp\n" */
  292.            /* "  SIOCGSTAMPNS - more accurate socket time stamp\n" */);
  293.     exit(1);
  294. }
  295.  
  296.  
  297. int main(int argc, char *argv[])
  298. {  
  299.     int sock;
  300.     struct in_addr iaddr;
  301.     int val;
  302.     socklen_t len;
  303.     struct timeval next;
  304.     struct ifreq device;
  305.     struct ifreq hwtstamp;
  306.     struct sockaddr_in addr;
  307.     struct ip_mreq imr;
  308.     int enabled = 1;
  309.     int i;
  310.     int ip_multicast_loop = 0;
  311.     char *interface;
  312.     /* char *interface = "lo0"; */
  313.     int siocgstamp = 0;
  314.  
  315.     int so_timestamp = 0;
  316.     int so_timestampns = 0;
  317.    
  318.     int siocgstampns = 0;
  319.  
  320.     if (argc < 2)
  321.         usage(0);
  322.     interface = argv[1];
  323.  
  324.  
  325.     for (i = 2; i < argc; i++) {
  326.         if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
  327.             so_timestamp = 1;
  328.         else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
  329.             so_timestampns = 1;
  330.     }
  331.  
  332.  
  333.     sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  334.     if (sock < 0)
  335.         fail("socket");
  336.  
  337.     memset(&device, 0, sizeof(device));
  338.     strncpy(device.ifr_name, interface, sizeof(device.ifr_name));
  339.     if (ioctl(sock, SIOCGIFADDR, &device) < 0)
  340.         fail("getting interface IP address");
  341.  
  342.     /* bind to PTP port */
  343.     addr.sin_family = AF_INET;
  344.     addr.sin_addr.s_addr = htonl(INADDR_ANY);
  345.     addr.sin_port = htons(319 /* PTP event port */);
  346.     if (bind(sock,
  347.              (struct sockaddr *)&addr,
  348.              sizeof(struct sockaddr_in)) < 0)
  349.         fail("bind");
  350.  
  351.     /* set multicast group for outgoing packets */
  352.     inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
  353.     addr.sin_addr = iaddr;
  354.     imr.imr_multiaddr.s_addr = iaddr.s_addr;
  355.     imr.imr_interface.s_addr =
  356.         ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
  357.     if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
  358.                    &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
  359.         fail("set multicast");
  360.  
  361.     /* join multicast group, loop our own packet */
  362.     if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  363.                    &imr, sizeof(struct ip_mreq)) < 0)
  364.         fail("join multicast group");
  365.  
  366.     /* if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, */
  367.     /*             &ip_multicast_loop, sizeof(enabled)) < 0) { */
  368.     /*  fail("loop multicast"); */
  369.     /* } */
  370.  
  371.     /* set socket options for time stamping */
  372.     if (so_timestamp &&
  373.         setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
  374.                    &enabled, sizeof(enabled)) < 0)
  375.         fail("setsockopt SO_TIMESTAMP");
  376.  
  377.     /* verify socket options */
  378.  
  379.     printf("Socket options: \n");
  380.     len = sizeof(val);
  381.     if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
  382.         printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
  383.     else
  384.         printf("SO_TIMESTAMP = %d\n", val);
  385.  
  386.    
  387.     /* set socket options for time stamping */
  388.     if (so_timestampns &&
  389.         setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
  390.                    &enabled, sizeof(enabled)) < 0)
  391.         fail("setsockopt SO_TIMESTAMPNS");
  392.  
  393.     /* verify socket options */
  394.  
  395.     printf("Socket options: \n");
  396.     len = sizeof(val);
  397.     if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
  398.         printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS", strerror(errno));
  399.     else
  400.         printf("SO_TIMESTAMPNS = %d\n", val);
  401.  
  402.     /* send packets forever every five seconds */
  403.     gettimeofday(&next, 0);
  404.     next.tv_sec = (next.tv_sec + 1) / 5 * 5;
  405.     next.tv_usec = 0;
  406.  
  407.     while (1) {
  408.         struct timeval now;
  409.         struct timeval delta;
  410.         long delta_us;
  411.         int res;
  412.         fd_set readfs, errorfs;
  413.  
  414.         gettimeofday(&now, 0);
  415.         delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
  416.             (long)(next.tv_usec - now.tv_usec);
  417.         if (delta_us > 0) {
  418.             /* continue waiting for timeout or data */
  419.             delta.tv_sec = delta_us / 1000000;
  420.             delta.tv_usec = delta_us % 1000000;
  421.  
  422.             FD_ZERO(&readfs);
  423.             FD_ZERO(&errorfs);
  424.             FD_SET(sock, &readfs);
  425.             FD_SET(sock, &errorfs);
  426.             printf("%ld.%06ld: select %ldus\n",
  427.                    (long)now.tv_sec, (long)now.tv_usec,
  428.                    delta_us);
  429.             res = select(sock+1, &readfs, 0, &errorfs, &delta);
  430.             gettimeofday(&now, 0);
  431.             printf("%ld.%06ld: select returned: %d, %s\n",
  432.                    (long)now.tv_sec, (long)now.tv_usec,
  433.                    res,
  434.                    res < 0 ? strerror(errno) : "success");
  435.             if (res > 0) {
  436.                 if (FD_ISSET(sock, &readfs))
  437.                     printf("ready for reading\n");
  438.                 if (FD_ISSET(sock, &errorfs))
  439.                     printf("has error\n");
  440.                 recvpacket(sock, 0,
  441.                            siocgstamp,
  442.                            siocgstampns);
  443.                 /* recvpacket(sock, MSG_ERRQUEUE, */
  444.                 /*         siocgstamp, */
  445.                 /*         siocgstampns); */
  446.             }
  447.         } else {
  448.             /* write one packet */
  449.             sendpacket(sock,
  450.                        (struct sockaddr *)&addr,
  451.                        sizeof(addr));
  452.             next.tv_sec += 5;
  453.             continue;
  454.         }
  455.     }
  456.  
  457.     return 0;
  458. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement