home *** CD-ROM | disk | FTP | other *** search
- /* socket.c - socket functions */
-
- /* NOTICE
- *
- * Copyright (c) 1990,1992,1993 Britt Yenne. All rights reserved.
- *
- * This software is provided AS-IS. The author gives no warranty,
- * real or assumed, and takes no responsibility whatsoever for any
- * use or misuse of this software, or any damage created by its use
- * or misuse.
- *
- * This software may be freely copied and distributed provided that
- * no part of this NOTICE is deleted or edited in any manner.
- *
- */
-
- /* Mail comments or questions to ytalk@austin.eds.com */
-
- #include "header.h"
- #include "menu.h"
- #include "socket.h"
- #include <sys/time.h>
- #ifdef _AIX
- # include <sys/select.h>
- #endif
-
- struct _talkd talkd[MAXDAEMON+1];
- int daemons = 0;
-
- static int otalk, ntalk; /* daemon numbers */
- static CTL_MSG omsg; /* old talk message */
- static CTL_RESPONSE orsp; /* old talk response */
- static CTL_MSG42 nmsg; /* new talk message */
- static CTL_RESPONSE42 nrsp; /* new talk response */
-
- static int autofd = -1; /* auto invite socket fd */
- static struct sockaddr_in autosock; /* auto invite socket */
- static long autoid[MAXDAEMON+1]; /* auto invite seq numbers */
- static u_long announce_id = 0; /* announce sequence id */
- static readdr *readdr_list = NULL; /* list of re-addresses */
-
- #define IN_ADDR(s) ((s).sin_addr.s_addr)
- #define IN_PORT(s) ((s).sin_port)
- #define SOCK_EQUAL(s,c) (IN_PORT(s) == IN_PORT(c) && IN_ADDR(s) == IN_ADDR(c))
-
- /* ---- local functions ---- */
-
- /* Create a datagram socket.
- */
- static int
- init_dgram(sock)
- struct sockaddr_in *sock;
- {
- int fd, socklen;
-
- sock->sin_family = AF_INET;
- IN_ADDR(*sock) = INADDR_ANY;
- IN_PORT(*sock) = 0;
- if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- show_error("init_dgram: socket() failed");
- bail(YTE_ERROR);
- }
- if(bind(fd, (struct sockaddr *)sock, sizeof(struct sockaddr_in)) != 0)
- {
- close(fd);
- show_error("init_dgram: bind() failed");
- bail(YTE_ERROR);
- }
- socklen = sizeof(struct sockaddr_in);
- if(getsockname(fd, (struct sockaddr *)sock, &socklen) < 0)
- {
- close(fd);
- show_error("init_dgram: getsockname() failed");
- bail(YTE_ERROR);
- }
- IN_ADDR(*sock) = me->host_addr;
- return fd;
- }
-
- /* Initialize a new daemon structure.
- */
- static int
- init_daemon(name, port, mptr, mlen, rptr, rlen)
- char *name;
- short port;
- yaddr mptr, rptr;
- int mlen, rlen;
- {
- struct servent *serv;
- int d;
-
- if(daemons >= MAXDAEMON)
- {
- show_error("init_daemon: too many daemons");
- bail(YTE_ERROR);
- }
- d = ++daemons; /* daemon number zero is not defined */
-
- if((serv = getservbyname(name, "udp")) != NULL)
- talkd[d].port = serv->s_port;
- else
- talkd[d].port = port;
-
- talkd[d].fd = init_dgram(&(talkd[d].sock));
- talkd[d].mptr = mptr;
- talkd[d].mlen = mlen;
- talkd[d].rptr = rptr;
- talkd[d].rlen = rlen;
- return d;
- }
-
- static void
- read_autoport(fd)
- int fd;
- {
- int socklen;
- static v2_pack pack;
- static char estr[V2_NAMELEN + V2_HOSTLEN + 20];
- static struct sockaddr_in temp;
-
- /* accept the connection */
-
- socklen = sizeof(struct sockaddr_in);
- if((fd = accept(autofd, (struct sockaddr *) &temp, &socklen)) == -1)
- {
- show_error("read_autoport: accept() failed");
- return;
- }
-
- /* The autoport socket just uses the old Ytalk version 2.?
- * packet.
- */
- errno = 0;
- if(full_read(fd, &pack, V2_PACKLEN) < 0 || pack.code != V2_AUTO)
- {
- show_error("read_autoport: unknown auto-invite connection");
- close(fd);
- return;
- }
- close(fd);
- if(!(def_flags & FL_INVITE))
- {
- sprintf(estr, "Talk to %s@%s?", pack.name, pack.host);
- if(yes_no(estr) == 'n')
- return;
- }
- sprintf(estr, "%s@%s", pack.name, pack.host);
- invite(estr, 1); /* we should be expected */
- }
-
- /* Create and initialize the auto-invitation socket.
- */
- static void
- init_autoport()
- {
- int socklen;
-
- autosock.sin_family = AF_INET;
- IN_ADDR(autosock) = INADDR_ANY;
- IN_PORT(autosock) = 0;
- if((autofd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- show_error("init_autoport: socket() failed");
- return;
- }
- if(bind(autofd, (struct sockaddr *)&autosock,
- sizeof(struct sockaddr_in)) < 0)
- {
- close(autofd);
- autofd = -1;
- show_error("init_autoport: bind() failed");
- return;
- }
- socklen = sizeof(struct sockaddr_in);
- if(getsockname(autofd, (struct sockaddr *)&autosock, &socklen) < 0)
- {
- close(autofd);
- autofd = -1;
- show_error("init_autoport: getsockname() failed");
- return;
- }
- IN_ADDR(autosock) = me->host_addr;
- if(listen(autofd, 5) < 0)
- {
- close(autofd);
- autofd = -1;
- show_error("init_autoport: listen() failed");
- return;
- }
- (void)memset(autoid, 0, (MAXDAEMON + 1) * sizeof(long));
- add_fd(autofd, read_autoport);
- }
-
- /* Fill the socket address field with the appropriate return address for
- * the host I'm sending to.
- */
- static void
- place_my_address(sock, addr)
- struct sockaddr_in *sock;
- register u_long addr;
- {
- register readdr *r;
-
- for(r = readdr_list; r != NULL; r = r->next)
- if((addr & r->mask) == r->addr)
- {
- addr = (r->id_addr & r->id_mask) |
- (me->host_addr & (~(r->id_mask)));
- IN_ADDR(*sock) = addr;
- break;
- }
- if(r == NULL)
- IN_ADDR(*sock) = me->host_addr;
- sock->sin_family = htons(AF_INET);
- }
-
- /* sendit() sends the completed message to the talk daemon at the given
- * hostname, then reads a response packet.
- */
- static int
- sendit(addr, d)
- u_long addr; /* host internet address */
- int d; /* daemon number */
- {
- int n;
- struct sockaddr_in daemon;
- struct timeval tv;
- char *rtype, *mtype;
- fd_set sel;
-
- /* set up the appropriate message structure */
-
- if(d == ntalk)
- {
- nmsg.vers = TALK_VERSION;
- place_my_address(&(nmsg.ctl_addr), addr);
- mtype = &(nmsg.type);
- rtype = &(nrsp.type);
- }
- else if(d == otalk)
- {
- omsg.type = nmsg.type;
- omsg.addr = nmsg.addr;
- omsg.id_num = nmsg.id_num;
- omsg.pid = nmsg.pid;
- strncpy(omsg.l_name, nmsg.l_name, NAME_SIZE);
- strncpy(omsg.r_name, nmsg.r_name, NAME_SIZE);
- strncpy(omsg.r_tty, nmsg.r_tty, TTY_SIZE);
- place_my_address(&(omsg.ctl_addr), addr);
- mtype = &(omsg.type);
- rtype = &(orsp.type);
- }
- else
- {
- sprintf(errstr, "Unkown daemon type: %d", d);
- show_error(errstr);
- return -1;
- }
-
- /* set up a sockaddr_in for the daemon we're sending to */
-
- daemon.sin_family = AF_INET;
- IN_ADDR(daemon) = addr;
- IN_PORT(daemon) = talkd[d].port;
-
- /* flush any lingering input */
-
- FD_ZERO(&sel);
- for(;;)
- {
- tv.tv_sec = 0L;
- tv.tv_usec = 0L;
- FD_SET(talkd[d].fd, &sel);
- if((n = select(talkd[d].fd + 1, &sel, 0, 0, &tv)) < 0)
- {
- show_error("sendit: flush select() failed");
- return -1;
- }
- if(n <= 0)
- break;
- if(recv(talkd[d].fd, talkd[d].rptr, talkd[d].rlen, 0) < 0)
- {
- show_error("sendit: flush recv() failed");
- return -1;
- }
- }
-
- /* Now we need to send the actual packet. Due to unreliability of
- * DGRAM sockets, we must resend the packet until we get a response
- * from the server. Geez... two different daemons, both on unreliable
- * sockets, and maybe even different daemons on different machines.
- * Is *nothing* reliable anymore???
- */
- do
- {
- do
- {
- n = sendto(talkd[d].fd, talkd[d].mptr, talkd[d].mlen,
- 0, (struct sockaddr *) &daemon, sizeof(daemon));
- if(n != talkd[d].mlen)
- {
- show_error("sendit: sendto() failed");
- return -1;
- }
-
- tv.tv_sec = 5L;
- tv.tv_usec = 0L;
- FD_SET(talkd[d].fd, &sel);
- if((n = select(talkd[d].fd + 1, &sel, 0, 0, &tv)) < 0)
- {
- show_error("sendit: first select() failed");
- return -1;
- }
- } while (n <= 0); /* ie: until we receive a reply */
-
- do
- {
- n = recv(talkd[d].fd, talkd[d].rptr, talkd[d].rlen, 0);
- if(n < 0)
- {
- show_error("sendit: recv() failed");
- return -1;
- }
-
- if(*rtype != *mtype)
- tv.tv_sec = 5L;
- else
- tv.tv_sec = 0L;
- tv.tv_usec = 0L;
- FD_SET(talkd[d].fd, &sel);
- if((n = select(talkd[d].fd + 1, &sel, 0, 0, &tv)) < 0)
- {
- show_error("sendit: second select() failed");
- return -1;
- }
- } while(n > 0 && *rtype != *mtype);
- } while(*rtype != *mtype);
-
- /* WHEW */
-
- /* Just because a person is a SYSADMIN doesn't necessarily mean he/she
- * knows everything about installing software. In fact, many have been
- * known to install the talk daemon without setting the option required
- * to pad out the structures so that "long"s are on four-byte boundaries
- * on machines where "long"s can be on two-byte boundaries. This "bug"
- * cost me about four hours of debugging to discover, so I'm not happy
- * right now. Anyway, here's a quick hack to fix this problem.
- */
- if(d == otalk && nrsp.type == LOOK_UP && nrsp.answer == 0)
- {
- u_short t;
- (void)memcpy((char *)&t, ((char *)&orsp.addr.sin_family)-2, sizeof(t));
- if(ntohs(t) == AF_INET && ntohs(orsp.addr.sin_family) != AF_INET)
- {
- char *c;
- c = ((char *)&orsp) + sizeof(orsp) - 1;
- for(; c >= (char *)&orsp.id_num; c--)
- *c = *(c-2);
- }
- }
-
- /* Fill in the new talk response structure if we just read an
- * old one.
- */
- if(d == otalk)
- {
- nrsp.type = orsp.type;
- nrsp.answer = orsp.answer;
- nrsp.id_num = orsp.id_num;
- nrsp.addr = orsp.addr;
- }
-
- return 0;
- }
-
- /* find_daemon() locates the talk daemon(s) on a machine and determines
- * what version(s) of the daemon are running.
- */
- static int
- find_daemon(addr)
- u_long addr;
- {
- register hostinfo *h;
- register int n, i, d;
- CTL_MSG m1;
- CTL_MSG42 m2;
- struct sockaddr_in daemon;
- struct timeval tv;
- int sel, out;
- static hostinfo *host_head = NULL;
-
- /* If we've already used this host, look it up instead of blitting to
- * the daemons again...
- */
- for(h = host_head; h; h = h->next)
- if(h->host_addr == addr)
- return h->dtype;
-
- daemon.sin_family = AF_INET;
- IN_ADDR(daemon) = addr;
-
- m1 = omsg;
- m2 = nmsg;
- m1.ctl_addr = talkd[otalk].sock;
- place_my_address(&(m1.ctl_addr), addr);
- m2.ctl_addr = talkd[ntalk].sock;
- place_my_address(&(m2.ctl_addr), addr);
- m1.type = m2.type = LOOK_UP;
- m1.id_num = m2.id_num = htonl(0);
- m1.r_tty[0] = m2.r_tty[0] = '\0';
- strcpy(m1.r_name, "ytalk");
- strcpy(m2.r_name, "ytalk");
- m1.addr.sin_family = m2.addr.sin_family = htons(AF_INET);
-
- out = 0;
- for(i = 0; i < 5; i++)
- {
- IN_PORT(daemon) = talkd[ntalk].port;
- n = sendto(talkd[ntalk].fd, &m2, sizeof(m2),
- 0, (struct sockaddr *) &daemon, sizeof(daemon));
- if(n != sizeof(m2))
- show_error("Warning: cannot write to new talk daemon");
-
- IN_PORT(daemon) = talkd[otalk].port;
- n = sendto(talkd[otalk].fd, &m1, sizeof(m1),
- 0, (struct sockaddr *) &daemon, sizeof(daemon));
- if(n != sizeof(m1))
- show_error("Warning: cannot write to old talk daemon");
-
- tv.tv_sec = 4L;
- tv.tv_usec = 0L;
- sel = (1 << talkd[ntalk].fd) | (1 << talkd[otalk].fd);
- if((n = select(32, &sel, 0, 0, &tv)) < 0)
- {
- show_error("find_daemon: first select() failed");
- continue;
- }
- if(n == 0)
- continue;
-
- do
- {
- for(d = 1; d <= daemons; d++)
- if(sel & (1 << talkd[d].fd))
- {
- out |= (1 << d);
- if(recv(talkd[d].fd, errstr, talkd[d].rlen, 0) < 0)
- show_error("find_daemon: recv() failed");
- }
-
- tv.tv_sec = 0L;
- tv.tv_usec = 500000L; /* give the other daemon a chance */
- sel = (1 << talkd[ntalk].fd) | (1 << talkd[otalk].fd);
- if((n = select(32, &sel, 0, 0, &tv)) < 0)
- show_error("find_daemon: second select() failed");
- } while(n > 0);
-
- h = (hostinfo *)get_mem(sizeof(hostinfo));
- h->next = host_head;
- host_head = h;
- h->host_addr = addr;
- h->dtype = out;
- return out;
- }
- sprintf(errstr, "No talk daemon on %s", host_name(addr));
- show_error(errstr);
- return 0;
- }
-
- static u_long
- make_net_mask(addr)
- u_long addr;
- {
- if(addr & (u_long)0xff)
- return (u_long)0xffffffff;
- if(addr & (u_long)0xffff)
- return (u_long)0xffffff00;
- if(addr & (u_long)0xffffff)
- return (u_long)0xffff0000;
- if(addr)
- return (u_long)0xff000000;
- return (u_long)0;
- }
-
- /* ---- global functions ---- */
-
- /* Initialize sockets and message parameters.
- */
- void
- init_socket()
- {
- /* init daemons in order of preference */
-
- ntalk = init_daemon("ntalk", 518, &nmsg, sizeof(nmsg),
- &nrsp, sizeof(nrsp));
- otalk = init_daemon("talk", 517, &omsg, sizeof(omsg),
- &orsp, sizeof(orsp));
-
- strncpy(nmsg.l_name, me->user_name, NAME_SIZE);
-
- omsg.ctl_addr = talkd[otalk].sock;
- nmsg.ctl_addr = talkd[ntalk].sock;
- nmsg.vers = TALK_VERSION;
-
- (void)find_daemon(me->host_addr);
- init_autoport();
- }
-
- /* Close every open descriptor. This should only be used for a quick
- * exit... it does not gracefully shut systems down.
- */
- void
- close_all()
- {
- register yuser *u;
- register int d;
-
- for(u = user_list; u; u = u->unext)
- {
- if(u->fd > 0)
- close(u->fd);
- if(u->output_fd > 0)
- close(u->output_fd);
- }
- if(autofd > 0)
- close(autofd);
- for(d = 1; d <= daemons; d++)
- close(talkd[d].fd);
- }
-
- /* The following routines send a request across the DGRAM socket to the
- * talk daemons.
- */
-
- /* First, a quick and easy interface for the user sockets.
- */
- int
- send_dgram(user, type)
- yuser *user;
- u_char type;
- {
- u_long addr;
- int d;
-
- /* set up the message type and where to send it */
-
- switch(type)
- {
- case LEAVE_INVITE: /* leave an invite on my machine */
- addr = me->host_addr;
- nmsg.type = LEAVE_INVITE;
- nmsg.id_num = htonl(user->l_id);
- break;
- case DELETE_INVITE: /* delete my invite on my machine */
- addr = me->host_addr;
- nmsg.type = DELETE;
- nmsg.id_num = htonl(user->l_id);
- break;
- case ANNOUNCE: /* ring a user */
- addr = user->host_addr;
- nmsg.type = ANNOUNCE;
- announce_id += 5; /* no guesswork here */
- nmsg.id_num = htonl(announce_id);
- break;
- case LOOK_UP: /* look up remote invitation */
- addr = user->host_addr;
- nmsg.type = LOOK_UP;
- nmsg.id_num = htonl(user->r_id);
- break;
- case DELETE: /* delete erroneous remote invitation */
- addr = user->host_addr;
- nmsg.type = DELETE;
- nmsg.id_num = htonl(user->r_id);
- break;
- case AUTO_LOOK_UP: /* look up remote auto-invitation */
- addr = user->host_addr;
- nmsg.type = LOOK_UP;
- nmsg.id_num = htonl(user->r_id);
- break;
- case AUTO_DELETE: /* delete erroneous remote auto-invitation */
- addr = user->host_addr;
- nmsg.type = DELETE;
- nmsg.id_num = htonl(user->r_id);
- break;
- default:
- errno = 0;
- show_error("send_dgram: unknown type");
- return -1;
- }
-
- /* find a common daemon, if possible */
-
- if(user->daemon != 0)
- d = user->daemon;
- else
- {
- int dtype, d1, d2;
-
- /* Find the daemon(s) their host supports. If our two machines
- * support a daemon in common, use that one. Else, normal UNIX
- * "talk" is already screwed to the wall, but YTalk will at least
- * work.
- */
- d1 = find_daemon(user->host_addr);
- d2 = find_daemon(me->host_addr);
- dtype = d1 & d2;
-
- if(d1 == 0 || d2 == 0)
- return -1;
- if(dtype == 0)
- {
- dtype = find_daemon(addr);
- for(d = 1; d <= daemons; d++)
- if(dtype & (1<<d))
- break;
- if(d > daemons)
- return -1;
- }
- else
- {
- for(d = 1; d <= daemons; d++)
- if(dtype & (1<<d))
- {
- user->daemon = d;
- break;
- }
- if(d > daemons)
- return -1;
- }
- }
-
- /* Each user has his own unique daemon id. Why? Tsch. Why.
- * Well, the talk daemons consider two users equivalent if their
- * usernames and machine names match. Hence, the daemons will not
- * allow ytalk to talk with two different users with the same name
- * on some machine. By assigning unique process id's, we trick
- * the daemons into thinking we're several different users trying
- * to talk to the same person. Sick? Don't blame me.
- */
- nmsg.pid = htonl(user->d_id);
- if(type == AUTO_LOOK_UP || type == AUTO_DELETE)
- {
- strcpy(nmsg.l_name, "+AUTO"); /* put on my mask... */
- strncpy(nmsg.r_name, user->user_name, NAME_SIZE);
- nmsg.r_tty[0] = '\0';
- }
- else
- {
- strncpy(nmsg.r_name, user->user_name, NAME_SIZE);
- strncpy(nmsg.r_tty, user->tty_name, TTY_SIZE);
- }
- nmsg.addr = user->sock;
- nmsg.addr.sin_family = htons(AF_INET);
- if(sendit(addr, d) != 0)
- return -2;
-
- switch(type)
- {
- case LEAVE_INVITE:
- user->l_id = ntohl(nrsp.id_num);
- break;
- case LOOK_UP:
- user->r_id = ntohl(nrsp.id_num);
- break;
- case AUTO_LOOK_UP:
- strncpy(nmsg.l_name, me->user_name, NAME_SIZE);
- user->r_id = ntohl(nrsp.id_num);
- break;
- case AUTO_DELETE:
- strncpy(nmsg.l_name, me->user_name, NAME_SIZE);
- break;
- }
- return nrsp.answer;
- }
-
- /* Next, an interface for the auto-invite socket. The auto-invite socket
- * always sends to the caller's host, and always does just an invite.
- */
- int
- send_auto(type)
- u_char type;
- {
- int dtype, d, rc;
-
- if(autofd < 0)
- return 0;
- nmsg.type = type;
- strcpy(nmsg.r_name, "+AUTO");
- nmsg.r_tty[0] = '\0';
- nmsg.addr = autosock;
- nmsg.addr.sin_family = htons(AF_INET);
-
- rc = 0;
- dtype = find_daemon(me->host_addr);
- for(d = daemons; d >= 1; d--)
- if(dtype & (1<<d))
- {
- nmsg.id_num = htonl(autoid[d]);
- nmsg.pid = htonl(1);
- if(sendit(me->host_addr, d) < 0)
- rc = -1;
- else
- autoid[d] = ntohl(nrsp.id_num);
- }
-
- if(rc)
- return rc;
- if(type == LEAVE_INVITE)
- return 0;
- return nrsp.answer;
- }
-
- /* Shut down the auto-invitation system.
- */
- void
- kill_auto()
- {
- if(autofd < 0)
- return;
- (void)send_auto(DELETE);
- remove_fd(autofd);
- close(autofd);
- autofd = -1;
- }
-
- /* Create a TCP socket for communication with other talk users.
- */
- int
- newsock(user)
- yuser *user;
- {
- int socklen, fd;
-
- user->sock.sin_family = AF_INET;
- IN_ADDR(user->sock) = INADDR_ANY;
- IN_PORT(user->sock) = 0;
- if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- show_error("newsock: socket() failed");
- return -1;
- }
- if(bind(fd, (struct sockaddr *)&user->sock, sizeof(struct sockaddr_in)) < 0)
- {
- close(fd);
- show_error("newsock: bind() failed");
- return -1;
- }
- socklen = sizeof(struct sockaddr_in);
- if(getsockname(fd, (struct sockaddr *)&user->sock, &socklen) < 0)
- {
- close(fd);
- show_error("newsock: getsockname() failed");
- return -1;
- }
- place_my_address(&(user->sock), user->host_addr);
- if(listen(fd, 5) < 0)
- {
- close(fd);
- show_error("newsock: listen() failed");
- return -1;
- }
- user->fd = fd;
- fd_to_user[user->fd] = user;
- user->orig_sock = user->sock;
- return 0;
- }
-
- /* Connect to another user's communication socket.
- */
- int
- connect_to(user)
- yuser *user;
- {
- register yuser *u;
- int socklen, fd;
- struct sockaddr_in sock, orig_sock;
-
- orig_sock = *(struct sockaddr_in *)&nrsp.addr;
- orig_sock.sin_family = AF_INET;
-
- /* it could be one of mine... */
- for(u = user_list; u; u = u->unext)
- if(SOCK_EQUAL(orig_sock, u->orig_sock))
- return -3;
- if(SOCK_EQUAL(orig_sock, autosock))
- return -3;
-
- sock = orig_sock;
- if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- show_error("connect_to: socket() failed");
- return -1;
- }
- if(connect(fd, (struct sockaddr *)&sock, sizeof(struct sockaddr_in)) < 0)
- {
- close(fd);
- if(errno == ECONNREFUSED)
- {
- errno = 0;
- return -2;
- }
- show_error("connect_to: connect() failed");
- return -1;
- }
- socklen = sizeof(struct sockaddr_in);
- if(getsockname(fd, (struct sockaddr *)&sock, &socklen) < 0)
- {
- close(fd);
- show_error("connect_to: getsockname() failed");
- return -1;
- }
- if(user)
- {
- user->sock = sock;
- user->orig_sock = orig_sock;
- user->fd = fd;
- fd_to_user[user->fd] = user;
- }
- return fd;
- }
-
- /* Find a host's address.
- */
- u_long
- get_host_addr(hostname)
- char *hostname;
- {
- struct hostent *host;
- u_long addr;
- u_long inet_addr();
-
- if((host = (struct hostent *) gethostbyname(hostname)) != NULL)
- {
- if(host->h_length != sizeof(addr))
- {
- sprintf(errstr, "Bad IN addr: %s\n", hostname);
- show_error(errstr);
- return (u_long)-1;
- }
- (void)memcpy(&addr, host->h_addr, sizeof(addr));
- }
- else if((addr = inet_addr(hostname)) == (u_long)-1)
- return (u_long)-1;
- return addr;
- }
-
- /* Find a host name by host address.
- */
- char *
- host_name(addr)
- u_long addr;
- {
- struct hostent *host;
- char *inet_ntoa();
-
- if((host = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) == NULL)
- {
- struct in_addr tmp;
- tmp.s_addr = addr;
- return inet_ntoa(tmp);
- }
- return host->h_name;
- }
-
- /* Re-address a given host ("from_id") to the given address or host
- * id ("to_id") when communicating with some other host id ("on_id").
- * This is useful especially over routers where "foo.com" is known
- * as the differently-addressed "bar.com" to host "xyzzy.com".
- */
- void
- readdress_host(from_id, to_id, on_id)
- char *from_id, *to_id, *on_id;
- {
- register readdr *new;
- u_long from_addr, to_addr, on_addr;
- u_long from_mask, to_mask, on_mask;
-
- if((from_addr = get_host_addr(from_id)) == (u_long)-1)
- {
- sprintf(errstr, "Unknown host: '%s'\n", from_id);
- show_error(errstr);
- return;
- }
- if((to_addr = get_host_addr(to_id)) == (u_long)-1)
- {
- sprintf(errstr, "Unknown host: '%s'\n", to_id);
- show_error(errstr);
- return;
- }
- if((on_addr = get_host_addr(on_id)) == (u_long)-1)
- {
- sprintf(errstr, "Unknown host: '%s'\n", on_id);
- show_error(errstr);
- return;
- }
- from_mask = make_net_mask(from_addr);
- to_mask = make_net_mask(to_addr);
- on_mask = make_net_mask(on_addr);
-
- if((from_addr & from_mask) != (me->host_addr & from_mask))
- return;
- if(from_addr == to_addr)
- return;
-
- new = (readdr *)get_mem(sizeof(readdr));
- new->addr = on_addr;
- new->mask = on_mask;
- new->id_addr = to_addr;
- new->id_mask = to_mask;
- new->next = readdr_list;
- readdr_list = new;
- }
-