home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / internet / netlite2 / NET / c / ICMPCMD < prev    next >
Encoding:
Text File  |  1993-04-13  |  7.7 KB  |  290 lines

  1. /* ICMP-related user commands */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include "dbox.h"
  7. #include "werr.h"
  8. #include "global.h"
  9. #include "icmp.h"
  10. #include "mbuf.h"
  11. #include "netuser.h"
  12. #include "internet.h"
  13. #include "timer.h"
  14. #include "ping.h"
  15. #include "misc.h"
  16. #include "session.h"
  17. #include "domain.h"
  18.  
  19. #define Ping_Host        1
  20. #define Ping_Interval    3
  21. #define Ping_Size        4
  22. #define Ping_OK          5
  23.  
  24. static int ping_start(int32, char *, char *, char *, struct session *);
  25. static int ping_error(char *, char *, struct session *);
  26. static int pingem(struct ping *);
  27. static int16 hash_ping(int32);
  28. static struct ping *add_ping(int32);
  29. static void pingparse(struct session *, char *, int16);
  30. static void del_ping(struct ping *);
  31.  
  32. /* Hash table list heads */
  33. struct ping *ping[PMOD];
  34.  
  35. void start_ping(void)
  36. {
  37.         struct session *session;
  38.         char buffer[80];
  39.         char Host[256];
  40.         char Interval[5];
  41.         char Size[5];
  42.         dbox d;
  43.  
  44.         if ((d = dbox_new("Ping")) == NULL)
  45.                 return;
  46.  
  47.         dbox_setfield(d, Ping_Host,     "");
  48.         dbox_setfield(d, Ping_Interval, "1");
  49.         dbox_setfield(d, Ping_Size,     "64");
  50.  
  51.         dbox_show(d);
  52.  
  53.         if (dbox_fillin(d) == Ping_OK)
  54.         {
  55.                 dbox_getfield(d, Ping_Host, Host, 50);
  56.                 dbox_getfield(d, Ping_Interval, Interval, 5);
  57.                 dbox_getfield(d, Ping_Size, Size, 5);
  58.  
  59.                 /* Allocate a session descriptor */
  60.                 sprintf(buffer, "PING - %.60s", Host);
  61.                 if ((session = newsession(buffer)) == NULLSESSION)
  62.                 {
  63.                        werr(0, "Too many sessions");
  64.                        return;
  65.                 }
  66.  
  67.                 session->name  = strdup(Host);
  68.                 session->type  = RESOLVING;
  69.                 session->parse = NULLVFP;
  70.  
  71.                 sprintf(buffer, "Resolving %.60s ...\n", Host);
  72.                 Window_Write(session->window, buffer, strlen(buffer));
  73.  
  74.                 resolve_a(Host, Interval, Size, session, ping_start, ping_error);
  75.         }
  76.  
  77.         dbox_dispose(&d);
  78. }
  79.  
  80. static int ping_error(char *host, char *message, struct session *s)
  81. {
  82.         char buffer[80];
  83.  
  84.         sprintf(buffer, "Cannot PING %s - %s\n", host, message);
  85.         Window_Write(s->window, buffer, strlen(buffer));
  86.  
  87.         detachsession(s);
  88.  
  89.         return 0;  
  90. }
  91.  
  92. /* Send ICMP Echo Request packets */
  93. static int ping_start(int32 address, char *host, char *arg1, char *arg2, struct session *s)
  94. {
  95.         char buffer[80];
  96.         register struct ping *pp;
  97.         int16 hval;
  98.         int interval;
  99.         int size;
  100.  
  101.         if ((interval = atoi(arg1)) == 0)
  102.                 interval = 1;
  103.  
  104.         if ((size = atoi(arg2)) == 0)
  105.                 size = 64;
  106.  
  107.         if (size < 4) size = 4;
  108.  
  109.         /* See if address is already in table */
  110.         hval = hash_ping(address);
  111.         for (pp = ping[hval]; pp != NULLPING; pp = pp->next){
  112.                 if (pp->remote == address){
  113.                         break;
  114.                 }
  115.         }
  116.  
  117.         s->type  = PING;
  118.         s->addr  = address;
  119.         s->parse = pingparse;
  120.         s->echo  = 0;
  121.         s->raw   = 1;
  122.  
  123.         /* Inter-ping time is specified; set up timer structure */
  124.         if (pp == NULLPING) pp = add_ping(address);
  125.         pp->timer.start = interval * (int32)(1000 / MSPTICK);
  126.         pp->timer.func = ptimeout;
  127.         pp->timer.arg = (char *)pp;
  128.         pp->interval= interval;
  129.         pp->size    = size;
  130.         pp->remote  = address;
  131.         pp->host    = strdup(host);
  132.         pp->id      = clock() & 0xFFFF;
  133.         pp->user    = s;
  134.         pp->mintime = 999999999;
  135.         pp->maxtime = 0;
  136.         start_timer(&pp->timer);
  137.         pp->count++;
  138.  
  139.         pingem(pp);
  140.  
  141.         sprintf(buffer, "PING %s (%s): %d data bytes\n", host, inet_ntoa(address), size);
  142.         Window_Write(s->window, buffer, strlen(buffer));
  143.  
  144.         s->cb.ping = pp;
  145.  
  146.         return 0;
  147. }
  148.  
  149. static void pingparse(struct session *s, char *buf, int16 n)
  150. {
  151.         char buffer[80];
  152.         struct ping *pp;
  153.         int percentage;
  154.         int average;
  155.  
  156.         if (n != 1 || *buf != 0x03) return;
  157.  
  158.         pp = s->cb.ping;
  159.  
  160.         percentage = ((pp->count - pp->echoes) * 100) / pp->count;
  161.  
  162.         sprintf(buffer, "\n--- %s ping statistics ---\n", s->name);
  163.         Window_Write(s->window, buffer, strlen(buffer));
  164.  
  165.         sprintf(buffer, "%d packets transmitted, %d packets received, %d%% packet loss\n", pp->count, pp->echoes, percentage);
  166.         Window_Write(s->window, buffer, strlen(buffer));
  167.  
  168.         if (pp->echoes > 0)
  169.         {
  170.                 average = pp->ttotal / pp->echoes;
  171.                 sprintf(buffer, "round-trip min/avg/max = %d/%d/%d ms\n", pp->mintime, average, pp->maxtime);
  172.                 Window_Write(s->window, buffer, strlen(buffer));
  173.         }
  174.  
  175.         del_ping(pp);
  176. }
  177.  
  178. /* Called by ping timeout */
  179. void ptimeout(char *p)
  180. {
  181.         register struct ping *pp;
  182.  
  183.         /* Send another ping */
  184.         pp = (struct ping *)p;
  185.  
  186.         pp->count++;
  187.  
  188.         pingem(pp);
  189.  
  190.         start_timer(&pp->timer);
  191. }
  192.  
  193. /* Send ICMP Echo Request packet */
  194. static int pingem(struct ping *pp)
  195. {
  196.         struct mbuf *bp, *tbp;
  197.         struct icmp icmp;
  198.         extern struct icmp_stats icmp_stats;
  199.         register int i;
  200.  
  201.         bp = alloc_mbuf(pp->size);
  202.         put32(bp->data, clock());
  203.         for (i = 4; i < pp->size; i++) bp->data[i] = i;
  204.         bp->cnt   = pp->size;
  205.         icmp_stats.output[ECHO]++;
  206.         icmp.type = ECHO;
  207.         icmp.code = 0;
  208.         icmp.args.echo.seq = pp->count - 1;
  209.         icmp.args.echo.id  = pp->id;
  210.         if ((tbp = htonicmp(&icmp,bp)) == NULLBUF) {
  211.                 free_p(bp);
  212.                 return 0;
  213.         }
  214.         return ip_send(ip_addr,pp->remote,ICMP_PTCL,0,0,tbp,len_mbuf(tbp),0,0);
  215. }
  216.  
  217. /* Called with incoming Echo Reply packet */
  218. void echo_proc(int32 source, int32 dest, struct icmp *icmp, struct mbuf *bp)
  219. {
  220.         char buffer[80];
  221.         register struct ping *pp;
  222.         struct session *s;
  223.         int16 hval;
  224.         int16 rtt;
  225.  
  226.         dest = dest;
  227.  
  228.         rtt = (clock() - get32(bp->data)) * MSPTICK;
  229.  
  230.         hval = hash_ping(source);
  231.         for (pp = ping[hval]; pp != NULLPING; pp = pp->next) {
  232.                  if (pp->remote == source) {
  233.                         s = (struct session *)pp->user;
  234.                         sprintf(buffer, "%d bytes from %s: icmp_seq=%d time=%d ms\n", len_mbuf(bp), inet_ntoa(pp->remote), icmp->args.echo.seq, rtt);
  235.                         Window_Write(s->window, buffer, strlen(buffer));
  236.                         if (pp->mintime > rtt) pp->mintime = rtt;
  237.                         if (pp->maxtime < rtt) pp->maxtime = rtt;
  238.                         pp->ttotal += rtt;
  239.                         pp->echoes++;
  240.                         return;
  241.                 }
  242.         }
  243. }
  244.  
  245. static int16 hash_ping(int32 dest)
  246. {
  247.         int16 hval;
  248.  
  249.         hval = (hiword(dest) ^ loword(dest)) % PMOD;
  250.         return hval;
  251. }
  252.  
  253. /* Add entry to ping table */
  254. static struct ping * add_ping(int32 dest)
  255. {
  256.         struct ping *pp;
  257.         int16 hval;
  258.  
  259.         if ((pp = (struct ping *)calloc(1, sizeof(struct ping))) == NULLPING)
  260.                 return NULLPING;
  261.  
  262.         hval = hash_ping(dest);
  263.         pp->prev = NULLPING;
  264.         pp->next = ping[hval];
  265.         if (pp->next != NULLPING) pp->next->prev = pp;
  266.         ping[hval] = pp;
  267.         return pp;
  268. }
  269.  
  270. /* Delete entry from ping table */
  271. static void del_ping(struct ping *pp)
  272. {
  273.         int16 hval;
  274.  
  275.         stop_timer(&pp->timer);
  276.  
  277.         if(pp->next != NULLPING)
  278.                 pp->next->prev = pp->prev;
  279.         if(pp->prev != NULLPING) {
  280.                 pp->prev->next = pp->next;
  281.         } else {
  282.                 hval = hash_ping(pp->remote);
  283.                 ping[hval] = pp->next;
  284.         }
  285.         if(pp->user != NULL)
  286.                 detachsession(pp->user);
  287.         free((char *)pp);
  288. }
  289.  
  290.