home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / ytalk-3.0 / part01 / socket.c < prev    next >
C/C++ Source or Header  |  1993-08-20  |  22KB  |  914 lines

  1. /* socket.c - socket functions */
  2.  
  3. /*               NOTICE
  4.  *
  5.  * Copyright (c) 1990,1992,1993 Britt Yenne.  All rights reserved.
  6.  * 
  7.  * This software is provided AS-IS.  The author gives no warranty,
  8.  * real or assumed, and takes no responsibility whatsoever for any 
  9.  * use or misuse of this software, or any damage created by its use
  10.  * or misuse.
  11.  * 
  12.  * This software may be freely copied and distributed provided that
  13.  * no part of this NOTICE is deleted or edited in any manner.
  14.  * 
  15.  */
  16.  
  17. /* Mail comments or questions to ytalk@austin.eds.com */
  18.  
  19. #include "header.h"
  20. #include "menu.h"
  21. #include "socket.h"
  22. #include <sys/time.h>
  23. #ifdef _AIX
  24. # include <sys/select.h>
  25. #endif
  26.  
  27. struct _talkd talkd[MAXDAEMON+1];
  28. int daemons = 0;
  29.  
  30. static int otalk, ntalk;        /* daemon numbers */
  31. static CTL_MSG omsg;            /* old talk message */
  32. static CTL_RESPONSE orsp;        /* old talk response */
  33. static CTL_MSG42 nmsg;            /* new talk message */
  34. static CTL_RESPONSE42 nrsp;        /* new talk response */
  35.  
  36. static int autofd = -1;            /* auto invite socket fd */
  37. static struct sockaddr_in autosock;    /* auto invite socket */
  38. static long autoid[MAXDAEMON+1];    /* auto invite seq numbers */
  39. static u_long announce_id = 0;        /* announce sequence id */
  40. static readdr *readdr_list = NULL;    /* list of re-addresses */
  41.  
  42. #define IN_ADDR(s)    ((s).sin_addr.s_addr)
  43. #define IN_PORT(s)    ((s).sin_port)
  44. #define SOCK_EQUAL(s,c)    (IN_PORT(s) == IN_PORT(c) && IN_ADDR(s) == IN_ADDR(c))
  45.  
  46. /* ---- local functions ---- */
  47.  
  48. /* Create a datagram socket.
  49.  */
  50. static int
  51. init_dgram(sock)
  52.   struct sockaddr_in *sock;
  53. {
  54.     int fd, socklen;
  55.  
  56.     sock->sin_family = AF_INET;
  57.     IN_ADDR(*sock) = INADDR_ANY;
  58.     IN_PORT(*sock) = 0;
  59.     if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  60.     {
  61.     show_error("init_dgram: socket() failed");
  62.     bail(YTE_ERROR);
  63.     }
  64.     if(bind(fd, (struct sockaddr *)sock, sizeof(struct sockaddr_in)) != 0)
  65.     {
  66.     close(fd);
  67.     show_error("init_dgram: bind() failed");
  68.     bail(YTE_ERROR);
  69.     }
  70.     socklen = sizeof(struct sockaddr_in);
  71.     if(getsockname(fd, (struct sockaddr *)sock, &socklen) < 0)
  72.     {
  73.     close(fd);
  74.     show_error("init_dgram: getsockname() failed");
  75.     bail(YTE_ERROR);
  76.     }
  77.     IN_ADDR(*sock) = me->host_addr;
  78.     return fd;
  79. }
  80.  
  81. /* Initialize a new daemon structure.
  82.  */
  83. static int
  84. init_daemon(name, port, mptr, mlen, rptr, rlen)
  85.   char *name;
  86.   short port;
  87.   yaddr mptr, rptr;
  88.   int mlen, rlen;
  89. {
  90.     struct servent *serv;
  91.     int d;
  92.  
  93.     if(daemons >= MAXDAEMON)
  94.     {
  95.     show_error("init_daemon: too many daemons");
  96.     bail(YTE_ERROR);
  97.     }
  98.     d = ++daemons;    /* daemon number zero is not defined */
  99.  
  100.     if((serv = getservbyname(name, "udp")) != NULL)
  101.     talkd[d].port = serv->s_port;
  102.     else
  103.     talkd[d].port = port;
  104.     
  105.     talkd[d].fd = init_dgram(&(talkd[d].sock));
  106.     talkd[d].mptr = mptr;
  107.     talkd[d].mlen = mlen;
  108.     talkd[d].rptr = rptr;
  109.     talkd[d].rlen = rlen;
  110.     return d;
  111. }
  112.  
  113. static void
  114. read_autoport(fd)
  115.   int fd;
  116. {
  117.     int socklen;
  118.     static v2_pack pack;
  119.     static char estr[V2_NAMELEN + V2_HOSTLEN + 20];
  120.     static struct sockaddr_in temp;
  121.  
  122.     /* accept the connection */
  123.  
  124.     socklen = sizeof(struct sockaddr_in);
  125.     if((fd = accept(autofd, (struct sockaddr *) &temp, &socklen)) == -1)
  126.     {
  127.     show_error("read_autoport: accept() failed");
  128.     return;
  129.     }
  130.  
  131.     /* The autoport socket just uses the old Ytalk version 2.?
  132.      * packet.
  133.      */
  134.     errno = 0;
  135.     if(full_read(fd, &pack, V2_PACKLEN) < 0 || pack.code != V2_AUTO)
  136.     {
  137.     show_error("read_autoport: unknown auto-invite connection");
  138.     close(fd);
  139.     return;
  140.     }
  141.     close(fd);
  142.     if(!(def_flags & FL_INVITE))
  143.     {
  144.     sprintf(estr, "Talk to %s@%s?", pack.name, pack.host);
  145.     if(yes_no(estr) == 'n')
  146.         return;
  147.     }
  148.     sprintf(estr, "%s@%s", pack.name, pack.host);
  149.     invite(estr, 1);    /* we should be expected */
  150. }
  151.  
  152. /* Create and initialize the auto-invitation socket.
  153.  */
  154. static void
  155. init_autoport()
  156. {
  157.     int socklen;
  158.  
  159.     autosock.sin_family = AF_INET;
  160.     IN_ADDR(autosock) = INADDR_ANY;
  161.     IN_PORT(autosock) = 0;
  162.     if((autofd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  163.     {
  164.     show_error("init_autoport: socket() failed");
  165.     return;
  166.     }
  167.     if(bind(autofd, (struct sockaddr *)&autosock,
  168.     sizeof(struct sockaddr_in)) < 0)
  169.     {
  170.     close(autofd);
  171.     autofd = -1;
  172.     show_error("init_autoport: bind() failed");
  173.     return;
  174.     }
  175.     socklen = sizeof(struct sockaddr_in);
  176.     if(getsockname(autofd, (struct sockaddr *)&autosock, &socklen) < 0)
  177.     {
  178.     close(autofd);
  179.     autofd = -1;
  180.     show_error("init_autoport: getsockname() failed");
  181.     return;
  182.     }
  183.     IN_ADDR(autosock) = me->host_addr;
  184.     if(listen(autofd, 5) < 0)
  185.     {
  186.     close(autofd);
  187.     autofd = -1;
  188.     show_error("init_autoport: listen() failed");
  189.     return;
  190.     }
  191.     (void)memset(autoid, 0, (MAXDAEMON + 1) * sizeof(long));
  192.     add_fd(autofd, read_autoport);
  193. }
  194.  
  195. /* Fill the socket address field with the appropriate return address for
  196.  * the host I'm sending to.
  197.  */
  198. static void
  199. place_my_address(sock, addr)
  200.   struct sockaddr_in *sock;
  201.   register u_long addr;
  202. {
  203.     register readdr *r;
  204.  
  205.     for(r = readdr_list; r != NULL; r = r->next)
  206.     if((addr & r->mask) == r->addr)
  207.     {
  208.         addr = (r->id_addr & r->id_mask) |
  209.            (me->host_addr & (~(r->id_mask)));
  210.         IN_ADDR(*sock) = addr;
  211.         break;
  212.     }
  213.     if(r == NULL)
  214.     IN_ADDR(*sock) = me->host_addr;
  215.     sock->sin_family = htons(AF_INET);
  216. }
  217.  
  218. /* sendit() sends the completed message to the talk daemon at the given
  219.  * hostname, then reads a response packet.
  220.  */
  221. static int
  222. sendit(addr, d)
  223.   u_long addr;    /* host internet address */
  224.   int d;    /* daemon number */
  225. {
  226.     int n;
  227.     struct sockaddr_in daemon;
  228.     struct timeval tv;
  229.     char *rtype, *mtype;
  230.     fd_set sel;
  231.  
  232.     /* set up the appropriate message structure */
  233.  
  234.     if(d == ntalk)
  235.     {
  236.     nmsg.vers = TALK_VERSION;
  237.     place_my_address(&(nmsg.ctl_addr), addr);
  238.     mtype = &(nmsg.type);
  239.     rtype = &(nrsp.type);
  240.     }
  241.     else if(d == otalk)
  242.     {
  243.     omsg.type = nmsg.type;
  244.     omsg.addr = nmsg.addr;
  245.     omsg.id_num = nmsg.id_num;
  246.     omsg.pid = nmsg.pid;
  247.     strncpy(omsg.l_name, nmsg.l_name, NAME_SIZE);
  248.     strncpy(omsg.r_name, nmsg.r_name, NAME_SIZE);
  249.     strncpy(omsg.r_tty, nmsg.r_tty, TTY_SIZE);
  250.     place_my_address(&(omsg.ctl_addr), addr);
  251.     mtype = &(omsg.type);
  252.     rtype = &(orsp.type);
  253.     }
  254.     else
  255.     {
  256.     sprintf(errstr, "Unkown daemon type: %d", d);
  257.     show_error(errstr);
  258.     return -1;
  259.     }
  260.  
  261.     /* set up a sockaddr_in for the daemon we're sending to */
  262.  
  263.     daemon.sin_family = AF_INET;
  264.     IN_ADDR(daemon) = addr;
  265.     IN_PORT(daemon) = talkd[d].port;
  266.  
  267.     /* flush any lingering input */
  268.  
  269.     FD_ZERO(&sel);
  270.     for(;;)
  271.     {
  272.     tv.tv_sec = 0L;
  273.     tv.tv_usec = 0L;
  274.     FD_SET(talkd[d].fd, &sel);
  275.     if((n = select(talkd[d].fd + 1, &sel, 0, 0, &tv)) < 0)
  276.     {
  277.         show_error("sendit: flush select() failed");
  278.         return -1;
  279.     }
  280.     if(n <= 0)
  281.         break;
  282.     if(recv(talkd[d].fd, talkd[d].rptr, talkd[d].rlen, 0) < 0)
  283.     {
  284.         show_error("sendit: flush recv() failed");
  285.         return -1;
  286.     }
  287.     }
  288.  
  289.     /* Now we need to send the actual packet.  Due to unreliability of
  290.      * DGRAM sockets, we must resend the packet until we get a response
  291.      * from the server.  Geez... two different daemons, both on unreliable
  292.      * sockets, and maybe even different daemons on different machines.
  293.      * Is *nothing* reliable anymore???
  294.      */
  295.     do
  296.     {
  297.         do
  298.     {
  299.         n = sendto(talkd[d].fd, talkd[d].mptr, talkd[d].mlen,
  300.         0, (struct sockaddr *) &daemon, sizeof(daemon));
  301.         if(n != talkd[d].mlen)
  302.         {
  303.         show_error("sendit: sendto() failed");
  304.         return -1;
  305.         }
  306.  
  307.         tv.tv_sec = 5L;
  308.         tv.tv_usec = 0L;
  309.         FD_SET(talkd[d].fd, &sel);
  310.         if((n = select(talkd[d].fd + 1, &sel, 0, 0, &tv)) < 0)
  311.         {
  312.         show_error("sendit: first select() failed");
  313.         return -1;
  314.         }
  315.      } while (n <= 0);    /* ie: until we receive a reply */
  316.  
  317.         do
  318.     {
  319.         n = recv(talkd[d].fd, talkd[d].rptr, talkd[d].rlen, 0);
  320.         if(n < 0)
  321.         {
  322.         show_error("sendit: recv() failed");
  323.         return -1;
  324.         }
  325.  
  326.         if(*rtype != *mtype)
  327.         tv.tv_sec = 5L;
  328.         else
  329.         tv.tv_sec = 0L;
  330.         tv.tv_usec = 0L;
  331.         FD_SET(talkd[d].fd, &sel);
  332.         if((n = select(talkd[d].fd + 1, &sel, 0, 0, &tv)) < 0)
  333.         {
  334.         show_error("sendit: second select() failed");
  335.         return -1;
  336.         }
  337.         } while(n > 0 && *rtype != *mtype);
  338.     } while(*rtype != *mtype);
  339.  
  340.     /* WHEW */
  341.  
  342.     /* Just because a person is a SYSADMIN doesn't necessarily mean he/she
  343.      * knows everything about installing software.  In fact, many have been
  344.      * known to install the talk daemon without setting the option required
  345.      * to pad out the structures so that "long"s are on four-byte boundaries
  346.      * on machines where "long"s can be on two-byte boundaries.  This "bug"
  347.      * cost me about four hours of debugging to discover, so I'm not happy
  348.      * right now.  Anyway, here's a quick hack to fix this problem.
  349.      */
  350.     if(d == otalk && nrsp.type == LOOK_UP && nrsp.answer == 0)
  351.     {
  352.     u_short t;
  353.     (void)memcpy((char *)&t, ((char *)&orsp.addr.sin_family)-2, sizeof(t));
  354.     if(ntohs(t) == AF_INET && ntohs(orsp.addr.sin_family) != AF_INET)
  355.     {
  356.         char *c;
  357.         c = ((char *)&orsp) + sizeof(orsp) - 1;
  358.         for(; c >= (char *)&orsp.id_num; c--)
  359.         *c = *(c-2);
  360.     }
  361.     }
  362.  
  363.     /* Fill in the new talk response structure if we just read an
  364.      * old one.
  365.      */
  366.     if(d == otalk)
  367.     {
  368.     nrsp.type = orsp.type;
  369.     nrsp.answer = orsp.answer;
  370.     nrsp.id_num = orsp.id_num;
  371.     nrsp.addr = orsp.addr;
  372.     }
  373.  
  374.     return 0;
  375. }
  376.  
  377. /* find_daemon() locates the talk daemon(s) on a machine and determines
  378.  * what version(s) of the daemon are running.
  379.  */
  380. static int
  381. find_daemon(addr)
  382.   u_long addr;
  383. {
  384.     register hostinfo *h;
  385.     register int n, i, d;
  386.     CTL_MSG m1;
  387.     CTL_MSG42 m2;
  388.     struct sockaddr_in daemon;
  389.     struct timeval tv;
  390.     int sel, out;
  391.     static hostinfo *host_head = NULL;
  392.  
  393.     /* If we've already used this host, look it up instead of blitting to
  394.      * the daemons again...
  395.      */
  396.     for(h = host_head; h; h = h->next)
  397.     if(h->host_addr == addr)
  398.         return h->dtype;
  399.  
  400.     daemon.sin_family = AF_INET;
  401.     IN_ADDR(daemon) = addr;
  402.  
  403.     m1 = omsg;
  404.     m2 = nmsg;
  405.     m1.ctl_addr = talkd[otalk].sock;
  406.     place_my_address(&(m1.ctl_addr), addr);
  407.     m2.ctl_addr = talkd[ntalk].sock;
  408.     place_my_address(&(m2.ctl_addr), addr);
  409.     m1.type = m2.type = LOOK_UP;
  410.     m1.id_num = m2.id_num = htonl(0);
  411.     m1.r_tty[0] = m2.r_tty[0] = '\0';
  412.     strcpy(m1.r_name, "ytalk");
  413.     strcpy(m2.r_name, "ytalk");
  414.     m1.addr.sin_family = m2.addr.sin_family = htons(AF_INET);
  415.  
  416.     out = 0;
  417.     for(i = 0; i < 5; i++)
  418.     {
  419.     IN_PORT(daemon) = talkd[ntalk].port;
  420.     n = sendto(talkd[ntalk].fd, &m2, sizeof(m2),
  421.         0, (struct sockaddr *) &daemon, sizeof(daemon));
  422.     if(n != sizeof(m2))
  423.         show_error("Warning: cannot write to new talk daemon");
  424.  
  425.     IN_PORT(daemon) = talkd[otalk].port;
  426.     n = sendto(talkd[otalk].fd, &m1, sizeof(m1),
  427.         0, (struct sockaddr *) &daemon, sizeof(daemon));
  428.     if(n != sizeof(m1))
  429.         show_error("Warning: cannot write to old talk daemon");
  430.  
  431.     tv.tv_sec = 4L;
  432.     tv.tv_usec = 0L;
  433.     sel = (1 << talkd[ntalk].fd) | (1 << talkd[otalk].fd);
  434.     if((n = select(32, &sel, 0, 0, &tv)) < 0)
  435.     {
  436.         show_error("find_daemon: first select() failed");
  437.         continue;
  438.     }
  439.     if(n == 0)
  440.         continue;
  441.  
  442.     do
  443.     {
  444.         for(d = 1; d <= daemons; d++)
  445.         if(sel & (1 << talkd[d].fd))
  446.         {
  447.             out |= (1 << d);
  448.             if(recv(talkd[d].fd, errstr, talkd[d].rlen, 0) < 0)
  449.             show_error("find_daemon: recv() failed");
  450.         }
  451.  
  452.         tv.tv_sec = 0L;
  453.         tv.tv_usec = 500000L;    /* give the other daemon a chance */
  454.         sel = (1 << talkd[ntalk].fd) | (1 << talkd[otalk].fd);
  455.         if((n = select(32, &sel, 0, 0, &tv)) < 0)
  456.         show_error("find_daemon: second select() failed");
  457.     } while(n > 0);
  458.  
  459.     h = (hostinfo *)get_mem(sizeof(hostinfo));
  460.     h->next = host_head;
  461.     host_head = h;
  462.     h->host_addr = addr;
  463.     h->dtype = out;
  464.     return out;
  465.     }
  466.     sprintf(errstr, "No talk daemon on %s", host_name(addr));
  467.     show_error(errstr);
  468.     return 0;
  469. }
  470.  
  471. static u_long
  472. make_net_mask(addr)
  473.   u_long addr;
  474. {
  475.     if(addr & (u_long)0xff)
  476.     return (u_long)0xffffffff;
  477.     if(addr & (u_long)0xffff)
  478.     return (u_long)0xffffff00;
  479.     if(addr & (u_long)0xffffff)
  480.     return (u_long)0xffff0000;
  481.     if(addr)
  482.     return (u_long)0xff000000;
  483.     return (u_long)0;
  484. }
  485.  
  486. /* ---- global functions ---- */
  487.  
  488. /* Initialize sockets and message parameters.
  489.  */
  490. void
  491. init_socket()
  492. {
  493.     /* init daemons in order of preference */
  494.  
  495.     ntalk = init_daemon("ntalk", 518, &nmsg, sizeof(nmsg),
  496.     &nrsp, sizeof(nrsp));
  497.     otalk = init_daemon("talk", 517, &omsg, sizeof(omsg),
  498.     &orsp, sizeof(orsp));
  499.  
  500.     strncpy(nmsg.l_name, me->user_name, NAME_SIZE);
  501.  
  502.     omsg.ctl_addr = talkd[otalk].sock;
  503.     nmsg.ctl_addr = talkd[ntalk].sock;
  504.     nmsg.vers = TALK_VERSION;
  505.  
  506.     (void)find_daemon(me->host_addr);
  507.     init_autoport();
  508. }
  509.  
  510. /* Close every open descriptor.  This should only be used for a quick
  511.  * exit... it does not gracefully shut systems down.
  512.  */
  513. void
  514. close_all()
  515. {
  516.     register yuser *u;
  517.     register int d;
  518.  
  519.     for(u = user_list; u; u = u->unext)
  520.     {
  521.     if(u->fd > 0)
  522.         close(u->fd);
  523.     if(u->output_fd > 0)
  524.         close(u->output_fd);
  525.     }
  526.     if(autofd > 0)
  527.     close(autofd);
  528.     for(d = 1; d <= daemons; d++)
  529.     close(talkd[d].fd);
  530. }
  531.  
  532. /* The following routines send a request across the DGRAM socket to the
  533.  * talk daemons.
  534.  */
  535.  
  536. /* First, a quick and easy interface for the user sockets.
  537.  */
  538. int
  539. send_dgram(user, type)
  540.   yuser *user;
  541.   u_char type;
  542. {
  543.     u_long addr;
  544.     int d;
  545.  
  546.     /* set up the message type and where to send it */
  547.  
  548.     switch(type)
  549.     {
  550.     case LEAVE_INVITE:    /* leave an invite on my machine */
  551.         addr = me->host_addr;
  552.         nmsg.type = LEAVE_INVITE;
  553.         nmsg.id_num = htonl(user->l_id);
  554.         break;
  555.     case DELETE_INVITE:    /* delete my invite on my machine */
  556.         addr = me->host_addr;
  557.         nmsg.type = DELETE;
  558.         nmsg.id_num = htonl(user->l_id);
  559.         break;
  560.     case ANNOUNCE:        /* ring a user */
  561.         addr = user->host_addr;
  562.         nmsg.type = ANNOUNCE;
  563.         announce_id += 5;    /* no guesswork here */
  564.         nmsg.id_num = htonl(announce_id);
  565.         break;
  566.     case LOOK_UP:        /* look up remote invitation */
  567.         addr = user->host_addr;
  568.         nmsg.type = LOOK_UP;
  569.         nmsg.id_num = htonl(user->r_id);
  570.         break;
  571.     case DELETE:        /* delete erroneous remote invitation */
  572.         addr = user->host_addr;
  573.         nmsg.type = DELETE;
  574.         nmsg.id_num = htonl(user->r_id);
  575.         break;
  576.     case AUTO_LOOK_UP:    /* look up remote auto-invitation */
  577.         addr = user->host_addr;
  578.         nmsg.type = LOOK_UP;
  579.         nmsg.id_num = htonl(user->r_id);
  580.         break;
  581.     case AUTO_DELETE:    /* delete erroneous remote auto-invitation */
  582.         addr = user->host_addr;
  583.         nmsg.type = DELETE;
  584.         nmsg.id_num = htonl(user->r_id);
  585.         break;
  586.     default:
  587.         errno = 0;
  588.         show_error("send_dgram: unknown type");
  589.         return -1;
  590.     }
  591.  
  592.     /* find a common daemon, if possible */
  593.  
  594.     if(user->daemon != 0)
  595.     d = user->daemon;
  596.     else
  597.     {
  598.     int dtype, d1, d2;
  599.  
  600.     /* Find the daemon(s) their host supports.  If our two machines
  601.      * support a daemon in common, use that one.  Else, normal UNIX
  602.      * "talk" is already screwed to the wall, but YTalk will at least
  603.      * work.
  604.      */
  605.     d1 = find_daemon(user->host_addr);
  606.     d2 = find_daemon(me->host_addr);
  607.     dtype = d1 & d2;
  608.  
  609.     if(d1 == 0 || d2 == 0)
  610.         return -1;
  611.     if(dtype == 0)
  612.     {
  613.         dtype = find_daemon(addr);
  614.         for(d = 1; d <= daemons; d++)
  615.         if(dtype & (1<<d))
  616.             break;
  617.         if(d > daemons)
  618.         return -1;
  619.     }
  620.     else
  621.     {
  622.         for(d = 1; d <= daemons; d++)
  623.         if(dtype & (1<<d))
  624.         {
  625.             user->daemon = d;
  626.             break;
  627.         }
  628.         if(d > daemons)
  629.         return -1;
  630.     }
  631.     }
  632.  
  633.     /* Each user has his own unique daemon id.  Why?  Tsch.  Why.
  634.      * Well, the talk daemons consider two users equivalent if their
  635.      * usernames and machine names match.  Hence, the daemons will not
  636.      * allow ytalk to talk with two different users with the same name
  637.      * on some machine.  By assigning unique process id's, we trick
  638.      * the daemons into thinking we're several different users trying
  639.      * to talk to the same person.  Sick?  Don't blame me.
  640.      */
  641.     nmsg.pid = htonl(user->d_id);
  642.     if(type == AUTO_LOOK_UP || type == AUTO_DELETE)
  643.     {
  644.     strcpy(nmsg.l_name, "+AUTO");    /* put on my mask... */
  645.     strncpy(nmsg.r_name, user->user_name, NAME_SIZE);
  646.     nmsg.r_tty[0] = '\0';
  647.     }
  648.     else
  649.     {
  650.     strncpy(nmsg.r_name, user->user_name, NAME_SIZE);
  651.     strncpy(nmsg.r_tty, user->tty_name, TTY_SIZE);
  652.     }
  653.     nmsg.addr = user->sock;
  654.     nmsg.addr.sin_family = htons(AF_INET);
  655.     if(sendit(addr, d) != 0)
  656.     return -2;
  657.  
  658.     switch(type)
  659.     {
  660.     case LEAVE_INVITE:
  661.         user->l_id = ntohl(nrsp.id_num);
  662.         break;
  663.     case LOOK_UP:
  664.         user->r_id = ntohl(nrsp.id_num);
  665.         break;
  666.     case AUTO_LOOK_UP:
  667.         strncpy(nmsg.l_name, me->user_name, NAME_SIZE);
  668.         user->r_id = ntohl(nrsp.id_num);
  669.         break;
  670.     case AUTO_DELETE:
  671.         strncpy(nmsg.l_name, me->user_name, NAME_SIZE);
  672.         break;
  673.     }
  674.     return nrsp.answer;
  675. }
  676.  
  677. /* Next, an interface for the auto-invite socket.  The auto-invite socket
  678.  * always sends to the caller's host, and always does just an invite.
  679.  */
  680. int
  681. send_auto(type)
  682.   u_char type;
  683. {
  684.     int dtype, d, rc;
  685.  
  686.     if(autofd < 0)
  687.     return 0;
  688.     nmsg.type = type;
  689.     strcpy(nmsg.r_name, "+AUTO");
  690.     nmsg.r_tty[0] = '\0';
  691.     nmsg.addr = autosock;
  692.     nmsg.addr.sin_family = htons(AF_INET);
  693.  
  694.     rc = 0;
  695.     dtype = find_daemon(me->host_addr);
  696.     for(d = daemons; d >= 1; d--)
  697.     if(dtype & (1<<d))
  698.     {
  699.         nmsg.id_num = htonl(autoid[d]);
  700.         nmsg.pid = htonl(1);
  701.         if(sendit(me->host_addr, d) < 0)
  702.         rc = -1;
  703.         else
  704.         autoid[d] = ntohl(nrsp.id_num);
  705.     }
  706.  
  707.     if(rc)
  708.     return rc;
  709.     if(type == LEAVE_INVITE)
  710.     return 0;
  711.     return nrsp.answer;
  712. }
  713.  
  714. /* Shut down the auto-invitation system.
  715.  */
  716. void
  717. kill_auto()
  718. {
  719.     if(autofd < 0)
  720.     return;
  721.     (void)send_auto(DELETE);
  722.     remove_fd(autofd);
  723.     close(autofd);
  724.     autofd = -1;
  725. }
  726.  
  727. /* Create a TCP socket for communication with other talk users.
  728.  */
  729. int
  730. newsock(user)
  731.   yuser *user;
  732. {
  733.     int socklen, fd;
  734.  
  735.     user->sock.sin_family = AF_INET;
  736.     IN_ADDR(user->sock) = INADDR_ANY;
  737.     IN_PORT(user->sock) = 0;
  738.     if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  739.     {
  740.     show_error("newsock: socket() failed");
  741.     return -1;
  742.     }
  743.     if(bind(fd, (struct sockaddr *)&user->sock, sizeof(struct sockaddr_in)) < 0)
  744.     {
  745.     close(fd);
  746.     show_error("newsock: bind() failed");
  747.     return -1;
  748.     }
  749.     socklen = sizeof(struct sockaddr_in);
  750.     if(getsockname(fd, (struct sockaddr *)&user->sock, &socklen) < 0)
  751.     {
  752.     close(fd);
  753.     show_error("newsock: getsockname() failed");
  754.     return -1;
  755.     }
  756.     place_my_address(&(user->sock), user->host_addr);
  757.     if(listen(fd, 5) < 0)
  758.     {
  759.     close(fd);
  760.     show_error("newsock: listen() failed");
  761.     return -1;
  762.     }
  763.     user->fd = fd;
  764.     fd_to_user[user->fd] = user;
  765.     user->orig_sock = user->sock;
  766.     return 0;
  767. }
  768.  
  769. /* Connect to another user's communication socket.
  770.  */
  771. int
  772. connect_to(user)
  773.   yuser *user;
  774. {
  775.     register yuser *u;
  776.     int socklen, fd;
  777.     struct sockaddr_in sock, orig_sock;
  778.  
  779.     orig_sock = *(struct sockaddr_in *)&nrsp.addr;
  780.     orig_sock.sin_family = AF_INET;
  781.  
  782.     /* it could be one of mine... */
  783.     for(u = user_list; u; u = u->unext)
  784.     if(SOCK_EQUAL(orig_sock, u->orig_sock))
  785.         return -3;
  786.     if(SOCK_EQUAL(orig_sock, autosock))
  787.     return -3;
  788.  
  789.     sock = orig_sock;
  790.     if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  791.     {
  792.     show_error("connect_to: socket() failed");
  793.     return -1;
  794.     }
  795.     if(connect(fd, (struct sockaddr *)&sock, sizeof(struct sockaddr_in)) < 0)
  796.     {
  797.     close(fd);
  798.     if(errno == ECONNREFUSED)
  799.     {
  800.         errno = 0;
  801.         return -2;
  802.     }
  803.     show_error("connect_to: connect() failed");
  804.     return -1;
  805.     }
  806.     socklen = sizeof(struct sockaddr_in);
  807.     if(getsockname(fd, (struct sockaddr *)&sock, &socklen) < 0)
  808.     {
  809.     close(fd);
  810.     show_error("connect_to: getsockname() failed");
  811.     return -1;
  812.     }
  813.     if(user)
  814.     {
  815.     user->sock = sock;
  816.     user->orig_sock = orig_sock;
  817.     user->fd = fd;
  818.     fd_to_user[user->fd] = user;
  819.     }
  820.     return fd;
  821. }
  822.  
  823. /* Find a host's address.
  824.  */
  825. u_long
  826. get_host_addr(hostname)
  827.   char *hostname;
  828. {
  829.     struct hostent *host;
  830.     u_long addr;
  831.     u_long inet_addr();
  832.  
  833.     if((host = (struct hostent *) gethostbyname(hostname)) != NULL)
  834.     {
  835.     if(host->h_length != sizeof(addr))
  836.     {
  837.         sprintf(errstr, "Bad IN addr: %s\n", hostname);
  838.         show_error(errstr);
  839.         return (u_long)-1;
  840.     }
  841.     (void)memcpy(&addr, host->h_addr, sizeof(addr));
  842.     }
  843.     else if((addr = inet_addr(hostname)) == (u_long)-1)
  844.     return (u_long)-1;
  845.     return addr;
  846. }
  847.  
  848. /* Find a host name by host address.
  849.  */
  850. char *
  851. host_name(addr)
  852.   u_long addr;
  853. {
  854.     struct hostent *host;
  855.     char *inet_ntoa();
  856.  
  857.     if((host = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) == NULL)
  858.     {
  859.     struct in_addr tmp;
  860.     tmp.s_addr = addr;
  861.     return inet_ntoa(tmp);
  862.     }
  863.     return host->h_name;
  864. }
  865.  
  866. /* Re-address a given host ("from_id") to the given address or host
  867.  * id ("to_id") when communicating with some other host id ("on_id").
  868.  * This is useful especially over routers where "foo.com" is known
  869.  * as the differently-addressed "bar.com" to host "xyzzy.com".
  870.  */
  871. void
  872. readdress_host(from_id, to_id, on_id)
  873.   char *from_id, *to_id, *on_id;
  874. {
  875.     register readdr *new;
  876.     u_long from_addr, to_addr, on_addr;
  877.     u_long from_mask, to_mask, on_mask;
  878.  
  879.     if((from_addr = get_host_addr(from_id)) == (u_long)-1)
  880.     {
  881.     sprintf(errstr, "Unknown host: '%s'\n", from_id);
  882.     show_error(errstr);
  883.     return;
  884.     }
  885.     if((to_addr = get_host_addr(to_id)) == (u_long)-1)
  886.     {
  887.     sprintf(errstr, "Unknown host: '%s'\n", to_id);
  888.     show_error(errstr);
  889.     return;
  890.     }
  891.     if((on_addr = get_host_addr(on_id)) == (u_long)-1)
  892.     {
  893.     sprintf(errstr, "Unknown host: '%s'\n", on_id);
  894.     show_error(errstr);
  895.     return;
  896.     }
  897.     from_mask = make_net_mask(from_addr);
  898.     to_mask = make_net_mask(to_addr);
  899.     on_mask = make_net_mask(on_addr);
  900.     
  901.     if((from_addr & from_mask) != (me->host_addr & from_mask))
  902.     return;
  903.     if(from_addr == to_addr)
  904.     return;
  905.  
  906.     new = (readdr *)get_mem(sizeof(readdr));
  907.     new->addr = on_addr;
  908.     new->mask = on_mask;
  909.     new->id_addr = to_addr;
  910.     new->id_mask = to_mask;
  911.     new->next = readdr_list;
  912.     readdr_list = new;
  913. }
  914.