forked from AllenDowney/ExercisesInC
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of https://github.com/maalvikabhat/ExercisesInC
- Loading branch information
Showing
9 changed files
with
784 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
downey@rocky.colby.edu.25374:1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
TROUT is a simple version of traceroute. | ||
|
||
It is based on code written by W. Richard Stevens and published in | ||
"UNIX Network Programming Volume 1, Second Edition Networking APIs: | ||
Sockets and XTI," Prentice Hall PTR, Upper Saddle River, NJ 07458. | ||
|
||
It has been modified a fair amount by Allen Downey | ||
([email protected]). Among other things, I did the following | ||
|
||
1) I collected all the procedures from Stevens's extensive library | ||
and put them in util.c, and put their prototypes in trout.h | ||
|
||
2) I killed all the IPv6 support, because I didn't need it and | ||
because I hate ifdefs and pointers to functions. | ||
|
||
3) For the same reason, I took out some of the configuration | ||
ifdefs. As a result, I don't know if this will still run | ||
on anything other than Linux. | ||
|
||
4) I fixed a race condition that may or may not have been the | ||
cause of some early problems I had. Anyway, the fix also | ||
came from Stevens, in Section 18.5 of Unix Network Programming. | ||
|
||
5) I split things up into more procedures. | ||
|
||
The copyright for the original code is held by Prentice Hall, | ||
but they make it available under a license that is more or | ||
less identical to the GNU GPL. | ||
|
||
This version is Copyright (C) 1999 Allen B. Downey. | ||
|
||
I am making it available under the GNU General Public License | ||
(which does not, I think, violate the original copyright). | ||
|
||
This program is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU General Public License | ||
as published by the Free Software Foundation; either version 2 | ||
of the License, or (at your option) any later version. | ||
|
||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
|
||
You should have received a copy of the GNU General Public License | ||
along with this program; if not, write to the Free Software | ||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
trout: trout.h trout.c util.h util.c main.c | ||
gcc -Wall -g -o trout trout.c main.c util.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#include "trout.h" | ||
|
||
int main (int argc, char **argv) | ||
{ | ||
int c; | ||
struct addrinfo *ai; | ||
char *host; | ||
|
||
opterr = 0; | ||
while ( (c = getopt (argc, argv, "m:")) != -1) { | ||
switch (c) { | ||
case 'm': | ||
if ( (max_ttl = atoi(optarg)) <= 1) { | ||
err_quit ("invalid -m value"); | ||
} | ||
break; | ||
default: | ||
err_quit ("unrecognizd option: %c", c); | ||
} | ||
} | ||
|
||
if (optind != argc - 1) { | ||
err_quit ("usage: trout [ -m <maxttl>] <hostname>"); | ||
} | ||
host = argv[optind]; | ||
ai = Host_serv (host, NULL, 0, 0); | ||
|
||
printf ("trout to %s (%s): %d hops max, %d data bytes\n", | ||
ai->ai_canonname, | ||
Sock_ntop_host (ai->ai_addr, ai->ai_addrlen), | ||
max_ttl, datalen); | ||
|
||
if (ai->ai_family != AF_INET) { | ||
err_quit ("unknown address family %d", ai->ai_family); | ||
} | ||
|
||
sasend = ai->ai_addr; | ||
salen = ai->ai_addrlen; | ||
sarecv = Calloc (1, salen); | ||
salast = Calloc (1, salen); | ||
sabind = Calloc (1, salen); | ||
|
||
loop_ttl (); | ||
exit (0); | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
#include "trout.h" | ||
|
||
/* variables we might want to configure */ | ||
Rec *rec = (Rec *) sendbuf; | ||
|
||
void sig_alrm (int signo) | ||
{ | ||
Write (pipefd[1], "", 1); /* write 1 null byte to pipe */ | ||
return; | ||
} | ||
|
||
int process_ip (struct ip *ip, int len) | ||
{ | ||
int hlen1, hlen2, icmplen; | ||
struct icmp *icmp; | ||
struct ip *hip; | ||
struct udphdr *udp; | ||
seq = 0; | ||
u_short dport = 32768 + 668; /* destination port -- hopefully unused */ | ||
|
||
hlen1 = ip->ip_hl << 2; /* length of IP header */ | ||
icmp = (struct icmp *) (recvbuf + hlen1); | ||
icmplen = len - hlen1; | ||
|
||
if (icmplen < 8 + 20 + 8) return 0; | ||
|
||
if (icmp->icmp_type != ICMP_TIME_EXCEEDED && | ||
icmp->icmp_type != ICMP_DEST_UNREACH) | ||
return 0; | ||
|
||
/* hip is the header of the enclosed IP packets, supposedly | ||
the header of the packet that caused the error */ | ||
|
||
hip = (struct ip *) (recvbuf + hlen1 + 8); | ||
if (hip->ip_p != IPPROTO_UDP) return 0; | ||
|
||
hlen2 = hip->ip_hl << 2; | ||
udp = (struct udphdr *) (recvbuf + hlen1 + 8 + hlen2); | ||
|
||
if (udp->source != htons (sport)) return 0; | ||
if (udp->dest != htons (dport + seq)) return 0; | ||
|
||
if (icmp->icmp_type == ICMP_TIME_EXCEEDED) { | ||
if (icmp->icmp_code == ICMP_EXC_TTL) { | ||
return -2; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
if (icmp->icmp_type == ICMP_DEST_UNREACH) { | ||
if (icmp->icmp_code == ICMP_PORT_UNREACH) { | ||
return -1; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
|
||
|
||
int recv_dgram () | ||
{ | ||
int err; | ||
socklen_t len; | ||
ssize_t n; | ||
struct ip *ip; | ||
int maxfdp1 = max (recvfd, pipefd[0]) + 1; | ||
fd_set rset[1]; | ||
FD_ZERO (rset); | ||
|
||
alarm(3); /* set the timeout alarm to handle dropped packets */ | ||
|
||
while (1) { | ||
FD_SET (recvfd, rset); | ||
FD_SET (pipefd[0], rset); | ||
|
||
n = select (maxfdp1, rset, NULL, NULL, NULL); | ||
if (n < 0 && errno != EINTR) { | ||
err_sys ("select error"); | ||
} | ||
|
||
if (FD_ISSET (recvfd, rset)) { | ||
len = salen; | ||
n = recvfrom (recvfd, recvbuf, sizeof(recvbuf), 0, sarecv, &len); | ||
err = errno; | ||
Gettimeofday (recvtv, NULL); /* get time of packet arrival */ | ||
if (n < 0 && err != EAGAIN) { | ||
err_sys ("recvfrom error"); | ||
} | ||
} | ||
|
||
if (FD_ISSET (pipefd[0], rset)) { | ||
Read (pipefd[0], &n, 1); | ||
return -3; /* timeout */ | ||
} | ||
|
||
ip = (struct ip *) recvbuf; | ||
return process_ip (ip, n); | ||
} | ||
} | ||
|
||
/* sub_tv: subtract minus from plus and put the result in res */ | ||
|
||
void sub_tv (Timeval *plus, Timeval *minus, Timeval *res) | ||
{ | ||
res->tv_sec = plus->tv_sec - minus->tv_sec; | ||
res->tv_usec = plus->tv_usec - minus->tv_usec; | ||
|
||
if (res->tv_usec < 0) { | ||
res->tv_sec--; | ||
res->tv_usec += 1000000; | ||
} | ||
} | ||
|
||
/* time_to_double: convert a Timeval to a double. This only | ||
works with Timevals that are small (like the difference between | ||
two real Timevals) */ | ||
|
||
double time_to_double (Timeval *time) | ||
{ | ||
return time->tv_sec * 1000.0 + time->tv_usec / 1000.0; | ||
} | ||
|
||
/* print_report: prints all the information about a successful round trip */ | ||
|
||
void print_report () | ||
{ | ||
int stat; | ||
char str[NI_MAXHOST]; | ||
|
||
stat = sock_cmp_addr (sarecv, salast, salen); | ||
|
||
/* if this reply comes from source different from the previous | ||
one, print the full host information */ | ||
|
||
if (stat != 0) { | ||
stat = getnameinfo (sarecv, salen, str, sizeof(str), NULL, 0, 0); | ||
if (stat == 0) { | ||
printf (" %s (%s)", str, Sock_ntop_host (sarecv, salen)); | ||
} else { | ||
printf (" %s", Sock_ntop_host (sarecv, salen)); | ||
} | ||
memcpy (salast, sarecv, salen); | ||
} | ||
|
||
/* calculate and print the round trip time using user-level timestamps */ | ||
|
||
sub_tv (recvtv, sendtv, difftv); | ||
|
||
printf (" %.3f", time_to_double (difftv)); | ||
} | ||
|
||
/* send_dgram: generate an outgoing UDP packet */ | ||
|
||
/* the second effort send is a kludge to handle a funny | ||
thing, which is that the last host seems to refuse the | ||
second or third connection consistently, which might | ||
might mean that something breaks when we get the | ||
ICMP_DEST_UNREACH error. The second attempt seems | ||
to succeed consistently. */ | ||
|
||
void send_dgram (int ttl) | ||
{ | ||
int n; | ||
datalen = sizeof (Rec); /* length of the data in a datagram */ | ||
seq = 0; | ||
u_short dport = 32768 + 668; /* destination port -- hopefully unused */ | ||
|
||
rec->seq = seq++; | ||
sock_set_port (sasend, salen, htons(dport+seq)); | ||
|
||
Gettimeofday (sendtv, NULL); | ||
n = sendto(sendfd, sendbuf, datalen, 0, sasend, salen); | ||
|
||
if (n==-1 && errno == ECONNREFUSED) { | ||
Gettimeofday (sendtv, NULL); | ||
n = sendto(sendfd, sendbuf, datalen, 0, sasend, salen); | ||
} | ||
|
||
if (n != datalen) { | ||
err_sys("sendto error"); | ||
} | ||
} | ||
|
||
/* send_probes: sends a set of probes with the given ttl and | ||
then waits for the replies. The weird TOS options are there | ||
as a signal to the kernel to identify clink packets so it can | ||
fill in the timestamps. I am assuming that they don't have | ||
any actual effect. */ | ||
|
||
int send_probes (int ttl) | ||
{ | ||
int probe, code, done; | ||
|
||
Setsockopt (sendfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int)); | ||
bzero (salast, salen); | ||
int nprobes = 2; | ||
|
||
printf ("%2d ", ttl); | ||
fflush (stdout); | ||
|
||
done = 0; /* count the number of probes that generate an ICMP_DEST_UNREACH */ | ||
|
||
for (probe = 0; probe < nprobes; probe++) { | ||
send_dgram (ttl); | ||
code = recv_dgram (); | ||
|
||
if (code == -3) { | ||
printf (" *"); | ||
} else { | ||
print_report (); | ||
} | ||
|
||
if (code == -1) done++; | ||
fflush (stdout); | ||
} | ||
printf ("ms\n"); | ||
return done; | ||
} | ||
|
||
/* loop_ttl: starting with ttl=1, gradually increase ttl until | ||
we start getting ICMP_DEST_UNREACH instead of ICMP_TIME_EXCEEDED */ | ||
|
||
void loop_ttl () | ||
{ | ||
int ttl, done; | ||
|
||
Pipe (pipefd); /* the pipe for the alarm handler */ | ||
max_ttl = 30; | ||
|
||
|
||
recvfd = socket (sasend->sa_family, SOCK_RAW, IPPROTO_ICMP); | ||
if (recvfd == -1) { | ||
if (errno == EPERM) { | ||
printf ("\nclink was unable to open a raw socket. The most\n"); | ||
printf ("likely cause is that you are not running it as root.\n"); | ||
exit (1); | ||
} else { | ||
err_sys ("opening raw socket in clink"); | ||
} | ||
} | ||
|
||
fcntl (recvfd, F_SETFL, O_NONBLOCK); | ||
setuid (getuid ()); | ||
|
||
sendfd = socket (sasend->sa_family, SOCK_DGRAM, 0); | ||
|
||
sabind->sa_family = sasend->sa_family; | ||
sport = (getpid() & 0xffff) | 0x8000; /* source UDP port # */ | ||
sock_set_port (sabind, salen, htons(sport)); | ||
Bind (sendfd, sabind, salen); | ||
|
||
Signal (SIGALRM, sig_alrm); | ||
|
||
for (ttl = 1; ttl <= max_ttl; ttl++) { | ||
done = send_probes (ttl); | ||
if (done > 0) break; | ||
} | ||
} |
Oops, something went wrong.