X-Git-Url: http://sjero.net/git/?p=dccpping;a=blobdiff_plain;f=dccpping.c;h=b71a7e3bb08998aaa0b0be4e00d482e1ae4011a4;hp=7a9e5e9d8e6f934f9da06c6e0389b9b027b1ea50;hb=HEAD;hpb=abad27c5eda52ad6e9c2c6a0e6483e40ba790856 diff --git a/dccpping.c b/dccpping.c index 7a9e5e9..b71a7e3 100644 --- a/dccpping.c +++ b/dccpping.c @@ -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(rlenihl*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(rlensin6_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; +}