]> sjero.net Git - dccpping/blobdiff - dccpping.c
Add manpage
[dccpping] / dccpping.c
index 7a9e5e9d8e6f934f9da06c6e0389b9b027b1ea50..b71a7e3bb08998aaa0b0be4e00d482e1ae4011a4 100644 (file)
@@ -45,16 +45,19 @@ Date: 11/2012
 #include "checksums.h"
 
 
-/*Use the DCCP source port to multiplex DCCP Ping streams by PID*/
-#define DCCP_SERVICE_CODE 0x50455246
+#define DEFAULT_SERVICE_CODE 1885957735
 #define DEFAULT_PORT 33434
 
-#define DCCPPING_VERSION 1.0
+
+#define DCCPPING_VERSION 1.1
 #define MAX(x,y) (x>y ? x : y)
 extern int errno;
 #ifndef NI_IDN
 #define NI_IDN 32
 #endif
+#ifndef SOL_DCCP
+#define SOL_DCCP 269
+#endif
 
 
 /*Structure for simpler IPv4/IPv6 Address handling*/
@@ -173,10 +176,12 @@ struct request_queue{
 struct stats{
        int                             requests_sent;
        int                             replies_received;
+       int                     duplicates;
        int                             errors;
-       double                  rtt_min;
-       double                  rtt_avg;
-       double                  rtt_max;
+       long long               rtt_min;
+       long long               rtt_sum;
+       long long               rtt_sum2;
+       long                    rtt_max;
        struct timeval  start;
        struct timeval  stop;
 };
@@ -193,6 +198,7 @@ struct params{
        ipaddr_ptr_t src_addr;  /*Source Address*/
        int dccp_socket;                /*DCCP Socket used to grab src addr/port*/
        char* hostname;                 /*Originally requested hostname*/
+       unsigned int service_code;/*DCCP Service Code*/
 };
 
 
@@ -217,12 +223,13 @@ int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2);
 const char *get_error_string(int type, int v1, int v2);
 void clearQueue();
 void sigHandler();
+void printStats();
 char* addr2str(ipaddr_ptr_t *res, int nores);
 void usage();
 void version();
 void sanitize_environment();
 void dbgprintf(int level, const char *fmt, ...);
-
+static long llsqrt(long long a);
 
 /*Parse commandline options*/
 int main(int argc, char *argv[])
@@ -230,13 +237,16 @@ int main(int argc, char *argv[])
        char c;
        char *src=NULL;
        char *dst=NULL;
+       char *tmp;
 
        /*Set Defaults*/
        queue.head=NULL;
        queue.tail=NULL;
        ping_stats.replies_received=0;
        ping_stats.requests_sent=0;
-       ping_stats.rtt_avg=0;
+       ping_stats.rtt_sum=0;
+       ping_stats.rtt_sum2=0;
+       ping_stats.duplicates=0;
        ping_stats.rtt_max=0;
        ping_stats.rtt_min=0;
        ping_stats.errors=0;
@@ -250,10 +260,11 @@ int main(int argc, char *argv[])
        parms.dccp_socket=-1;
        parms.no_resolve=0;
        parms.hostname=NULL;
+       parms.service_code=DEFAULT_SERVICE_CODE;
 
        sanitize_environment();
 
