1 /*
2  *    Common support routines for sockets
3  *
4  *       James L. Peterson
5  *
6  * Copyright (C) 1987 MCC
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and its
9  * documentation for any purpose is hereby granted without fee, provided that
10  * the above copyright notice appear in all copies and that both that
11  * copyright notice and this permission notice appear in supporting
12  * documentation, and that the name of MCC not be used in
13  * advertising or publicity pertaining to distribution of the software without
14  * specific, written prior permission.  MCC makes no
15  * representations about the suitability of this software for any purpose.  It
16  * is provided "as is" without express or implied warranty.
17  *
18  * MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20  * EVENT SHALL MCC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24  * PERFORMANCE OF THIS SOFTWARE.
25  *
26  */
27 /*
28  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
29  *
30  * Permission is hereby granted, free of charge, to any person obtaining a
31  * copy of this software and associated documentation files (the "Software"),
32  * to deal in the Software without restriction, including without limitation
33  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34  * and/or sell copies of the Software, and to permit persons to whom the
35  * Software is furnished to do so, subject to the following conditions:
36  *
37  * The above copyright notice and this permission notice (including the next
38  * paragraph) shall be included in all copies or substantial portions of the
39  * Software.
40  *
41  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47  * DEALINGS IN THE SOFTWARE.
48  *
49  */
50 
51 #include "scope.h"
52 #include <fcntl.h>
53 #include <unistd.h>
54 
55 /* ********************************************** */
56 /*						  */
57 /*       Debugging support routines               */
58 /*						  */
59 /* ********************************************** */
60 
61 void
enterprocedure(const char * s)62 enterprocedure(const char *s)
63 {
64     debug(2, (stderr, "-> %s\n", s));
65 }
66 
67 void
warn(const char * s)68 warn(const char *s)
69 {
70     fprintf(stderr, "####### %s\n", s);
71 }
72 
73 void
panic(const char * s)74 panic(const char *s)
75 {
76     fprintf(stderr, "%s\n", s);
77     exit(1);
78 }
79 
80 /* ************************************************************ */
81 /*								*/
82 /*    Signal Handling support					*/
83 /*								*/
84 /* ************************************************************ */
85 
86 #define __USE_BSD_SIGNAL
87 #include <signal.h>
88 
89 static void
SignalURG(int sig)90 SignalURG(int sig)
91 {
92     debug(1, (stderr, "==> SIGURG received\n"));
93 }
94 
95 static void
SignalPIPE(int sig)96 SignalPIPE(int sig)
97 {
98     signal(SIGPIPE, SignalPIPE);
99     debug(1, (stderr, "==> SIGPIPE received\n"));
100 }
101 
102 static void
SignalINT(int sig)103 SignalINT(int sig)
104 {
105     signal(SIGINT, SignalINT);
106     debug(1, (stderr, "==> SIGINT received\n"));
107     Interrupt = 1;
108 }
109 
110 static void _X_NORETURN
SignalQUIT(int sig)111 SignalQUIT(int sig)
112 {
113     debug(1, (stderr, "==> SIGQUIT received\n"));
114     exit(1);
115 }
116 
117 static void _X_NORETURN
SignalTERM(int sig)118 SignalTERM(int sig)
119 {
120     debug(1, (stderr, "==> SIGTERM received\n"));
121     exit(1);
122 }
123 
124 static void
SignalTSTP(int sig)125 SignalTSTP(int sig)
126 {
127     debug(1, (stderr, "==> SIGTSTP received\n"));
128 }
129 
130 static void
SignalCONT(int sig)131 SignalCONT(int sig)
132 {
133     debug(1, (stderr, "==> SIGCONT received\n"));
134 }
135 
136 static void
SignalUSR1(int sig)137 SignalUSR1(int sig)
138 {
139     debug(1, (stderr, "==> SIGUSR1 received\n"));
140     ScopeEnabled = !ScopeEnabled;
141 }
142 
143 void
SetSignalHandling(void)144 SetSignalHandling(void)
145 {
146     enterprocedure("SetSignalHandling");
147     (void) signal(SIGURG, SignalURG);
148     (void) signal(SIGPIPE, SignalPIPE);
149     (void) signal(SIGINT, SignalINT);
150     (void) signal(SIGQUIT, SignalQUIT);
151     (void) signal(SIGTERM, SignalTERM);
152     (void) signal(SIGTSTP, SignalTSTP);
153     (void) signal(SIGCONT, SignalCONT);
154     if (HandleSIGUSR1)
155         (void) signal(SIGUSR1, SignalUSR1);
156 }
157 
158 
159 
160 /* ************************************************************ */
161 /*								*/
162 /*   Create a socket for a service to listen for clients        */
163 /*								*/
164 /* ************************************************************ */
165 
166 #ifdef USE_XTRANS
167 
168 #define TRANS_CLIENT
169 #define TRANS_SERVER
170 #define X11_t
171 #include <X11/Xtrans/Xtrans.h>
172 static XtransConnInfo *ListenTransConns = NULL;
173 static int *ListenTransFds = NULL;
174 static int ListenTransCount;
175 
176 #else
177 
178 #include <sys/types.h>          /* needed by sys/socket.h and netinet/in.h */
179 #include <sys/uio.h>            /* for struct iovec, used by socket.h */
180 #include <sys/socket.h>         /* for AF_INET, SOCK_STREAM, ... */
181 #include <sys/ioctl.h>          /* for FIONCLEX, FIONBIO, ... */
182 #include <sys/fcntl.h>          /* for FIONCLEX, FIONBIO, ... */
183 #if !defined(FIOCLEX) && defined(HAVE_SYS_FILIO_H)
184 #include <sys/filio.h>
185 #endif
186 
187 #include <netinet/in.h>         /* struct sockaddr_in */
188 #include <netdb.h>              /* struct servent * and struct hostent *  */
189 
190 #define	BACKLOG	5
191 #endif
192 
193 void
SetUpConnectionSocket(int iport,void (* connectionFunc)(int))194 SetUpConnectionSocket(int iport, void (*connectionFunc) (int))
195 {
196 #ifdef USE_XTRANS
197     char port[20];
198     int partial;
199     int i;
200 #else
201     FD ConnectionSocket;
202     struct sockaddr_in sin;
203     short port;
204     int one = 1;
205     int ON = 1;                 /* used in ioctl */
206 #ifndef	SO_DONTLINGER
207     struct linger linger;
208 #endif                          /* SO_DONTLINGER */
209 #endif
210     char MyHostName[256];
211 
212     enterprocedure("SetUpConnectionSocket");
213 
214     (void) gethostname(MyHostName, sizeof(MyHostName));
215     ScopeHost = strdup(MyHostName);
216     if (ScopeHost == NULL)
217         panic("Can't allocate memory for hostname");
218 
219 #ifdef USE_XTRANS
220     ScopePort = iport - ServerBasePort;
221     snprintf(port, sizeof(port), "%d", ScopePort);
222     if ((_X11TransMakeAllCOTSServerListeners(port, &partial, &ListenTransCount,
223                                              &ListenTransConns) >= 0) &&
224         (ListenTransCount >= 1)) {
225         if (partial) {
226             debug(4, (stderr,
227                       "Warning: Failed to establish listening connections on some transports\n"));
228         }
229         ListenTransFds = malloc(ListenTransCount * sizeof(int));
230         if (ListenTransFds == NULL)
231             panic("Can't allocate memory for ListenTransFds");
232 
233         for (i = 0; i < ListenTransCount; i++) {
234             int fd = _X11TransGetConnectionNumber(ListenTransConns[i]);
235 
236             ListenTransFds[i] = fd;
237             debug(4, (stderr, "Listening on FD %d\n", fd));
238             UsingFD(fd, NewConnection, NULL, ListenTransConns[i]);
239         }
240     }
241     else {
242         panic("Could not open any listening connections");
243     }
244 #else
245 
246     /* create the connection socket and set its parameters of use */
247     ConnectionSocket = socket(AF_INET, SOCK_STREAM, 0);
248     if (ConnectionSocket < 0) {
249         perror("socket");
250         exit(-1);
251     }
252     (void) setsockopt(ConnectionSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
253                       sizeof(int));
254 #ifdef SO_USELOOPBACK
255     (void) setsockopt(ConnectionSocket, SOL_SOCKET, SO_USELOOPBACK,
256                       (char *) NULL, 0);
257 #endif
258 #ifdef	SO_DONTLINGER
259     (void) setsockopt(ConnectionSocket, SOL_SOCKET, SO_DONTLINGER,
260                       (char *) NULL, 0);
261 #else                           /* SO_DONTLINGER */
262     linger.l_onoff = 0;
263     linger.l_linger = 0;
264     (void) setsockopt(ConnectionSocket, SOL_SOCKET, SO_LINGER, (char *) &linger,
265                       sizeof linger);
266 #endif                          /* SO_DONTLINGER */
267 
268     /* define the name and port to be used with the connection socket */
269     bzero((char *) &sin, sizeof(sin));
270     sin.sin_family = AF_INET;
271 
272     /* the address of the socket is composed of two parts: the host machine and
273        the port number.  We need the host machine address for the current host
274      */
275     {
276         /* define the host part of the address */
277         struct hostent *hp = gethostbyname(MyHostName);
278 
279         if (hp == NULL)
280             panic("No address for our host");
281         memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
282     }
283     /* new code -- INADDR_ANY should be better than using the name of the
284        host machine.  The host machine may have several different network
285        addresses.  INADDR_ANY should work with all of them at once. */
286     sin.sin_addr.s_addr = INADDR_ANY;
287 
288     port = iport;
289     sin.sin_port = htons(port);
290     ScopePort = port;
291 
292     /* bind the name and port number to the connection socket */
293     if (bind(ConnectionSocket, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
294         perror("bind");
295         exit(-1);
296     }
297 
298     debug(4, (stderr, "Socket is FD %d for %s,%d\n",
299               ConnectionSocket, ScopeHost, ScopePort));
300 
301     /* now activate the named connection socket to get messages */
302     if (listen(ConnectionSocket, BACKLOG) < 0) {
303         perror("listen");
304         exit(-1);
305     };
306 
307     /* a few more parameter settings */
308 #ifdef FD_CLOEXEC
309     (void) fcntl(ConnectionSocket, F_SETFD, FD_CLOEXEC);
310 #else
311     (void) ioctl(ConnectionSocket, FIOCLEX, 0);
312 #endif
313     /* ultrix reads hang on Unix sockets, hpux reads fail */
314 #if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux))
315     (void) fcntl(ConnectionSocket, F_SETFL, O_NONBLOCK);
316 #else
317 #ifdef FIOSNBIO
318     (void) ioctl(ConnectionSocket, FIOSNBIO, &ON);
319 #else
320     (void) fcntl(ConnectionSocket, F_SETFL, FNDELAY);
321 #endif
322 #endif
323 
324     debug(4, (stderr, "Listening on FD %d\n", ConnectionSocket));
325     UsingFD(ConnectionSocket, connectionFunc, NULL, NULL);
326 #endif
327 }
328