crp@ccivax.UUCP (Chuck Privitera) (11/13/84)
Index: src/ucb/talk/get_addrs.c 4.2BSD/(2.9BSD?) Description: This is actually a follow up to article <1311@dalcs.UUCP>. The subject was "TCP/IP Communications Problem" and was posted to net.unix-wizards. I wanted to change the subject (to be more informative) and post this reply to a more appropriate news group. Anyways, here goes. When using the software loopback network interface as your primary network, talk can't communicate with foreign hosts. Repeat-by: Make the loopback interface your primary network, then try to talk to a user on another machine. (via ethernet, harvard's itt interface, rick adam's serial line interface, or whatever). Talk will (appear to) hang with the message: "Checking for invitation on caller's machine." Fix: Talk isn't really hung. It is actually waiting for a response from the foreign host. Well, the foreign host will never be able to respond. The problem is that talk sends a "control" packet to the remote talk daemon which contains (among other things) the address of the remote talk's socket (who is on the loopback network). So, the foreign host receives the control packets correctly, but when it tries to respond (by writing to the address supplied in the packet it just received), the response gets swallowed by the loopback driver on the foreign host!! What I did to fix it was to have talk find out the name of the network it will be using, and if the user being "talked to" is on another machine, make sure the network name doesn't start with "loop". Sort of kludgy I know, but the loopback interface is the only one that doesn't allow inter-machine communication, and 4.2 is distributed with "loopback-net" in /etc/networks, so .... To fix talk, apply the changes in this context diff to get_addrs.c, and add the local host name to the alias list for the network you really want talk to use. rcsdiff -c3 -r1.1 get_addrs.c RCS file: RCS/get_addrs.c,v retrieving revision 1.1 diff -c3 -r1.1 get_addrs.c *** /tmp/,RCSt1008987 Tue Nov 13 15:28:38 1984 --- get_addrs.c Tue Nov 13 15:23:06 1984 *************** *** 1,4 ! /* $Header: get_addrs.c,v 1.1 84/04/06 15:16:21 root Rel $ */ #include "talk_ctl.h" --- 1,4 ----- ! /* $Header: get_addrs.c,v 1.3 84/11/13 15:22:12 root Exp $ */ #include "talk_ctl.h" *************** *** 9,15 char *my_machine_name; char *his_machine_name; { ! struct hostent *hp; struct servent *sp; msg.pid = getpid(); --- 9,15 ----- char *my_machine_name; char *his_machine_name; { ! struct hostent *hp, *p; struct servent *sp; struct netent *np; char **cp; *************** *** 11,16 { struct hostent *hp; struct servent *sp; msg.pid = getpid(); --- 11,18 ----- { struct hostent *hp, *p; struct servent *sp; + struct netent *np; + char **cp; msg.pid = getpid(); *************** *** 16,23 /* look up the address of the local host */ ! hp = gethostbyname(my_machine_name); ! if (hp == (struct hostent *) 0) { printf("This machine doesn't exist. Boy, am I confused!\n"); exit(-1); --- 18,39 ----- /* look up the address of the local host */ ! sethostent(1); /* Don't rewind hosts file */ ! again: ! while(p = gethostent()) { ! if (strcmp(p->h_name, my_machine_name) == 0) ! break; ! for(cp = p->h_aliases; *cp != 0; cp++) ! if (strcmp(*cp, my_machine_name) == 0) ! goto found; ! } ! found: ! if (hp && !p) { ! printf("No suitable network for %s to talk to %s on.\n", ! my_machine_name, his_machine_name); ! exit(-1); ! } ! hp = p; if (hp == (struct hostent *) 0) { printf("This machine doesn't exist. Boy, am I confused!\n"); exit(-1); *************** *** 29,34 } bcopy(hp->h_addr, (char *)&my_machine_addr, hp->h_length); /* if he is on the same machine, then simply copy */ --- 45,51 ----- } bcopy(hp->h_addr, (char *)&my_machine_addr, hp->h_length); + np = getnetbyaddr(inet_netof(my_machine_addr), AF_INET); /* if he is on the same machine, then simply copy */ *************** *** 37,42 bcopy((char *)&my_machine_addr, (char *)&his_machine_addr, sizeof(his_machine_name)); } else { /* look up the address of the recipient's machine */ --- 54,69 ----- bcopy((char *)&my_machine_addr, (char *)&his_machine_addr, sizeof(his_machine_name)); } else { + + /* + * Don't try to talk to a remote machine on + * the loopback network. + */ + + #define min(a, b) (a < b ? a : b) + + if (np && !bcmp(np->n_name, "loop", min(strlen(np->name), 4))) + goto again; /* look up the address of the recipient's machine */
ron@uthub.UUCP (Ron Wessels) (11/18/84)
>> From: crp@ccivax.UUCP (Chuck Privitera) >> Subject: Problem with 4.2BSD talk >> Message-ID: <220@ccivax.UUCP> >> Posted: Tue Nov 13 15:33:05 1984 >> >> . . . >> When using the software loopback network interface as your primary >> network, talk can't communicate with foreign hosts. >> . . . >> Talk isn't really hung. It is actually waiting for a response from >> the foreign host. Well, the foreign host will never be able to >> respond. The problem is that talk sends a "control" packet to the >> remote talk daemon which contains (among other things) the address >> of the remote talk's socket (who is on the loopback network). So, >> the foreign host receives the control packets correctly, but when >> it tries to respond (by writing to the address supplied in the >> packet it just received), the response gets swallowed by the >> loopback driver on the foreign host!! The analysis of this problem provided by Chuck is right on the money. The fix, however, isn't all that great. Firstly, let me explain that, by your "primary network", we mean the network referenced in the (textually) first line in /etc/hosts that contains `hostname`. If you have any network that is capable of talking to itself [ie. you make that network your primary network and "rlogin `hostname`" works], then you should not have the looopback network as your primary network. Talk(1) is just one example of the general philosophy that a user program should be able to determine a valid network address for its machine using a "gethostbyname (gethostname ())" construct [ignore incorrect syntax]. Your primary network should be one of these real networks [if you have more than one]. The choice of which one is a separate issue ... any one will work, assuming your routes are set up correctly [see route(8) and routed(8)]. Assuming you just have point-to-point network(s) connected to your machine [or some other network that can't talk to itself], you can still make one of these your primary network, but you have to adjust the network routes somewhat. If you are not running the /etc/routed routing daemon [which I highly recommend you don't run ... it's a useless CPU pig that we couldn't get working with point- to-point networks], then simply add the line /etc/route add `hostname` localhost into your /etc/rc.local file. If you are running /etc/routed [and I can't persuade you to trash it and go to manual "/etc/route add" lines in /etc/rc.local ... how often does your network topology change anyway?], then creating an /etc/gateways file with the line host `hostname` gateway localhost metric 0 passive should work. Of course, you should expand `hostname` to your real host name. This has the effect of routing all traffic destined for the local host [`hostname`] to go through the loopback interface. For those of you who braved through all that junk, the net result [pun unintended] is that talk(1) will now send a valid network address to the remote host. Thus, everyone is happy. And you don't need that "oops, it's the loopback net ... let's look for another entry" stuff in /etc/talkd. -- Ron Wessels Computer Systems Research Institute University of Toronto { decvax , floyd , ihnp4 , linus , utzoo , uw-beaver }!utcsrgv!uthub!ron