ping.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:7k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* ICMP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "icmp.h"
  7. #include "mbuf.h"
  8. #include "netuser.h"
  9. #include "internet.h"
  10. #include "socket.h"
  11. #include "proc.h"
  12. #include "session.h"
  13. #include "commands.h"
  14. #include "ping.h"
  15. static void pingtx(int s,void *ping1,void *p);
  16. static void pinghdr(struct session *sp,struct ping *ping);
  17. static int pingproc(int c);
  18. static int keychar(int c);
  19. /* Send ICMP Echo Request packets */
  20. int
  21. doping(argc,argv,p)
  22. int argc;
  23. char *argv[];
  24. void *p;
  25. {
  26. struct sockaddr_in from;
  27. struct icmp icmp;
  28. struct mbuf *bp;
  29. int32 timestamp,rtt,abserr;
  30. int s,fromlen;
  31. struct ping ping;
  32. struct session *sp;
  33. memset(&ping,0,sizeof(ping));
  34. /* Allocate a session descriptor */
  35. if((sp = ping.sp = newsession(Cmdline,PING,1)) == NULL){
  36. printf("Too many sessionsn");
  37. return 1;
  38. }
  39. if((ping.s = s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  40. printf("Can't create socketn");
  41. keywait(NULL,1);
  42. freesession(sp);
  43. return 1;
  44. }
  45. sp->inproc = keychar; /* Intercept ^C */
  46. if(SETSIG(EABORT)){
  47. keywait(NULL,1);
  48. freesession(sp);
  49. return 1;
  50. }
  51. printf("Resolving %s...n",argv[1]);
  52. if((ping.target = resolve(argv[1])) == 0){
  53. printf("unknownn");
  54. keywait(NULL,1);
  55. freesession(sp);
  56. return 1;
  57. }
  58. printf("Pinging %sn",inet_ntoa(ping.target));
  59. sp->cb.p = &ping;
  60. if(argc > 2)
  61. ping.len = atoi(argv[2]);
  62. if(argc > 3)
  63. ping.interval = atol(argv[3]);
  64. /* Optionally ping a range of IP addresses */
  65. if(argc > 4)
  66. ping.incflag = 1;
  67. if(ping.interval != 0){
  68. sp->proc1 = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
  69. } else {
  70. /* One shot ping; let echo_proc hook handle response.
  71.  * An ID of MAXINT16 will not be confused with a legal socket
  72.  * number, which is used to identify repeated pings
  73.  */
  74. pingem(s,ping.target,0,MAXINT16,ping.len);
  75. close(s);
  76. freesession(sp);
  77. return 0;
  78. }
  79. sp->inproc = pingproc;
  80. /* Now collect the replies */
  81. pinghdr(sp,&ping);
  82. for(;;){
  83. fromlen = sizeof(from);
  84. if(recv_mbuf(s,&bp,0,(struct sockaddr *)&from,&fromlen) == -1)
  85. break;
  86. ntohicmp(&icmp,&bp);
  87. if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  88. /* Ignore other people's responses */
  89. free_p(&bp);
  90. continue;
  91. }
  92. /* Get stamp */
  93. if(pullup(&bp,&timestamp,sizeof(timestamp))
  94.  != sizeof(timestamp)){
  95. /* The timestamp is missing! */
  96. free_p(&bp); /* Probably not necessary */
  97. continue;
  98. }
  99. free_p(&bp);
  100. ping.responses++;
  101. /* Compute round trip time, update smoothed estimates */
  102. rtt = msclock() - timestamp;
  103. abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
  104. if(ping.responses == 1){
  105. /* First response, base entire SRTT on it */
  106. ping.srtt = rtt;
  107. ping.mdev = 0;
  108. ping.maxrtt = ping.minrtt = rtt;
  109. } else {
  110. ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  111. ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  112. if(rtt > ping.maxrtt)
  113. ping.maxrtt = rtt;
  114. if(rtt < ping.minrtt)
  115. ping.minrtt = rtt;
  116. }
  117. if((ping.responses % 20) == 0)
  118. pinghdr(sp,&ping);
  119. printf("%10lu%10lu%5lu%8lu%8lu%8lu%8lu%8lun",
  120.  ping.sent,ping.responses,
  121.  (ping.responses*100 + ping.sent/2)/ping.sent,
  122.  rtt,ping.srtt,ping.mdev,ping.maxrtt,ping.minrtt);
  123. }
  124. if(sp->proc1 != NULL){
  125. killproc(sp->proc1);
  126. sp->proc1 = NULL;
  127. }
  128. close(s);
  129. keywait(NULL,1);
  130. freesession(sp);
  131. return 0;
  132. }
  133. static int
  134. keychar(c)
  135. int c;
  136. {
  137. if(c != CTLC)
  138. return 1; /* Ignore all but ^C */
  139. fprintf(Current->output,"^Cn");
  140. alert(Current->proc,EABORT);
  141. return 0;
  142. }
  143. static void
  144. pinghdr(sp,ping)
  145. struct session *sp;
  146. struct ping *ping;
  147. {
  148. printf("      sent      rcvd    %     rtt     avg    mdev     max     minn");
  149. }
  150. void
  151. echo_proc(
  152. int32 source,
  153. int32 dest,
  154. struct icmp *icmp,
  155. struct mbuf **bpp
  156. ){
  157. int32 timestamp,rtt;
  158. if(Icmp_echo && icmp->args.echo.id == MAXINT16
  159.  && pullup(bpp,&timestamp,sizeof(timestamp))
  160.  == sizeof(timestamp)){
  161. /* Compute round trip time */
  162. rtt = msclock() - timestamp;
  163. printf("%s: rtt %lun",inet_ntoa(source),rtt);
  164. }
  165. free_p(bpp);
  166. }
  167. /* Ping transmit process. Runs until killed */
  168. static void
  169. pingtx(s,ping1,p)
  170. int s; /* Socket to use */
  171. void *ping1;
  172. void *p;
  173. {
  174. struct ping *ping;
  175. ping = (struct ping *)ping1;
  176. if(ping->incflag){
  177. for(;;){
  178. pingem(s,ping->target++,0,MAXINT16,ping->len);
  179. ping->sent++;
  180. ppause(ping->interval);
  181. }
  182. } else {
  183. for(;;){
  184. pingem(s,ping->target,(uint16)ping->sent++,(uint16)s,ping->len);
  185. ppause(ping->interval);
  186. }
  187. }
  188. }
  189. /* Send ICMP Echo Request packet */
  190. int
  191. pingem(s,target,seq,id,len)
  192. int s; /* Raw socket on which to send ping */
  193. int32 target; /* Site to be pinged */
  194. uint16 seq; /* ICMP Echo Request sequence number */
  195. uint16 id; /* ICMP Echo Request ID */
  196. uint16 len; /* Length of optional data field */
  197. {
  198. struct mbuf *data;
  199. struct icmp icmp;
  200. struct sockaddr_in to;
  201. int32 clock;
  202. int i;
  203. uint8 *cp;
  204. clock = msclock();
  205. data = ambufw((uint16)(len+sizeof(clock)));
  206. data->cnt = len+sizeof(clock);
  207. #define counter 1
  208. #ifdef rnd
  209. /* Set data field to random pattern */
  210. cp = data->data+sizeof(clock);
  211. while(len-- != 0)
  212. *cp++ = rand();
  213. #elif alternate
  214. /* Set optional data field, if any, to all 55's */
  215. if(len != 0)
  216. memset(data->data+sizeof(clock),0x55,len);
  217. #elif counter
  218. cp = data->data+sizeof(clock);
  219. i = 0;
  220. while(len-- != 0)
  221. *cp++ = i++;
  222. #endif
  223. /* Insert timestamp and build ICMP header */
  224. memcpy(data->data,&clock,sizeof(clock));
  225. icmpOutEchos++;
  226. icmpOutMsgs++;
  227. icmp.type = ICMP_ECHO;
  228. icmp.code = 0;
  229. icmp.args.echo.seq = seq;
  230. icmp.args.echo.id = id;
  231. htonicmp(&icmp,&data);
  232. to.sin_family = AF_INET;
  233. to.sin_addr.s_addr = target;
  234. send_mbuf(s,&data,0,(struct sockaddr *)&to,sizeof(to));
  235. return 0;
  236. }
  237. static int
  238. pingproc(c)
  239. int c;
  240. {
  241. struct ping *p;
  242. struct session *sp;
  243. sp = Current;
  244. p = (struct ping *)sp->cb.p;
  245. if(p->s == -1)
  246. return 1; /* Shutting down, let keywait have it */
  247. switch(c){
  248. case '33':
  249. case 'Q':
  250. case 'q':
  251. case 3: /* ctl-c - quit */
  252. alert(sp->proc,EABORT);
  253. if(Current->proc1 != NULL){
  254. killproc(sp->proc1);
  255. sp->proc1 = NULL;
  256. }
  257. shutdown(p->s,2);
  258. p->s = -1;
  259. break;
  260. case ' ': /* Toggle pinger */
  261. if(sp->proc1 != NULL){
  262. killproc(sp->proc1);
  263. sp->proc1 = NULL;
  264. fprintf(sp->output,"Pinging suspended, %lu sentn",p->sent);
  265. } else {
  266. p->sent = p->responses = 0;
  267. sp->proc1 = newproc("pingtx",300,pingtx,p->s,p,NULL,0);
  268. fprintf(sp->output,"Pinging resumedn");
  269. }
  270. break;
  271. }
  272. return 0;
  273. }