/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #if DXD_HAS_UNIX_SYS_INCLUDES #include #endif #include #include #include #ifdef DXD_HAS_WINSOCKETS #include #define EADDRINUSE WSAEADDRINUSE #else #include #endif #ifdef DXD_WIN #include #else #include #endif #ifndef DXD_HAS_WINSOCKETS #include #endif #if DXD_SOCKET_UNIXDOMAIN_OK #include #endif #ifndef DXD_HAS_WINSOCKETS #include #endif #include #if DXD_NEEDS_SYS_SELECT_H #include #endif #if DXD_HAS_UNIX_SYS_INCLUDES #include #endif #define SOCK_QUEUE_LENGTH 1 #define SOCK_ACCEPT_TIMEOUT 60 /* Seconds */ /* * Open a socket port and wait for a client to connect. * This opens 2 sockets (except on the server), one internet domain, and * one unix domain. It then selects on both sockets to see to which one the * ui connects, and returns the new connection, closing the one not * selected. */ int _dxfSetupServer(int pport, int *psock, struct sockaddr_in *pserver #if DXD_SOCKET_UNIXDOMAIN_OK , int *pusock, struct sockaddr_un *puserver #endif ) { int sock = -1; struct sockaddr_in server; #if DXD_SOCKET_UNIXDOMAIN_OK int usock = -1; struct sockaddr_un userver; int oldUmask; #endif struct linger sl; int length; u_short port; int fd; int sts; int oldPort; extern int errno; int tries; fd_set fds; #ifdef DXD_HAS_WINSOCKETS int width = FD_SETSIZE; #else #if DXD_HAS_GETDTABLESIZE int width = getdtablesize(); #else int width = MAXFUPLIM; #endif #endif struct timeval to; port = pport; retry: sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); fd = -1; goto error; } sl.l_onoff = 1; sl.l_linger = 0; setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&sl, sizeof(sl)); #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(sock); #endif #if DXD_SOCKET_UNIXDOMAIN_OK usock = socket(AF_UNIX, SOCK_STREAM, 0); if (usock < 0) { perror ("socket"); fd = -1; goto error; } setsockopt(usock, SOL_SOCKET, SO_LINGER, (char *)&sl, sizeof(sl)); #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(sock); #endif #endif server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(port); length = sizeof(struct sockaddr_in); /* Try to find a working port, and keep trying if you get EADDRINUSE. * If we get some other error, try a few times because we sometimes * get bad error numbers on the server. */ tries = 0; while ((sts = bind(sock, (struct sockaddr *)&server, length)) < 0 && (errno == EADDRINUSE || tries++ < 5)) { oldPort = port; server.sin_port = htons(++port); if (ntohs(server.sin_port) < oldPort) break; } if (sts < 0) { perror ("bind"); fd = -1; goto error; } if (getsockname(sock, (struct sockaddr *)&server, &length) < 0) { perror ("getsockname"); fd = -1; goto error; } #if DXD_SOCKET_UNIXDOMAIN_OK userver.sun_family = AF_UNIX; sprintf(userver.sun_path, "/tmp/.DX-unix/DX%d", port); length = sizeof (userver) - sizeof(userver.sun_path) + strlen (userver.sun_path); oldUmask = umask(0); mkdir("/tmp/.DX-unix/", 0777); chmod("/tmp/.DX-unix/", 0777); umask(oldUmask); unlink(userver.sun_path); /* Try to find a working port, and keep trying if you get EADDRINUSE. * If we get some other error, try a few times because we sometimes * get bad error numbers on the server. */ if ((sts = bind(usock, (struct sockaddr *)&userver, length)) < 0 && errno == EADDRINUSE) { oldPort = port; server.sin_port = htons(++port); close (sock); close (usock); sock = -1; usock = -1; if (ntohs(server.sin_port) > oldPort) goto retry; } if (sts < 0) { perror ("bind"); fd = -1; goto error; } #endif if (listen(sock, SOCK_QUEUE_LENGTH) < 0) { perror ("listen"); fd = -1; goto error; } #if DXD_SOCKET_UNIXDOMAIN_OK if (listen(usock, SOCK_QUEUE_LENGTH) < 0) { perror ("listen"); fd = -1; goto error; } #endif *psock = sock; *pserver = server; #if DXD_SOCKET_UNIXDOMAIN_OK *pusock = usock; *puserver = userver; #endif return (port); error: *psock = -1; #if DXD_SOCKET_UNIXDOMAIN_OK *pusock = -1; #endif return (-1); } void _dxfPrintConnectTimeOut(char *execname, char *hostname) { DXMessage("Starting %s on %s; will wait up to %d seconds for connections.", execname, hostname, SOCK_ACCEPT_TIMEOUT); } int _dxfCompleteServer(int sock, struct sockaddr_in server #if DXD_SOCKET_UNIXDOMAIN_OK , int usock, struct sockaddr_un userver #endif , int timeout ) { #if DXD_SOCKET_UNIXDOMAIN_OK int oldUmask; #endif struct linger sl; int length; u_short port; int fd; int sts; int oldPort; extern int errno; int tries; fd_set fds; #ifdef DXD_HAS_WINSOCKETS int width = FD_SETSIZE; #else #if DXD_HAS_GETDTABLESIZE int width = getdtablesize(); #else int width = MAXFUPLIM; #endif #endif struct timeval to; /* Wait (in select) for someone to connect. * if we get through the error checks, someone must want to connect to * our port, accept him/her. Otherwize, block in accept until someone * connects. If stdin is not a terminal, timeout after SOCK_ACCEPT_TIMEOUT * seconds. */ FD_ZERO(&fds); FD_SET(sock, &fds); #if DXD_SOCKET_UNIXDOMAIN_OK FD_SET(usock, &fds); #endif to.tv_sec = SOCK_ACCEPT_TIMEOUT; to.tv_usec = 0; if(timeout) sts = select(width, (SelectPtr) &fds, NULL, NULL, &to); else sts = select(width, (SelectPtr) &fds, NULL, NULL, NULL); if (sts < 0) { perror("select"); fd = -1; goto error; } else if (sts == 0) { fprintf (stderr, "connection timed out\n"); fd = -1; goto error; } if (FD_ISSET(sock, &fds)) { length = sizeof(server); if ((fd = accept(sock, (struct sockaddr *)&server, &length)) < 0) { perror ("accept"); fd = -1; goto error; } #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(fd); #endif } #if DXD_SOCKET_UNIXDOMAIN_OK else { length = sizeof (userver) - sizeof(userver.sun_path) + strlen (userver.sun_path); if ((fd = accept(usock, (struct sockaddr *)&userver, &length)) < 0) { perror ("accept"); fd = -1; goto error; } #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(fd); #endif } #endif error: #if DXD_SOCKET_UNIXDOMAIN_OK if (userver.sun_path[0] != '\0') unlink (userver.sun_path); if (usock >= 0) close (usock); #endif if (sock >= 0) close (sock); return (fd); }