1 /* $XConsortium: spc-net.c /main/9 1996/11/21 19:53:44 drk $
5 * (c) Copyright 1989, Hewlett-Packard Company, all rights reserved.
7 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
8 * (c) Copyright 1993, 1994 International Business Machines Corp. *
9 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
10 * (c) Copyright 1993, 1994 Novell, Inc. *
13 #define __need_timeval
15 #define __need_all_errors
17 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
19 #include <sys/socket.h>
20 #include <netinet/in.h>
22 #define X_INCLUDE_NETDB_H
23 #define XOS_USE_XT_LOCKING
24 #include <X11/Xos_r.h>
27 #include <bms/MemoryMgr.h>
28 #include <SPC/spc-proto.h>
29 #include "DtSvcLock.h"
31 extern int SPC_Initialized;
39 /* Variables representing the local machine (initialized only once) */
41 static struct hostent *official_hp = NULL;
42 XeString official_hostname = NULL;
45 * my_gethost will return a copy of the data returned by gethostbyname
49 /*----------------------------------------------------------------------+*/
50 static struct hostent *my_gethost(XeString hostname)
51 /*----------------------------------------------------------------------+*/
53 struct hostent *host_def, *copy;
54 int alias_count, i, addr_count, addrlen;
55 _Xgethostbynameparams host_buf;
57 host_def = _XGethostbyname(hostname, host_buf);
61 copy=(struct hostent *)XeMalloc(sizeof(struct hostent));
63 /* Copy non-pointer info */
64 memcpy((char *)copy, (char *)host_def, sizeof(struct hostent));
68 while(host_def->h_aliases[alias_count++]);
70 copy->h_aliases=(char **)XeMalloc(alias_count*(sizeof(XeString)));
73 while(host_def->h_addr_list[addr_count++]);
75 copy->h_addr_list=(char **)XeMalloc(addr_count*(sizeof(XeString)));
79 copy->h_name=SPC_copy_string(host_def->h_name);
81 /* Copy the host address. We do not use SPC_copy_string here,
82 because the address is not a string, and may have embedded
85 addrlen = host_def->h_length;
87 copy->h_addr_list[addr_count]=XeChar_NULL;
88 for (i=0; i < addr_count; i++) {
89 copy->h_addr_list[i]=(char *)XeMalloc(addrlen);
90 memcpy(copy->h_addr_list[i], host_def->h_addr_list[i], addrlen);
93 while(alias_count--) {
94 copy->h_aliases[alias_count]=SPC_copy_string(host_def->h_aliases[alias_count]);
101 * SPC_Lookup_Host will try its darndest to return a hostent structure
102 * for the passed hostname.
106 /*----------------------------------------------------------------------+*/
107 static struct hostent *SPC_Lookup_Host(XeString hostname)
108 /*----------------------------------------------------------------------+*/
111 struct hostent *official_def;
113 official_def = my_gethost(hostname);
115 SPC_Error(SPC_Unknown_Host, hostname);
119 return(official_def);
125 * SPC_Init_Local_Host_Info will initialize the local host info. It
126 * is intended to be called only once.
130 /*----------------------------------------------------------------------+*/
131 Boolean SPC_Init_Local_Host_Info(void)
132 /*----------------------------------------------------------------------+*/
135 official_hostname=(XeString) XeMalloc(MAXHOSTNAMELEN+1);
137 Xegethostname(official_hostname, MAXHOSTNAMELEN);
138 official_hostname[MAXHOSTNAMELEN]=0;
141 official_hp = SPC_Lookup_Host(official_hostname);
143 _DtSvcProcessUnlock();
144 return(official_hp != NULL);
148 * SPC_Local_Hostname takes a string indicating a hostname, and returns
149 * TRUE if it represents a local host, and FALSE if it is remote.
152 /*----------------------------------------------------------------------+*/
153 SPC_Local_Hostname(XeString hostname)
154 /*----------------------------------------------------------------------+*/
156 /* Return TRUE if the specified hostname is local, otherwise it's remote */
158 /* If no hostname specified, then local by definition */
160 if (!hostname || !*hostname) return TRUE;
166 return(XeIsLocalHostP(hostname));
171 * SPC_Open_Connection will a connection pointer to be used for any
172 * subsequent communication to the remote host. It will either return
173 * an already opened connection, or create and initialize a new one.
177 /*----------------------------------------------------------------------+*/
178 SPC_Connection_Ptr SPC_Open_Connection(XeString hostname)
179 /*----------------------------------------------------------------------+*/
181 SPC_Connection_Ptr connection;
183 XeString canonical_hostname;
186 /* I was told that XeFindShortHost was the correct routine to use here,
187 but that may change in the future. */
189 canonical_hostname=XeFindShortHost(hostname);
191 /* check for a currently open connection */
192 connection=SPC_Lookup_Connection(canonical_hostname);
194 if(connection->connected) {
195 XeFree(canonical_hostname);
199 SPC_Close_Connection(connection);
204 /* None currently open. Grab a new one & initialize it. */
206 if((connection = SPC_Make_Connection(canonical_hostname))==SPC_ERROR) {
207 SPC_Close_Connection(connection);
208 XeFree(canonical_hostname);
211 connection->local=official_hp;
212 if((connection->remote = SPC_Lookup_Host(canonical_hostname)) == SPC_ERROR) {
213 SPC_Close_Connection(connection);
214 XeFree(canonical_hostname);
218 if(SPC_Contact_Server(connection)==SPC_ERROR) {
219 SPC_Close_Connection(connection);
220 XeFree(canonical_hostname);
224 connection->connected=TRUE;
226 if(SPC_Validate_User(canonical_hostname, connection)==SPC_ERROR) {
227 SPC_Close_Connection(connection);
228 XeFree(canonical_hostname);
232 seqno=SPC_Write_Protocol_Request(connection, NULL, ENVIRON_RESET);
234 tmp_errorno = XeSPCErrorNumber;
235 if(SPC_Waitfor_Reply(connection, NULL, seqno) == SPC_ERROR) {
236 SPC_Close_Connection(connection);
238 * XeSPCErrorNumber could have been changed but want to
239 * return the value from Write_Protocol_Request to the
242 if (tmp_errorno != 0)
243 XeSPCErrorNumber = tmp_errorno;
244 XeFree(canonical_hostname);
245 _DtSvcProcessUnlock();
248 _DtSvcProcessUnlock();
250 /* We no long ever send a RESET_TERMIO request as this was hpux */
251 /* specific and VERY non-portable. */
253 if (connection->protocol_version >= 2) {
254 seqno=SPC_Write_Protocol_Request(connection, NULL, RESET_TERMIOS);
255 if(SPC_Waitfor_Reply(connection, NULL, seqno) == SPC_ERROR) {
256 SPC_Close_Connection(connection);
257 XeFree(canonical_hostname);
262 XeFree(canonical_hostname);
267 /*----------------------------------------------------------------------+*/
268 SPC_Open_Socket(SPC_Connection_Ptr conn,
270 /*----------------------------------------------------------------------+*/
273 struct servent *service;
275 conn->sid=socket(type, SOCK_STREAM, NULL);
276 if(conn->sid == ERROR) {
277 SPC_Error(SPC_Bad_Socket);
281 service=getservbyname(SPC_SERVICE, SPC_PROTOCOL);
283 SPC_Error(SPC_Bad_Service, SPC_SERVICE, SPC_PROTOCOL);
287 return(service->s_port);
293 * SPC_Contact_Server will attempt to contact the server specified by
294 * the passed connection data structure. IT ASSUMES THAT ALL FIELDS
295 * EXCEPT THE SOCKET ID ARE FILLED IN!!!
299 /*----------------------------------------------------------------------+*/
300 SPC_Contact_Server(SPC_Connection_Ptr connection)
301 /*----------------------------------------------------------------------+*/
303 struct sockaddr_in saddr;
305 struct hostent *remote;
308 /* Check that the connection is initialized correctly */
311 if(!(remote=connection->remote))
313 if(connection->connected)
316 addrtype=saddr.sin_family=remote->h_addrtype;
317 if(!(saddr.sin_port=SPC_Open_Socket(connection, addrtype)))
319 memcpy(&saddr.sin_addr, remote->h_addr, remote->h_length);
321 if(connect(connection->sid, (struct sockaddr *)&saddr, sizeof(saddr)) == ERROR) {
322 SPC_Error(SPC_Bad_Connect,
323 XeFindShortHost(remote->h_name));
332 **** Server (daemon) side code
337 #define MAX_SERVER_BIND_ATTEMPTS 30
338 #define SERVER_PAUSE_INTERVAL 10
340 /*----------------------------------------------------------------------+*/
341 SPC_Connection_Ptr SPC_Init_Child(SPC_Connection_Ptr conn,
343 /*----------------------------------------------------------------------+*/
345 /* We are the child. Close the connection file descriptor
346 (which is the socket, not our input). */
349 /* Make the from file descriptor correspond to STDIN/STDOUT */
354 /* make conn point to STDIN */
361 SPC_Connection_Ptr SPC_Standalone_Daemon(SPC_Connection_Ptr conn)
363 struct sockaddr_in saddr, client_saddr;
365 /* Only UnixWare 2.02 uses the Spec1170 parameter profile for accept(). */
366 size_t len=sizeof(client_saddr);
368 int len=sizeof(client_saddr);
370 int server_bind_attempts = MAX_SERVER_BIND_ATTEMPTS;
371 int server_bind_pause = SERVER_PAUSE_INTERVAL;
374 int on=1; /* required by setsockopt */
377 saddr.sin_family=AF_INET;
378 if(!(saddr.sin_port=SPC_Open_Socket(conn, saddr.sin_family)))
380 saddr.sin_addr.s_addr=INADDR_ANY; /* Any host address */
382 /* Reuse the socket address if it is still in a timeout state */
385 if (setsockopt(conn->sid, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))==ERROR) {
387 if (setsockopt(conn->sid, SOL_SOCKET, SO_REUSEADDR, NULL, NULL)==ERROR) {
389 SPC_Error(SPC_Bad_Reuse);
393 while (bind(conn->sid, (struct sockaddr *)&saddr, sizeof(saddr)) == ERROR) {
394 if (errno == EADDRINUSE) {
395 SPC_Error(SPC_Bind_Timeout);
396 /* Try to get the connection in a little while */
397 if (server_bind_attempts > 0) {
398 server_bind_attempts--;
399 sleep(server_bind_pause);
402 /* We don't want to wait forever */
403 SPC_Error(SPC_Timeout);
407 SPC_Error(SPC_Bad_Bind);
412 /* Set up a queue for incoming connection requests */
414 listen(conn->sid, BACKLOG);
416 /* We are running standalone, so we need to loop forever waiting for
417 requests. When we get one, we will fork a child to take care of
418 the processing for us, and then the parent will listen some more */
421 struct hostent *addr_ret;
422 _Xgethostbynameparams addr_buf;
424 /* Attempt to accept a connection with a client */
426 from = accept(conn->sid, (struct sockaddr *)&client_saddr, &len);
428 SPC_Error(SPC_Bad_Accept);
432 addr_ret = _XGethostbyaddr((char *)&client_saddr.sin_addr,
433 sizeof(client_saddr.sin_addr),
434 client_saddr.sin_family,
437 conn->remote = addr_ret;
438 strncpy(conn->hostname, conn->remote->h_name, MAXHOSTNAMELEN);
443 /* Fork a process to handle I/O from/to client */
448 SPC_Error(SPC_Cannot_Fork);
449 /* We don't return here, but simply go around for a new try */
453 /* We are the child. Do whatever processing we need to do
454 on the connection & return */
455 return(SPC_Init_Child(conn, from));
456 /* Otherwise, we are still the parent. Loop around for another
457 connection request */
461 /*----------------------------------------------------------------------+*/
462 SPC_Inetd_Daemon(SPC_Connection_Ptr conn)
463 /*----------------------------------------------------------------------+*/
469 /*----------------------------------------------------------------------+*/
470 SPC_Connection_Ptr SPC_Start_Daemon(int standalone)
471 /*----------------------------------------------------------------------+*/
474 SPC_Connection_Ptr connection;
476 /* Do whatever it takes to initialize SPC */
478 if (!SPC_Initialized)
479 if(SPC_Initialize()==SPC_ERROR) {
480 _DtSvcProcessUnlock();
483 _DtSvcProcessUnlock();
485 /* Get ourselves a connection structure. We don't know the name
486 of the remote client yet, so use the null string as hostname */
488 if((connection=SPC_Make_Connection(NULL))==SPC_ERROR)
490 connection->local=official_hp;
492 if((SPC_Standalone_Daemon(connection))==SPC_ERROR)
495 if((SPC_Inetd_Daemon(connection))==SPC_ERROR)
498 connection->connected=TRUE;