int main(int argc, char **argv) { int so_timestamping_flags = 0; int so_timestamp = 0; int so_timestampns = 0; int siocgstamp = 0; int siocgstampns = 0; int ip_multicast_loop = 0; char *interface; int i; int enabled = 1; int sock; struct ifreq device; struct ifreq hwtstamp; struct hwtstamp_config hwconfig, hwconfig_requested; struct sockaddr_in addr; struct ip_mreq imr; struct in_addr iaddr; int val; socklen_t len; struct timeval next; if (argc < 2) usage(0); interface = argv[1]; for (i = 2; i < argc; i++) { if (!strcasecmp(argv[i], "SO_TIMESTAMP")) so_timestamp = 1; else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS")) so_timestampns = 1; else if (!strcasecmp(argv[i], "SIOCGSTAMP")) siocgstamp = 1; else if (!strcasecmp(argv[i], "SIOCGSTAMPNS")) siocgstampns = 1; else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP")) ip_multicast_loop = 1; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE; //No message of desired type else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE; //No message of desired type else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; else usage(argv[i]); } sock = socket(PF_INET, SOCK_DGRAM/*SOCK_RAW*/, /*IPPROTO_UDP*/0); if (sock < 0) bail("socket"); memset(&device, 0, sizeof(device)); strncpy(device.ifr_name, interface, sizeof(device.ifr_name)); if (ioctl(sock, SIOCGIFADDR, &device) < 0) bail("getting interface IP address"); memset(&hwtstamp, 0, sizeof(hwtstamp)); strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name)); hwtstamp.ifr_data = (void *)&hwconfig; memset(&hwconfig, 0, sizeof(hwconfig)); hwconfig.tx_type = (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; hwconfig.rx_filter = (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ? HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; hwconfig_requested = hwconfig; if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) { if ((errno == EINVAL || errno == ENOTSUP) && hwconfig_requested.tx_type == HWTSTAMP_TX_OFF && hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE) printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n"); else bail("SIOCSHWTSTAMP"); } printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n", hwconfig_requested.tx_type, hwconfig.tx_type, hwconfig_requested.rx_filter, hwconfig.rx_filter); /* bind to PTP port */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(319 /* PTP event port */); if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) bail("bind"); /* set multicast group for outgoing packets */ inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */ addr.sin_addr = iaddr; imr.imr_multiaddr.s_addr = iaddr.s_addr; imr.imr_interface.s_addr = ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr; if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0) bail("set multicast"); /* join multicast group, loop our own packet */ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0) bail("join multicast group"); if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &ip_multicast_loop, sizeof(enabled)) < 0) { bail("loop multicast"); } /* set socket options for time stamping */ if (so_timestamp && setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &enabled, sizeof(enabled)) < 0) bail("setsockopt SO_TIMESTAMP"); if (so_timestampns && setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &enabled, sizeof(enabled)) < 0) bail("setsockopt SO_TIMESTAMPNS"); if (so_timestamping_flags && setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_flags, sizeof(so_timestamping_flags)) < 0) bail("setsockopt SO_TIMESTAMPING"); /* request IP_PKTINFO for debugging purposes */ if (setsockopt(sock, SOL_IP, IP_PKTINFO, &enabled, sizeof(enabled)) < 0) printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno)); /* verify socket options */ len = sizeof(val); if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0) printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno)); else printf("SO_TIMESTAMP %d\n", val); if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0) printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS", strerror(errno)); else printf("SO_TIMESTAMPNS %d\n", val); if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) { printf("%s: %s\n", "getsockopt SO_TIMESTAMPING", strerror(errno)); } else { printf("SO_TIMESTAMPING %d\n", val); if (val != so_timestamping_flags) printf(" not the expected value %d\n", so_timestamping_flags); } /* send packets forever every five seconds */ gettimeofday(&next, 0); next.tv_sec = (next.tv_sec + 1) / 5 * 5; next.tv_usec = 0; while (1) { struct timeval now; struct timeval delta; long delta_us; int res; fd_set readfs, errorfs; gettimeofday(&now, 0); delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 + (long)(next.tv_usec - now.tv_usec); if (delta_us > 0) { /* continue waiting for timeout or data */ delta.tv_sec = delta_us / 1000000; delta.tv_usec = delta_us % 1000000; FD_ZERO(&readfs); FD_ZERO(&errorfs); FD_SET(sock, &readfs); FD_SET(sock, &errorfs); printf("%ld.%06ld: select %ldus\n", (long)now.tv_sec, (long)now.tv_usec, delta_us); res = select(sock + 1, &readfs, 0, &errorfs, &delta); gettimeofday(&now, 0); printf("%ld.%06ld: select returned: %d, %s\n", (long)now.tv_sec, (long)now.tv_usec, res, res < 0 ? strerror(errno) : "success"); if (res > 0) { if (FD_ISSET(sock, &readfs)) printf("ready for reading\n"); if (FD_ISSET(sock, &errorfs)) printf("has error\n"); // printf("read from socket error queue...\n"); // recvpacket(sock, MSG_ERRQUEUE, // siocgstamp, // siocgstampns); printf("read from socket queue...\n"); print_sock_buff_opt(sock); recvpacket(sock, 0, siocgstamp, siocgstampns); // print_sock_buff_opt(sock); printf("read from socket error queue...\n"); print_sock_buff_opt(sock); recvpacket(sock, MSG_ERRQUEUE, siocgstamp, siocgstampns); // print_sock_buff_opt(sock); } } else { /* write one packet */ printf("write to socket queue...\n"); // print_sock_buff_opt(sock); sendpacket(sock, (struct sockaddr *)&addr, sizeof(addr)); sendpacket(sock, (struct sockaddr *)&addr, sizeof(addr)); // print_sock_buff_opt(sock); next.tv_sec += 2; continue; } } return 0; }
static void query_names(FILE *ofp, SOCKET sockfd) { short seq = 1000; int npending = 0; struct in_addr next_addr; int have_next_addr = FALSE; char errbuf[256]; assert( ofp != 0 ); assert( SOCKET_IS_VALID(sockfd) ); /*---------------------------------------------------------------- * Figure out our starting and ending addresses to be scanning. * These are treated as simple long integers that are incremented * on each loop, and we must have at least one loop to be valid. */ while ( have_next_addr || ((have_next_addr = next_target(&next_addr)) != 0) || (npending > 0) ) { fd_set rfds, /* list of read descriptors */ wfds, /* list of write descriptors */ *pwfds = 0; int n; struct timeval tv; /*-------------------------------------------------------- * Our select is just a bit tricky. We always are waiting * on the read channel, but we only want to wait on the * write channel if there are any more addresses in our * list to process. After we've sent all the packets to * the other end, we stop writing and do only reading. */ FD_ZERO(&rfds); FD_SET(sockfd, &rfds); timeval_set_secs(&tv, timeout_secs); if ( have_next_addr ) { wfds = rfds; pwfds = &wfds; } if ( (n = select(sockfd+1, &rfds, pwfds, 0, &tv)) == 0 ) { fprintf(stderr, "*timeout (normal end of scan)\n"); fflush(ofp); break; } else if ( n < 0) { printf("ERROR [%s]\n", strerror(errno)); break; } /*-------------------------------------------------------- * Has the read descriptor fired? */ if ( n > 0 && FD_ISSET(sockfd, &rfds) ) { int paklen; struct sockaddr_in src; struct NMBpacket pak; struct NMB_query_response rsp; memset(&src, 0, sizeof src); memset(&rsp, 0, sizeof rsp); paklen = (int)recvpacket(sockfd, &pak, sizeof pak,&src); if ( verbose ) { if ( paklen < 0 ) { fprintf(ofp, "Error on read: %s\n", strerror(errno)); } else { fprintf(ofp, "Got %d bytes from %s\n", paklen, inet_ntoa(src.sin_addr) ); if ( verbose > 1 ) dump_nbtpacket(&pak, paklen, stdout); } } /*------------------------------------------------ * If we actually got something from the other end, * parse the response, plug in the remote's IP addr, * and display it. */ if ( paklen <= 0 ) continue; npending--; if ( parse_nbtstat(&pak, paklen, &rsp, errbuf) ) { rsp.remote = src; if ( target_responded(&rsp.remote.sin_addr) ) { #ifdef ENABLE_PERL if ( gen_Perl ) generate_perl(ofp, &rsp); else #endif display_nbtstat(ofp,&rsp,full_nbtstat); } } else { fprintf(ofp, "ERROR: no parse for %s -- %s\n", inet_ntoa(src.sin_addr), errbuf); } } /*-------------------------------------------------------- * If we have room to write one packet, do so here. Note * that we make not notice whether the write succeeds or * not: we don't care. */ if ( n > 0 && pwfds && FD_ISSET(sockfd, pwfds) ) { struct sockaddr_in dst; struct NMBpacket pak; int sendlen; memset(&dst, 0, sizeof dst); dst.sin_family = AF_INET; dst.sin_addr.s_addr = next_addr.s_addr; dst.sin_port = htons(dest_portno); have_next_addr = FALSE; fill_namerequest(&pak, &sendlen, seq++); if ( verbose ) { fprintf(ofp, "sending to %s\n", inet_ntoa(dst.sin_addr)); } /* yes, ignore response! */ (void) sendpacket(sockfd, &pak, sendlen, &dst); if ( write_sleep_msecs > 0 ) sleep_msecs(write_sleep_msecs); npending++; continue; } } }