You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

libping.c 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /**
  2. * PING module
  3. *
  4. * Copyright (C) 2001 Jeffrey Fulmer <jdfulmer@armstrong.com>
  5. * This file is part of LIBPING
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. *
  21. * --
  22. *
  23. * This code has been lightly modified to adapt it in the Netsukuku source
  24. * code.
  25. */
  26. #include <sys/types.h>
  27. #include <sys/socket.h>
  28. #include <netdb.h>
  29. #include <pthread.h>
  30. #include <stdlib.h>
  31. #include "libping.h"
  32. #include "xmalloc.h"
  33. #include "log.h"
  34. #define MAXPACKET 65535
  35. #define PKTSIZE 64
  36. #define HDRLEN ICMP_MINLEN
  37. #define DATALEN (PKTSIZE-HDRLEN)
  38. #define MAXDATA (MAXPKT-HDRLEN-TIMLEN)
  39. #define DEF_TIMEOUT 5
  40. struct ping_priv
  41. ping_priv_default(void)
  42. {
  43. struct ping_priv datum;
  44. datum.ident = IDENT_DEFAULT;
  45. datum.timo = TIMO_DEFAULT;
  46. return datum;
  47. }
  48. /**
  49. * elapsed_time
  50. * returns an int value for the difference
  51. * between now and starttime in milliseconds.
  52. */
  53. int
  54. elapsed_time(struct timeval *starttime)
  55. {
  56. struct timeval *newtime;
  57. int elapsed;
  58. newtime = (struct timeval *) xmalloc(sizeof(struct timeval));
  59. gettimeofday(newtime, NULL);
  60. elapsed = 0;
  61. if ((newtime->tv_usec - starttime->tv_usec) > 0) {
  62. elapsed += (newtime->tv_usec - starttime->tv_usec) / 1000;
  63. } else {
  64. elapsed +=
  65. (1000000 + newtime->tv_usec - starttime->tv_usec) / 1000;
  66. newtime->tv_sec--;
  67. }
  68. if ((newtime->tv_sec - starttime->tv_sec) > 0) {
  69. elapsed += 1000 * (newtime->tv_sec - starttime->tv_sec);
  70. }
  71. if (elapsed < 1)
  72. elapsed = 1;
  73. xfree(newtime);
  74. return (elapsed);
  75. }
  76. void
  77. JOEfreeprotoent(struct protoent *p)
  78. {
  79. char **a;
  80. xfree(p->p_name);
  81. if (p->p_aliases != NULL) {
  82. for (a = p->p_aliases; *a != NULL; a++) {
  83. xfree(*a);
  84. }
  85. }
  86. xfree(p);
  87. }
  88. void
  89. JOEfreehostent(struct hostent *h)
  90. {
  91. char **p;
  92. xfree(h->h_name);
  93. if (h->h_aliases != NULL) {
  94. for (p = h->h_aliases; *p != NULL; ++p)
  95. xfree(*p);
  96. xfree(h->h_aliases);
  97. }
  98. if (h->h_addr_list != NULL) {
  99. for (p = h->h_addr_list; *p != NULL; ++p)
  100. xfree(*p);
  101. xfree(h->h_addr_list);
  102. }
  103. xfree(h);
  104. }
  105. static int
  106. in_checksum(u_short * buf, int len)
  107. {
  108. register long sum = 0;
  109. u_short answer = 0;
  110. while (len > 1) {
  111. sum += *buf++;
  112. len -= 2;
  113. }
  114. if (len == 1) {
  115. *(u_char *) (&answer) = *(u_char *) buf;
  116. sum += answer;
  117. }
  118. sum = (sum >> 16) + (sum & 0xffff);
  119. sum += (sum >> 16);
  120. answer = ~sum;
  121. return (answer);
  122. }
  123. static int
  124. send_ping(const char *host, struct sockaddr_in *taddr,
  125. struct ping_priv *datum)
  126. {
  127. int len;
  128. int ss;
  129. unsigned char buf[HDRLEN + DATALEN];
  130. #define PROTO_BUF_LEN 1024
  131. char proto_buf[PROTO_BUF_LEN];
  132. struct protoent *proto = NULL;
  133. struct protoent proto_datum;
  134. struct hostent *hp = NULL;
  135. struct hostent hent;
  136. int herrno;
  137. char hbf[9000];
  138. #if defined(_AIX)
  139. char *aixbuf;
  140. char *probuf;
  141. int rc;
  142. #endif/*_AIX*/
  143. struct icmp *icp;
  144. unsigned short last;
  145. len = HDRLEN + DATALEN;
  146. #if defined(__GLIBC__)
  147. /* for systems using GNU libc */
  148. getprotobyname_r("icmp", &proto_datum, proto_buf, PROTO_BUF_LEN,
  149. &proto);
  150. if ((gethostbyname_r(host, &hent, hbf, sizeof(hbf), &hp, &herrno) < 0)) {
  151. hp = NULL;
  152. }
  153. #elif defined(sun)
  154. /* Solaris 5++ */
  155. proto =
  156. getprotobyname_r("icmp", &proto_datum, proto_buf, PROTO_BUF_LEN);
  157. hp = gethostbyname_r(host, &hent, hbf, sizeof(hbf), &herrno);
  158. #elif defined(_AIX)
  159. aixbuf = (char *) xmalloc(9000);
  160. probuf = (char *) xmalloc(9000);
  161. rc = getprotobyname_r("icmp", &proto,
  162. (struct protoent_data *) (probuf +
  163. sizeof(struct
  164. protoent)));
  165. rc = gethostbyname_r(host, (struct hostent *) aixbuf,
  166. (struct hostent_data *) (aixbuf +
  167. sizeof(struct hostent)));
  168. hp = (struct hostent *) aixbuf;
  169. #elif ( defined(hpux) || defined(__osf__) )
  170. proto = getprotobyname("icmp");
  171. hp = gethostbyname(host);
  172. herrno = h_errno;
  173. #else
  174. /* simply hoping that get*byname is thread-safe */
  175. proto = getprotobyname("icmp");
  176. hp = gethostbyname(host);
  177. herrno = h_errno;
  178. #endif /*OS SPECIFICS */
  179. if (proto == NULL) {
  180. return -1;
  181. }
  182. if (hp != NULL) {
  183. memcpy(&taddr->sin_addr, hp->h_addr_list[0],
  184. sizeof(taddr->sin_addr));
  185. taddr->sin_port = 0;
  186. taddr->sin_family = AF_INET;
  187. } else if (inet_aton(host, &taddr->sin_addr) == 0) {
  188. return -1;
  189. }
  190. last = ntohl(taddr->sin_addr.s_addr) & 0xFF;
  191. if ((last == 0x00) || (last == 0xFF)) {
  192. return -1;
  193. }
  194. if ((datum->sock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  195. #ifdef DEBUG
  196. debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
  197. #endif /*DEBUG*/
  198. return -2;
  199. }
  200. icp = (struct icmp *) buf;
  201. icp->icmp_type = ICMP_ECHO;
  202. icp->icmp_code = 0;
  203. icp->icmp_cksum = 0;
  204. icp->icmp_id = getpid() & 0xFFFF;
  205. icp->icmp_cksum = in_checksum((u_short *) icp, len);
  206. if ((ss = sendto(datum->sock, buf, sizeof(buf), 0,
  207. (struct sockaddr *) taddr, sizeof(*taddr))) < 0) {
  208. #ifdef DEBUG
  209. debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
  210. #endif /*DEBUG*/
  211. return -2;
  212. }
  213. if (ss != len) {
  214. #ifdef DEBUG
  215. debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
  216. #endif /*DEBUG*/
  217. return -2;
  218. }
  219. #if defined(_AIX)
  220. xfree(aixbuf);
  221. xfree(probuf);
  222. #endif
  223. /* JOEfreeprotoent( proto ); */
  224. /* JOEfreeprotoent( &proto_datum ); */
  225. /* JOEfreehostent( hp ); */
  226. /* JOEfreehostent( &hent ); */
  227. return 0;
  228. }
  229. static int
  230. recv_ping(struct sockaddr_in *taddr, struct ping_priv *datum)
  231. {
  232. int len;
  233. int from;
  234. int nf, cc;
  235. unsigned char buf[HDRLEN + DATALEN];
  236. //struct icmp *icp;
  237. struct sockaddr_in faddr;
  238. struct timeval to;
  239. fd_set readset;
  240. to.tv_sec = datum->timo / 100000;
  241. to.tv_usec = (datum->timo - (to.tv_sec * 100000)) * 10;
  242. FD_ZERO(&readset);
  243. FD_SET(datum->sock, &readset);
  244. /* we use select to see if there is any activity
  245. on the socket. If not, then we've requested an
  246. unreachable network and we'll time out here. */
  247. if ((nf = select(datum->sock + 1, &readset, NULL, NULL, &to)) < 0) {
  248. datum->rrt = -4;
  249. #ifdef DEBUG
  250. debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
  251. #endif /*DEBUG*/
  252. return 0;
  253. }
  254. if (nf == 0) {
  255. return -1;
  256. }
  257. len = HDRLEN + DATALEN;
  258. from = sizeof(faddr);
  259. cc = recvfrom(datum->sock, buf, len, 0, (struct sockaddr *) &faddr,
  260. (socklen_t *) & from);
  261. if (cc < 0) {
  262. datum->rrt = -4;
  263. #ifdef DEBUG
  264. debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
  265. #endif /*DEBUG*/
  266. return 0;
  267. }
  268. //icp = (struct icmp *) (buf + HDRLEN + DATALEN);
  269. if (faddr.sin_addr.s_addr != taddr->sin_addr.s_addr) {
  270. return 1;
  271. }
  272. /*****
  273. if( icp->icmp_id != ( getpid() & 0xFFFF )){
  274. printf( "id: %d\n", icp->icmp_id );
  275. return 1;
  276. }
  277. *****/
  278. return 0;
  279. }
  280. int
  281. myping(const char *hostname, int t, struct ping_priv *datum)
  282. {
  283. int err;
  284. int rrt;
  285. struct sockaddr_in sa;
  286. struct timeval mytime;
  287. datum->ident = getpid() & 0xFFFF;
  288. if (t == 0)
  289. datum->timo = 2;
  290. else
  291. datum->timo = t;
  292. datum->rrt = 0;
  293. (void) gettimeofday(&mytime, (struct timezone *) NULL);
  294. if ((err = send_ping(hostname, &sa, datum)) < 0) {
  295. close(datum->sock);
  296. return err;
  297. }
  298. do {
  299. rrt = elapsed_time(&mytime);
  300. if (datum->rrt < 0)
  301. return 0;
  302. datum->rrt = rrt;
  303. if (datum->rrt > datum->timo * 1000) {
  304. close(datum->sock);
  305. return 0;
  306. }
  307. } while (recv_ping(&sa, datum));
  308. close(datum->sock);
  309. return 1;
  310. }
  311. int
  312. pinghost(const char *hostname)
  313. {
  314. struct ping_priv datum = ping_priv_default();
  315. return myping(hostname, 0, &datum);
  316. }
  317. int
  318. pingthost(const char *hostname, int t)
  319. {
  320. struct ping_priv datum = ping_priv_default();
  321. return myping(hostname, t, &datum);
  322. }
  323. int
  324. tpinghost(const char *hostname)
  325. {
  326. int ret;
  327. struct ping_priv datum = ping_priv_default();
  328. ret = myping(hostname, 0, &datum);
  329. if (ret > 0)
  330. ret = datum.rrt;
  331. return ret;
  332. }
  333. int
  334. tpingthost(const char *hostname, int t)
  335. {
  336. int ret;
  337. struct ping_priv datum = ping_priv_default();
  338. ret = myping(hostname, t, &datum);
  339. if (ret > 0)
  340. ret = datum.rrt;
  341. return ret;
  342. }