home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / Misc / ytalk / Source / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  18.3 KB  |  758 lines

  1. /* socket.c - socket functions for YTalk V2.0 */
  2.  
  3. /*               NOTICE
  4.  *
  5.  * Copyright (c) 1990 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 yenne@ccwf.cc.utexas.edu */
  18.  
  19. #include "ytalk.h"
  20. #include <sys/time.h>
  21. #include <netdb.h>
  22. #include <pwd.h>
  23. #include <stdio.h>
  24.  
  25. struct sockaddr_in bsd_sock;    /* for communicating udp with talk daemon */
  26. struct sockaddr_in bsd42_sock;    /* for communicating udp with talk daemon */
  27. struct sockaddr_in yt_sock;    /* for YTalk daemon */
  28. struct in_addr myaddr;        /* caller's machine address */
  29. char myhost[100];        /* caller's machine hostname */
  30. short bsd_daemon = 0;        /* udp talk daemon port number */
  31. short bsd42_daemon = 0;        /* udp talk daemon version >4.2 */
  32. int bsd_fd, bsd42_fd, yt_fd;    /* socket descriptors */
  33.  
  34. extern char *prog;
  35. extern int errno;
  36. extern person p[MAXC];
  37. extern char errstr[100];
  38. extern int pnum;
  39. CTL_MSG msg;
  40. CTL_RESPONSE rc;
  41. CTL_MSG42 msg42;
  42. CTL_RESPONSE42 rc42;
  43.  
  44. int autofd;            /* auto invite socket fd */
  45. struct sockaddr_in autosock;    /* auto invite socket */
  46. int autoid = 0;            /* for the talk daemon */
  47.  
  48. /* We need to keep a list of accessed hosts and their daemon types.
  49.  */
  50. short find_daemon();
  51.  
  52. typedef struct {
  53.     char *host;            /* host name */
  54.     short dtype;        /* daemon type */
  55. } hostlist;
  56.  
  57. #define MAXH    MAXC+2
  58. hostlist hostl[MAXH];        /* list of accessed hosts */
  59. int hcnt = 0;            /* count of current host list */
  60.  
  61. /* Look up a hostid by host name or inet number */
  62.  
  63. struct hostent *lookup_host(name)
  64. char *name;
  65. {
  66.     register int n;
  67.     register char *h;
  68.     unsigned char *a;
  69.     struct hostent *host;
  70.     static char init = 0;
  71.     static char addr[1][20];
  72.     static struct hostent out;
  73.  
  74.     if((host = (struct hostent *) gethostbyname(name)) != NULL)
  75.     return host;
  76.     if(!init)
  77.     {
  78.     out.h_name = name;
  79.     out.h_aliases = NULL;
  80.     out.h_addr_list = (char **) addr;
  81.     init = 1;
  82.     }
  83.     out.h_length = 0;
  84.     a = (unsigned char *) out.h_addr;
  85.     for(h = name, n = 0; *name; name++)
  86.     {
  87.     if(*name == '.' && h < name)
  88.     {
  89.         if(++out.h_length >= 20 || n > 255)
  90.         return (struct hostent *) 0;
  91.         *(a++) = n;
  92.         n = 0;
  93.         h = name + 1;
  94.         continue;
  95.     }
  96.     else if(*name >= '0' && *name <= '9')
  97.         n = (n * 10) + (*name - '0');
  98.     else
  99.         return (struct hostent *) 0;
  100.     }
  101.     if(++out.h_length >= 20 || n > 255 || h >= name)
  102.     return (struct hostent *) 0;
  103.     *a = n;
  104.     return &out;
  105. }
  106.  
  107. /* Initialize sockets and message parameters.
  108.  */
  109. init_socks()
  110. {
  111.     struct hostent *host;
  112.     struct servent *serv;
  113.     struct passwd *pw;
  114.  
  115.     if((serv = getservbyname("talk", "udp")) == 0)
  116.     {
  117.     panic("Talk server not found");
  118.     yytalkabort(2);
  119.     }
  120.     bsd_daemon = serv->s_port;
  121.  
  122.     if((serv = getservbyname("ntalk", "udp")) != 0)
  123.     bsd42_daemon = serv->s_port;
  124.     else
  125.     bsd42_daemon = 518;
  126.  
  127.     gethostname(myhost, 100);
  128.     if((host = lookup_host(myhost)) == 0)
  129.     {
  130.     sprintf(errstr, "Unknown host: %s", myhost);
  131.     panic(errstr);
  132.     yytalkabort(5);
  133.     }
  134.     bcopy(host->h_addr, &myaddr, host->h_length);
  135. #ifdef CODE3
  136.     (char) *((char *) &myaddr + 2) = CODE3;
  137. #endif
  138.     strcpy(myhost, host->h_name);
  139.  
  140.     bsd_fd = init_dgram(&bsd_sock);
  141.     bsd42_fd = init_dgram(&bsd42_sock);
  142.     yt_fd = init_dgram(&yt_sock);
  143.  
  144.     if((pw = (struct passwd *) getpwuid(getuid())) == 0)
  145.     {
  146.     panic("Who are you?");
  147.     yytalkabort(1);
  148.     }
  149.     strncpy(msg42.l_name, pw->pw_name, NAME_SIZE);
  150.     strncpy(msg.l_name, msg42.l_name, NAME_SIZE);
  151.  
  152.     msg42.pid = msg.pid = htonl(getpid());
  153.  
  154.     msg.ctl_addr = bsd_sock;
  155.     msg.ctl_addr.sin_family = htons(AF_INET);
  156.     msg42.ctl_addr = bsd42_sock;
  157.     msg42.ctl_addr.sin_family = htons(AF_INET);
  158.     msg42.vers = TALK_VERSION;
  159.  
  160.     (void) find_daemon(myhost);
  161. }
  162.  
  163. /* Create and initialize the auto-invitation socket.
  164.  */
  165. init_autoport()
  166. {
  167.     int socklen;
  168.  
  169.     autosock.sin_family = AF_INET;
  170.     autosock.sin_addr.s_addr = INADDR_ANY;
  171.     autosock.sin_port = 0;
  172.     if((autofd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  173.     {
  174.     panic("Cannot open AUTOPORT socket");
  175.     return -1;
  176.     }
  177.     if(bind(autofd,(struct sockaddr *) &autosock, sizeof(struct sockaddr_in)) == -1)
  178.     {
  179.     close(autofd);
  180.     autofd = -1;
  181.     panic("Cannot bind AUTOPORT socket");
  182.     return -1;
  183.     }
  184.     socklen = sizeof(struct sockaddr_in);
  185.     if(getsockname(autofd,(struct sockaddr *) &autosock, &socklen) == -1)
  186.     {
  187.     close(autofd);
  188.     autofd = -1;
  189.     panic("Cannot read AUTOPORT socket address");
  190.     return -1;
  191.     }
  192.     autosock.sin_addr = myaddr;
  193.     if(listen(autofd, 5) == -1)
  194.     {
  195.     close(autofd);
  196.     autofd = -1;
  197.     panic("Cannot listen on AUTOPORT socket");
  198.     return -1;
  199.     }
  200. }
  201.  
  202. /* The following routines send a request across the DGRAM socket to the
  203.  * BSD talk daemons.
  204.  */
  205.  
  206. /* First, a quick and easy interface for the user sockets.
  207.  */
  208. int send_dgram(hostname, type, i)
  209. char *hostname;
  210. u_char type;
  211. int i;        /* user number */
  212. {
  213.     int n;
  214.     short dtype, d1, d2;
  215.     short got_ytalk = 0;
  216.  
  217.     msg.type = type;
  218.     if(type == ANNOUNCE)
  219.     msg.id_num = htonl(p[i].a_id+1);
  220.     else
  221.     msg.id_num = htonl(p[i].id);
  222.     msg.addr = p[i].sock;
  223.     msg.addr.sin_family = htons(AF_INET);
  224.  
  225.     /* Find the daemon(s) their host supports.  If our two machines support
  226.      * a daemon in common, use that one.  Else, Berkeley "talk" is already
  227.      * screwed to the wall, but YTalk will at least work.
  228.      */
  229.     dtype = find_daemon(hostname);    /* the host I'm sending to */
  230.     d1 = find_daemon(p[i].host);    /* user's host */
  231.     d2 = hostl[0].dtype;        /* my host */
  232.     got_ytalk = dtype & D_YTALK;
  233.  
  234.     if(dtype == 0 || d1 == 0)
  235.     return -1;
  236.     if((dtype & D_BSD42) && (d1 & D_BSD42) && (d2 & D_BSD42))
  237.     dtype = D_BSD42;
  238.     else if((dtype & D_BSD) && (d1 & D_BSD) && (d2 & D_BSD))
  239.     dtype = D_BSD;
  240.     else if(dtype & D_BSD42)
  241.     dtype = D_BSD42;
  242.     else
  243.     dtype = D_BSD;
  244.  
  245.     dtype |= got_ytalk;
  246.     if(sendit(hostname, dtype) != 0)
  247.     return -1;
  248.  
  249.     if(type == ANNOUNCE)
  250.     p[i].a_id = ntohl(rc.id_num);
  251.     else if(type == LEAVE_INVITE || type == LOOK_UP)
  252.     p[i].id = ntohl(rc.id_num);
  253.     return rc.answer;
  254. }
  255.  
  256. /* Next, an interface for the auto-invite socket.  The auto-invite socket
  257.  * always sends to the caller's host, and always does just an invite.
  258.  */
  259. int send_auto(type)
  260. u_char type;
  261. {
  262.     if(autofd == -1)
  263.     return;
  264.     msg.type = type;
  265.     msg.id_num = htonl(autoid);
  266.     strncpy(msg.r_name, "+AUTO", NAME_SIZE);
  267.     msg.r_tty[0] = '\0';
  268.     msg.addr = autosock;
  269.     msg.addr.sin_family = htons(AF_INET);
  270.  
  271.     if(hostl[0].dtype & D_BSD42)
  272.     if(sendit(myhost, D_BSD42) != 0)
  273.         return -1;
  274.     if(hostl[0].dtype & D_BSD)
  275.     if(sendit(myhost, D_BSD) != 0)
  276.         return -1;
  277.  
  278.     autoid = ntohl(rc.id_num);
  279.     if(type == LEAVE_INVITE)
  280.     return 0;
  281.     return rc.answer;
  282. }
  283.  
  284. /* sendit() sends the completed message to the talk daemon at the given
  285.  * hostname, then reads a response packet.
  286.  */
  287. sendit(hostname, dtype)
  288. char *hostname;
  289. short dtype;    /* daemon type */
  290. {
  291.     int n, sel, fd;
  292.     struct hostent *host;
  293.     struct sockaddr_in daemon;
  294.     struct timeval tv;
  295.     char *packet, *rcp;
  296.     int mlen, rlen;
  297.     char *rtype, *mtype;
  298.     rcpack ypack;
  299.  
  300.     if((host = lookup_host(hostname)) == 0)
  301.     {
  302.     sprintf(errstr, "Unknown host: %s", hostname);
  303.     panic(errstr);
  304.     return -1;
  305.     }
  306.  
  307.     daemon.sin_family = AF_INET;
  308.     daemon.sin_addr.s_addr = ((struct in_addr *) (host->h_addr))->s_addr;
  309.  
  310.     /* If this host supports the BSD4.2 daemon, set up that structure.
  311.      */
  312.     if(dtype & D_BSD42)
  313.     {
  314.     msg42.vers = TALK_VERSION;
  315.     msg42.type = msg.type;
  316.     msg42.addr = msg.addr;
  317.     msg42.id_num = msg.id_num;
  318.     strncpy(msg42.l_name, msg.l_name, NAME_SIZE);
  319.     strncpy(msg42.r_name, msg.r_name, NAME_SIZE);
  320.     strncpy(msg42.r_tty, msg.r_tty, TTY_SIZE);
  321.     }
  322.  
  323.     /* Now determine which daemon to send to, and initialize the transfer
  324.      * variables.
  325.      */
  326.     if(dtype & D_BSD42)
  327.     {
  328.     daemon.sin_port = bsd42_daemon;
  329.     packet = (char *) &msg42;
  330.     rcp = (char *) &rc42;
  331.     mlen = sizeof(msg42);
  332.     rlen = sizeof(rc42);
  333.     mtype = &msg42.type;
  334.     rtype = &rc42.type;
  335.     fd = bsd42_fd;
  336.     if(dtype & D_YTALK)
  337.     {
  338.         daemon.sin_port = YTPORT;
  339.         ypack.type = 2;
  340.         ypack.length = sizeof(msg42);
  341.         bcopy(&msg42, ypack.buf, ypack.length);
  342.         packet = (char *) &ypack;
  343.         mlen = sizeof(ypack);
  344.     }
  345.     }
  346.     else if(dtype & D_BSD)
  347.     {
  348.     daemon.sin_port = bsd_daemon;
  349.     packet = (char *) &msg;
  350.     rcp = (char *) &rc;
  351.     mlen = sizeof(msg);
  352.     rlen = sizeof(rc);
  353.     mtype = &msg.type;
  354.     rtype = &rc.type;
  355.     fd = bsd_fd;
  356.     if(dtype & D_YTALK)
  357.     {
  358.         daemon.sin_port = YTPORT;
  359.         ypack.type = 1;
  360.         ypack.length = sizeof(msg);
  361.         bcopy(&msg, ypack.buf, ypack.length);
  362.         packet = (char *) &ypack;
  363.         mlen = sizeof(ypack);
  364.     }
  365.     }
  366.     else
  367.     {
  368.     sprintf(errstr, "Unkown daemon type: %d", dtype);
  369.     panic(errstr);
  370.     return -1;
  371.     }
  372.  
  373.     /* Now clear out any extraneous input still remaining on either of the
  374.      * two sockets.  Due to dual-daemon support, this may sometimes be
  375.      * necessary in order to prevent confusion.
  376.      */
  377.     for(;;)
  378.     {
  379.     tv.tv_sec = 0L;
  380.     tv.tv_usec = 0L;
  381.     sel = (1<<bsd_fd) | (1<<bsd42_fd);
  382.     if((n = select(32, &sel, 0, 0, &tv)) <= 0)
  383.         break;
  384.     if(sel & (1<<bsd_fd))
  385.         if(recv(bsd_fd, &rc, sizeof(rc), 0) <= 0)
  386.         {
  387.         if (errno == EINTR)
  388.             continue;
  389.         panic("recv failed");
  390.         break;
  391.         }
  392.     if(sel & (1<<bsd42_fd))
  393.         if(recv(bsd42_fd, &rc42, sizeof(rc42), 0) <= 0)
  394.         {
  395.         if (errno == EINTR)
  396.             continue;
  397.         panic("recv42 failed");
  398.         break;
  399.         }
  400.     }
  401.  
  402.     /* Now we need to send the actual packet.  Due to unreliability of
  403.      * DGRAM sockets, we must resend the packet until we get a response
  404.      * from the server.  Geez... two different daemons, both on unreliable
  405.      * sockets, and maybe even different daemons on different machines.
  406.      * Is *nothing* reliable anymore???
  407.      */
  408.     do
  409.     {
  410.         do
  411.     {
  412.         n = sendto(fd, packet, mlen, 0,(struct sockaddr *) &daemon, sizeof(daemon));
  413.         if (n != mlen)
  414.         {
  415.         if (errno == EINTR)    /* interrupted by some stray signal */
  416.             continue;
  417.         panic("Cannot write to talk daemon");
  418.         return -1;
  419.         }
  420.  
  421.         tv.tv_sec = 5L;
  422.         tv.tv_usec = 0L;
  423.         sel = 1<<fd;
  424.         if((n = select(32, &sel, 0, 0, &tv)) < 0)
  425.         {
  426.         if(errno == EINTR)
  427.             continue;
  428.         panic("first select failed in sendit()");
  429.         return -1;
  430.         }
  431.      } while (n == 0);    /* ie: until we receive a reply */
  432.  
  433.         do
  434.     {
  435.         n = recv(fd, rcp, rlen, 0);
  436.         if (n < 0)
  437.         {
  438.         if (errno == EINTR)
  439.             continue;
  440.         panic("Cannot read from talk daemon");
  441.         return -1;
  442.         }
  443.  
  444.         tv.tv_sec = 0L;
  445.         tv.tv_usec = 0L;
  446.         sel = 1<<fd;
  447.         if((n = select(32, &sel, 0, 0, &tv)) < 0)
  448.         {
  449.         if(errno == EINTR)
  450.             continue;
  451.         panic("second select failed in sendit()");
  452.         return -1;
  453.         }
  454.         } while(n > 0 && *rtype != *mtype);
  455.     } while(*rtype != *mtype);
  456.  
  457.     /* WHEW */
  458.  
  459.     if(dtype & D_BSD42)
  460.     {
  461.     rc.type = rc42.type;
  462.     rc.answer = rc42.answer;
  463.     rc.id_num = rc42.id_num;
  464.     rc.addr = rc42.addr;
  465.     }
  466.  
  467.     /* Just because a person is a SYSADMIN doesn't necessarily mean he/she
  468.      * knows everything about installing software.  In fact, many have been
  469.      * known to install the talk daemon without setting the option required
  470.      * to pad out the structures so that "long"s are on four-byte boundaries
  471.      * on machines where "long"s can be on two-byte boundaries.  This "bug"
  472.      * cost me about four hours of debugging to discover, so I'm not happy
  473.      * right now.  Anyway, here's a quick hack to fix this problem.
  474.      */
  475.     if(rc.type == LOOK_UP && rc.answer == 0)
  476.     {
  477.     u_short t;
  478.     bcopy(((char *)&rc.addr.sin_family)-2, (char *)&t, sizeof(t));
  479.     if(ntohs(t) == AF_INET && ntohs(rc.addr.sin_family) != AF_INET)
  480.     {
  481.         char *c;
  482.         c = ((char *)&rc) + sizeof(rc) - 1;
  483.         for(; c >= (char *)&rc.id_num; c--)
  484.         *c = *(c-2);
  485.     }
  486.     }
  487.  
  488.     return 0;
  489. }
  490.  
  491. /* find_daemon() locates the talk daemon(s) on a machine and determines
  492.  * what version of the daemon is running.
  493.  */
  494. short find_daemon(hostname)
  495. char *hostname;
  496. {
  497.     register int n, i;
  498.     CTL_MSG m1;
  499.     CTL_MSG42 m2;
  500.     CTL_RESPONSE r1;
  501.     CTL_RESPONSE42 r2;
  502.     struct sockaddr_in daemon;
  503.     struct hostent *host;
  504.     struct timeval tv;
  505.     int m1len, m2len;
  506.     int sel;
  507.     static short out;
  508.     rcpack ypack;
  509.  
  510.     if(bsd42_daemon == 0)
  511.     return D_BSD;
  512.  
  513.     /* If we've already used this host, look it up instead of blitting to
  514.      * the daemons again...
  515.      */
  516.     for(n = 0; n < hcnt; n++)
  517.     if(strncmp(hostl[n].host, hostname, HOSTLEN) == 0)
  518.         return hostl[n].dtype;
  519.     if(hcnt >= MAXH)
  520.     {
  521.     errno = 0;
  522.     panic("Too many different hostnames!");
  523.     return D_UNKNOWN;
  524.     }
  525.  
  526.     if((host = lookup_host(hostname)) == 0)
  527.     return D_UNKNOWN;
  528.  
  529.     if((hostl[hcnt].host = (char *) malloc(HOSTLEN)) == NULL)
  530.     {
  531.     panic("Cannot allocate memory");
  532.     return D_UNKNOWN;
  533.     }
  534.     strncpy(hostl[hcnt].host, hostname, HOSTLEN);
  535.  
  536.     daemon.sin_family = AF_INET;
  537.     daemon.sin_addr.s_addr = ((struct in_addr *) (host->h_addr))->s_addr;
  538.  
  539.     m1 = msg;
  540.     m2 = msg42;
  541.     m1.type = m2.type = LOOK_UP;
  542.     m1.id_num = m2.id_num = htonl(0);
  543.     m1.r_tty[0] = m2.r_tty[0] = '\0';
  544.     strcpy(m1.r_name, "ytalk");
  545.     strcpy(m2.r_name, "ytalk");
  546.     m1.ctl_addr = bsd_sock;
  547.     m1.ctl_addr.sin_family = htons(AF_INET);
  548.     m2.ctl_addr = bsd42_sock;
  549.     m2.ctl_addr.sin_family = htons(AF_INET);
  550.     m1.addr.sin_family = m2.addr.sin_family = htons(AF_INET);
  551.  
  552.     ypack.type = 0;
  553.     ypack.length = sizeof(yt_sock);
  554.     bcopy(&yt_sock, ypack.buf, ypack.length);
  555.  
  556.     out = 0;
  557.     for(i = 0; i < 5; i++)
  558.     {
  559.     if(out & D_YTALK)
  560.     {
  561.         daemon.sin_port = YTPORT;
  562.         ypack.type = 2;
  563.         ypack.length = sizeof(m2);
  564.         bcopy(&m2, ypack.buf, ypack.length);
  565.         n = sendto(bsd42_fd, &ypack, sizeof(ypack), 0,(struct sockaddr *) &daemon, sizeof(daemon));
  566.         if(n != sizeof(ypack) && errno != EINTR)
  567.         panic("Warning: cannot write to YTalk daemon");
  568.  
  569.         ypack.type = 1;
  570.         ypack.length = sizeof(m1);
  571.         bcopy(&m1, ypack.buf, ypack.length);
  572.         n = sendto(bsd_fd, &ypack, sizeof(ypack), 0,(struct sockaddr *) &daemon, sizeof(daemon));
  573.         if(n != sizeof(ypack) && errno != EINTR)
  574.         panic("Warning: cannot write to YTalk daemon");
  575.     }
  576.     else
  577.     {
  578.         daemon.sin_port = bsd42_daemon;
  579.         n = sendto(bsd42_fd, &m2, sizeof(m2), 0,(struct sockaddr *) &daemon, sizeof(daemon));
  580.         if(n != sizeof(m2) && errno != EINTR)
  581.         panic("Warning: cannot write to post-4.2 talk daemon");
  582.  
  583.         daemon.sin_port = bsd_daemon;
  584.         n = sendto(bsd_fd, &m1, sizeof(m1), 0,(struct sockaddr *) &daemon, sizeof(daemon));
  585.         if(n != sizeof(m1) && errno != EINTR)
  586.         panic("Warning: cannot write to pre-4.2 talk daemon");
  587.  
  588.         daemon.sin_port = YTPORT;
  589.         n=sendto(yt_fd, &ypack, sizeof(ypack), 0,(struct sockaddr *) &daemon, sizeof(daemon));
  590.         if(n != sizeof(ypack) && errno != EINTR)
  591.         panic("Warning: cannot write to YTalk daemon");
  592.     }
  593.  
  594.     tv.tv_sec = 4L;
  595.     tv.tv_usec = 0L;
  596.     sel = (1<<bsd_fd) | (1<<bsd42_fd) | (1<<yt_fd);
  597.     if((n = select(32, &sel, 0, 0, &tv)) < 0)
  598.     {
  599.         if(errno == EINTR)
  600.         continue;
  601.         panic("first select failed in find_daemon()");
  602.         continue;
  603.     }
  604.     if(n == 0)
  605.         continue;
  606.  
  607.     do
  608.     {
  609.         if(sel & (1<<bsd_fd))
  610.         {
  611.         out |= D_BSD;
  612.         if(recv(bsd_fd, &r1, sizeof(r1), 0) < 0)
  613.             panic("Cannot read from pre-4.2 talk daemon!");
  614.         }
  615.         if(sel & (1<<bsd42_fd))
  616.         {
  617.         out |= D_BSD42;
  618.         if(recv(bsd42_fd, &r2, sizeof(r2), 0) < 0)
  619.             panic("Cannot read from post-4.2 talk daemon!");
  620.         }
  621.         if(sel & (1<<yt_fd))
  622.         {
  623.         out |= D_YTALK;
  624.         if(recv(yt_fd, ypack.buf, RCSIZ, 0) < 0)
  625.             panic("Cannot read from YTalk daemon!");
  626.         }
  627.         tv.tv_sec = 0L;
  628.         tv.tv_usec = 500000L;    /* give the other daemon a chance */
  629.         sel = (1<<bsd_fd) | (1<<bsd42_fd);
  630.         if((n = select(32, &sel, 0, 0, &tv)) < 0)
  631.         {
  632.         if(errno == EINTR)
  633.             continue;
  634.         panic("second select failed in find_daemon()");
  635.         }
  636.     } while(n > 0);
  637.     if(out == D_YTALK)
  638.         continue;
  639.  
  640.     hostl[hcnt++].dtype = out;
  641.     return out;
  642.     }
  643.     sprintf(errstr, "No talk daemon on %s", hostname);
  644.     panic(errstr);
  645.     free(hostl[hcnt].host);
  646.     return D_UNKNOWN;
  647. }
  648.  
  649. /* Create a datagram socket.
  650.  */
  651. init_dgram(sock)
  652. struct sockaddr_in *sock;
  653. {
  654.     int fd, socklen;
  655.  
  656.     sock->sin_family = AF_INET;
  657.     sock->sin_addr.s_addr = INADDR_ANY;
  658.     sock->sin_port = 0;
  659.     if((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  660.     {
  661.     panic("Cannot open DGRAM socket");
  662.     yytalkabort(2);
  663.     }
  664.     if(bind(fd, (struct sockaddr *) sock, sizeof(struct sockaddr_in)) != 0)
  665.     {
  666.     close(fd);
  667.     panic("Cannot bind DGRAM socket");
  668.     yytalkabort(2);
  669.     }
  670.     socklen = sizeof(struct sockaddr_in);
  671.     if(getsockname(fd,(struct sockaddr *) sock, &socklen) == -1)
  672.     {
  673.     close(fd);
  674.     panic("Cannot read DGRAM socket address");
  675.     yytalkabort(2);
  676.     }
  677.     sock->sin_addr = myaddr;
  678.     return fd;
  679. }
  680.  
  681.  
  682. /* Create a TCP socket for communication with other talk users.
  683.  */
  684. int newsock(i)
  685. {
  686.     int socklen;
  687.  
  688.     p[i].sock.sin_family = AF_INET;
  689.     p[i].sock.sin_addr.s_addr = INADDR_ANY;
  690.     p[i].sock.sin_port = 0;
  691.     if((p[i].sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  692.     {
  693.     panic("Cannot open socket");
  694.     return -1;
  695.     }
  696.     if(bind(p[i].sfd, (struct sockaddr *) &p[i].sock, sizeof(struct sockaddr_in)) == -1)
  697.     {
  698.     close(p[i].sfd);
  699.     panic("Cannot bind socket");
  700.     return -1;
  701.     }
  702.     socklen = sizeof(struct sockaddr_in);
  703.     if(getsockname(p[i].sfd, (struct sockaddr *) &p[i].sock, &socklen) == -1)
  704.     {
  705.     close(p[i].sfd);
  706.     panic("Cannot read socket address");
  707.     return -1;
  708.     }
  709.     p[i].sock.sin_addr = myaddr;
  710.     if(listen(p[i].sfd, 5) == -1)
  711.     {
  712.     close(p[i].sfd);
  713.     panic("Cannot listen on socket");
  714.     return -1;
  715.     }
  716.     return 0;
  717. }
  718.  
  719. /* Connect to another user's communication socket.
  720.  */
  721. int connect_to(i)
  722. int i;    /* user number, or -1 to just return a file descriptor */
  723. {
  724.     int socklen, fd;
  725.     struct sockaddr_in sock;
  726.  
  727.     sock = *(struct sockaddr_in *)&rc.addr;
  728.     sock.sin_family = AF_INET;
  729.     if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  730.     {
  731.     panic("Cannot open socket");
  732.     return -1;
  733.     }
  734.     if(connect(fd,(struct sockaddr *) &sock, sizeof(struct sockaddr_in)) == -1)
  735.     {
  736.     close(fd);
  737.     if(errno == ECONNREFUSED)
  738.         return -2;
  739.     panic("Cannot connect to host");
  740.     return -1;
  741.     }
  742.     socklen = sizeof(struct sockaddr_in);
  743.     if(getsockname(fd, (struct sockaddr *) &sock, &socklen) == -1)
  744.     {
  745.     close(fd);
  746.     panic("Cannot read socket address");
  747.     return -1;
  748.     }
  749.     if(i != -1)
  750.     {
  751.     p[i].sock = sock;
  752.     p[i].sfd = fd;
  753.     p[i].flags |= P_CONNECT;
  754.     }
  755.     return fd;
  756. }
  757.  
  758.