1 /************************************************************************
2 *									*
3 *   Copyright 1988, 1989, 1990, Brown University, Providence, RI.	*
4 *   Permission to use, copy, modify and distribute this software and	*
5 *   its documentation for any purpose other than its incorporation	*
6 *   into a commercial product, is hereby granted, provided that this	*
7 *   copyright notice appears on all copies and the distribution is	*
8 *   only within the organization represented by the person receiving	*
9 *   the software from Brown.  Brown requests notification of the of	*
10 *   any important modifications to this software or its documentation.	*
11 *									*
12 ************************************************************************/
13 /************************************************************************
14 *									*
15 *   socket.c								*
16 *									*
17 *	All socket setup and io system calls are done here.		*
18 *									*
19 ************************************************************************/
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
25 #include <arpa/inet.h>
26 #include <netdb.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <errno.h>
30 
31 #ifdef __SVR4
32 #include <sys/file.h>
33 #endif
34 
35 #include "xmx.h"
36 
37 #define X_UNIX_DIR	"/tmp/.X11-unix"
38 #define X_UNIX_PATH	"/tmp/.X11-unix/X"
39 #define X_TCP_PORT	6000
40 
41 /************************************************************************
42 *									*
43 *   server_sockets							*
44 *									*
45 *	Create X server style sockets, bind to well known addresses	*
46 *	and listen on them.  Returns the number of sockets or -1 if	*
47 *	an error occurs.   Fdsp is pointed to a static array of the	*
48 *	descriptors.							*
49 *									*
50 ************************************************************************/
51 int
server_sockets(display,fdsp)52 server_sockets(display, fdsp)
53    int display;
54    int **fdsp;
55 {
56    register i;
57    int s, oumask;
58    struct linger linger;
59    static int fds[2];			/* return array */
60    static struct sockaddr_un usock;
61    static struct sockaddr_in isock;
62 
63 					/* create UNIX domain socket */
64    usock.sun_family = AF_UNIX;
65    (void)sprintf(usock.sun_path, "%s%d", X_UNIX_PATH, display);
66    oumask = umask(0);
67    (void)mkdir(X_UNIX_DIR, 0777);
68    (void)umask(oumask);
69    (void)unlink(usock.sun_path);
70    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
71       return perr(-1, usock.sun_path);
72 
73    i = strlen(usock.sun_path) + sizeof(usock.sun_family);
74    if (bind(s, (struct sockaddr *)&usock, i))
75       return perr(-1, usock.sun_path);
76 
77    if (listen(s, 5))
78       return perr(-1, usock.sun_path);
79 
80    fds[0] = s;
81 					/* create TCP socket */
82    isock.sin_family = AF_INET;
83    isock.sin_port = htons((u_short)(X_TCP_PORT + display));
84    isock.sin_addr.s_addr = htonl(INADDR_ANY);
85    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
86       return perr(-1, "tcp socket");
87 
88    for (i=20; i && bind(s, (struct sockaddr *)&isock, sizeof(isock)); i--)
89       sleep(10);
90    if (i == 0)
91       return perr(-1, "tcp socket");
92 
93    linger.l_onoff = 0;
94    linger.l_linger = 0;
95    if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger)))
96       return perr(-1, "tcp socket");
97 
98    if (listen(s, 5))
99       return perr(-1, "tcp socket");
100 
101    fds[1] = s;
102 
103    *fdsp = fds;
104    return 2;
105 }
106 
107 /************************************************************************
108 *									*
109 *   accept_client							*
110 *									*
111 *	Accept a pending connection from a client.  Returns the new	*
112 *	socket file descriptor or -1 if an error occurred.		*
113 *									*
114 ************************************************************************/
115 int
accept_client(s)116 accept_client(s)
117    int s;
118 {
119    int i;
120    int ns;
121    int addrlen;
122    struct sockaddr addr;
123 
124    addrlen = sizeof(addr);
125    if ((ns = accept(s, &addr, &addrlen)) < 0)
126       return perr(-1, "accept");
127 
128    if (addr.sa_family == AF_INET) {
129       i = 1;
130       if (setsockopt(ns, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)))
131          return perr(-1, "client socket");
132    }
133    (void)fcntl(ns, F_SETFL, FNDELAY);
134 
135    return ns;
136 }
137 
138 /************************************************************************
139 *									*
140 *   client_socket							*
141 *									*
142 *	Connect to an X server.  Returns the socket file descriptor or	*
143 *	-1 if an error occurred.					*
144 *									*
145 ************************************************************************/
146 int
client_socket(hostname,display,bfactor)147 client_socket(hostname, display, bfactor)
148    char *hostname;
149    int display;
150    int bfactor;
151 {
152    register len;
153    int s;
154    int sendbufopt, sendbuflen;
155    unsigned long iaddr;
156    struct hostent *h;
157    struct sockaddr *sock;
158    static struct sockaddr_un usock;
159    static struct sockaddr_in isock;
160 
161 						/* UNIX domain socket */
162    if (*hostname == '\0' || strcmp(hostname, "unix") == 0) {
163       usock.sun_family = AF_UNIX;
164       sprintf(usock.sun_path, "%s%d", X_UNIX_PATH, display);
165       if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
166          return perr(-1, usock.sun_path);
167 
168       sock = (struct sockaddr *)&usock;
169       len = sizeof(usock);
170    }
171    else {					/* TCP socket */
172       isock.sin_family = AF_INET;
173       isock.sin_port = htons((u_short)(X_TCP_PORT + display));
174       if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
175          return perr(-1, "tcp socket");
176 
177       if ((long)(iaddr = inet_addr(hostname)) < 0) {
178          if ((h = gethostbyname(hostname)) == 0)
179             return err(-1, "%s: host not found\n", hostname);
180 
181          if (h->h_addrtype != AF_INET)
182             return err(-1, "%s: not an internet host\n", hostname);
183 
184          bcopy((char *)*h->h_addr_list,(char *)&isock.sin_addr,h->h_length);
185       }
186       else
187          isock.sin_addr.s_addr = iaddr;
188       sock = (struct sockaddr *)&isock;
189       len = sizeof(isock);
190    }
191 #ifdef SO_SNDBUF
192    if (bfactor > 1) {
193       sendbuflen = sizeof(sendbufopt);
194       if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sendbufopt, &sendbuflen))
195          perror("getsockopt[SNDBUF]");
196       else {
197          sendbufopt *= bfactor;
198 /*
199 warn("client_socket: changing sndbuf size to %d\n",sendbufopt);
200 */
201          if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sendbufopt, sendbuflen))
202             perror("getsockopt[SNDBUF]");
203       }
204    }
205 #endif
206    if (connect(s, sock, len) < 0) {
207       perror("connect");
208       (void)close(s);
209       return -1;
210    }
211    (void)fcntl(s, F_SETFL, FNDELAY);
212 
213    return s;
214 }
215