2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: spc-net.c /main/9 1996/11/21 19:53:44 drk $
27 * (c) Copyright 1989, Hewlett-Packard Company, all rights reserved.
29 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
30 * (c) Copyright 1993, 1994 International Business Machines Corp. *
31 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
32 * (c) Copyright 1993, 1994 Novell, Inc. *
35 #define __need_timeval
37 #define __need_all_errors
39 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
41 #include <sys/socket.h>
42 #include <netinet/in.h>
44 #define X_INCLUDE_NETDB_H
45 #define XOS_USE_XT_LOCKING
46 #include <X11/Xos_r.h>
49 #include <bms/MemoryMgr.h>
50 #include <SPC/spc-proto.h>
51 #include "DtSvcLock.h"
53 extern int SPC_Initialized;
61 /* Variables representing the local machine (initialized only once) */
63 static struct hostent *official_hp = NULL;
64 XeString official_hostname = NULL;
67 * my_gethost will return a copy of the data returned by gethostbyname
71 /*----------------------------------------------------------------------+*/
72 static struct hostent *my_gethost(XeString hostname)
73 /*----------------------------------------------------------------------+*/
75 struct hostent *host_def, *copy;
76 int alias_count, i, addr_count, addrlen;
77 _Xgethostbynameparams host_buf;
79 host_def = _XGethostbyname(hostname, host_buf);
83 copy=(struct hostent *)XeMalloc(sizeof(struct hostent));
85 /* Copy non-pointer info */
86 memcpy((char *)copy, (char *)host_def, sizeof(struct hostent));
90 while(host_def->h_aliases[alias_count++]);
92 copy->h_aliases=(char **)XeMalloc(alias_count*(sizeof(XeString)));
95 while(host_def->h_addr_list[addr_count++]);
97 copy->h_addr_list=(char **)XeMalloc(addr_count*(sizeof(XeString)));
101 copy->h_name=SPC_copy_string(host_def->h_name);
103 /* Copy the host address. We do not use SPC_copy_string here,
104 because the address is not a string, and may have embedded
107 addrlen = host_def->h_length;
109 copy->h_addr_list[addr_count]=XeChar_NULL;
110 for (i=0; i < addr_count; i++) {
111 copy->h_addr_list[i]=(char *)XeMalloc(addrlen);
112 memcpy(copy->h_addr_list[i], host_def->h_addr_list[i], addrlen);
115 while(alias_count--) {
116 copy->h_aliases[alias_count]=SPC_copy_string(host_def->h_aliases[alias_count]);
123 * SPC_Lookup_Host will try its darndest to return a hostent structure
124 * for the passed hostname.
128 /*----------------------------------------------------------------------+*/
129 static struct hostent *SPC_Lookup_Host(XeString hostname)
130 /*----------------------------------------------------------------------+*/
133 struct hostent *official_def;
135 official_def = my_gethost(hostname);
137 SPC_Error(SPC_Unknown_Host, hostname);
141 return(official_def);
147 * SPC_Init_Local_Host_Info will initialize the local host info. It
148 * is intended to be called only once.
152 /*----------------------------------------------------------------------+*/
153 Boolean SPC_Init_Local_Host_Info(void)
154 /*----------------------------------------------------------------------+*/
157 official_hostname=(XeString) XeMalloc(MAXHOSTNAMELEN+1);
159 Xegethostname(official_hostname, MAXHOSTNAMELEN);
160 official_hostname[MAXHOSTNAMELEN]=0;
163 official_hp = SPC_Lookup_Host(official_hostname);
165 _DtSvcProcessUnlock();
166 return(official_hp != NULL);
170 * SPC_Local_Hostname takes a string indicating a hostname, and returns
171 * TRUE if it represents a local host, and FALSE if it is remote.
174 /*----------------------------------------------------------------------+*/
176 SPC_Local_Hostname(XeString hostname)
177 /*----------------------------------------------------------------------+*/
179 /* Return TRUE if the specified hostname is local, otherwise it's remote */
181 /* If no hostname specified, then local by definition */
183 if (!hostname || !*hostname) return TRUE;
189 return(XeIsLocalHostP(hostname));
194 * SPC_Open_Connection will a connection pointer to be used for any
195 * subsequent communication to the remote host. It will either return
196 * an already opened connection, or create and initialize a new one.
200 /*----------------------------------------------------------------------+*/
201 SPC_Connection_Ptr SPC_Open_Connection(XeString hostname)
202 /*----------------------------------------------------------------------+*/
204 SPC_Connection_Ptr connection;
206 XeString canonical_hostname;
209 /* I was told that XeFindShortHost was the correct routine to use here,
210 but that may change in the future. */
212 canonical_hostname=XeFindShortHost(hostname);
214 /* check for a currently open connection */
215 connection=SPC_Lookup_Connection(canonical_hostname);
217 if(connection->connected) {
218 XeFree(canonical_hostname);
222 SPC_Close_Connection(connection);
227 /* None currently open. Grab a new one & initialize it. */
229 if((connection = SPC_Make_Connection(canonical_hostname))==SPC_ERROR) {
230 SPC_Close_Connection(connection);
231 XeFree(canonical_hostname);
234 connection->local=official_hp;
235 if((connection->remote = SPC_Lookup_Host(canonical_hostname)) == SPC_ERROR) {
236 SPC_Close_Connection(connection);
237 XeFree(canonical_hostname);
241 if(SPC_Contact_Server(connection)==SPC_ERROR) {
242 SPC_Close_Connection(connection);
243 XeFree(canonical_hostname);
247 connection->connected=TRUE;
249 if(SPC_Validate_User(canonical_hostname, connection)==SPC_ERROR) {
250 SPC_Close_Connection(connection);
251 XeFree(canonical_hostname);
255 seqno=SPC_Write_Protocol_Request(connection, NULL, ENVIRON_RESET);
257 tmp_errorno = XeSPCErrorNumber;
258 if(SPC_Waitfor_Reply(connection, NULL, seqno) == SPC_ERROR) {
259 SPC_Close_Connection(connection);
261 * XeSPCErrorNumber could have been changed but want to
262 * return the value from Write_Protocol_Request to the
265 if (tmp_errorno != 0)
266 XeSPCErrorNumber = tmp_errorno;
267 XeFree(canonical_hostname);
268 _DtSvcProcessUnlock();
271 _DtSvcProcessUnlock();
273 /* We no long ever send a RESET_TERMIO request as this was hpux */
274 /* specific and VERY non-portable. */
276 if (connection->protocol_version >= 2) {
277 seqno=SPC_Write_Protocol_Request(connection, NULL, RESET_TERMIOS);
278 if(SPC_Waitfor_Reply(connection, NULL, seqno) == SPC_ERROR) {
279 SPC_Close_Connection(connection);
280 XeFree(canonical_hostname);
285 XeFree(canonical_hostname);
290 /*----------------------------------------------------------------------+*/
292 SPC_Open_Socket(SPC_Connection_Ptr conn,
294 /*----------------------------------------------------------------------+*/
297 struct servent *service;
299 conn->sid=socket(type, SOCK_STREAM, 0);
300 if(conn->sid == ERROR) {
301 SPC_Error(SPC_Bad_Socket);
305 service=getservbyname(SPC_SERVICE, SPC_PROTOCOL);
307 SPC_Error(SPC_Bad_Service, SPC_SERVICE, SPC_PROTOCOL);
311 return(service->s_port);
317 * SPC_Contact_Server will attempt to contact the server specified by
318 * the passed connection data structure. IT ASSUMES THAT ALL FIELDS
319 * EXCEPT THE SOCKET ID ARE FILLED IN!!!
323 /*----------------------------------------------------------------------+*/
325 SPC_Contact_Server(SPC_Connection_Ptr connection)
326 /*----------------------------------------------------------------------+*/
328 struct sockaddr_in saddr;
330 struct hostent *remote;
333 /* Check that the connection is initialized correctly */
336 if(!(remote=connection->remote))
338 if(connection->connected)
341 addrtype=saddr.sin_family=remote->h_addrtype;
342 if(!(saddr.sin_port=SPC_Open_Socket(connection, addrtype)))
344 memcpy(&saddr.sin_addr, remote->h_addr, remote->h_length);
346 if(connect(connection->sid, (struct sockaddr *)&saddr, sizeof(saddr)) == ERROR) {
347 XeString shorthost = XeFindShortHost(remote->h_name);
348 SPC_Error(SPC_Bad_Connect, shorthost);
359 **** Server (daemon) side code
364 #define MAX_SERVER_BIND_ATTEMPTS 30
365 #define SERVER_PAUSE_INTERVAL 10
367 /*----------------------------------------------------------------------+*/
368 SPC_Connection_Ptr SPC_Init_Child(SPC_Connection_Ptr conn,
370 /*----------------------------------------------------------------------+*/
372 /* We are the child. Close the connection file descriptor
373 (which is the socket, not our input). */
376 /* Make the from file descriptor correspond to STDIN/STDOUT */
381 /* make conn point to STDIN */
388 SPC_Connection_Ptr SPC_Standalone_Daemon(SPC_Connection_Ptr conn)
390 struct sockaddr_in saddr, client_saddr;
391 int len=sizeof(client_saddr);
392 int server_bind_attempts = MAX_SERVER_BIND_ATTEMPTS;
393 int server_bind_pause = SERVER_PAUSE_INTERVAL;
396 int on=1; /* required by setsockopt */
399 saddr.sin_family=AF_INET;
400 if(!(saddr.sin_port=SPC_Open_Socket(conn, saddr.sin_family)))
402 saddr.sin_addr.s_addr=INADDR_ANY; /* Any host address */
404 /* Reuse the socket address if it is still in a timeout state */
407 if (setsockopt(conn->sid, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))==ERROR) {
409 if (setsockopt(conn->sid, SOL_SOCKET, SO_REUSEADDR, NULL, 0)==ERROR) {
411 SPC_Error(SPC_Bad_Reuse);
415 while (bind(conn->sid, (struct sockaddr *)&saddr, sizeof(saddr)) == ERROR) {
416 if (errno == EADDRINUSE) {
417 SPC_Error(SPC_Bind_Timeout);
418 /* Try to get the connection in a little while */
419 if (server_bind_attempts > 0) {
420 server_bind_attempts--;
421 sleep(server_bind_pause);
424 /* We don't want to wait forever */
425 SPC_Error(SPC_Timeout);
429 SPC_Error(SPC_Bad_Bind);
434 /* Set up a queue for incoming connection requests */
436 listen(conn->sid, BACKLOG);
438 /* We are running standalone, so we need to loop forever waiting for
439 requests. When we get one, we will fork a child to take care of
440 the processing for us, and then the parent will listen some more */
443 struct hostent *addr_ret;
444 _Xgethostbynameparams addr_buf;
446 /* Attempt to accept a connection with a client */
448 from = accept(conn->sid, (struct sockaddr *)&client_saddr, &len);
450 SPC_Error(SPC_Bad_Accept);
454 addr_ret = _XGethostbyaddr((char *)&client_saddr.sin_addr,
455 sizeof(client_saddr.sin_addr),
456 client_saddr.sin_family,
459 conn->remote = addr_ret;
460 strncpy(conn->hostname, conn->remote->h_name, MAXHOSTNAMELEN);
465 /* Fork a process to handle I/O from/to client */
470 SPC_Error(SPC_Cannot_Fork);
471 /* We don't return here, but simply go around for a new try */
475 /* We are the child. Do whatever processing we need to do
476 on the connection & return */
477 return(SPC_Init_Child(conn, from));
478 /* Otherwise, we are still the parent. Loop around for another
479 connection request */
483 /*----------------------------------------------------------------------+*/
485 SPC_Inetd_Daemon(SPC_Connection_Ptr conn)
486 /*----------------------------------------------------------------------+*/
492 /*----------------------------------------------------------------------+*/
493 SPC_Connection_Ptr SPC_Start_Daemon(int standalone)
494 /*----------------------------------------------------------------------+*/
497 SPC_Connection_Ptr connection;
499 /* Do whatever it takes to initialize SPC */
501 if (!SPC_Initialized)
502 if(SPC_Initialize()==SPC_ERROR) {
503 _DtSvcProcessUnlock();
506 _DtSvcProcessUnlock();
508 /* Get ourselves a connection structure. We don't know the name
509 of the remote client yet, so use the null string as hostname */
511 if((connection=SPC_Make_Connection(NULL))==SPC_ERROR)
513 connection->local=official_hp;
515 if((SPC_Standalone_Daemon(connection))==SPC_ERROR)
518 if((SPC_Inetd_Daemon(connection))==SPC_ERROR)
521 connection->connected=TRUE;