-       while ((c = getopt(argc, argv, "64vhnc:p:i:dt:S:")) != -1) {
+       while ((c = getopt(argc, argv, "64vVhnc:p:i:t:S:s:")) != -1) {
                switch (c) {
                        case '6':
                                parms.ip_type=AF_INET6;
@@ -278,7 +289,7 @@ int main(int argc, char *argv[])
                                        exit(1);
                                }
                                break;
-                       case 'd':
+                       case 'v':
                                debug++;
                                break;
                        case 'n':
@@ -288,12 +299,24 @@ int main(int argc, char *argv[])
                                parms.ttl = atoi(optarg);
                                if (parms.ttl < 1 || parms.ttl > 255) {
                                        dbgprintf(0,"Error: Invalid TTL\n");
+                                       exit(1);
+                               }
+                               break;
+                       case 's':
+                               parms.service_code=strtol(optarg,&tmp,0);
+                               if(*tmp!='\0'){
+                                       dbgprintf(0,"Error: Invalid Service Code\n");
+                                       exit(1);
+                               }
+                               if(parms.service_code<=0){
+                                       dbgprintf(0, "Error: Service Code MUST be positive");
+                                       exit(1);
                                }
                                break;
                        case 'S':
                                src=optarg;
                                break;
-                       case 'v':
+                       case 'V':
                                version();
                                break;
                        case 'h':
@@ -340,6 +363,7 @@ void getAddresses(char *src, char* dst){
        struct sockaddr_in* iv42;
        int addrlen;
        int err;
+       int opt;
 
        /*Lookup destination Address*/
        memset(&hint,0,sizeof(struct addrinfo));
@@ -452,6 +476,11 @@ void getAddresses(char *src, char* dst){
                        exit(1);
                }
        }
+       opt=htonl(parms.service_code);
+       if(setsockopt(parms.dccp_socket,SOL_DCCP, DCCP_SOCKOPT_SERVICE,&opt,sizeof(opt))<0){
+               dbgprintf(0, "Error: Failed setsockopt() on DCCP socket (%s)\n",strerror(errno));
+               exit(1);
+       }
 
        /*Connect socket to get source address/port*/
        if(parms.ip_type==AF_INET){
@@ -542,13 +571,7 @@ void doping(){
                if (logPacket(request_seq,packet_seq)<0){
                        dbgprintf(0,"Error: Couldn't record request!\n");
                }
-               if(parms.ip_type==AF_INET){
-                       dbgprintf(1, "Sending DCCP Request to %s\n",
-                                       addr2str(&parms.dest_addr,0));
-               }else{
-                       dbgprintf(1, "Sending DCCP Request to %s\n",
-                                       addr2str(&parms.dest_addr,0));
-               }
+               dbgprintf(2, "Sending DCCP Request to %s\n", addr2str(&parms.dest_addr,1));
 
                /*Use select to wait on packets or until interval has passed*/
                add.tv_sec=parms.interval/1000;
@@ -596,6 +619,8 @@ void doping(){
                updateRequestPacket(sbuffer,&slen, packet_seq);
        }
 
+       printStats();
+
        close(rs);
        close(is4);
        close(is6);
@@ -634,7 +659,7 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
        }
 
        if(rcv_addr.gen->sa_family!=parms.ip_type){ //confirm IP type
-               dbgprintf(1, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6");
+               dbgprintf(2, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6");
                free(rcv_addr.gen);
                return;
        }
@@ -643,13 +668,13 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
                /*IPv4*/
                if(memcmp(&rcv_addr.ipv4->sin_addr,&parms.dest_addr.ipv4->sin_addr,
                                sizeof(parms.dest_addr.ipv4->sin_addr))!=0){ //not from destination
-                       dbgprintf(1,"DCCP packet from 3rd host\n");
+                       dbgprintf(2,"DCCP packet from 3rd host\n");
                        free(rcv_addr.gen);
                        return;
                }
                if(rlen < sizeof(struct dccp_hdr)+sizeof(struct iphdr)){ //check packet size
 
-                       dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n");
+                       dbgprintf(2, "Packet smaller than possible DCCP packet received on DCCP socket\n");
                        free(rcv_addr.gen);
                        return;
                }
@@ -659,13 +684,13 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
                /*IPv6*/
                if(memcmp(&rcv_addr.ipv6->sin6_addr, &parms.dest_addr.ipv6->sin6_addr,
                                sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){ //not from destination
-                       dbgprintf(1,"DCCP packet from 3rd host\n");
+                       dbgprintf(2,"DCCP packet from 3rd host\n");
                        free(rcv_addr.gen);
                        return;
                }
                if(rlen < sizeof(struct dccp_hdr)){ //check packet size
 
-                       dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n");
+                       dbgprintf(2, "Packet smaller than possible DCCP packet received on DCCP socket\n");
                        free(rcv_addr.gen);
                        return;
                }
@@ -675,12 +700,12 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
        /*DCCP checks*/
        dhdr=(struct dccp_hdr*)ptr;
        if(dhdr->dccph_sport!=htons(parms.dest_port)){
-               dbgprintf(1,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport));
+               dbgprintf(2,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport));
                free(rcv_addr.gen);
                return;
        }
        if(dhdr->dccph_dport!=htons(parms.src_port)){
-               dbgprintf(1,"DCCP packet with wrong Destination Port\n");
+               dbgprintf(2,"DCCP packet with wrong Destination Port\n");
                free(rcv_addr.gen);
                return;
        }
@@ -688,7 +713,7 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
        /*Pick Response*/
        if(dhdr->dccph_type==DCCP_PKT_RESET){
                if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_reset)){
-                       dbgprintf(1, "Tossing DCCP Reset packet that's small!\n");
+                       dbgprintf(2, "Tossing DCCP Reset packet that's small!\n");
                        return;
                }
                dhdr_re=(struct dccp_hdr_reset*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
@@ -701,7 +726,7 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
        }
        if(dhdr->dccph_type==DCCP_PKT_RESPONSE){
                if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_response)){
-                       dbgprintf(1, "Tossing DCCP Response packet that's too small!\n");
+                       dbgprintf(2, "Tossing DCCP Response packet that's too small!\n");
                        return;
                }
 
@@ -713,7 +738,7 @@ void handleDCCPpacket(int rcv_socket, int send_socket){
        }
        if(dhdr->dccph_type==DCCP_PKT_SYNC || dhdr->dccph_type==DCCP_PKT_SYNCACK){
                if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_ack_bits)){
-                       dbgprintf(1, "Tossing DCCP Sync/SyncAck packet that's too small!\n");
+                       dbgprintf(2, "Tossing DCCP Sync/SyncAck packet that's too small!\n");
                        return;
                }
 
@@ -760,21 +785,21 @@ void handleICMP4packet(int rcv_socket){
 
 
        if(rlen < sizeof(struct icmphdr)+sizeof(struct iphdr)){ //check packet size
-               dbgprintf(1, "Packet smaller than possible ICMPv4 packet!\n");
+               dbgprintf(2, "Packet smaller than possible ICMPv4 packet!\n");
                free(rcv_addr.gen);
                return;
        }
 
        icmp4=(struct icmphdr*)(rbuffer+iph->ihl*4);
        if(icmp4->type!=ICMP_DEST_UNREACH && icmp4->type!=ICMP_TIME_EXCEEDED){ //check icmp types
-               dbgprintf(1, "Tossing ICMPv4 packet of type %i\n", icmp4->type);
+               dbgprintf(2, "Tossing ICMPv4 packet of type %i\n", icmp4->type);
                free(rcv_addr.gen);
                return;
        }
 
        /*Check packet size again*/
        if(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+4){
-               dbgprintf(1, "Tossing ICMPv4 packet that's too small to contain DCCP header!\n");
+               dbgprintf(2, "Tossing ICMPv4 packet that's too small to contain DCCP header!\n");
                free(rcv_addr.gen);
                return;
        }
@@ -783,19 +808,19 @@ void handleICMP4packet(int rcv_socket){
        ip4hdr=(struct iphdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr));
        if(memcmp(&parms.src_addr.ipv4->sin_addr,&ip4hdr->saddr,sizeof(parms.src_addr.ipv4->sin_addr))!=0){
                /*Source address doesn't match*/
-               dbgprintf(1,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n");
+               dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n");
                free(rcv_addr.gen);
                return;
        }
        if(memcmp(&parms.dest_addr.ipv4->sin_addr,&ip4hdr->daddr,sizeof(parms.dest_addr.ipv4->sin_addr))!=0){
                /*Destination address doesn't match*/
-               dbgprintf(1,"Tossing ICMPv4 packet because the embedded IPv4 destination address isn't our target\n");
+               dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 destination address isn't our target\n");
                free(rcv_addr.gen);
                return;
        }
        if(ip4hdr->protocol!=IPPROTO_DCCP){
                /*Not DCCP!*/
-               dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
+               dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
                free(rcv_addr.gen);
                return;
        }
@@ -804,13 +829,13 @@ void handleICMP4packet(int rcv_socket){
        dhdr=(struct dccp_hdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4);
        if(dhdr->dccph_dport!=htons(parms.dest_port)){
                /*DCCP Destination Ports don't match*/
-               dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP destination port\n");
+               dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP destination port\n");
                free(rcv_addr.gen);
                return;
        }
        if(dhdr->dccph_sport!=htons(parms.src_port)){
                /*DCCP Source Ports don't match*/
-               dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP source port\n");
+               dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP source port\n");
                free(rcv_addr.gen);
                return;
        }
@@ -850,7 +875,7 @@ void handleICMP6packet(int rcv_socket){
        }
 
        if(rlen < sizeof(struct icmp6_hdr)){ //check packet size
-               dbgprintf(1, "Packet smaller than possible ICMPv6 packet!\n");
+               dbgprintf(2, "Packet smaller than possible ICMPv6 packet!\n");
                free(rcv_addr.gen);
                return;
        }
@@ -858,14 +883,14 @@ void handleICMP6packet(int rcv_socket){
        icmp6=(struct icmp6_hdr*)rbuffer;
        if(icmp6->icmp6_type!=ICMP6_DST_UNREACH && icmp6->icmp6_type!=ICMP6_PACKET_TOO_BIG
                        && icmp6->icmp6_type!=ICMP6_TIME_EXCEEDED && icmp6->icmp6_type!=ICMP6_PARAM_PROB){ //check icmp types
-               dbgprintf(1, "Tossing ICMPv6 packet of type %i\n", icmp6->icmp6_type);
+               dbgprintf(2, "Tossing ICMPv6 packet of type %i\n", icmp6->icmp6_type);
                free(rcv_addr.gen);
                return;
        }
 
        /*Check packet size again*/
        if(rlen<sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
-               dbgprintf(1, "Tossing ICMPv6 packet that's too small to contain DCCP header!\n");
+               dbgprintf(2, "Tossing ICMPv6 packet that's too small to contain DCCP header!\n");
                free(rcv_addr.gen);
                return;
        }
@@ -873,20 +898,20 @@ void handleICMP6packet(int rcv_socket){
        /*Decode IPv6 header*/
        ip6hdr=(struct ip6_hdr*)(rbuffer+sizeof(struct icmp6_hdr));
        if(memcmp(&parms.src_addr.ipv6->sin6_addr,&ip6hdr->ip6_src,sizeof(parms.src_addr.ipv6->sin6_addr))!=0){
-               dbgprintf(1,"Tossing ICMPv6 packet because the embedded IPv6 source address isn't us\n");
+               dbgprintf(2,"Tossing ICMPv6 packet because the embedded IPv6 source address isn't us\n");
                /*Source address doesn't match*/
                free(rcv_addr.gen);
                return;
        }
        if(memcmp(&parms.dest_addr.ipv6->sin6_addr,&ip6hdr->ip6_dst,sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){
                /*Destination address doesn't match*/
-               dbgprintf(1,"Tossing ICMPv6 packet because the embedded IPv6 destination address isn't our target\n");
+               dbgprintf(2,"Tossing ICMPv6 packet because the embedded IPv6 destination address isn't our target\n");
                free(rcv_addr.gen);
                return;
        }
        if(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt!=IPPROTO_DCCP){
                /*Not DCCP!*/
-               dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
+               dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
                free(rcv_addr.gen);
                return;
        }
@@ -895,13 +920,13 @@ void handleICMP6packet(int rcv_socket){
        dhdr=(struct dccp_hdr*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr));
        if(dhdr->dccph_dport!=htons(parms.dest_port)){
                /*DCCP Destination Ports don't match*/
-               dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP destination port\n");
+               dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP destination port\n");
                free(rcv_addr.gen);
                return;
        }
        if(dhdr->dccph_sport!=htons(parms.src_port)){
                /*DCCP Source Ports don't match*/
-               dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP source port\n");
+               dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP source port\n");
                free(rcv_addr.gen);
                return;
        }
@@ -973,7 +998,7 @@ void buildRequestPacket(unsigned char* buffer, int *len, int seq){
        dhdr->dccph_seq2=htonl(0); //Reserved if using 48 bit sequence numbers
        dhdr->dccph_seq=htonl(0);  //High 16bits of sequence number. Always make 0 for simplicity.
        dhdre->dccph_seq_low=htonl(seq);
-       dhdrr->dccph_req_service=htonl(DCCP_SERVICE_CODE);
+       dhdrr->dccph_req_service=htonl(parms.service_code);
 
        /*Checksums*/
        if(parms.ip_type==AF_INET){
@@ -1066,10 +1091,10 @@ int logPacket(int req_seq, int packet_seq){
 
 int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2){
        struct request *cur;
-       double diff;
+       long long diff;
 
        if(queue.tail==NULL){
-               dbgprintf(1,"Response received but no requests sent!\n");
+               dbgprintf(2,"Response received but no requests sent!\n");
                return -1;
        }
 
@@ -1078,9 +1103,6 @@ int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2){
        while(cur!=NULL){
                if(cur->packet_seq==seq){
                        gettimeofday(&cur->reply,NULL);
-                       if(cur->num_replies>0){
-                               printf("Duplicate packet detected! (%i)\n",cur->request_seq);
-                       }
                        if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
                                cur->num_replies++;
                        }else{
@@ -1099,18 +1121,21 @@ int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2){
                        ping_stats.errors++;
                        return 0;
                }else{
-                       dbgprintf(1,"Response received but no requests sent with sequence number %i!\n", seq);
+                       dbgprintf(2,"Response received but no requests sent with sequence number %i!\n", seq);
                        return -1;
                }
        }
 
        diff=(cur->reply.tv_usec + 1000000*cur->reply.tv_sec) - (cur->sent.tv_usec + 1000000*cur->sent.tv_sec);
-       diff=diff/1000.0;
 
        /*Print Message*/
        if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
-               printf( "Response from %s : seq=%i  time=%.1fms  status=%s\n",
-                                       addr2str(src,0),cur->request_seq, diff,response_good[type]);
+               if(debug==0){
+                       printf( "Response from %s : seq=%i  time=%.1fms\n",addr2str(src,0),cur->request_seq, diff/1000.0);
+               }else{
+                       printf( "Response from %s : seq=%i  time=%.1fms  status=%s\n",
+                                       addr2str(src,0),cur->request_seq, diff/1000.0,response_good[type]);
+               }
        }else{
 
                printf("%s from %s : seq=%i\n",get_error_string(type,v1,v2),addr2str(src,0),cur->request_seq);
@@ -1120,10 +1145,12 @@ int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2){
        if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
                /*Good Response*/
                if(cur->num_replies==1){
-                       ping_stats.rtt_avg=((ping_stats.replies_received*ping_stats.rtt_avg)+(diff))/(ping_stats.replies_received+1);
+                       ping_stats.rtt_sum+=diff;
+                       ping_stats.rtt_sum2+=(diff*diff);
                        ping_stats.replies_received++;
                }else{
-                       ping_stats.errors++;
+                       printf("Duplicate packet detected! (%i)\n",cur->request_seq);
+                       ping_stats.duplicates++;
                }
                if(diff < ping_stats.rtt_min || ping_stats.rtt_min==0){
                        ping_stats.rtt_min=diff;
@@ -1204,26 +1231,46 @@ void clearQueue(){
 }
 
 void sigHandler(){
-       int diff;
-       double ploss;
+       /*Exit Quickly*/
+       parms.count=0;
+}
 
-       /*Print Stats*/
-       gettimeofday(&ping_stats.stop,NULL);
-       printf("-----------%s PING STATISTICS-----------\n",parms.hostname);
+void printStats(){
+       int diff;
+       double ploss, rtt_avg, rtt_avg2, rtt_mdev;
 
+       /*Compute Stats*/
+       if(ping_stats.replies_received>0){
+               rtt_avg=ping_stats.rtt_sum/(ping_stats.replies_received*1.0);
+               rtt_avg2=ping_stats.rtt_sum2/(ping_stats.replies_received*1.0);
+               rtt_mdev=llsqrt(rtt_avg2 - (rtt_avg*rtt_avg));
+       }else{
+               rtt_avg=0;
+               rtt_avg2=0;
+               rtt_mdev=0;
+       }
        diff=(ping_stats.stop.tv_usec + 1000000*ping_stats.stop.tv_sec) -
                        (ping_stats.start.tv_usec + 1000000*ping_stats.start.tv_sec);
        diff=diff/1000.0;
-       ploss=(1.0*(ping_stats.requests_sent-ping_stats.replies_received)/ping_stats.requests_sent*1.0)*100;
-       printf("%i packets transmitted, %i received, %i errors, %.2f%% loss, time %ims\n",
-                       ping_stats.requests_sent,ping_stats.replies_received,ping_stats.errors,
-                       ploss,diff);
-       printf("rtt min/avg/max = %.1f/%.1f/%.1f ms\n",
-                       ping_stats.rtt_min,ping_stats.rtt_avg,ping_stats.rtt_max);
 
+       /*Print Stats*/
+       gettimeofday(&ping_stats.stop,NULL);
+       printf("-----------%s PING STATISTICS-----------\n",parms.hostname);
+       ploss=(1.0*(ping_stats.requests_sent-ping_stats.replies_received)/ping_stats.requests_sent*1.0)*100;
+       printf("%i packets transmitted, %i received, ",ping_stats.requests_sent,ping_stats.replies_received);
+       if(ping_stats.duplicates>0){
+               printf("%i duplicates, ",ping_stats.duplicates);
+       }
+       if(ping_stats.errors>0){
+               printf("%i errors, ",ping_stats.errors);
+       }
+       printf("%.2f%% loss, time %ims\n",ploss,diff);
+       if(ping_stats.replies_received>ping_stats.requests_sent){
+               printf("+Somebody is creating packets out of thing air!\n");
+       }
+       printf("rtt min/avg/max/mdev = %.1f/%.1f/%.1f/%.1f ms\n",
+                       ping_stats.rtt_min/1000.0,rtt_avg/1000.0,ping_stats.rtt_max/1000.0,rtt_mdev/1000.0);
 
-       /*Exit Quickly*/
-       parms.count=0;
 }
 
 char* addr2str(ipaddr_ptr_t *res, int nores){
@@ -1241,7 +1288,7 @@ char* addr2str(ipaddr_ptr_t *res, int nores){
        }
        if((ret=getnameinfo(res->gen, size,
                        addr2str_buf, sizeof (addr2str_buf), 0, 0, NI_NUMERICHOST))<0){
-               dbgprintf(0,"Error! %s\n",gai_strerror(ret));
+               dbgprintf(0,"Error: getnameinfo() returned %s\n",gai_strerror(ret));
        }
 
        if (parms.no_resolve||nores){
@@ -1259,11 +1306,11 @@ char* addr2str(ipaddr_ptr_t *res, int nores){
 /*Usage information for program*/
 void usage()
 {
-       dbgprintf(0, "dccpping: [-d] [-v] [-h] [-n] [-6|-4] [-c count] [-p port] [-i interval]\n");
-       dbgprintf(0, "          [-t ttl] [-S srcaddress] remote_host\n");
+       dbgprintf(0, "dccpping: [-v] [-V] [-h] [-n] [-6|-4] [-c count] [-p port] [-i interval]\n");
+       dbgprintf(0, "          [-t ttl] [-s service_code] [-S srcaddress] remote_host\n");
        dbgprintf(0, "\n");
-       dbgprintf(0, "          -d   Debug. May be repeated for aditional verbosity\n");
-       dbgprintf(0, "          -v   Version information\n");
+       dbgprintf(0, "          -v   Verbose. May be repeated for aditional verbosity.\n");
+       dbgprintf(0, "          -V   Version information\n");
        dbgprintf(0, "          -h   Help\n");
        dbgprintf(0, "          -n   Numeric output only\n");
        dbgprintf(0, "          -6   Force IPv6 mode\n");
@@ -1299,3 +1346,21 @@ void dbgprintf(int level, const char *fmt, ...)
        va_end(args);
     }
 }
+
+/*Square Root function for longs*/
+/*Borrowed from iputils/ping_common.c*/
+/* http://www.skbuff.net/iputils/ */
+static long llsqrt(long long a)
+{
+       long long prev = ~((long long)1 << 63);
+       long long x = a;
+
+       if (x > 0) {
+               while (x < prev) {
+                       prev = x;
+                       x = (x+(a/x))/2;
+               }
+       }
+
+       return (long)x;
+}